mirror of
https://github.com/Foundryborne/daggerheart.git
synced 2026-01-13 04:01:06 +01:00
Initial datamodel
This commit is contained in:
parent
1f5b5f9915
commit
c9e123e389
15 changed files with 279 additions and 101 deletions
|
|
@ -75,6 +75,7 @@ Hooks.once('init', () => {
|
|||
|
||||
Actors.unregisterSheet('core', foundry.applications.sheets.ActorSheetV2);
|
||||
Actors.registerSheet(SYSTEM.id, applications.DhCharacterSheet, { types: ['character'], makeDefault: true });
|
||||
Actors.registerSheet(SYSTEM.id, applications.DhCompanionSheet, { types: ['companion'], makeDefault: true });
|
||||
Actors.registerSheet(SYSTEM.id, applications.DhpAdversarySheet, { types: ['adversary'], makeDefault: true });
|
||||
Actors.registerSheet(SYSTEM.id, applications.DhpEnvironment, { types: ['environment'], makeDefault: true });
|
||||
|
||||
|
|
|
|||
18
lang/en.json
18
lang/en.json
|
|
@ -14,6 +14,7 @@
|
|||
},
|
||||
"Actor": {
|
||||
"character": "Character",
|
||||
"companion": "Companion",
|
||||
"adversary": "Adversary",
|
||||
"environment": "Environment"
|
||||
}
|
||||
|
|
@ -1201,6 +1202,23 @@
|
|||
"tooLowLevel": "You cannot lower the character level below starting level"
|
||||
}
|
||||
},
|
||||
"Companion": {
|
||||
"FIELDS": {
|
||||
"partner": { "label": "Partner" },
|
||||
"evasion": {
|
||||
"value": { "label": "Evasion" }
|
||||
},
|
||||
"resources": {
|
||||
"stress": {
|
||||
"value": { "label": "Stress" }
|
||||
}
|
||||
},
|
||||
"attack": {
|
||||
"name": { "label": "Attack Name" }
|
||||
}
|
||||
},
|
||||
"Experiences": "Experiences"
|
||||
},
|
||||
"Adversary": {
|
||||
"FIELDS": {
|
||||
"tier": { "label": "Tier" },
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
export { default as DhCharacterSheet } from './sheets/character.mjs';
|
||||
export { default as DhCompanionSheet } from './sheets/companion.mjs';
|
||||
export { default as DhpAdversarySheet } from './sheets/adversary.mjs';
|
||||
export { default as DhpClassSheet } from './sheets/items/class.mjs';
|
||||
export { default as DhpSubclass } from './sheets/items/subclass.mjs';
|
||||
|
|
|
|||
35
module/applications/sheets/companion.mjs
Normal file
35
module/applications/sheets/companion.mjs
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
import DaggerheartSheet from './daggerheart-sheet.mjs';
|
||||
|
||||
const { ActorSheetV2 } = foundry.applications.sheets;
|
||||
export default class DhCompanionSheet extends DaggerheartSheet(ActorSheetV2) {
|
||||
static DEFAULT_OPTIONS = {
|
||||
tag: 'form',
|
||||
classes: ['daggerheart', 'sheet', 'actor', 'dh-style', 'companion'],
|
||||
position: { width: 700, height: 1000 },
|
||||
actions: {},
|
||||
form: {
|
||||
handler: this.updateForm,
|
||||
submitOnChange: true,
|
||||
closeOnSubmit: false
|
||||
}
|
||||
};
|
||||
|
||||
static PARTS = {
|
||||
sidebar: { template: 'systems/daggerheart/templates/sheets/actors/companion/tempMain.hbs' }
|
||||
};
|
||||
|
||||
async _prepareContext(_options) {
|
||||
const context = await super._prepareContext(_options);
|
||||
context.document = this.document;
|
||||
context.playerCharacters = game.users
|
||||
.filter(x => !x.isGM && x.character)
|
||||
.map(x => ({ key: x.character.uuid, name: x.character.name }));
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
static async updateForm(event, _, formData) {
|
||||
await this.document.update(formData.object);
|
||||
this.render();
|
||||
}
|
||||
}
|
||||
|
|
@ -244,48 +244,6 @@ export const tiers = {
|
|||
}
|
||||
};
|
||||
|
||||
export const objectTypes = {
|
||||
character: {
|
||||
name: 'TYPES.Actor.character'
|
||||
},
|
||||
npc: {
|
||||
name: 'TYPES.Actor.npc'
|
||||
},
|
||||
adversary: {
|
||||
name: 'TYPES.Actor.adversary'
|
||||
},
|
||||
ancestry: {
|
||||
name: 'TYPES.Item.ancestry'
|
||||
},
|
||||
community: {
|
||||
name: 'TYPES.Item.community'
|
||||
},
|
||||
class: {
|
||||
name: 'TYPES.Item.class'
|
||||
},
|
||||
subclass: {
|
||||
name: 'TYPES.Item.subclass'
|
||||
},
|
||||
feature: {
|
||||
name: 'TYPES.Item.feature'
|
||||
},
|
||||
domainCard: {
|
||||
name: 'TYPES.Item.domainCard'
|
||||
},
|
||||
consumable: {
|
||||
name: 'TYPES.Item.consumable'
|
||||
},
|
||||
miscellaneous: {
|
||||
name: 'TYPES.Item.miscellaneous'
|
||||
},
|
||||
weapon: {
|
||||
name: 'TYPES.Item.weapon'
|
||||
},
|
||||
armor: {
|
||||
name: 'TYPES.Item.armor'
|
||||
}
|
||||
};
|
||||
|
||||
export const diceTypes = {
|
||||
d4: 'd4',
|
||||
d6: 'd6',
|
||||
|
|
|
|||
|
|
@ -1,11 +1,13 @@
|
|||
import DhCharacter from './character.mjs';
|
||||
import DhCompanion from './companion.mjs';
|
||||
import DhAdversary from './adversary.mjs';
|
||||
import DhEnvironment from './environment.mjs';
|
||||
|
||||
export { DhCharacter, DhAdversary, DhEnvironment };
|
||||
export { DhCharacter, DhCompanion, DhAdversary, DhEnvironment };
|
||||
|
||||
export const config = {
|
||||
character: DhCharacter,
|
||||
companion: DhCompanion,
|
||||
adversary: DhAdversary,
|
||||
environment: DhEnvironment
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { burden } from '../../config/generalConfig.mjs';
|
||||
import ForeignDocumentUUIDField from '../fields/foreignDocumentUUIDField.mjs';
|
||||
import { LevelOptionType } from '../levelTier.mjs';
|
||||
import DhLevelData from '../levelData.mjs';
|
||||
import BaseDataActor from './base.mjs';
|
||||
|
||||
const attributeField = () =>
|
||||
|
|
@ -88,7 +88,7 @@ export default class DhCharacter extends BaseDataActor {
|
|||
value: new ForeignDocumentUUIDField({ type: 'Item', nullable: true }),
|
||||
subclass: new ForeignDocumentUUIDField({ type: 'Item', nullable: true })
|
||||
}),
|
||||
levelData: new fields.EmbeddedDataField(DhPCLevelData),
|
||||
levelData: new fields.EmbeddedDataField(DhLevelData),
|
||||
bonuses: new fields.SchemaField({
|
||||
attack: new fields.NumberField({ integer: true, initial: 0 }),
|
||||
spellcast: new fields.NumberField({ integer: true, initial: 0 }),
|
||||
|
|
@ -117,6 +117,13 @@ export default class DhCharacter extends BaseDataActor {
|
|||
return !this.class.value || !this.class.subclass;
|
||||
}
|
||||
|
||||
get spellcastingModifiers() {
|
||||
return {
|
||||
main: this.class.subclass?.system?.spellcastingTrait,
|
||||
multiclass: this.multiclass.subclass?.system?.spellcastingTrait
|
||||
};
|
||||
}
|
||||
|
||||
get domains() {
|
||||
const classDomains = this.class.value ? this.class.value.system.domains : [];
|
||||
const multiclassDomains = this.multiclass.value ? this.multiclass.value.system.domains : [];
|
||||
|
|
@ -260,57 +267,3 @@ export default class DhCharacter extends BaseDataActor {
|
|||
};
|
||||
}
|
||||
}
|
||||
|
||||
class DhPCLevelData extends foundry.abstract.DataModel {
|
||||
static defineSchema() {
|
||||
const fields = foundry.data.fields;
|
||||
|
||||
return {
|
||||
level: new fields.SchemaField({
|
||||
current: new fields.NumberField({ required: true, integer: true, initial: 1 }),
|
||||
changed: new fields.NumberField({ required: true, integer: true, initial: 1 })
|
||||
}),
|
||||
levelups: new fields.TypedObjectField(
|
||||
new fields.SchemaField({
|
||||
achievements: new fields.SchemaField(
|
||||
{
|
||||
experiences: new fields.TypedObjectField(
|
||||
new fields.SchemaField({
|
||||
name: new fields.StringField({ required: true }),
|
||||
modifier: new fields.NumberField({ required: true, integer: true })
|
||||
})
|
||||
),
|
||||
domainCards: new fields.ArrayField(
|
||||
new fields.SchemaField({
|
||||
uuid: new fields.StringField({ required: true }),
|
||||
itemUuid: new fields.StringField({ required: true })
|
||||
})
|
||||
),
|
||||
proficiency: new fields.NumberField({ integer: true })
|
||||
},
|
||||
{ nullable: true, initial: null }
|
||||
),
|
||||
selections: new fields.ArrayField(
|
||||
new fields.SchemaField({
|
||||
tier: new fields.NumberField({ required: true, integer: true }),
|
||||
level: new fields.NumberField({ required: true, integer: true }),
|
||||
optionKey: new fields.StringField({ required: true }),
|
||||
type: new fields.StringField({ required: true, choices: LevelOptionType }),
|
||||
checkboxNr: new fields.NumberField({ required: true, integer: true }),
|
||||
value: new fields.NumberField({ integer: true }),
|
||||
minCost: new fields.NumberField({ integer: true }),
|
||||
amount: new fields.NumberField({ integer: true }),
|
||||
data: new fields.ArrayField(new fields.StringField({ required: true })),
|
||||
secondaryData: new fields.TypedObjectField(new fields.StringField({ required: true })),
|
||||
itemUuid: new fields.StringField({ required: true })
|
||||
})
|
||||
)
|
||||
})
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
get canLevelUp() {
|
||||
return this.level.current < this.level.changed;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
84
module/data/actor/companion.mjs
Normal file
84
module/data/actor/companion.mjs
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
import BaseDataActor from './base.mjs';
|
||||
import DhLevelData from '../levelData.mjs';
|
||||
import ForeignDocumentUUIDField from '../fields/foreignDocumentUUIDField.mjs';
|
||||
|
||||
export default class DhCompanion extends BaseDataActor {
|
||||
static LOCALIZATION_PREFIXES = ['DAGGERHEART.Sheets.Companion'];
|
||||
|
||||
static get metadata() {
|
||||
return foundry.utils.mergeObject(super.metadata, {
|
||||
label: 'TYPES.Actor.companion',
|
||||
type: 'character'
|
||||
});
|
||||
}
|
||||
|
||||
static defineSchema() {
|
||||
const fields = foundry.data.fields;
|
||||
|
||||
return {
|
||||
partner: new ForeignDocumentUUIDField({ type: 'Actor' }),
|
||||
resources: new fields.SchemaField({
|
||||
stress: new fields.SchemaField({
|
||||
value: new fields.NumberField({ initial: 0, integer: true }),
|
||||
bonus: new fields.NumberField({ initial: 0, integer: true }),
|
||||
max: new fields.NumberField({ initial: 3, integer: true })
|
||||
})
|
||||
}),
|
||||
evasion: new fields.SchemaField({
|
||||
value: new fields.NumberField({ required: true, min: 1, initial: 10, integer: true }),
|
||||
bonus: new fields.NumberField({ initial: 0, integer: true })
|
||||
}),
|
||||
experiences: new fields.TypedObjectField(
|
||||
new fields.SchemaField({
|
||||
description: new fields.StringField({}),
|
||||
value: new fields.NumberField({ integer: true, initial: 0 }),
|
||||
bonus: new fields.NumberField({ integer: true, initial: 0 })
|
||||
}),
|
||||
{
|
||||
initial: {
|
||||
experience1: { value: 2 },
|
||||
experience2: { value: 2 }
|
||||
}
|
||||
}
|
||||
),
|
||||
attack: new fields.SchemaField({
|
||||
name: new fields.StringField({}),
|
||||
range: new fields.StringField({
|
||||
required: true,
|
||||
choices: SYSTEM.GENERAL.range,
|
||||
initial: SYSTEM.GENERAL.range.melee.id
|
||||
}),
|
||||
damage: new fields.SchemaField({
|
||||
value: new fields.StringField({ initial: 'd6' }),
|
||||
type: new fields.StringField({
|
||||
required: true,
|
||||
choices: SYSTEM.GENERAL.damageTypes,
|
||||
initial: SYSTEM.GENERAL.damageTypes.physical.id
|
||||
})
|
||||
})
|
||||
}),
|
||||
levelData: new fields.EmbeddedDataField(DhLevelData)
|
||||
};
|
||||
}
|
||||
|
||||
prepareBaseData() {
|
||||
this.attack.modifier = this.partner?.system?.spellcastingModifiers?.main ?? 0; // Needs to expand on which modifier it is that should be used because of multiclassing;
|
||||
}
|
||||
|
||||
prepareDerivedData() {
|
||||
for (var experienceKey in this.experiences) {
|
||||
var experience = this.experiences[experienceKey];
|
||||
experience.total = experience.value + experience.bonus;
|
||||
}
|
||||
|
||||
this.resources.stress.maxTotal = this.resources.stress.max + this.resources.stress.bonus;
|
||||
this.evasion.total = this.evasion.value + this.evasion.bonus;
|
||||
}
|
||||
|
||||
getRollData() {
|
||||
const data = super.getRollData();
|
||||
return {
|
||||
...data
|
||||
};
|
||||
}
|
||||
}
|
||||
55
module/data/levelData.mjs
Normal file
55
module/data/levelData.mjs
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
import { LevelOptionType } from './levelTier.mjs';
|
||||
|
||||
export default class DhLevelData extends foundry.abstract.DataModel {
|
||||
static defineSchema() {
|
||||
const fields = foundry.data.fields;
|
||||
|
||||
return {
|
||||
level: new fields.SchemaField({
|
||||
current: new fields.NumberField({ required: true, integer: true, initial: 1 }),
|
||||
changed: new fields.NumberField({ required: true, integer: true, initial: 1 })
|
||||
}),
|
||||
levelups: new fields.TypedObjectField(
|
||||
new fields.SchemaField({
|
||||
achievements: new fields.SchemaField(
|
||||
{
|
||||
experiences: new fields.TypedObjectField(
|
||||
new fields.SchemaField({
|
||||
name: new fields.StringField({ required: true }),
|
||||
modifier: new fields.NumberField({ required: true, integer: true })
|
||||
})
|
||||
),
|
||||
domainCards: new fields.ArrayField(
|
||||
new fields.SchemaField({
|
||||
uuid: new fields.StringField({ required: true }),
|
||||
itemUuid: new fields.StringField({ required: true })
|
||||
})
|
||||
),
|
||||
proficiency: new fields.NumberField({ integer: true })
|
||||
},
|
||||
{ nullable: true, initial: null }
|
||||
),
|
||||
selections: new fields.ArrayField(
|
||||
new fields.SchemaField({
|
||||
tier: new fields.NumberField({ required: true, integer: true }),
|
||||
level: new fields.NumberField({ required: true, integer: true }),
|
||||
optionKey: new fields.StringField({ required: true }),
|
||||
type: new fields.StringField({ required: true, choices: LevelOptionType }),
|
||||
checkboxNr: new fields.NumberField({ required: true, integer: true }),
|
||||
value: new fields.NumberField({ integer: true }),
|
||||
minCost: new fields.NumberField({ integer: true }),
|
||||
amount: new fields.NumberField({ integer: true }),
|
||||
data: new fields.ArrayField(new fields.StringField({ required: true })),
|
||||
secondaryData: new fields.TypedObjectField(new fields.StringField({ required: true })),
|
||||
itemUuid: new fields.StringField({ required: true })
|
||||
})
|
||||
)
|
||||
})
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
get canLevelUp() {
|
||||
return this.level.current < this.level.changed;
|
||||
}
|
||||
}
|
||||
|
|
@ -11,7 +11,7 @@ export default class DhpActor extends Actor {
|
|||
|
||||
// Configure prototype token settings
|
||||
const prototypeToken = {};
|
||||
if (this.type === 'character')
|
||||
if (['character', 'companion'].includes(this.type))
|
||||
Object.assign(prototypeToken, {
|
||||
sight: { enabled: true },
|
||||
actorLink: true,
|
||||
|
|
|
|||
|
|
@ -3619,13 +3619,35 @@ div.daggerheart.views.multiclass {
|
|||
.theme-light .application.sheet.daggerheart.actor.dh-style.character .character-sidebar-sheet {
|
||||
background: transparent;
|
||||
}
|
||||
.application.sheet.daggerheart.actor.dh-style.character .character-sidebar-sheet img {
|
||||
.application.sheet.daggerheart.actor.dh-style.character .character-sidebar-sheet .portrait {
|
||||
position: relative;
|
||||
height: 235px;
|
||||
width: 275px;
|
||||
border-bottom: 1px solid light-dark(#18162e, #f3c267);
|
||||
cursor: pointer;
|
||||
}
|
||||
.application.sheet.daggerheart.actor.dh-style.character .character-sidebar-sheet .portrait img {
|
||||
height: 235px;
|
||||
width: 275px;
|
||||
object-fit: cover;
|
||||
}
|
||||
.application.sheet.daggerheart.actor.dh-style.character .character-sidebar-sheet .portrait .death-roll-btn {
|
||||
display: none;
|
||||
}
|
||||
.application.sheet.daggerheart.actor.dh-style.character .character-sidebar-sheet .portrait.death-roll {
|
||||
filter: grayscale(1);
|
||||
}
|
||||
.application.sheet.daggerheart.actor.dh-style.character .character-sidebar-sheet .portrait.death-roll .death-roll-btn {
|
||||
display: flex;
|
||||
position: absolute;
|
||||
top: 30%;
|
||||
right: 30%;
|
||||
font-size: 6rem;
|
||||
color: #efe6d8;
|
||||
}
|
||||
.application.sheet.daggerheart.actor.dh-style.character .character-sidebar-sheet .portrait.death-roll .death-roll-btn:hover {
|
||||
text-shadow: 0 0 8px #efe6d8;
|
||||
}
|
||||
.application.sheet.daggerheart.actor.dh-style.character .character-sidebar-sheet .info-section {
|
||||
position: relative;
|
||||
display: flex;
|
||||
|
|
@ -4023,6 +4045,14 @@ div.daggerheart.views.multiclass {
|
|||
scrollbar-width: thin;
|
||||
scrollbar-color: light-dark(#18162e, #f3c267) transparent;
|
||||
}
|
||||
.application.sheet.daggerheart.actor.dh-style.companion .profile {
|
||||
height: 80px;
|
||||
width: 80px;
|
||||
}
|
||||
.application.sheet.daggerheart.actor.dh-style.companion .temp-container {
|
||||
position: relative;
|
||||
top: 32px;
|
||||
}
|
||||
.application.sheet.daggerheart.actor.dh-style.adversary .window-content {
|
||||
overflow: auto;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,6 +24,8 @@
|
|||
@import './less/actors/character/biography.less';
|
||||
@import './less/actors/character/features.less';
|
||||
|
||||
@import './less/actors/companion/sheet.less';
|
||||
|
||||
@import './less/actors/adversary.less';
|
||||
@import './less/actors/environment.less';
|
||||
|
||||
|
|
|
|||
11
styles/less/actors/companion/sheet.less
Normal file
11
styles/less/actors/companion/sheet.less
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
.application.sheet.daggerheart.actor.dh-style.companion {
|
||||
.profile {
|
||||
height: 80px;
|
||||
width: 80px;
|
||||
}
|
||||
|
||||
.temp-container {
|
||||
position: relative;
|
||||
top: 32px;
|
||||
}
|
||||
}
|
||||
|
|
@ -206,6 +206,7 @@
|
|||
"character": {
|
||||
"htmlFields": ["story", "description", "scars.*.description"]
|
||||
},
|
||||
"companion": {},
|
||||
"adversary": {
|
||||
"htmlFields": ["description", "motivesAndTactics"]
|
||||
},
|
||||
|
|
|
|||
27
templates/sheets/actors/companion/tempMain.hbs
Normal file
27
templates/sheets/actors/companion/tempMain.hbs
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
<div class="temp-container standard-form">
|
||||
<img class="profile" src="{{document.img}}" alt="{{document.name}}" data-action='editImage' data-edit="img">
|
||||
<div class="form-group">
|
||||
<div class="form-fields">
|
||||
<label>{{localize "DAGGERHEART.Sheets.Companion.FIELDS.partner.label"}}</label>
|
||||
<select name="system.partner">
|
||||
{{selectOptions playerCharacters selected=source.system.partner.uuid labelAttr="name" valueAttr="key" blank=""}}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{formGroup systemFields.resources.fields.stress.fields.value value=source.system.resources.stress.value localize=true }}
|
||||
{{formGroup systemFields.evasion.fields.value value=source.system.evasion.value localize=true }}
|
||||
|
||||
<div class="flexcol">
|
||||
{{#each source.system.experiences as |experience key|}}
|
||||
<div class="flexrow">
|
||||
<input type="text" name="{{concat "system.experiences." key ".description"}}" value="{{experience.description}}" />
|
||||
<input type="text" data-dtype="Number" name="{{concat "system.experiences." key ".value"}}" value="{{experience.value}}" />
|
||||
</div>
|
||||
{{/each}}
|
||||
</div>
|
||||
|
||||
<div class="flexcol">
|
||||
{{formGroup systemFields.attack.fields.name value=source.system.attack.name localize=true }}
|
||||
</div>
|
||||
</div>
|
||||
Loading…
Add table
Add a link
Reference in a new issue