Adds Binding example a of one-to-many relation between a Character and multiple Skills (#15)

Erweitert das PlayerCharacterDataModel um zwei Arrays welche andere eine Ansammlung von DocumentTypes entgegennehmen können. Diese können dann in dem characterSheet.mjs ausgewertet werden (von den verknüpften Dokumenten muss jeweils der Konstruktor aufgerufen werden) und dann via context injection im Template angezeigt werden.

Um aktuell via Developer Konsole in Foundry Felder hinzuzufügen wird folgendes benutzt:

```javascript
game.actors.getName(<Name des Akteurs>).update({"system": {"talente": [ game.items.getName(<Name des Talents>)/*, ...weitere Talente */ ]}})
```

Dies können wir für Basis Talente nutzen wenn ein Charakter angelegt wird.

Co-authored-by: macniel <yuna.baehr@proton.me>
Reviewed-on: #15
pull/38/head
macniel 2025-09-27 21:59:47 +02:00
parent ecece11f8b
commit cfb7abc803
10 changed files with 2000 additions and 48 deletions

8
.idea/.gitignore vendored 100644
View File

@ -0,0 +1,8 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

1855
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -16,6 +16,7 @@
"@foundryvtt/foundryvtt-cli": "^3.0.0",
"cb": "^0.1.1",
"del": "^8.0.1",
"fvtt-types": "npm:@league-of-foundry-developers/foundry-vtt-types@^13.346.0-beta.20250812191140",
"gulp": "^5.0.1",
"gulp-replace": "^1.1.4",
"gulp-sass": "^6.0.1",

View File

@ -1,6 +1,7 @@
import { PlayerCharacterDataModel } from "./module/character/character.mjs";
import { PlayerCharacterDataModel } from "./module/data/character.mjs";
import { SkillSheet } from "./module/sheets/skillSheet.mjs";
import { SpellSheet } from "./module/sheets/spellSheet.mjs";
import { CharacterSheet } from "./module/sheets/characterSheet.mjs";
import { SkillDataModel } from "./module/data/skill.mjs";
import { SpellDataModel } from "./module/data/spell.mjs";
import { Character } from "./module/documents/character.mjs";
@ -22,6 +23,12 @@ Hooks.once("init", () => {
console.log("DSA 4.1 is ready for development!")
Actors.registerSheet('dsa41.character', CharacterSheet, {
types: ["character"],
makeDefault: true,
label: 'DSA41.CharacterLabels.Item'
})
// Register sheet application classes
Items.registerSheet('dsa41.skill', SkillSheet, {
types: ["Skill"],

View File

@ -1,8 +1,8 @@
import { Skill } from "./Items/skill.mjs";
import { Spell } from "./Items/spell.mjs";
import {SkillDataModel} from "./skill.mjs";
import {SpellDataModel} from "./spell.mjs";
const {
SchemaField, NumberField, StringField, ArrayField, BooleanField, EmbeddedCollectionField,
SchemaField, NumberField, StringField, ArrayField, BooleanField, ForeignDocumentField
} = foundry.data.fields;
export class PlayerCharacterDataModel extends foundry.abstract.TypeDataModel {
@ -43,17 +43,13 @@ export class PlayerCharacterDataModel extends foundry.abstract.TypeDataModel {
so: new NumberField({ required: true, integer: true }),
gilde: new StringField(),
}),
talente: new EmbeddedCollectionField( { model: Skill }),
zauber: new EmbeddedCollectionField( { model: Spell }),
liturgien: new ArrayField(new SchemaField({
name: new StringField(),
})),
kampfwerte: new ArrayField(new SchemaField({
name: new StringField(),
at: new NumberField({ required: true, integer: true }),
pa: new NumberField({ required: true, integer: true }),
})),
talente: new ArrayField ( new ForeignDocumentField(Item) ),
zauber: new ArrayField ( new ForeignDocumentField(Item) ),
}
}
_initialize(options) {
super._initialize(options);
}
}

View File

@ -1,9 +1,10 @@
export class Character extends Item {
export class Character extends Actor {
/**
* Augment the basic Item data model with additional dynamic data.
*/
prepareData() {
super.prepareData();
this.prepareEmbeddedDocuments();
}
}

View File

@ -0,0 +1,62 @@
export class CharacterSheet extends ActorSheet {
/**@override */
static get defaultOptions() {
return foundry.utils.mergeObject(super.defaultOptions, {
classes: ['dsa41', 'sheet', 'actor', 'character'],
width: 520,
height: 480,
tabs: [
{
navSelector: '.sheet-tabs',
contentSelector: '.sheet-body',
initial: 'description',
},
],
});
}
/** @override */
get template() {
return `systems/DSA_4-1/templates/actor/actor-character-sheet.hbs`;
}
/** @override */
getData() {
// Retrieve the data structure from the base sheet. You can inspect or log
// the context variable to see the structure, but some key properties for
// sheets are the actor object, the data object, whether or not it's
// editable, the items array, and the effects array.
const context = super.getData();
// Use a safe clone of the actor data for further operations.
const actorData = context.data;
// Add the actor's data to context.data for easier access, as well as flags.
context.system = actorData.system;
context.flags = actorData.flags;
context.skills = [];
if ( context.system.talente?.length >= 0) {
context.system.talente.forEach(talent => {
const tempTalent = talent();
console.log(tempTalent.system.probe);
context.skills.push({
talentName: tempTalent.name,
probe: `ROLLDATA(${Object.values(tempTalent.system.probe).join("/")})`
});
})
}
console.log(context);
return context;
}
activateListeners(html) {
super.activateListeners(html);
// Everything below here is only needed if the sheet is editable
if (!this.isEditable) return;
}
}

View File

@ -73,7 +73,21 @@
],
"documentTypes": {
"Actor": {
"character": {}
"character": {
"numberFields": [
"groesse", "alter", "gewicht"
],
"stringFields": [
"name"
],
"schemaFields": [
"attribute", "meta"
],
"arrayFields": [
"talente",
"zauber"
]
}
},
"Item": {
"Skill": {

View File

@ -0,0 +1,45 @@
<form class="{{cssClass}} {{actor.type}} flexcol" autocomplete="off">
{{!-- Sheet Header --}}
<header class="sheet-header">
{{!-- Header stuff goes here --}}
<img class="profile-img" src="{{actor.img}}" data-edit="img" title="{{actor.name}}" height="100" width="100"/>
<div class="header-fields">
<h1 class="charname"><input name="name" type="text" value="{{actor.name}}" placeholder="Name"/></h1>
</div>
</header>
{{!-- Sheet Tab Navigation --}}
<nav class="sheet-tabs tabs" data-group="primary">
<a class="item" data-tab="overview">Übersicht</a>
<a class="item" data-tab="skills">Talente</a>
</nav>
{{!-- Sheet Body --}}
<section class="sheet-body">
<div class="tab description" data-group="primary" data-tab="description">
<div><label>Spezies
<input type="text" name="system.meta.spezies.value" value="{{system.meta.spezies}}"/>
</label>
</div>
<div><label>Kultur<input type="text" name="system.meta.kultur.value" value="{{system.meta.kultur}}"/></label>
</div>
<div><label>Profession<input type="text" name="system.meta.profession.value"
value="{{system.meta.profession}}"/></label>
</div>
<div><label>Geschlecht<input type="text" name="system.meta.geschlecht.value"
value="{{system.meta.geschlecht}}"/></label>
</div>
</div>
<div class="tab skills" data-group="primary" data-tab="skills">
<ul>
{{#each skills}}
<li><div>
<b>{{this.talentName}}</b>
{{this.probe}}
</div></li>
{{/each}}
</ul>
</div>
</section>
</form>

View File

@ -1,27 +0,0 @@
<form class="{{cssClass}} {{actor.type}} flexcol" autocomplete="off">
{{!-- Sheet Header --}}
<header class="sheet-header">
{{!-- Header stuff goes here --}}
<img class="profile-img" src="{{actor.img}}" data-edit="img" title="{{actor.name}}" height="100" width="100"/>
<div class="header-fields">
<h1 class="charname"><input name="name" type="text" value="{{actor.name}}" placeholder="Name"/></h1>
</div>
</header>
{{!-- Sheet Tab Navigation --}}
<nav class="sheet-tabs tabs" data-group="primary">
<a class="item" data-tab="overview">Übersicht</a>
<a class="item" data-tab="skills">Talente</a>
</nav>
{{!-- Sheet Body --}}
<section class="sheet-body">
<div class="tab description" data-group="primary" data-tab="description">
<input type="text" name="system.meta.spezies.value" value="{{system.meta.spezies.value}}" />
<input type="text" name="system.meta.kultur.value" value="{{system.meta.kultur.value}}" />
<input type="text" name="system.meta.profession.value" value="{{system.meta.profession.value}}" />
<input type="text" name="system.meta.geschlecht.value" value="{{system.meta.geschlecht.value}}" />
</div>
</section>
</form>