From d383667f52bc089cd67ecb52fb34e1c13539c922 Mon Sep 17 00:00:00 2001 From: juanferrer Date: Sun, 24 Nov 2024 22:26:14 +0000 Subject: [PATCH] Fully migrate ancestry to use levels and make consistent with path and role --- src/module/active-effects/item-effects.js | 155 +++----- src/module/actor/sheets/character-sheet.js | 8 +- src/module/combat/combat.js | 4 +- src/module/data/common.js | 3 +- src/module/data/item/AncestryDataModel.js | 175 +++++---- src/module/data/item/CreatureRoleDataModel.js | 16 +- src/module/data/item/PathDataModel.js | 153 +++++--- src/module/dialog/stat-editor.js | 26 +- src/module/item/item.js | 99 +++-- src/module/item/nested-objects.js | 94 +++-- src/module/item/sheets/base-item-sheet.js | 110 +++--- src/module/templates.js | 1 + src/templates/chat/formulaeroll.hbs | 6 + src/templates/item/item-ancestry-edit.hbs | 371 +++++++++--------- src/templates/item/item-ancestry-sheet.hbs | 3 - src/templates/item/item-ancestry-view.hbs | 369 +++++++++-------- src/templates/item/item-path-edit.hbs | 22 +- src/templates/item/item-path-view.hbs | 30 +- src/templates/item/item-role-edit.hbs | 12 +- src/templates/item/item-role-view.hbs | 13 +- 20 files changed, 871 insertions(+), 799 deletions(-) create mode 100644 src/templates/chat/formulaeroll.hbs diff --git a/src/module/active-effects/item-effects.js b/src/module/active-effects/item-effects.js index 86b7e049..390fb99d 100644 --- a/src/module/active-effects/item-effects.js +++ b/src/module/active-effects/item-effects.js @@ -128,51 +128,7 @@ export class DLActiveEffects { const priority = 1 const ancestryData = item.system - const effectDataList = [{ - name: `${item.name} (${game.i18n.localize('DL.CharLevel')} 0)`, - icon: item.img, - origin: item.uuid, - disabled: false, - transfer: false, - duration: { startTime: 0 }, - flags: { - sourceType: 'ancestry', - levelRequired: 0, - notDeletable: true, - notEditable: true, - notToggleable: true, - permanent: true, - slug: `ancestry-${item.name.toLowerCase()}-L0`, - }, - changes: [ - addEffect('system.attributes.strength.value', ancestryData.attributes.strength.value - 10, priority), - addEffect('system.attributes.agility.value', ancestryData.attributes.agility.value - 10, priority), - addEffect('system.attributes.intellect.value', ancestryData.attributes.intellect.value - 10, priority), - addEffect('system.attributes.will.value', ancestryData.attributes.will.value - 10, priority), - addEffect('system.attributes.perception.value', ancestryData.characteristics.perceptionmodifier, priority), - addEffect('system.attributes.strength.immune', ancestryData.attributes.strength.immune, priority), - addEffect('system.attributes.agility.immune', ancestryData.attributes.agility.immune, priority), - addEffect('system.attributes.intellect.immune', ancestryData.attributes.intellect.immune, priority), - addEffect('system.attributes.will.immune', ancestryData.attributes.will.immune, priority), - - //addEffect('system.characteristics.insanity.value', ancestryData.characteristics.insanity.value, priority), - //addEffect('system.characteristics.corruption.value', ancestryData.characteristics.corruption.value, priority), - addEffect('system.characteristics.insanity.immune', ancestryData.characteristics.insanity.immune, priority), - addEffect('system.characteristics.corruption.immune', ancestryData.characteristics.corruption.immune, priority), - addEffect('system.characteristics.defense', ancestryData.characteristics.defensemodifier, priority), - addEffect('system.characteristics.health.max', ancestryData.characteristics.healthmodifier, priority), - addEffect('system.characteristics.health.healingrate', ancestryData.characteristics.healingratemodifier, priority), - addEffect('system.characteristics.power', ancestryData.characteristics.power, priority), - addEffect('system.characteristics.speed', ancestryData.characteristics.speed - 10, priority), - { - key: 'system.characteristics.size', - value: ancestryData.characteristics.size, - mode: CONST.ACTIVE_EFFECT_MODES.OVERRIDE, - priority: priority, - }, - // overrideEffect('system.characteristics.size', dataL0.characteristics.size, priority) - ].filter(falsyChangeFilter), - }] + const effectDataList = [] ancestryData.levels.forEach(ancestryLevel => { const levelEffectData = { @@ -193,38 +149,42 @@ export class DLActiveEffects { }, changes: [ // Characteristics - addEffect('system.characteristics.health.max', ancestryLevel.characteristicsHealth, priority), - addEffect('system.characteristics.power', ancestryLevel.characteristicsPower, priority), - addEffect('system.attributes.perception.value', ancestryLevel.characteristicsPerception, priority), - addEffect('system.characteristics.speed', ancestryLevel.characteristicsSpeed, priority), - addEffect('system.characteristics.defense', ancestryLevel.characteristicsDefense, priority), + addEffect('system.characteristics.health.max', ancestryLevel.characteristics.health, priority), + addEffect('system.characteristics.health.healingrate', ancestryLevel.characteristics.healingRate, priority), + overrideEffect('system.characteristics.size', ancestryLevel.characteristics.size, priority, true), + addEffect('system.characteristics.power', ancestryLevel.characteristics.power, priority), + addEffect('system.attributes.perception.value', ancestryLevel.characteristics.perception, priority), + addEffect('system.characteristics.speed', ancestryLevel.characteristics.speed, priority), + addEffect('system.characteristics.defense', ancestryLevel.characteristics.defense, priority), + addEffect('system.characteristics.insanity.immune', ancestryLevel.characteristics.insanity.immune, priority), + addEffect('system.characteristics.corruption.immune', ancestryLevel.characteristics.corruption.immune, priority), // FIXME - // addEffect('system.characteristics.insanityModifier', pathLevel.characteristicsInsanity, priority), - // addEffect('system.characteristics.corruptionModifier', pathLevel.characteristicsCorruption, priority), - - // Selected checkbox (select two, three, fixed) - addEffect( - 'system.attributes.strength.value', - ancestryLevel.attributeStrength * (ancestryLevel.attributeStrengthSelected || ancestryLevel.attributeSelectIsFixed), - priority - ), - addEffect( - 'system.attributes.agility.value', - ancestryLevel.attributeAgility * (ancestryLevel.attributeAgilitySelected || ancestryLevel.attributeSelectIsFixed), - priority - ), - addEffect( - 'system.attributes.intellect.value', - ancestryLevel.attributeIntellect * (ancestryLevel.attributeIntellectSelected || ancestryLevel.attributeSelectIsFixed), - priority - ), - addEffect( - 'system.attributes.will.value', - ancestryLevel.attributeWill * (ancestryLevel.attributeWillSelected || ancestryLevel.attributeSelectIsFixed), - priority - ), - ].filter(falsyChangeFilter), + //addEffect('system.characteristics.insanity.value', ancestryLevel.characteristics.insanity.value, priority), + //addEffect('system.characteristics.corruption.value', ancestryLevel.characteristics.corruption.value, priority), + + // Starting attributes or selected checkbox (select two, three, fixed) + (ancestryLevel.level === '0' ? [ + addEffect('system.attributes.strength.value', ancestryLevel.attributes.strength.value - 10, priority), + addEffect('system.attributes.strength.immune', ancestryLevel.attributes.strength.immune, priority), + ] : addEffect('system.attributes.strength.value', ancestryLevel.attributes.strength.value * (ancestryLevel.attributes.strength.selected || ancestryLevel.attributeSelectIsFixed), priority)), + + (ancestryLevel.level === '0' ? [ + addEffect('system.attributes.agility.value', ancestryLevel.attributes.agility.value - 10, priority), + addEffect('system.attributes.agility.immune', ancestryLevel.attributes.agility.immune, priority), + ] : addEffect('system.attributes.agility.value', ancestryLevel.attributes.agility.value * (ancestryLevel.attributes.agility.selected || ancestryLevel.attributeSelectIsFixed), priority)), + + (ancestryLevel.level === '0' ? [ + addEffect('system.attributes.intellect.value', ancestryLevel.attributes.intellect.value - 10, priority), + addEffect('system.attributes.intellect.immune', ancestryLevel.attributes.intellect.immune, priority), + ] : addEffect('system.attributes.intellect.value', ancestryLevel.attributes.intellect.value * (ancestryLevel.attributes.intellect.selected || ancestryLevel.attributeSelectIsFixed), priority)), + + (ancestryLevel.level === '0' ? [ + addEffect('system.attributes.will.value', ancestryLevel.attributes.will.value - 10, priority), + addEffect('system.attributes.will.immune', ancestryLevel.attributes.will.immune, priority), + ] : addEffect('system.attributes.will.value', ancestryLevel.attributes.will.value * (ancestryLevel.attributes.will.selected || ancestryLevel.attributeSelectIsFixed), priority + )), + ].flat().filter(falsyChangeFilter), } // Two set attributes @@ -276,35 +236,35 @@ export class DLActiveEffects { }, changes: [ // Characteristics - addEffect('system.characteristics.health.max', pathLevel.characteristicsHealth, priority), - addEffect('system.characteristics.power', pathLevel.characteristicsPower, priority), - addEffect('system.attributes.perception.value', pathLevel.characteristicsPerception, priority), - addEffect('system.characteristics.speed', pathLevel.characteristicsSpeed, priority), - addEffect('system.characteristics.defense', pathLevel.characteristicsDefense, priority), + addEffect('system.characteristics.health.max', pathLevel.characteristics.health, priority), + addEffect('system.characteristics.power', pathLevel.characteristics.power, priority), + addEffect('system.attributes.perception.value', pathLevel.characteristics.perception, priority), + addEffect('system.characteristics.speed', pathLevel.characteristics.speed, priority), + addEffect('system.characteristics.defense', pathLevel.characteristics.defense, priority), // FIXME - // addEffect('system.characteristics.insanityModifier', pathLevel.characteristicsInsanity, priority), - // addEffect('system.characteristics.corruptionModifier', pathLevel.characteristicsCorruption, priority), + // addEffect('system.characteristics.insanity.value', pathLevel.characteristics.insanity.value, priority), + // addEffect('system.characteristics.corruption.value', pathLevel.characteristics.corruption.value, priority), // Selected checkbox (select two, three, fixed) addEffect( 'system.attributes.strength.value', - pathLevel.attributeStrength * (pathLevel.attributeStrengthSelected || pathLevel.attributeSelectIsFixed), + pathLevel.attributes.strength * (pathLevel.attributes.strength.selected || pathLevel.attributeSelectIsFixed), priority ), addEffect( 'system.attributes.agility.value', - pathLevel.attributeAgility * (pathLevel.attributeAgilitySelected || pathLevel.attributeSelectIsFixed), + pathLevel.attributes.agility * (pathLevel.attributes.agility.selected || pathLevel.attributeSelectIsFixed), priority ), addEffect( 'system.attributes.intellect.value', - pathLevel.attributeIntellect * (pathLevel.attributeIntellectSelected || pathLevel.attributeSelectIsFixed), + pathLevel.attributes.intellect * (pathLevel.attributes.intellect.selected || pathLevel.attributeSelectIsFixed), priority ), addEffect( 'system.attributes.will.value', - pathLevel.attributeWill * (pathLevel.attributeWillSelected || pathLevel.attributeSelectIsFixed), + pathLevel.attributes.will * (pathLevel.attributes.will.selected || pathLevel.attributeSelectIsFixed), priority ), ].filter(falsyChangeFilter), @@ -357,21 +317,24 @@ export class DLActiveEffects { }, changes: [ addEffect('system.attributes.strength.value', data.attributes.strength, priority), - addEffect('system.attributes.strength.immune', data.attributes.strengthImmune, priority, true), + addEffect('system.attributes.strength.immune', data.attributes.strength.immune, priority, true), addEffect('system.attributes.agility.value', data.attributes.agility, priority), - addEffect('system.attributes.agility.immune', data.attributes.agilityImmune, priority, true), + addEffect('system.attributes.agility.immune', data.attributes.agility.immune, priority, true), addEffect('system.attributes.intellect.value', data.attributes.intellect, priority), - addEffect('system.attributes.intellect.immune', data.attributes.intellectImmune, priority, true), + addEffect('system.attributes.intellect.immune', data.attributes.intellect.immune, priority, true), addEffect('system.attributes.will.value', data.attributes.will, priority), - addEffect('system.attributes.will.immune', data.attributes.willImmune, priority, true), - addEffect('system.attributes.perception.value', data.characteristics.perceptionmodifier, priority), - addEffect('system.characteristics.defense', data.characteristics.defensemodifier, priority), - addEffect('system.characteristics.health.max', data.characteristics.healthmodifier, priority), - addEffect('system.characteristics.health.healingrate', data.characteristics.healingratemodifier, priority), + addEffect('system.attributes.will.immune', data.attributes.will.immune, priority, true), + addEffect('system.attributes.perception.value', data.characteristics.perception, priority), + addEffect('system.characteristics.defense', data.characteristics.defense, priority), + addEffect('system.characteristics.health.max', data.characteristics.health, priority), + addEffect('system.characteristics.health.healingrate', data.characteristics.healingRate, priority), addEffect('system.characteristics.power', data.characteristics.power, priority), addEffect('system.characteristics.speed', data.characteristics.speed, priority), - addEffect('system.characteristics.corruption', data.characteristics.corruption, priority), - addEffect('system.characteristics.insanity', data.characteristics.insanity, priority), + + // FIXME + // addEffect('system.characteristics.corruption.value', data.characteristics.corruption.value, priority), + // addEffect('system.characteristics.insanity.value', data.characteristics.insanity.value, priority), + addEffect('system.difficulty', data.difficulty, priority), overrideEffect('system.characteristics.size', data.characteristics.size, priority), overrideEffect('system.frightening', data.frightening, priority, true), diff --git a/src/module/actor/sheets/character-sheet.js b/src/module/actor/sheets/character-sheet.js index 49c74347..00cbc088 100644 --- a/src/module/actor/sheets/character-sheet.js +++ b/src/module/actor/sheets/character-sheet.js @@ -120,10 +120,10 @@ export default class DLCharacterSheet extends DLBaseActorSheet { if (item.type === 'ancestry') { // Add insanity and corruption values - const insanityImmune = this.actor.system.characteristics.insanity.immune || item.system.characteristics.insanity.immune - const corruptionImmune = this.actor.system.characteristics.corruption.immune || item.system.characteristics.corruption.immune - const newInsanity = this.actor.system.characteristics.insanity.value + item.system.characteristics.insanity.value - const newCorruption = this.actor.system.characteristics.corruption.value + item.system.characteristics.corruption.value + const insanityImmune = this.actor.system.characteristics.insanity.immune || item.system.levels.filter(l => l.characteristics.insanity.immune).length > 0 + const corruptionImmune = this.actor.system.characteristics.corruption.immune || item.system.levels.filter(l => l.characteristics.corruption.immune).length > 0 + const newInsanity = this.actor.system.characteristics.insanity.value + item.system.levels.reduce((s, l) => s + l.characteristics.insanity.value, 0) + const newCorruption = this.actor.system.characteristics.corruption.value + item.system.levels.reduce((s, l) => s + l.characteristics.corruption.value, 0) await this.actor.update({ 'system.characteristics': { diff --git a/src/module/combat/combat.js b/src/module/combat/combat.js index 1c060d6f..0aefa756 100644 --- a/src/module/combat/combat.js +++ b/src/module/combat/combat.js @@ -83,7 +83,7 @@ async rollInitiativeInduvidual(ids, {formula = null, updateTurn = true, messageO // Update multiple combatants await this.updateEmbeddedDocuments("Combatant", combatantUpdates) - await this.update({turn: 0}); + await this.update({ turn: 0 }); return this; } @@ -228,7 +228,7 @@ async rollInitiativeGroup(ids, { formula = null, updateTurn = true, messageOptio // Ensure the turn order remains with the same combatant if (updateTurn && currentId) { - await this.update({turn: this.turns.findIndex(t => t.id === currentId)}); + await this.update({ turn: this.turns.findIndex(t => t.id === currentId) }); } // Create multiple chat messages diff --git a/src/module/data/common.js b/src/module/data/common.js index 534a64d9..cc488d3f 100644 --- a/src/module/data/common.js +++ b/src/module/data/common.js @@ -140,6 +140,7 @@ export function levelItem(makeDataSchema) { name: makeStringField(), pack: makeStringField(), selected: makeBoolField(), - uuid: makeStringField() + uuid: makeStringField(), + img: makeStringField() }) } \ No newline at end of file diff --git a/src/module/data/item/AncestryDataModel.js b/src/module/data/item/AncestryDataModel.js index e4492671..12b849e2 100644 --- a/src/module/data/item/AncestryDataModel.js +++ b/src/module/data/item/AncestryDataModel.js @@ -14,55 +14,6 @@ export default class AncestryDataModel extends foundry.abstract.DataModel { return { description: makeHtmlField(), enrichedDescription: makeHtmlField(), - attributes: new foundry.data.fields.SchemaField({ - strength: new foundry.data.fields.SchemaField({ - value: makeIntField(10), - min: makeIntField(), - max: makeIntField(20), - formula: makeStringField(), - immune: makeBoolField() - }), - agility: new foundry.data.fields.SchemaField({ - value: makeIntField(10), - min: makeIntField(), - max: makeIntField(20), - formula: makeStringField(), - immune: makeBoolField() - }), - intellect: new foundry.data.fields.SchemaField({ - value: makeIntField(10), - min: makeIntField(), - max: makeIntField(20), - formula: makeStringField(), - immune: makeBoolField() - }), - will: new foundry.data.fields.SchemaField({ - value: makeIntField(10), - min: makeIntField(), - max: makeIntField(20), - formula: makeStringField(), - immune: makeBoolField() - }), - }), - characteristics: new foundry.data.fields.SchemaField({ - perceptionmodifier: makeIntField(), - healthmodifier: makeIntField(), - defensemodifier: makeIntField(), - healingratemodifier: makeIntField(), - size: makeStringField('1'), - speed: makeIntField(10), - power: makeIntField(), - insanity: new foundry.data.fields.SchemaField({ - value: makeIntField(), - formula: makeStringField(), - immune: makeBoolField() - }), - corruption: new foundry.data.fields.SchemaField({ - value: makeIntField(), - formula: makeStringField(), - immune: makeBoolField() - }) - }), levels: new foundry.data.fields.ArrayField(new foundry.data.fields.SchemaField({ level: makeStringField('1'), attributeSelect: makeStringField('choosetwo'), @@ -82,21 +33,51 @@ export default class AncestryDataModel extends foundry.abstract.DataModel { attributeSelectTwoSetValue2: makeIntField(), attributeSelectTwoSetSelectedValue1: makeBoolField(true), attributeSelectTwoSetSelectedValue2: makeBoolField(true), - attributeStrength: makeIntField(1), - attributeAgility: makeIntField(1), - attributeIntellect: makeIntField(1), - attributeWill: makeIntField(1), - attributeStrengthSelected: makeBoolField(false), - attributeAgilitySelected: makeBoolField(false), - attributeIntellectSelected: makeBoolField(false), - attributeWillSelected: makeBoolField(false), - characteristicsPerception: makeIntField(), - characteristicsDefense: makeIntField(), - characteristicsPower: makeIntField(), - characteristicsSpeed: makeIntField(), - characteristicsHealth: makeIntField(), - characteristicsCorruption: makeIntField(), - characteristicsInsanity: makeIntField(), + attributes: new foundry.data.fields.SchemaField({ + strength: new foundry.data.fields.SchemaField({ + value: makeIntField(10, 20, 0), + formula: makeStringField(), + immune: makeBoolField(), + selected: makeBoolField(), + }), + agility: new foundry.data.fields.SchemaField({ + value: makeIntField(10, 20, 0), + formula: makeStringField(), + immune: makeBoolField(), + selected: makeBoolField(), + }), + intellect: new foundry.data.fields.SchemaField({ + value: makeIntField(10, 20, 0), + formula: makeStringField(), + immune: makeBoolField(), + selected: makeBoolField(), + }), + will: new foundry.data.fields.SchemaField({ + value: makeIntField(10, 20, 0), + formula: makeStringField(), + immune: makeBoolField(), + selected: makeBoolField(), + }), + }), + characteristics: new foundry.data.fields.SchemaField({ + health: makeIntField(), + healingRate: makeIntField(), + size: makeStringField(), + defense: makeIntField(), + perception: makeIntField(), + speed: makeIntField(10), + power: makeIntField(), + insanity: new foundry.data.fields.SchemaField({ + value: makeIntField(), + formula: makeStringField(), + immune: makeBoolField() + }), + corruption: new foundry.data.fields.SchemaField({ + value: makeIntField(), + formula: makeStringField(), + immune: makeBoolField() + }) + }), languagesText: makeStringField(), equipmentText: makeStringField(), magicText: makeStringField(), @@ -109,10 +90,6 @@ export default class AncestryDataModel extends foundry.abstract.DataModel { talentspick: new foundry.data.fields.ArrayField(levelItem(makeTalentSchema)), languages: new foundry.data.fields.ArrayField(levelItem(makeLanguageSchema)) })), - languages: makeStringField(), - talents: new foundry.data.fields.ArrayField(levelItem(makeTalentSchema)), - languagelist: new foundry.data.fields.ArrayField(levelItem(makeLanguageSchema)), - equipment: makeStringField(), editTalents: makeBoolField(), editAncestry: makeBoolField(true) } @@ -135,9 +112,31 @@ export default class AncestryDataModel extends foundry.abstract.DataModel { } } + // Move attributes and characteristics into a new level 0 + if (source.attributes && source.levels?.filter(l => l.level === '0').length === 0) { + if (!source.levels) source.levels = [] + + source.levels = [{ + level: '0', + attributes: source.attributes, + characteristics: { + health: source.characteristics.healthmodifier, + healingRate: source.characteristics.healingratemodifier, + size: source.characteristics.size, + defense: source.characteristics.defensemodifier, + perception: source.characteristics.perceptionmodifier, + speed: source.characteristics.speed, + power: source.characteristics.power, + insanity: source.characteristics.insanity.value, + corruption: source.characteristics.corruption.value, + }, + talents: source.talents, + languages: source.languagelist + }, ...source.levels] + } + // Update from level4 to any number of levels if (source.level4 && !source.levels) { - if (!source.levels) source.levels = [] source.levels = source.levels.concat([ @@ -156,6 +155,44 @@ export default class AncestryDataModel extends foundry.abstract.DataModel { ]) } + // Move separate attribute and characteristics properties into their respective objects + if (source.levels[source.levels.length - 1].attributeStrength != undefined) { + for (const level of source.levels) { + level.attributes = { + strength: { + value: level.attributes?.strength?.value ?? level.attributeStrength, + selected: level.attributes?.strength?.selected ?? level.attributeStrengthSelected + }, + agility: { + value: level.attributes?.agility?.value ?? level.attributeAgility, + selected: level.attributes?.agility?.selected ?? level.attributeAgilitySelected + }, + intellect: { + value: level.attributes?.intellect?.value ?? level.attributeIntellect, + selected: level.attributes?.intellect?.selected ?? level.attributeIntellectSelected + }, + will: { + value: level.attributes?.will?.value ?? level.attributeWill, + selected: level.attributes?.will?.selected ?? level.attributeWillSelected + } + } + + level.characteristics = { + health: level.characteristics?.health ?? level.characteristicsHealth, + defense: level.characteristics?.defense ?? level.characteristicsDefense, + perception: level.characteristics?.perception ?? level.characteristicsPerception, + speed: level.characteristics?.speed ?? level.characteristicsSpeed, + power: level.characteristics?.power ?? level.characteristicsPower, + insanity: { + value: level.characteristics?.insanity?.value ?? level.characteristicsInsanity, + }, + corruption: { + value: level.characteristics?.corruption?.value ?? level.characteristicsCorruption + } + } + } + } + return super.migrateData(source) } } \ No newline at end of file diff --git a/src/module/data/item/CreatureRoleDataModel.js b/src/module/data/item/CreatureRoleDataModel.js index 0ca34933..35b2a62e 100644 --- a/src/module/data/item/CreatureRoleDataModel.js +++ b/src/module/data/item/CreatureRoleDataModel.js @@ -2,7 +2,9 @@ import { makeIntField, makeStringField, makeHtmlField, - makeBoolField + makeBoolField, + makeInsanity, + makeCorruption } from '../helpers.js' import { levelItem } from '../common.js' import { makeTalentSchema } from './TalentDataModel.js' @@ -26,15 +28,15 @@ import { makeEndOfTheRoundSchema } from './EndOfTheRoundDataModel.js' willImmune: makeBoolField(), }), characteristics: new foundry.data.fields.SchemaField({ - perceptionmodifier: makeIntField(), - healthmodifier: makeIntField(), - defensemodifier: makeIntField(), - healingratemodifier: makeIntField(), + perception: makeIntField(), + health: makeIntField(), + defense: makeIntField(), + healingRate: makeIntField(), size: makeStringField(), speed: makeIntField(10), power: makeIntField(), - insanity: makeIntField(), - corruption: makeIntField(), + insanity: makeInsanity(), + corruption: makeCorruption(), difficulty: makeIntField() }), frightening: makeBoolField(), diff --git a/src/module/data/item/PathDataModel.js b/src/module/data/item/PathDataModel.js index b2029899..d95a0627 100644 --- a/src/module/data/item/PathDataModel.js +++ b/src/module/data/item/PathDataModel.js @@ -2,6 +2,7 @@ import { makeBoolField, makeHtmlField, makeIntField, makeStringField } from '../ import { makeLanguageSchema } from './LanguageDataModel.js' import { makeSpellSchema } from './SpellDataModel.js' import { makeTalentSchema } from './TalentDataModel.js' +import { levelItem } from '../common.js' export default class PathDataModel extends foundry.abstract.DataModel { static defineSchema() { @@ -28,74 +29,106 @@ export default class PathDataModel extends foundry.abstract.DataModel { attributeSelectTwoSetValue2: makeIntField(), attributeSelectTwoSetSelectedValue1: makeBoolField(true), attributeSelectTwoSetSelectedValue2: makeBoolField(true), - attributeStrength: makeIntField(1), - attributeAgility: makeIntField(1), - attributeIntellect: makeIntField(1), - attributeWill: makeIntField(1), - attributeStrengthSelected: makeBoolField(false), - attributeAgilitySelected: makeBoolField(false), - attributeIntellectSelected: makeBoolField(false), - attributeWillSelected: makeBoolField(false), - characteristicsPerception: makeIntField(), - characteristicsDefense: makeIntField(), - characteristicsPower: makeIntField(), - characteristicsSpeed: makeIntField(), - characteristicsHealth: makeIntField(), - characteristicsCorruption: makeIntField(), - characteristicsInsanity: makeIntField(), + attributes: new foundry.data.fields.SchemaField({ + strength: new foundry.data.fields.SchemaField({ + value: makeIntField(10, 20, 0), + formula: makeStringField(), + immune: makeBoolField(), + selected: makeBoolField(), + }), + agility: new foundry.data.fields.SchemaField({ + value: makeIntField(10, 20, 0), + formula: makeStringField(), + immune: makeBoolField(), + selected: makeBoolField(), + }), + intellect: new foundry.data.fields.SchemaField({ + value: makeIntField(10, 20, 0), + formula: makeStringField(), + immune: makeBoolField(), + selected: makeBoolField(), + }), + will: new foundry.data.fields.SchemaField({ + value: makeIntField(10, 20, 0), + formula: makeStringField(), + immune: makeBoolField(), + selected: makeBoolField(), + }), + }), + characteristics: new foundry.data.fields.SchemaField({ + health: makeIntField(), + healingrate: makeIntField(), + size: makeStringField('1'), + defense: makeIntField(), + perception: makeIntField(), + speed: makeIntField(), + power: makeIntField(), + insanity: new foundry.data.fields.SchemaField({ + value: makeIntField(), + formula: makeStringField(), + immune: makeBoolField() + }), + corruption: new foundry.data.fields.SchemaField({ + value: makeIntField(), + formula: makeStringField(), + immune: makeBoolField() + }) + }), languagesText: makeStringField(), equipmentText: makeStringField(), magicText: makeStringField(), optionsText: makeStringField(), talentsSelect: makeStringField(), talentsChooseOne: makeBoolField(false), - talentsSelected: new foundry.data.fields.ArrayField(new foundry.data.fields.SchemaField({ - system: makeTalentSchema(), - description: makeStringField(), - id: makeStringField(), - name: makeStringField(), - pack: makeStringField(), - selected: makeBoolField(), - uuid: makeStringField() - })), - talents: new foundry.data.fields.ArrayField(new foundry.data.fields.SchemaField({ - system: makeTalentSchema(), - description: makeStringField(), - id: makeStringField(), - name: makeStringField(), - pack: makeStringField(), - selected: makeBoolField(), - uuid: makeStringField() - })), - spells: new foundry.data.fields.ArrayField(new foundry.data.fields.SchemaField({ - system: makeSpellSchema(), - description: makeStringField(), - id: makeStringField(), - name: makeStringField(), - pack: makeStringField(), - selected: makeBoolField(), - uuid: makeStringField() - })), - talentspick: new foundry.data.fields.ArrayField(new foundry.data.fields.SchemaField({ - system: makeTalentSchema(), - description: makeStringField(), - id: makeStringField(), - name: makeStringField(), - pack: makeStringField(), - selected: makeBoolField(), - uuid: makeStringField() - })), - languages: new foundry.data.fields.ArrayField(new foundry.data.fields.SchemaField({ - system: makeLanguageSchema(), - description: makeStringField(), - id: makeStringField(), - name: makeStringField(), - pack: makeStringField(), - selected: makeBoolField(), - uuid: makeStringField() - })) + talentsSelected: new foundry.data.fields.ArrayField(levelItem(makeTalentSchema)), + talents: new foundry.data.fields.ArrayField(levelItem(makeTalentSchema)), + spells: new foundry.data.fields.ArrayField(levelItem(makeSpellSchema)), + talentspick: new foundry.data.fields.ArrayField(levelItem(makeTalentSchema)), + languages: new foundry.data.fields.ArrayField(levelItem(makeLanguageSchema)), })), editPath: makeBoolField(true) } } + + static migrateData(source) { + // Move separate attribute and characteristics properties into their respective objects + if (source.levels[0].attributeStrength != undefined) { + for (const level of source.levels) { + level.attributes = { + strength: { + value: level.attributes?.strength?.value ?? level.attributeStrength, + selected: level.attributes?.strength?.selected ?? level.attributeStrengthSelected + }, + agility: { + value: level.attributes?.agility?.value ?? level.attributeAgility, + selected: level.attributes?.agility?.selected ?? level.attributeAgilitySelected + }, + intellect: { + value: level.attributes?.intellect?.value ?? level.attributeIntellect, + selected: level.attributes?.intellect?.selected ?? level.attributeIntellectSelected + }, + will: { + value: level.attributes?.will?.value ?? level.attributeWill, + selected: level.attributes?.will?.selected ?? level.attributeWillSelected + } + } + + level.characteristics = { + health: level.characteristics?.health ?? level.characteristicsHealth, + defense: level.characteristics?.defense ?? level.characteristicsDefense, + perception: level.characteristics?.perception ?? level.characteristicsPerception, + speed: level.characteristics?.speed ?? level.characteristicsSpeed, + power: level.characteristics?.power ?? level.characteristicsPower, + insanity: { + value: level.characteristics?.insanity?.value ?? level.characteristicsInsanity, + }, + corruption: { + value: level.characteristics?.corruption?.value ?? level.characteristicsCorruption + } + } + } + } + + return super.migrateData(source) + } } \ No newline at end of file diff --git a/src/module/dialog/stat-editor.js b/src/module/dialog/stat-editor.js index 2a222607..a220c064 100644 --- a/src/module/dialog/stat-editor.js +++ b/src/module/dialog/stat-editor.js @@ -38,7 +38,7 @@ export class DLStatEditor extends HandlebarsApplicationMixin(ApplicationV2) { * @protected */ async _prepareContext(options) { // eslint-disable-line no-unused-vars - return this.ancestry.system[this.statType][this.statName] + return this.item.system.levels[0][this.statType][this.statName] } /** @@ -50,19 +50,21 @@ export class DLStatEditor extends HandlebarsApplicationMixin(ApplicationV2) { * @returns {Promise} */ static async onSubmit(event, form, formData) { - await this.ancestry.update({ + const levels = this.item.system.levels + + levels.find(l => l.level === '0')[this.statType][this.statName] = { + value: formData.object.value, + formula: formData.object.formula, + immune: formData.object.immune + }; + + await this.item.update({ system: { - [this.statType]: { - [this.statName]: { - value: formData.object.value, - formula: formData.object.formula, - immune: formData.object.immune - } - } + levels: levels } }) - this.ancestry.sheet.render(true) + this.item.sheet.render(true) } /** @@ -73,14 +75,14 @@ export class DLStatEditor extends HandlebarsApplicationMixin(ApplicationV2) { static async rollStat(event, target) { // eslint-disable-line no-unused-vars const divTarget = document.getElementById('stat-editor-roll-target') const formula = document.getElementById('stat-editor-roll-formula').value - const roll = new Roll(formula, this.ancestry.system) + const roll = new Roll(formula, this.item.system) await roll.evaluate() divTarget.value = roll.total } constructor(object, options) { super(options) - this.ancestry = object.ancestry + this.item = object.item this.statType = object.statType this.statName = object.statName } diff --git a/src/module/item/item.js b/src/module/item/item.js index 69afaf18..86868220 100644 --- a/src/module/item/item.js +++ b/src/module/item/item.js @@ -1,6 +1,7 @@ import {deleteActorNestedItems} from './nested-objects' import {DemonlordActor} from '../actor/actor' import { DLEndOfRound } from '../dialog/endofround' +import { getChatBaseData } from '../chat/base-messages' export class DemonlordItem extends Item { /** @override */ @@ -114,63 +115,79 @@ export class DemonlordItem extends Item { } // Before adding the item, roll any formulas and apply the values // Attributes - let newStrength = ancestry.system.attributes.strength?.value ?? 10 - let newAgility = ancestry.system.attributes.agility?.value ?? 10 - let newIntellect = ancestry.system.attributes.intellect?.value ?? 10 - let newWill = ancestry.system.attributes.will?.value ?? 10 - let newInsanity = ancestry.system.characteristics.insanity?.value ?? 0 - let newCorruption = ancestry.system.characteristics.corruption?.value ?? 0 - - if (ancestry.system.attributes.strength?.formula) { - const roll = new Roll(ancestry.system.attributes.strength.formula) + let newStrength = ancestry.system.levels[0].attributes.strength?.value ?? 10 + let newAgility = ancestry.system.levels[0].attributes.agility?.value ?? 10 + let newIntellect = ancestry.system.levels[0].attributes.intellect?.value ?? 10 + let newWill = ancestry.system.levels[0].attributes.will?.value ?? 10 + let newInsanity = ancestry.system.levels[0].characteristics.insanity?.value ?? 0 + let newCorruption = ancestry.system.levels[0].characteristics.corruption?.value ?? 0 + + const rolls = [] + + if (ancestry.system.levels[0].attributes.strength?.formula) { + const roll = new Roll(ancestry.system.levels[0].attributes.strength.formula) newStrength = (await roll.evaluate()).total + rolls.push({property: 'strength', roll: roll }) } - if (ancestry.system.attributes.agility?.formula) { - const roll = new Roll(ancestry.system.attributes.agility.formula) + if (ancestry.system.levels[0].attributes.agility?.formula) { + const roll = new Roll(ancestry.system.levels[0].attributes.agility.formula) newAgility = (await roll.evaluate()).total + rolls.push({property: 'agility', roll: roll }) } - if (ancestry.system.attributes.intellect?.formula) { - const roll = new Roll(ancestry.system.attributes.intellect.formula) + if (ancestry.system.levels[0].attributes.intellect?.formula) { + const roll = new Roll(ancestry.system.levels[0].attributes.intellect.formula) newIntellect = (await roll.evaluate()).total + rolls.push({property: 'intellect', roll: roll }) } - if (ancestry.system.attributes.will?.formula) { - const roll = new Roll(ancestry.system.attributes.will.formula) + if (ancestry.system.levels[0].attributes.will?.formula) { + const roll = new Roll(ancestry.system.levels[0].attributes.will.formula) newWill = (await roll.evaluate()).total + rolls.push({property: 'will', roll: roll }) } - if (ancestry.system.characteristics.insanity?.formula) { - const roll = new Roll(ancestry.system.characteristics.insanity.formula) + if (ancestry.system.levels[0].characteristics.insanity?.formula) { + const roll = new Roll(ancestry.system.levels[0].characteristics.insanity.formula) newInsanity = (await roll.evaluate()).total + rolls.push({property: 'insanity', roll: roll }) } - if (ancestry.system.characteristics.corruption?.formula) { - const roll = new Roll(ancestry.system.characteristics.corruption.formula) + if (ancestry.system.levels[0].characteristics.corruption?.formula) { + const roll = new Roll(ancestry.system.levels[0].characteristics.corruption.formula) newCorruption = (await roll.evaluate()).total + rolls.push({property: 'corruption', roll: roll }) + } + + // Send a message to chat with all the rolls + if (rolls.length > 0) { + const templateData = { + item: ancestry, + rolls, + } + + const actor = game.user.character ?? canvas.tokens.controlled[0].actor + const rollMode = game.settings.get('core', 'rollMode') + + const chatData = getChatBaseData(actor, rollMode) + + const template = 'systems/demonlord/templates/chat/formulaeroll.hbs' + renderTemplate(template, templateData).then(async content => { + chatData.content = content + chatData.sound = CONFIG.sounds.dice + await ChatMessage.create(chatData) + }) } + const l0 = this.system.levels.find(l => l.level === '0') + l0.attributes.strength.value = newStrength + l0.attributes.agility.value = newAgility + l0.attributes.intellect.value = newIntellect + l0.attributes.will.value = newWill + l0.characteristics.insanity.value = newInsanity + l0.characteristics.corruption.value = newCorruption + return await this.updateSource({ - 'system.attributes': { - strength: { - value: newStrength - }, - agility: { - value: newAgility - }, - intellect: { - value: newIntellect - }, - will: { - value: newWill - }, - }, - - 'system.characteristics': { - insanity: { - value: newInsanity - }, - corruption: { - value: newCorruption - } + system: { + levels: this.system.levels } }) } diff --git a/src/module/item/nested-objects.js b/src/module/item/nested-objects.js index 5d1c16af..3b3097bb 100644 --- a/src/module/item/nested-objects.js +++ b/src/module/item/nested-objects.js @@ -12,11 +12,10 @@ export class PathLevel { const locAtt = s => game.i18n.localize('DL.Attribute' + capitalize(s)) - this.level = obj.level || 0 + this.level = obj.level || 1 this.attributeSelect = obj.attributeSelect || '' this.attributeSelectIsChooseTwo = obj.attributeSelectIsChooseTwo || obj.attributeSelect === 'choosetwo' || false - this.attributeSelectIsChooseThree = - obj.attributeSelectIsChooseThree || obj.attributeSelect === 'choosethree' || false + this.attributeSelectIsChooseThree = obj.attributeSelectIsChooseThree || obj.attributeSelect === 'choosethree' || false this.attributeSelectIsFixed = obj.attributeSelectIsFixed || obj.attributeSelect === 'fixed' || false this.attributeSelectIsTwoSet = obj.attributeSelectIsTwoSet || obj.attributeSelect === 'twosets' || false @@ -35,22 +34,52 @@ export class PathLevel { this.attributeSelectTwoSetSelectedValue1 = +obj.attributeSelectTwoSetSelectedValue1 || true this.attributeSelectTwoSetSelectedValue2 = +obj.attributeSelectTwoSetSelectedValue2 || true - this.attributeStrength = +obj.attributeStrength || 0 - this.attributeAgility = +obj.attributeAgility || 0 - this.attributeIntellect = +obj.attributeIntellect || 0 - this.attributeWill = +obj.attributeWill || 0 - this.attributeStrengthSelected = +obj.attributeStrengthSelected || false - this.attributeAgilitySelected = +obj.attributeAgilitySelected || false - this.attributeIntellectSelected = +obj.attributeIntellectSelected || false - this.attributeWillSelected = +obj.attributeWillSelected || false - - this.characteristicsPerception = +obj.characteristicsPerception || 0 - this.characteristicsDefense = +obj.characteristicsDefense || 0 - this.characteristicsPower = +obj.characteristicsPower || 0 - this.characteristicsSpeed = +obj.characteristicsSpeed || 0 - this.characteristicsHealth = +obj.characteristicsHealth || 0 - this.characteristicsCorruption = +obj.characteristicsCorruption || 0 - this.characteristicsInsanity = +obj.characteristicsInsanity || 0 + this.attributes = { + strength: { + value: +obj.attributes?.strength?.value || 0, + formula: obj.attributes?.strength?.formula || '', + immune: obj.attributes?.strength?.immune || false, + selected: +obj.attributes?.strength?.selected || false, + }, + agility: { + value: +obj.attributes?.agility?.value || 0, + formula: obj.attributes?.agility?.formula || '', + immune: obj.attributes?.agility?.immune || false, + selected: +obj.attributes?.agility?.selected || false, + }, + intellect: { + value: +obj.attributes?.intellect?.value || 0, + formula: obj.attributes?.intellect?.formula || '', + immune: obj.attributes?.intellect?.immune || false, + selected: +obj.attributes?.intellect?.selected || false, + }, + will: { + value: +obj.attributes?.will?.value || 0, + formula: obj.attributes?.will?.formula || '', + immune: obj.attributes?.will?.immune || false, + selected: +obj.attributes?.will?.selected || false, + } + } + + this.characteristics = { + health: +obj.characteristics?.health || 0, + healingRate: +obj.characteristics?.healingRate || 0, + size: obj.characteristics?.size || '1', + defense: +obj.characteristics?.defense || 0, + perception: +obj.characteristics?.perception || 0, + speed: +obj.characteristics?.speed || 0, + power: +obj.characteristics?.power || 0, + insanity: { + value: +obj.characteristics?.insanity?.value || 0, + formula: obj.characteristics?.insanity?.formula || '', + immune: obj.characteristics?.insanity?.immune || false, + }, + corruption: { + value: +obj.characteristics?.corruption?.value || 0, + formula: obj.characteristics?.corruption?.formula || '', + immune: obj.characteristics?.corruption?.immune || false, + } + } this.languagesText = obj.languagesText || '' this.equipmentText = obj.equipmentText || '' @@ -69,13 +98,13 @@ export class PathLevel { Handlebars.registerHelper('hasCharacteristics', level => { return ( - level.characteristicsPerception || - level.characteristicsDefense || - level.characteristicsPower || - level.characteristicsSpeed || - level.characteristicsHealth || - level.characteristicsCorruption || - level.characteristicsInsanity + level.characteristics.perception || + level.characteristics.defense || + level.characteristics.power || + level.characteristics.speed || + level.characteristics.health || + (level.characteristics.corruption.value || level.characteristics.corruption.formula) || + (level.characteristics.insanity.value || level.characteristics.insanity.formula) ) }) @@ -89,6 +118,7 @@ export class PathLevelItem { this.description = obj.description || '' this.pack = obj.pack || '' this.selected = Boolean(obj.selected) || false + this.img = obj.img } } @@ -286,19 +316,15 @@ export async function handleLevelChange(actor, newLevel, curLevel = undefined) { /* -------------------------------------------- */ export async function handleCreateAncestry(actor, ancestryItem) { - const ancestryData = ancestryItem.system const actorLevel = parseInt(actor.system.level) - let nestedItems = [...ancestryData.talents, ...ancestryData.languagelist] - let createdItems = await createActorNestedItems(actor, nestedItems, ancestryItem.id, 0) + const ancestryData = ancestryItem.system const leqLevels = ancestryData.levels.filter(l => +l.level <= +actorLevel) - // If character level >= 4, add chosen nested items + // For each level that is <= actor level, add all talents and *selected* nested items for await (let level of leqLevels) { - let chosenNestedItems = [...level.talents, ...level.spells].filter(i => Boolean(i.selected)) - createdItems = createdItems.concat(await createActorNestedItems(actor, chosenNestedItems, ancestryItem.id, level.level)) + await createActorNestedItems(actor, _getLevelItemsToTransfer(level), ancestryItem.id, level.level) } - - return createdItems + return await Promise.resolve() } /* -------------------------------------------- */ diff --git a/src/module/item/sheets/base-item-sheet.js b/src/module/item/sheets/base-item-sheet.js index 9f80a754..07aae66b 100644 --- a/src/module/item/sheets/base-item-sheet.js +++ b/src/module/item/sheets/base-item-sheet.js @@ -1,3 +1,4 @@ +import deepmerge from 'deepmerge' const { HandlebarsApplicationMixin } = foundry.applications.api const { ItemSheetV2 } = foundry.applications.sheets @@ -174,7 +175,6 @@ export default class DLBaseItemSheet extends HandlebarsApplicationMixin(ItemShee /* -------------------------------------------- */ /* Data */ - /* -------------------------------------------- */ /** @override */ @@ -193,17 +193,13 @@ export default class DLBaseItemSheet extends HandlebarsApplicationMixin(ItemShee // Retrieve data for nested items if (['ancestry', 'path'].includes(this.document.type)) { - for await (let i of context.item.system.levels.keys()) { + for await (const i of context.item.system.levels.keys()) { context.item.system.levels[i].talents = await Promise.all(context.item.system.levels[i].talents.map(await getNestedItemData)) context.item.system.levels[i].talentspick = await Promise.all(context.item.system.levels[i].talentspick.map(await getNestedItemData)) context.item.system.levels[i].spells = await Promise.all(context.item.system.levels[i].spells.map(await getNestedItemData)) + context.item.system.levels[i].languages = await Promise.all(context.item.system.levels[i].languages.map(await getNestedItemData)) } } - - if (this.document.type === 'ancestry') { - context.item.system.talents = await Promise.all(context.item.system.talents.map(await getNestedItemData)) - context.item.system.languagelist = await Promise.all(context.item.system.languagelist.map(await getNestedItemData)) - } if (this.document.type === 'creaturerole') { context.item.system.talents = await Promise.all(context.item.system.talents.map(await getNestedItemData)) @@ -263,12 +259,7 @@ export default class DLBaseItemSheet extends HandlebarsApplicationMixin(ItemShee context.active = context.tab.active break case 'ancestry': - context.tab = context.tabs[partId] - context.cssClass = context.tab.cssClass - context.active = context.tab.active - context.system.selectedLevelIndex = this._selectedLevelIndex ?? -1 - break - case 'path': + case 'path': context.tab = context.tabs[partId] context.cssClass = context.tab.cssClass context.active = context.tab.active @@ -370,9 +361,6 @@ export default class DLBaseItemSheet extends HandlebarsApplicationMixin(ItemShee formData = formData.object const completeFormData = this._getPathDataFromForm() - // Remove first level 0, as it's not relevant for this - completeFormData.splice(0, 1) - system.editAncestry = formData['system.editAncestry'] ?? item.system.editAncestry system.description = formData['system.description'] || item.system.description system.type = formData['system.type'] @@ -381,10 +369,6 @@ export default class DLBaseItemSheet extends HandlebarsApplicationMixin(ItemShee if (completeFormData.length > 0) { if (item.system.editAncestry) { - system.attributes = updateData.system.attributes - system.characteristics = updateData.system.characteristics - system.equipment = updateData.system.equipment - system.languages = updateData.system.languages system.levels = this._getEditLevelsUpdateData(completeFormData) system.levels.sort(this._sortLevels) @@ -502,13 +486,9 @@ export default class DLBaseItemSheet extends HandlebarsApplicationMixin(ItemShee let nestedData if (levelIndex) { - if (levelIndex === '-1' && data.type === 'ancestry') { - if (itemGroup === 'feature') nestedData = data.system.talents.find(i => i._id === itemId) - else nestedData = data.system[itemGroup].find(i => i._id === itemId) - } else { - // Path or ancestry item (except for ancestry's level 0) - nestedData = data.system.levels[levelIndex][itemGroup].find(i => i._id === itemId) - } + // Path or ancestry item + if (itemGroup === 'feature') nestedData = data.system.levels[levelIndex].talents.find(i => i._id === itemId) + else nestedData = data.system.levels[levelIndex][itemGroup].find(i => i._id === itemId) } else { // Anything without levels nestedData = data.system[itemGroup].find(i => i._id === itemId) @@ -522,23 +502,19 @@ export default class DLBaseItemSheet extends HandlebarsApplicationMixin(ItemShee } static async onDeleteItem(event) { - const levelIndex = event.target.closest('[data-level-index]')?.dataset?.levelIndex const itemGroup = event.target.closest('[data-group]')?.dataset?.group + const levelIndex = event.target.closest('[data-level-index]')?.dataset?.levelIndex const itemIndex = event.target.closest('[data-item-index]')?.dataset?.itemIndex if (this.document.type === 'ancestry' || this.document.type === 'path') { // Part of path or ancestry - const itemData = foundry.utils.duplicate(this.document) + const data = foundry.utils.duplicate(this.document) - if (levelIndex === '-1' && this.document.type === 'ancestry') { - // It's an ancestry deleting from level 0 - if (itemGroup === 'feature') itemData.system.talents.splice(itemIndex, 1) - else itemData.system[itemGroup].splice(itemIndex, 1) - } else { - if (['talents', 'talentspick', 'spells'].includes(itemGroup)) itemData.system.levels[levelIndex][itemGroup].splice(itemIndex, 1) - else if (itemGroup === 'primary') itemData.system.levels.splice(levelIndex, 1) // Deleting a level - } - await this.document.update(itemData) + if (itemGroup === 'feature') data.system.levels[levelIndex].talents.splice(itemIndex, 1) + else if (itemGroup === 'primary') data.system.levels.splice(levelIndex, 1) // Deleting a level + else data.system.levels[levelIndex][itemGroup].splice(itemIndex, 1) + + await this.document.update(data) } else { // Anything without levels const itemData = foundry.utils.duplicate(this.document) @@ -799,7 +775,7 @@ export default class DLBaseItemSheet extends HandlebarsApplicationMixin(ItemShee const div = event.currentTarget const statType = div.dataset.statType const statName = div.dataset.statName - new DLStatEditor({ ancestry: this.document, statType: statType, statName: statName }, { + new DLStatEditor({ item: this.document, statType: statType, statName: statName }, { top: 50, right: 700, }).render(true) @@ -886,23 +862,33 @@ export default class DLBaseItemSheet extends HandlebarsApplicationMixin(ItemShee } // Convert new level to map - const newLevel = new Map(Object.entries(formLevels[index++])) + const newLevel = formLevels[index++] + const newLevelMap = new Map(Object.entries(newLevel)) + // Get number of choices let newChoices = 0 - newLevel.forEach((v, k) => { - if (k.includes('attribute') && v === true) newChoices++ - }) + if (newLevel.attributes) { + for (const a of Object.keys(newLevel.attributes)) { + if (newLevel.attributes[a].selected) newChoices++ + } + + if (newChoices > 2 && currentLevel.attributeSelectIsChooseTwo || newChoices > 3 && currentLevel.attributeSelectIsChooseThree) { + return warn() + } + } if (currentLevel.attributeSelectIsTwoSet) { - currentLevel.attributeSelectTwoSetSelectedValue1 = newLevel.get('attributeSelectTwoSetSelectedValue1') - currentLevel.attributeSelectTwoSetSelectedValue2 = newLevel.get('attributeSelectTwoSetSelectedValue2') - } else if (currentLevel.attributeSelectIsChooseTwo) { - if (newChoices > 2) return warn() - newLevel.forEach((v, k) => (currentLevel[k] = v)) - } else if (currentLevel.attributeSelectIsChooseThree) { - if (newChoices > 3) return warn() - newLevel.forEach((v, k) => (currentLevel[k] = v)) + currentLevel.attributeSelectTwoSetSelectedValue1 = newLevelMap.get('attributeSelectTwoSetSelectedValue1') + currentLevel.attributeSelectTwoSetSelectedValue2 = newLevelMap.get('attributeSelectTwoSetSelectedValue2') + } else if (currentLevel.attributeSelectIsChooseTwo || currentLevel.attributeSelectIsChooseThree) { + newLevelMap.forEach((v, k) => { + if (v instanceof Object) { + if (newLevel[k]) currentLevel[k] = deepmerge(currentLevel[k], newLevel[k]) + } else { + currentLevel[k] = v + } + }) } }) @@ -927,7 +913,8 @@ export default class DLBaseItemSheet extends HandlebarsApplicationMixin(ItemShee // Match the new levels with the old ones and keep the nested items const oldLevels = this.document.toObject().system.levels const notFound = [] // stores path levels that do not have been found in the current levels - newLevels.forEach(newLevel => { + + for (const newLevel of newLevels) { const foundIndex = oldLevels.findIndex(l => +l.level === +newLevel.level) if (foundIndex >= 0) { // if index is found, remove the relative level from the list of old levels and keep the nested items @@ -935,13 +922,14 @@ export default class DLBaseItemSheet extends HandlebarsApplicationMixin(ItemShee this._keepNestedItems(newLevel, foundLevel) // Keep also the chosen user attributes if (newLevel.attributeSelectIsChooseTwo === foundLevel.attributeSelectIsChooseTwo || newLevel.attributeSelectIsChooseThree === foundLevel.attributeSelectIsChooseThree) { - newLevel.attributeStrengthSelected = foundLevel.attributeStrengthSelected - newLevel.attributeAgilitySelected = foundLevel.attributeAgilitySelected - newLevel.attributeIntellectSelected = foundLevel.attributeIntellectSelected - newLevel.attributeWillSelected = foundLevel.attributeWillSelected + newLevel.attributes.strength.selected = foundLevel.attributes.strength.selected + newLevel.attributes.agility.selected = foundLevel.attributes.agility.selected + newLevel.attributes.intellect.selected = foundLevel.attributes.intellect.selected + newLevel.attributes.will.selected = foundLevel.attributes.will.selected } } else notFound.push(newLevel) - }) + } + // Assert that there is only one level not matching. // Not matching levels happen when a path level level changes so there should only be one if ((oldLevels.length > 1 && notFound.length > 1) || oldLevels.length !== notFound.length) { @@ -987,7 +975,7 @@ export default class DLBaseItemSheet extends HandlebarsApplicationMixin(ItemShee levelItem.uuid = item.uuid ?? data.uuid levelItem.id = item.id || item._id - levelItem._id = item.id || item._id + levelItem._id = item._id || item.id levelItem.name = item.name levelItem.description = item.system.description levelItem.pack = data.pack ? data.pack : '' @@ -995,9 +983,9 @@ export default class DLBaseItemSheet extends HandlebarsApplicationMixin(ItemShee levelItem.img = item.img if (this.document.type === 'ancestry' || this.document.type === 'path') { - if (level === '-1') { - if (group === 'feature') itemData.system.talents.push(levelItem) - else itemData.system[group].push(levelItem) + if (level === '0') { + if (group === 'feature') itemData.system.levels[level].talents.push(levelItem) + else itemData.system.levels[level][group].push(levelItem) } else { itemData.system.levels[level][group].push(levelItem) } diff --git a/src/module/templates.js b/src/module/templates.js index a68d488b..d60c60b2 100644 --- a/src/module/templates.js +++ b/src/module/templates.js @@ -34,6 +34,7 @@ export const preloadHandlebarsTemplates = async function () { 'systems/demonlord/templates/chat/spell.hbs', 'systems/demonlord/templates/chat/talent.hbs', 'systems/demonlord/templates/chat/useitem.hbs', + 'systems/demonlord/templates/chat/formulaeroll.hbs', 'systems/demonlord/templates/actor/actor-sheet.hbs', 'systems/demonlord/templates/actor/limited-sheet.hbs', 'systems/demonlord/templates/actor/sidemenu.hbs', diff --git a/src/templates/chat/formulaeroll.hbs b/src/templates/chat/formulaeroll.hbs new file mode 100644 index 00000000..29f00443 --- /dev/null +++ b/src/templates/chat/formulaeroll.hbs @@ -0,0 +1,6 @@ +

Rolling formulae for {{item.name}}

+
+ {{#each rolls as |roll|}} +

{{capitalize roll.property}}: {{roll.roll}}

+ {{/each}} +

\ No newline at end of file diff --git a/src/templates/item/item-ancestry-edit.hbs b/src/templates/item/item-ancestry-edit.hbs index 1232d1c0..c5900f34 100644 --- a/src/templates/item/item-ancestry-edit.hbs +++ b/src/templates/item/item-ancestry-edit.hbs @@ -25,226 +25,225 @@ {{/inline}} -
-
-
-
- {{localize 'DL.PathsLevelsSubTitle'}} 0 -
- - - -
- -
- -
-
- {{localize "DL.AncestryStartingAttributes"}} -
- {{> AttributeInput icon="strength" value=system.attributes.strength.value name="system.attributes.strength.value" loc="DL.AttributeStrength" editableStat=true statType="attributes" statName="strength"}} - {{> AttributeInput icon="agility" value=system.attributes.agility.value name="system.attributes.agility.value" loc="DL.AttributeAgility" editableStat=true statType="attributes" statName="agility"}} - {{> AttributeInput icon="intellect" value=system.attributes.intellect.value name="system.attributes.intellect.value" loc="DL.AttributeIntellect" editableStat=true statType="attributes" statName="intellect"}} - {{> AttributeInput icon="will" value=system.attributes.will.value name="system.attributes.will.value" loc="DL.AttributeWill" editableStat=true statType="attributes" statName="will"}} +{{#each system.levels as |level index|}} +
+
+ {{#if (eq level.level '0')}} +
+
+ {{localize 'DL.PathsLevelsSubTitle'}} 0 +
+ + +
-
- - - -
- {{localize "DL.PathsLevelCharacteristicsSubtitle"}} -
- {{> AttributeInput icon="health" value=system.characteristics.healthmodifier name="system.characteristics.healthmodifier" loc="DL.CharHealth"}} - {{> AttributeInput icon="healing" value=system.characteristics.healingratemodifier name="system.characteristics.healingratemodifier" loc="DL.CharHealthHealingRating"}} -
-
- - - +
+ +
+
+ {{localize "DL.AncestryStartingAttributes"}} +
+ {{> AttributeInput icon="strength" value=level.attributes.strength.value name="level.attributes.strength.value" loc="DL.AttributeStrength" editableStat=true statType="attributes" statName="strength"}} + {{> AttributeInput icon="agility" value=level.attributes.agility.value name="level.attributes.agility.value" loc="DL.AttributeAgility" editableStat=true statType="attributes" statName="agility"}} + {{> AttributeInput icon="intellect" value=level.attributes.intellect.value name="level.attributes.intellect.value" loc="DL.AttributeIntellect" editableStat=true statType="attributes" statName="intellect"}} + {{> AttributeInput icon="will" value=level.attributes.will.value name="level.attributes.will.value" loc="DL.AttributeWill" editableStat=true statType="attributes" statName="will"}}
- {{> AttributeInput icon="defense" value=system.characteristics.defensemodifier name="system.characteristics.defensemodifier" loc="DL.AttributeDefense"}} - {{> AttributeInput icon="perception" value=system.characteristics.perceptionmodifier name="system.characteristics.perceptionmodifier" loc="DL.AttributePerception"}} - {{> AttributeInput icon="speed" value=system.characteristics.speed name="system.characteristics.speed" loc="DL.CharSpeed"}} -
-
- - - + + + + +
+ {{localize "DL.PathsLevelCharacteristicsSubtitle"}} +
+ {{> AttributeInput icon="health" value=level.characteristics.health name="level.characteristics.health" loc="DL.CharHealth"}} + {{> AttributeInput icon="healing" value=level.characteristics.healingRate name="level.characteristics.healingRate" loc="DL.CharHealthHealingRating"}} +
+
+ + + +
+
+ {{> AttributeInput icon="defense" value=level.characteristics.defense name="level.characteristics.defense" loc="DL.AttributeDefense"}} + {{> AttributeInput icon="perception" value=level.characteristics.perception name="level.characteristics.perception" loc="DL.AttributePerception"}} + {{> AttributeInput icon="speed" value=level.characteristics.speed name="level.characteristics.speed" loc="DL.CharSpeed"}} +
+
+ + + +
+
+
+
+ + + +
+
+ {{> AttributeInput icon="power" value=level.characteristics.power name="level.characteristics.power" loc="DL.CharPower"}}
-
-
- - - -
+
+ +
+
+ {{localize "DL.PathsLevelLanguages"}} + +
+
+ {{localize "DL.PathsLevelEquipment"}} +
- {{> AttributeInput icon="power" value=system.characteristics.power name="system.characteristics.power" loc="DL.CharPower"}}
-
-
-
-
- {{localize "DL.PathsLevelLanguages"}} - -
-
- {{localize "DL.PathsLevelEquipment"}} - -
-
+
-
+
+
+
+
+ {{localize "DL.FeaturesTitle"}} + + + +
+ {{> DropZoneEdit collection=level.talents dataGroup="feature" dataLevel=level.level}} +
-
-
-
-
- {{localize "DL.FeaturesTitle"}} - - - + + +
+
+ {{localize "DL.LanguagesTitle"}} + + + +
+ {{> DropZoneEdit collection=level.languages dataGroup="languages" dataLevel=level.level}} +
- {{> DropZoneEdit collection=system.talents dataGroup="feature" dataLevel=0}}
- - - -
-
- {{localize "DL.LanguagesTitle"}} - - - + {{else}} +
+
+ {{localize 'DL.PathsLevelsSubTitle'}} +
- {{> DropZoneEdit collection=system.languagelist dataGroup="languagelist" dataLevel=0}} + + +
-
-
-
-{{#each system.levels as |level index|}} -
-
-
-
- {{localize 'DL.PathsLevelsSubTitle'}} - -
- - - -
+
-
- -
-
- {{localize "DL.PathsLevelAttributesSubtitle"}} -
- {{AttributeSelectDropdown "level.attributeSelect" level.attributeSelect}} - - {{#if (or level.attributeSelectIsChooseTwo level.attributeSelectIsChooseThree level.attributeSelectIsFixed)}} - {{> AttributeInput icon="strength" value=level.attributeStrength name="level.attributeStrength" loc="DL.AttributeStrength"}} - {{> AttributeInput icon="agility" value=level.attributeAgility name="level.attributeAgility" loc="DL.AttributeAgility"}} - {{> AttributeInput icon="intellect" value=level.attributeIntellect name="level.attributeIntellect" loc="DL.AttributeIntellect"}} - {{> AttributeInput icon="will" value=level.attributeWill name="level.attributeWill" loc="DL.AttributeWill"}} - {{else if level.attributeSelectIsTwoSet}} -
- {{LevelAttributeTwoSet 'level.attributeSelectTwoSet1' level.attributeSelectTwoSet1 }} - {{localize "DL.PathsLevelAttributesSelectOr"}} - {{LevelAttributeTwoSet 'level.attributeSelectTwoSet2' level.attributeSelectTwoSet2 }} -
- +
+
+ {{localize "DL.PathsLevelAttributesSubtitle"}} +
+ {{AttributeSelectDropdown "level.attributeSelect" level.attributeSelect}} + + {{#if (or level.attributeSelectIsChooseTwo level.attributeSelectIsChooseThree level.attributeSelectIsFixed)}} + {{> AttributeInput icon="strength" value=level.attributes.strength.value name="level.attributes.strength.value" loc="DL.AttributeStrength"}} + {{> AttributeInput icon="agility" value=level.attributes.agility.value name="level.attributes.agility.value" loc="DL.AttributeAgility"}} + {{> AttributeInput icon="intellect" value=level.attributes.intellect.value name="level.attributes.intellect.value" loc="DL.AttributeIntellect"}} + {{> AttributeInput icon="will" value=level.attributes.will.value name="level.attributes.will.value" loc="DL.AttributeWill"}} + {{else if level.attributeSelectIsTwoSet}} +
+ {{LevelAttributeTwoSet 'level.attributeSelectTwoSet1' level.attributeSelectTwoSet1 }} + {{localize "DL.PathsLevelAttributesSelectOr"}} + {{LevelAttributeTwoSet 'level.attributeSelectTwoSet2' level.attributeSelectTwoSet2 }} +
+ +
-
-
- {{LevelAttributeTwoSet 'level.attributeSelectTwoSet3' level.attributeSelectTwoSet3}} - {{localize "DL.PathsLevelAttributesSelectOr"}} - {{LevelAttributeTwoSet 'level.attributeSelectTwoSet4' level.attributeSelectTwoSet4}} -
- +
+ {{LevelAttributeTwoSet 'level.attributeSelectTwoSet3' level.attributeSelectTwoSet3}} + {{localize "DL.PathsLevelAttributesSelectOr"}} + {{LevelAttributeTwoSet 'level.attributeSelectTwoSet4' level.attributeSelectTwoSet4}} +
+ +
-
- {{/if}} + {{/if}} +
-
- - -
- {{localize "DL.PathsLevelCharacteristicsSubtitle"}} -
- {{> AttributeInput icon="health" value=level.characteristicsHealth name="level.characteristicsHealth" loc="DL.CharHealth"}} - {{> AttributeInput icon="defense" value=level.characteristicsDefense name="level.characteristicsDefense" loc="DL.AttributeDefense"}} - {{> AttributeInput icon="perception" value=level.characteristicsPerception name="level.characteristicsPerception" loc="DL.AttributePerception"}} - {{> AttributeInput icon="speed" value=level.characteristicsSpeed name="level.characteristicsSpeed" loc="DL.CharSpeed"}} - {{> AttributeInput icon="insanity" value=level.characteristicsInsanity name="level.characteristicsInsanity" loc="DL.CharInsanity"}} - {{> AttributeInput icon="corruption" value=level.characteristicsCorruption name="level.characteristicsCorruption" loc="DL.CharCorruption"}} - {{> AttributeInput icon="power" value=level.characteristicsPower name="level.characteristicsPower" loc="DL.CharPower"}} + + +
+ {{localize "DL.PathsLevelCharacteristicsSubtitle"}} +
+ {{> AttributeInput icon="health" value=level.characteristics.health name="level.characteristics.health" loc="DL.CharHealth"}} + {{> AttributeInput icon="defense" value=level.characteristics.defense name="level.characteristics.defense" loc="DL.AttributeDefense"}} + {{> AttributeInput icon="perception" value=level.characteristics.perception name="level.characteristics.perception" loc="DL.AttributePerception"}} + {{> AttributeInput icon="speed" value=level.characteristics.speed name="level.characteristics.speed" loc="DL.CharSpeed"}} + {{> AttributeInput icon="insanity" value=level.characteristics.insanity.value name="level.characteristics.insanity.value" loc="DL.CharInsanity"}} + {{> AttributeInput icon="corruption" value=level.characteristics.corruption.value name="level.characteristics.corruption.value" loc="DL.CharCorruption"}} + {{> AttributeInput icon="power" value=level.characteristics.power name="level.characteristics.power" loc="DL.CharPower"}} +
-
-
+
-
-
- {{localize "DL.PathsLevelLanguages"}} - -
-
- {{localize "DL.PathsLevelEquipment"}} - -
-
- {{localize "DL.TabsMagic"}} - -
-
- {{localize "DL.OptionsText"}} - +
+
+ {{localize "DL.PathsLevelLanguages"}} + +
+
+ {{localize "DL.PathsLevelEquipment"}} + +
+
+ {{localize "DL.TabsMagic"}} + +
+
+ {{localize "DL.OptionsText"}} + +
-
-
+
-
-
-
-
- {{localize "DL.TalentTitle"}} - - - +
+
+
+
+ {{localize "DL.TalentTitle"}} + + + +
+ {{> DropZoneEdit collection=level.talents dataGroup="talents" dataLevel=level.level}} +
+ + + +
+
+ {{localize "DL.TalentTitle"}} ({{localize 'DL.PathsLevelTalentChooseOne'}}) + + + +
+ {{> DropZoneEdit collection=level.talentspick dataGroup="talentspick" dataLevel=level.level}}
- {{> DropZoneEdit collection=level.talents dataGroup="talents" dataLevel=level.level}}
- - -
+
- {{localize "DL.TalentTitle"}} ({{localize 'DL.PathsLevelTalentChooseOne'}}) - + {{localize "DL.MagicSpellsTitle"}} +
- {{> DropZoneEdit collection=level.talentspick dataGroup="talentspick" dataLevel=level.level}} + {{> DropZoneEdit collection=level.spells dataGroup="spells" dataLevel=level.level}}
- -
-
- {{localize "DL.MagicSpellsTitle"}} - - - -
- {{> DropZoneEdit collection=level.spells dataGroup="spells" dataLevel=level.level}} -
-
+ {{/if}}
{{/each}} diff --git a/src/templates/item/item-ancestry-sheet.hbs b/src/templates/item/item-ancestry-sheet.hbs index 9a9383b1..359981a3 100644 --- a/src/templates/item/item-ancestry-sheet.hbs +++ b/src/templates/item/item-ancestry-sheet.hbs @@ -1,9 +1,6 @@