Compare commits

..

3 Commits

12 changed files with 228 additions and 126 deletions

View File

@ -5,7 +5,7 @@ import {getRandomValues} from 'node:crypto';
import * as dartSass from 'sass';
import gulpSass from 'gulp-sass';
import {deleteAsync} from 'del';
import {readdirSync, readFileSync, writeFileSync, rmdirSync, existsSync, mkdirSync} from "fs";
import {readdirSync, readFileSync, writeFileSync, rmdirSync, existsSync, mkdirSync, statSync} from "fs";
import {join} from 'node:path';
import {compilePack} from '@foundryvtt/foundryvtt-cli';
@ -30,36 +30,46 @@ function randomID(length = 16) {
return id;
}
const convert = function (from, to, ofType) {
const convert = function (from, to, ofType, overwrite = true) {
const SOURCE = from;
const DEST = to;
const TYPE = ofType;
try {
rmdirSync(DEST, {force: true, recursive: true})
} catch (e) {
}
mkdirSync(DEST)
readdirSync(SOURCE).forEach(file => {
console.log(file)
let originalSource = JSON.parse(readFileSync(join(SOURCE, file), {encoding: "utf8"}));
let id = randomID();
let targetSource = {
_id: id,
_key: "!items!" + id,
type: TYPE,
img: originalSource.image,
name: originalSource.name.trim(),
system: {...originalSource},
if (overwrite) {
try {
rmdirSync(DEST, {force: true, recursive: true})
} catch (e) {
}
delete targetSource.system.image;
let target = JSON.stringify(targetSource, null, 2);
let newFileName = "./" + join(DEST, id + ".json");
writeFileSync(newFileName, target, {encoding: "utf8"});
});
mkdirSync(DEST)
}
const filewalker = (source) => {
console.log("entering directory", source);
readdirSync(source).forEach(file => {
if (statSync(join(source, file)).isDirectory()) {
filewalker(join(source, file));
} else {
let originalSource = JSON.parse(readFileSync(join(source, file), {encoding: "utf8"}));
let id = randomID();
let targetSource = {
_id: id,
_key: "!items!" + id,
type: TYPE,
img: originalSource.image,
name: originalSource.name.trim(),
system: {...originalSource},
}
delete targetSource.system.image;
let target = JSON.stringify(targetSource, null, 2);
let newFileName = "./" + join(DEST, id + ".json");
writeFileSync(newFileName, target, {encoding: "utf8"});
}
});
}
filewalker(SOURCE)
}
@ -99,7 +109,8 @@ async function prepareDB() {
convert("./src/packs/_source/talente", "./src/packs/__source/talente", "Skill");
convert("./src/packs/_source/zauber", "./src/packs/__source/zauber", "Spell");
convert("./src/packs/_source/vorteile", "./src/packs/__source/vorteile", "Advantage");
convert("./src/packs/_source/nachteile", "./src/packs/__source/vorteile", "Advantage");
convert("./src/packs/_source/nachteile", "./src/packs/__source/vorteile", "Advantage", false);
convert("./src/packs/_source/sonderfertigkeiten", "./src/packs/__source/sonderfertigkeiten", "SpecialAbility");
convert("./src/packs/_source/waffen", "./src/packs/__source/waffen", "Equipment");
convert("./src/packs/_source/munition", "./src/packs/__source/munition", "Equipment");
convert("./src/packs/_source/ruestzeug", "./src/packs/__source/ruestzeug", "Equipment");

View File

@ -1,12 +1,28 @@
import BaseItem from "./base-item.mjs";
const {BooleanField, NumberField, SchemaField, ArrayField, StringField, HTMLField} = foundry.data.fields;
const {
BooleanField,
NumberField,
SchemaField,
ArrayField,
StringField,
HTMLField,
ObjectField
} = foundry.data.fields;
export class SpecialAbilityDataModel extends BaseItem {
static defineSchema() {
return {
name: new StringField()
name: new StringField(),
seite: new NumberField(),
aktionsText: new HTMLField(),
text: new HTMLField(),
requirements: new ObjectField(), // TODO something more meaningful with this data
waffenLimit: new ArrayField(
new StringField(),
),
mehrereAktionen: new BooleanField(),
}
}
}

View File

@ -18,9 +18,9 @@ export class SpecialAbilitySheet extends HandlebarsApplicationMixin(DocumentShee
static TABS = {
sheet: {
tabs: [
{id: 'json', group: 'sheet', label: 'JSON'},
{id: 'specialability', group: 'sheet', label: 'Sonderfertigkeit'},
],
initial: 'json'
initial: 'specialability'
}
}
@ -29,8 +29,8 @@ export class SpecialAbilitySheet extends HandlebarsApplicationMixin(DocumentShee
form: {
template: `systems/DSA_4-1/templates/item/specialability/main-sheet.hbs`
},
json: {
template: `systems/DSA_4-1/templates/item/specialability/tab-json.hbs`
specialability: {
template: `systems/DSA_4-1/templates/item/specialability/tab-specialability.hbs`
},
}
@ -55,7 +55,9 @@ export class SpecialAbilitySheet extends HandlebarsApplicationMixin(DocumentShee
context.system = specialabilityData.system;
context.flags = specialabilityData.flags;
context.json = JSON.stringify(specialabilityData);
context.text = specialabilityData.system.text;
context.aktionsText = specialabilityData.system.aktionsText;
return context;
}

View File

@ -3,6 +3,7 @@ import {Blessing} from "../documents/blessing.mjs";
import {Profession} from "../documents/profession.mjs";
import {Culture} from "../documents/culture.mjs";
import {Species} from "../documents/species.mjs";
import {SpecialAbility} from "../documents/specialAbility.mjs";
export class XmlImport {
#months = [
@ -273,7 +274,7 @@ export class XmlImport {
}
}
}
json.sonderfertigkeiten = specialAbilities
this.#mapSpecialAbilities(actor, specialAbilities)
json.liturgien = liturgies
let combatValues = []
@ -510,6 +511,33 @@ export class XmlImport {
})
}
async #mapSpecialAbilities(actor, specialAbilities) {
if (actor.itemTypes["SpecialAbility"].length > 0) {
actor.itemTypes["SpecialAbility"].forEach(s => {
actor.items.get(s._id).delete()
})
}
specialAbilities.forEach((specialAbility) => {
const compendiumOfSF = game.packs.get('DSA_4-1.sonderfertigkeiten');
const sfId = compendiumOfSF?.index.find(sf => sf.name === specialAbility.name)
if (sfId) {
compendiumOfSF.getDocument(sfId._id).then(sf => actor.createEmbeddedDocuments('Item', [sf]))
} else {
actor.createEmbeddedDocuments('Item', [
new SpecialAbility({
name: specialAbility.name,
type: "SpecialAbility",
system: {
description: specialAbility.auswahl?.wahl?.join("\n"),
}
})
])
}
})
}
async #mapSpezies(actor, spezies) {
if (actor.itemTypes["Species"].length > 0) {
actor.itemTypes["Species"].forEach(s => {

View File

@ -3,7 +3,7 @@
@use "../atoms/colours" as colour;
@use "./character-tabs/meta";
@use "./character-tabs/social";
@use "./character-tabs/attributes";
@use "./character-tabs/advsf";
@use "./character-tabs/inventory";
@use "./character-tabs/combat";
@use "./character-tabs/spells";
@ -78,8 +78,8 @@
@include social.tab;
}
.tab.attributes.active {
@include attributes.tab;
.tab.advsf.active {
@include advsf.tab;
}
.tab.equipment.active {

View File

@ -0,0 +1,77 @@
@mixin tab {
.advantages-and-specialabilities {
display: flex;
height: unset;
gap: 8px;
}
.advantages, .special-abilities {
margin-bottom: 16px;
ul {
list-style-type: none;
padding: 0;
margin: 0;
text-indent: 0;
li {
display: inline-block;
}
.advantage, .special-ability {
position: relative;
border: 1px solid gold;
box-shadow: 2px 2px 4px #000;
border-radius: 8px;
height: 24px;
color: gold;
text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.2);
display: inline-block;
padding: 0 8px;
margin-left: 0;
margin-bottom: 4px;
background-image: url("/systems/DSA_4-1/assets/velvet_button.png");
background-repeat: repeat-y;
background-size: cover;
span {
position: relative;
z-index: 2;
line-height: 24px;
vertical-align: middle;
}
&.special-ability {
&::after {
background: rgba(128, 0, 96, 0.5);
}
}
&::after {
content: "";
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
border-radius: 8px;
background: rgba(0, 128, 0, 0.5);
}
& + .advantage, & + .special-ability {
margin-left: 8px;
}
&.disadvantage {
font-style: italic;
&::after {
background: rgba(128, 0, 0, 0.5);
}
}
}
}
}
}

View File

@ -1,80 +0,0 @@
@mixin tab {
height: 100%;
.advantages-and-specialabilities {
height: unset;
display: unset;
gap: 0;
padding: unset;
.advantages, .special-abilities {
margin-bottom: 16px;
ul {
list-style-type: none;
padding: 0;
margin: 0;
text-indent: 0;
li {
display: inline-block;
}
.advantage, .special-ability {
position: relative;
border: 1px solid gold;
box-shadow: 2px 2px 4px #000;
border-radius: 8px;
height: 24px;
color: gold;
text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.2);
display: inline-block;
padding: 0 8px;
margin-left: 0;
margin-bottom: 4px;
background-image: url("../../assets/velvet_button.png");
background-repeat: repeat-y;
background-size: cover;
span {
position: relative;
z-index: 2;
line-height: 24px;
vertical-align: middle;
}
&.special-ability {
&::after {
background: rgba(128, 0, 96, 0.5);
}
}
&::after {
content: "";
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
border-radius: 8px;
background: rgba(0, 128, 0, 0.5);
}
& + .advantage, & + .special-ability {
margin-left: 8px;
}
&.disadvantage {
font-style: italic;
&::after {
background: rgba(128, 0, 0, 0.5);
}
}
}
}
}
}
}

View File

@ -35,7 +35,7 @@
},
{
"name": "spells",
"label": "Basiszauber",
"label": "Zauber",
"system": "DSA_4-1",
"type": "Item",
"path": "packs/zauber",
@ -43,15 +43,17 @@
},
{
"name": "liturgien",
"label": "Basisliturgien",
"label": "Liturgien",
"system": "DSA_4-1",
"type": "Item"
"type": "Item",
"path": "packs/liturgien"
},
{
"name": "sonderfertigkeiten",
"label": "Basissonderfertigkeiten",
"label": "Sonderfertigkeiten",
"system": "DSA_4-1",
"type": "Item"
"type": "Item",
"path": "packs/sonderfertigkeiten"
},
{
"name": "Advantage",

View File

@ -1,4 +1,14 @@
<div>
<!-- TODO Add this sheet with meaningful options -->
Sonderfertigkeiten bitte sei Besonders und Fertig
{{!-- Sheet Tab Navigation --}}
<nav class="sheet-tabs tabs{{#if verticalTabs}} vertical{{/if}}"
aria-roledescription="{{localize "SHEETS.FormNavLabel"}}">
{{#each tabs as |tab|}}
<a data-action="tab" data-group="{{tab.group}}" data-tab="{{tab.id}}"
{{#if tab.cssClass}}class="{{tab.cssClass}}"{{/if}}
{{#if tab.tooltip}}data-tooltip="{{tab.tooltip}}"{{/if}}>
{{#if tab.icon}}<i class="{{tab.icon}}" inert></i>{{/if}}
{{#if tab.label}}<span>{{localize tab.label}}</span>{{/if}}
</a>
{{/each}}
</nav>
</div>

View File

@ -0,0 +1,35 @@
<section class="tab {{tabs.specialability.id}} {{tabs.specialability.cssClass}}"
data-tab="{{tabs.specialability.id}}"
data-group="{{tabs.specialability.group}}">
<div>
<div>
<label>Name</label>
<input name="system.name" value="{{system.name}}"/>
</div>
<div class="body">
<label>Aktionstext</label>
<prose-mirror
name=" system.aktionsText"
button="false"
editable="{{editable}}"
toggled="true"
value="{{aktionsText}}">
{{{aktionsText}}}
</prose-mirror>
</div>
<div class="body">
<label>Beschreibung</label>
<prose-mirror
name=" system.text"
button="false"
editable="{{editable}}"
toggled="true"
value="{{text}}">
{{{text}}}
</prose-mirror>
</div>
</div>
</div>

View File

@ -1,3 +1,4 @@
<div class="advantage {{#if isDisadvantage}}disadvantage{{/if}}">
<span class="name" data-id="{{this.id}}">{{this.name}} {{#if this.value}}: {{this.value}}{{/if}}</span>
<span class="name" data-action="openEmbeddedDocument" data-item-id="{{this.id}}">{{this.name}} {{#if this.value}}
: {{this.value}}{{/if}}</span>
</div>

View File

@ -1,3 +1,3 @@
<div class="special-ability">
<span class="name" data-id="{{this.id}}">{{this.name}}</span>
<span class="name" data-action="openEmbeddedDocument" data-item-id="{{this.id}}">{{this.name}}</span>
</div>