Fixed normal levelup

This commit is contained in:
WBHarry 2025-06-30 13:43:12 +02:00
parent 0aa08deaa3
commit b18f072c64
14 changed files with 159 additions and 104 deletions

View file

@ -1,12 +1,13 @@
import LevelUpBase from './levelup.mjs';
import { DhLevelup } from '../../data/levelup.mjs';
import { domains } from '../../config/domainConfig.mjs';
import { abilities } from '../../config/actorConfig.mjs';
export default class DhCharacterLevelUp extends LevelUpBase {
constructor(actor) {
super(actor);
this.levelTiers = game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.LevelTiers);
this.levelTiers = this.addBonusChoices(game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.LevelTiers));
const playerLevelupData = actor.system.levelData;
this.levelup = new DhLevelup(DhLevelup.initializeData(this.levelTiers, playerLevelupData));
}
@ -50,7 +51,7 @@ export default class DhCharacterLevelUp extends LevelUpBase {
.flatMap(exp =>
exp.data.map(data => {
const experience = Object.keys(this.actor.system.experiences).find(x => x === data);
return this.actor.system.experiences[experience].description;
return this.actor.system.experiences[experience].name;
})
);
context.experienceIncreases = {

View file

@ -7,7 +7,7 @@ export default class DhCompanionLevelUp extends BaseLevelUp {
constructor(actor) {
super(actor);
this.levelTiers = defaultCompanionTier;
this.levelTiers = this.addBonusChoices(defaultCompanionTier);
const playerLevelupData = actor.system.levelData;
this.levelup = new DhLevelup(DhLevelup.initializeData(this.levelTiers, playerLevelupData));
}
@ -40,7 +40,7 @@ export default class DhCompanionLevelUp extends BaseLevelUp {
.flatMap(exp =>
exp.data.map(data => {
const experience = Object.keys(this.actor.system.experiences).find(x => x === data);
return this.actor.system.experiences[experience].description;
return this.actor.system.experiences[experience].name;
})
);
context.experienceIncreases = {
@ -69,23 +69,7 @@ export default class DhCompanionLevelUp extends BaseLevelUp {
break;
case 'summary':
const { current: currentActorLevel, changed: changedActorLevel } = this.actor.system.levelData.level;
const levelKeys = Object.keys(this.levelup.levels);
let achievementExperiences = [];
for (var levelKey of levelKeys) {
const level = this.levelup.levels[levelKey];
if (Number(levelKey) < this.levelup.startLevel) continue;
achievementExperiences = level.achievements.experiences
? Object.values(level.achievements.experiences).reduce((acc, experience) => {
if (experience.name) acc.push(experience);
return acc;
}, [])
: [];
}
context.achievements = {};
const actorDamageDice = this.actor.system.attack.damage.parts[0].value.dice;
const actorRange = this.actor.system.attack.range;
const advancement = {};
@ -97,13 +81,13 @@ export default class DhCompanionLevelUp extends BaseLevelUp {
const choice = level.choices[choiceKey];
for (var checkbox of Object.values(choice)) {
switch (choiceKey) {
case 'resilient':
case 'aware':
case 'stress':
case 'evasion':
advancement[choiceKey] = advancement[choiceKey]
? advancement[choiceKey] + Number(checkbox.value)
: Number(checkbox.value);
break;
case 'intelligent':
case 'experience':
if (!advancement[choiceKey]) advancement[choiceKey] = [];
const data = checkbox.data.map(data => {
const experience = Object.keys(this.actor.system.experiences).find(

View file

@ -76,6 +76,21 @@ export default class DhlevelUp extends HandlebarsApplicationMixin(ApplicationV2)
}
};
addBonusChoices(levelTiers) {
for (var tierKey in levelTiers.tiers) {
const tier = levelTiers.tiers[tierKey];
tier.maxSelections = [...Array(tier.levels.end - tier.levels.start + 1).keys()].reduce((acc, index) => {
const level = tier.levels.start + index;
const bonus = this.actor.system.levelData.level.bonuses[level];
acc[level] = tier.availableOptions + (bonus ?? 0);
return acc;
}, {});
}
return levelTiers;
}
async _prepareContext(_options) {
const context = await super._prepareContext(_options);
context.levelup = this.levelup;
@ -336,7 +351,7 @@ export default class DhlevelUp extends HandlebarsApplicationMixin(ApplicationV2)
experienceIncreaseTagify,
Object.keys(this.actor.system.experiences).reduce((acc, id) => {
const experience = this.actor.system.experiences[id];
acc[id] = { label: experience.description };
acc[id] = { label: experience.name };
return acc;
}, {}),

View file

@ -1,3 +1,4 @@
import { GMUpdateEvent, socketEvent } from '../../helpers/socket.mjs';
import DhCompanionlevelUp from '../levelup/companionLevelup.mjs';
import DaggerheartSheet from './daggerheart-sheet.mjs';
@ -31,9 +32,15 @@ export default class DhCompanionSheet extends DaggerheartSheet(ActorSheetV2) {
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 }));
context.playerCharacters = game.actors
.filter(
x =>
x.type === 'character' &&
(x.ownership.default === 3 ||
x.ownership[game.user.id] === 3 ||
this.document.system.partner?.uuid === x.uuid)
)
.map(x => ({ key: x.uuid, name: x.name }));
return context;
}
@ -48,7 +55,22 @@ export default class DhCompanionSheet extends DaggerheartSheet(ActorSheetV2) {
const partner = game.actors.find(a => a.uuid === event.target.value);
await partner.update({ 'system.companion': this.document.uuid });
} else {
await this.document.system.partner.update({ 'system.companion': null });
const update = { 'system.companion': null };
if (
this.document.system.partner.ownership.default !== 3 &&
this.document.system.partner.ownership[game.user.id] !== 3
) {
await game.socket.emit(`system.${SYSTEM.id}`, {
action: socketEvent.GMUpdate,
data: {
action: GMUpdateEvent.UpdateDocument,
uuid: this.document.system.partner.uuid,
update: update
}
});
} else {
await this.document.system.partner.update(update);
}
}
await this.document.update({ 'system.partner': event.target.value });

View file

@ -115,7 +115,7 @@ export default class DhCharacter extends BaseDataActor {
magic: new fields.NumberField({ integer: true, initial: 0 })
})
}),
companion: new ForeignDocumentUUIDField({ type: 'actor', nullable: true, initial: null }),
companion: new ForeignDocumentUUIDField({ type: 'Actor', nullable: true, initial: null }),
rules: new fields.SchemaField({
maxArmorMarked: new fields.SchemaField({
value: new fields.NumberField({ required: true, integer: true, initial: 1 }),
@ -315,4 +315,10 @@ export default class DhCharacter extends BaseDataActor {
level: this.levelData.level.current
};
}
async _preDelete() {
if (this.companion) {
this.companion.updateLevel(1);
}
}
}

View file

@ -85,23 +85,23 @@ export default class DhCompanion extends BaseDataActor {
const level = this.levelData.levelups[levelKey];
for (let selection of level.selections) {
switch (selection.type) {
case 'lightInTheDark':
case 'hope':
this.resources.hope += selection.value;
break;
case 'vicious':
if (selection.data === 'damage') {
if (selection.data[0] === 'damage') {
this.attack.damage.parts[0].value.dice = adjustDice(this.attack.damage.parts[0].value.dice);
} else {
this.attack.range = adjustRange(this.attack.range);
}
break;
case 'resilient':
case 'stress':
this.resources.stress.bonus += selection.value;
break;
case 'aware':
case 'evasion':
this.evasion.bonus += selection.value;
break;
case 'intelligent':
case 'experience':
Object.keys(this.experiences).forEach(key => {
const experience = this.experiences[key];
experience.bonus += selection.value;
@ -118,6 +118,10 @@ export default class DhCompanion extends BaseDataActor {
experience.total = experience.value + experience.bonus;
}
if (this.partner) {
this.partner.system.resources.hope.max += this.resources.hope;
}
this.resources.stress.maxTotal = this.resources.stress.max + this.resources.stress.bonus;
this.evasion.total = this.evasion.value + this.evasion.bonus;
}
@ -129,7 +133,9 @@ export default class DhCompanion extends BaseDataActor {
};
}
_preDelete() {
/* Null Character Companion field */
async _preDelete() {
if (this.partner) {
await this.partner.update({ 'system.companion': null });
}
}
}

View file

@ -7,7 +7,8 @@ export default class DhLevelData extends foundry.abstract.DataModel {
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 })
changed: new fields.NumberField({ required: true, integer: true, initial: 1 }),
bonuses: new fields.TypedObjectField(new fields.NumberField({ integer: true, nullable: false }))
}),
levelups: new fields.TypedObjectField(
new fields.SchemaField({

View file

@ -59,13 +59,16 @@ class DhLevelOption extends foundry.abstract.DataModel {
}
export const CompanionLevelOptionType = {
lightInTheDark: {
id: 'lightInTheDark',
hope: {
id: 'hope',
label: 'Light In The Dark'
},
createComfort: {
id: 'createComfort',
label: 'Create Comfort'
creatureComfort: {
id: 'creatureComfort',
label: 'Creature Comfort'
// actions: [
// ],
},
armored: {
id: 'armored',
@ -390,20 +393,20 @@ export const defaultCompanionTier = {
minCost: 1,
type: LevelOptionType.experience.id,
value: 1,
amount: 2
amount: 1
},
lightInTheDark: {
hope: {
label: 'DAGGERHEART.LevelUp.Options.lightInTheDark',
checkboxSelections: 1,
minCost: 1,
type: CompanionLevelOptionType.lightInTheDark.id,
type: CompanionLevelOptionType.hope.id,
value: 1
},
creatureComfort: {
label: 'DAGGERHEART.LevelUp.Options.creatureComfort',
checkboxSelections: 1,
minCost: 1,
type: CompanionLevelOptionType.createComfort.id,
type: CompanionLevelOptionType.creatureComfort.id,
value: 1
},
armored: {
@ -421,11 +424,11 @@ export const defaultCompanionTier = {
value: 1,
amount: 1
},
resilient: {
stress: {
label: 'DAGGERHEART.LevelUp.Options.resilient',
checkboxSelections: 3,
minCost: 1,
type: CompanionLevelOptionType.resilient.id,
type: LevelOptionType.stress.id,
value: 1
},
bonded: {
@ -435,11 +438,11 @@ export const defaultCompanionTier = {
type: CompanionLevelOptionType.bonded.id,
value: 1
},
aware: {
evasion: {
label: 'DAGGERHEART.LevelUp.Options.aware',
checkboxSelections: 3,
minCost: 1,
type: CompanionLevelOptionType.aware.id,
type: LevelOptionType.evasion.id,
value: 2,
amount: 1
}

View file

@ -32,7 +32,7 @@ export class DhLevelup extends foundry.abstract.DataModel {
return acc;
}, {});
levels[i] = DhLevelupLevel.initializeData(pcLevelData.levelups[i], tier.availableOptions, {
levels[i] = DhLevelupLevel.initializeData(pcLevelData.levelups[i], tier.maxSelections[i], {
...initialAchievements,
experiences,
domainCards
@ -99,7 +99,6 @@ export class DhLevelup extends foundry.abstract.DataModel {
case 'domainCard':
case 'subclass':
case 'vicious':
case 'intelligent':
return checkbox.data.length === (checkbox.amount ?? 1);
case 'multiclass':
const classSelected = checkbox.data.length === 1;

View file

@ -18,7 +18,11 @@ export default class DhpActor extends Actor {
}
async updateLevel(newLevel) {
if (this.type !== 'character' || newLevel === this.system.levelData.level.changed) return;
if (!['character', 'companion'].includes(this.type) || newLevel === this.system.levelData.level.changed) return;
if (this.system.companion) {
this.system.companion.updateLevel(newLevel);
}
if (newLevel > this.system.levelData.level.current) {
const maxLevel = Object.values(
@ -67,12 +71,16 @@ export default class DhpActor extends Actor {
});
if (experiences.length > 0) {
this.update({
const getUpdate = () => ({
'system.experiences': experiences.reduce((acc, key) => {
acc[`-=${key}`] = null;
return acc;
}, {})
});
this.update(getUpdate());
if (this.system.companion) {
this.system.companion.update(getUpdate());
}
}
if (subclassFeatureState.class) {
@ -126,10 +134,19 @@ export default class DhpActor extends Actor {
const experience = level.achievements.experiences[experienceKey];
await this.update({
[`system.experiences.${experienceKey}`]: {
description: experience.name,
name: experience.name,
value: experience.modifier
}
});
if (this.system.companion) {
await this.system.companion.update({
[`system.experiences.${experienceKey}`]: {
name: '',
value: experience.modifier
}
});
}
}
let multiclass = null;

View file

@ -113,7 +113,7 @@
<div class="experience-value">
+{{experience.total}}
</div>
<input name="{{concat "system.experiences." id ".description"}}" data-experience={{id}} value="{{experience.description}}" type="text" />
<input name="{{concat "system.experiences." id ".name"}}" data-experience={{id}} value="{{experience.name}}" type="text" />
<div class="controls">
<a data-action="toChat" data-type="experience" data-uuid="{{id}}"><i class="fa-regular fa-message"></i></a>
</div>

View file

@ -35,7 +35,7 @@
<div class="form-group">
<div class="form-fields">
<label>{{localize "DAGGERHEART.Sheets.Companion.Level"}}</label>
<input type="text" name="system.levelData.level.changed" value="{{source.system.levelData.level.changed}}" />
<div>{{source.system.levelData.level.changed}}</div>
<button data-action="levelUp" {{#if (not source.system.levelData.canLevelUp)}}disabled{{/if}}>Level Up</button>
</div>
</div>

View file

@ -117,7 +117,7 @@
<h3>{{localize "DAGGERHEART.Application.LevelUp.summary.vicious"}}</h3>
{{#each this.vicious}}
<div class="levelup-radio-choices">
{{radioBoxes (concat "levelup." this.path ".data") @root.viciousChoices checked=this.data}}
{{radioBoxes (concat "levelup." this.path ".data") @root.viciousChoices checked=(lookup this.data 0)}}
</div>
{{/each}}
</div>

View file

@ -4,57 +4,58 @@
data-group='{{tabs.summary.group}}'
>
<div class="section-container levelup-summary-container">
<fieldset>
<legend>{{localize "DAGGERHEART.Application.LevelUp.summary.levelAchievements"}}</legend>
{{#if this.achievements}}
<fieldset>
<legend>{{localize "DAGGERHEART.Application.LevelUp.summary.levelAchievements"}}</legend>
<div class="level-achievements-container">
{{#if this.achievements.proficiency.shown}}
<div>
<div class="increase-container">
{{localize "DAGGERHEART.Application.LevelUp.summary.proficiencyIncrease" proficiency=this.achievements.proficiency.old }}
<i class="fa-solid fa-arrow-right-long"></i>
{{this.achievements.proficiency.new}}
<div class="level-achievements-container">
{{#if this.achievements.proficiency.shown}}
<div>
<div class="increase-container">
{{localize "DAGGERHEART.Application.LevelUp.summary.proficiencyIncrease" proficiency=this.achievements.proficiency.old }}
<i class="fa-solid fa-arrow-right-long"></i>
{{this.achievements.proficiency.new}}
</div>
</div>
</div>
{{/if}}
{{#if this.achievements.damageThresholds}}
<div>
<h5 class="summary-section">{{localize "DAGGERHEART.Application.LevelUp.summary.damageThresholds"}}{{#if this.levelAchievements.damageThresholds.unarmored}}({{localize "DAGGERHEART.General.unarmored"}}){{/if}}</h5>
<div class="increase-container">
{{localize "DAGGERHEART.Application.LevelUp.summary.damageThresholdMajorIncrease" threshold=this.achievements.damageThresholds.major.old }}
<i class="fa-solid fa-arrow-right-long"></i>
{{this.achievements.damageThresholds.major.new}}
{{/if}}
{{#if this.achievements.damageThresholds}}
<div>
<h5 class="summary-section">{{localize "DAGGERHEART.Application.LevelUp.summary.damageThresholds"}}{{#if this.levelAchievements.damageThresholds.unarmored}}({{localize "DAGGERHEART.General.unarmored"}}){{/if}}</h5>
<div class="increase-container">
{{localize "DAGGERHEART.Application.LevelUp.summary.damageThresholdMajorIncrease" threshold=this.achievements.damageThresholds.major.old }}
<i class="fa-solid fa-arrow-right-long"></i>
{{this.achievements.damageThresholds.major.new}}
</div>
<div class="increase-container">
{{localize "DAGGERHEART.Application.LevelUp.summary.damageThresholdSevereIncrease" threshold=this.achievements.damageThresholds.severe.old }}
<i class="fa-solid fa-arrow-right-long"></i>
{{this.achievements.damageThresholds.severe.new}}
</div>
</div>
<div class="increase-container">
{{localize "DAGGERHEART.Application.LevelUp.summary.damageThresholdSevereIncrease" threshold=this.achievements.damageThresholds.severe.old }}
<i class="fa-solid fa-arrow-right-long"></i>
{{this.achievements.damageThresholds.severe.new}}
{{/if}}
{{#if this.achievements.domainCards.shown}}
<div>
<h5>{{localize "DAGGERHEART.Application.LevelUp.summary.domainCards"}}</h5>
<div class="summary-selection-container">
{{#each this.achievements.domainCards.values}}
<div class="summary-selection">{{this.name}}</div>
{{/each}}
</div>
</div>
</div>
{{/if}}
{{#if this.achievements.domainCards.shown}}
<div>
<h5>{{localize "DAGGERHEART.Application.LevelUp.summary.domainCards"}}</h5>
<div class="summary-selection-container">
{{#each this.achievements.domainCards.values}}
<div class="summary-selection">{{this.name}}</div>
{{/each}}
{{/if}}
{{#if this.achievements.experiences.shown}}
<div>
<h5>{{localize "DAGGERHEART.Application.LevelUp.summary.newExperiences"}}</h5>
<div class="summary-selection-container">
{{#each this.achievements.experiences.values}}
<div class="summary-selection">{{this.name}} {{signedNumber this.modifier}}</div>
{{/each}}
</div>
</div>
</div>
{{/if}}
{{#if this.achievements.experiences.shown}}
<div>
<h5>{{localize "DAGGERHEART.Application.LevelUp.summary.newExperiences"}}</h5>
<div class="summary-selection-container">
{{#each this.achievements.experiences.values}}
<div class="summary-selection">{{this.name}} {{signedNumber this.modifier}}</div>
{{/each}}
</div>
</div>
{{/if}}
</div>
</fieldset>
{{/if}}
</div>
</fieldset>
{{/if}}
<fieldset>
<legend>{{localize "DAGGERHEART.Application.LevelUp.summary.levelAdvancements"}}</legend>