[Feature] Beastform Types (#372)

* Temp

* Finished Evolved

* Fixed hybrid

* Changed generalConfig.tiers to be number based

* Weaponhandling while in beastform

* Added unarmed strike in sidebar

* Added DamageEnricher

* Added effect enricher

* Corrected downtime buttons and actions

* Added BeastformTooltip

* Split the BeastformDialog into parts with tabs

* Added temp beastform features

* rollData change

* Improvement

* character.getRollData cleanup
This commit is contained in:
WBHarry 2025-07-20 21:56:22 +02:00 committed by GitHub
parent 867947c2c5
commit 42a705a870
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
93 changed files with 2795 additions and 538 deletions

View file

@ -113,7 +113,7 @@ export class DHResourceData extends foundry.abstract.DataModel {
}),
value: new fields.EmbeddedDataField(DHActionDiceData),
valueAlt: new fields.EmbeddedDataField(DHActionDiceData)
}
};
}
}
@ -134,6 +134,6 @@ export class DHDamageData extends DHResourceData {
label: 'Type'
}
)
}
};
}
}

View file

@ -163,7 +163,7 @@ export default class DHBaseAction extends foundry.abstract.DataModel {
}
getRollData(data = {}) {
if(!this.actor) return null;
if (!this.actor) return null;
const actorData = this.actor.getRollData(false);
// Add Roll results to RollDatas
@ -178,8 +178,8 @@ export default class DHBaseAction extends foundry.abstract.DataModel {
}
async use(event, ...args) {
if(!this.actor) throw new Error("An Action can't be used outside of an Actor context.");
if (!this.actor) throw new Error("An Action can't be used outside of an Actor context.");
const isFastForward = event.shiftKey || (!this.hasRoll && !this.hasSave);
// Prepare base Config
const initConfig = this.initActionConfig(event);

View file

@ -10,10 +10,10 @@ export default class DhBeastformAction extends DHBaseAction {
const abort = await this.handleActiveTransformations();
if (abort) return;
const beastformUuid = await BeastformDialog.configure(beastformConfig);
if (!beastformUuid) return;
const { selected, evolved, hybrid } = await BeastformDialog.configure(beastformConfig);
if (!selected) return;
await this.transform(beastformUuid);
await this.transform(selected, evolved, hybrid);
}
prepareBeastformConfig(config) {
@ -29,21 +29,48 @@ export default class DhBeastformAction extends DHBaseAction {
};
}
async transform(beastformUuid) {
const beastform = await foundry.utils.fromUuid(beastformUuid);
this.actor.createEmbeddedDocuments('Item', [beastform.toObject()]);
async transform(selectedForm, evolvedData, hybridData) {
const formData = evolvedData?.form ? evolvedData.form.toObject() : selectedForm.toObject();
const beastformEffect = formData.effects.find(x => x.type === 'beastform');
if (!beastformEffect) {
ui.notifications.error('DAGGERHEART.UI.Notifications.beastformMissingEffect');
return;
}
if (evolvedData?.form) {
const evolvedForm = selectedForm.effects.find(x => x.type === 'beastform');
if (!evolvedForm) {
ui.notifications.error('DAGGERHEART.UI.Notifications.beastformMissingEffect');
return;
}
beastformEffect.changes = [...beastformEffect.changes, ...evolvedForm.changes];
formData.system.features = [...formData.system.features, ...selectedForm.system.features.map(x => x.uuid)];
}
if (selectedForm.system.beastformType === CONFIG.DH.ITEM.beastformTypes.hybrid.id) {
formData.system.advantageOn = Object.values(hybridData.advantages).reduce((advantages, formCategory) => {
Object.keys(formCategory).forEach(advantageKey => {
advantages[advantageKey] = formCategory[advantageKey];
});
return advantages;
}, {});
formData.system.features = [
...formData.system.features,
...Object.values(hybridData.features).flatMap(x => Object.keys(x))
];
}
this.actor.createEmbeddedDocuments('Item', [formData]);
}
async handleActiveTransformations() {
const beastformEffects = this.actor.effects.filter(x => x.type === 'beastform');
if (beastformEffects.length > 0) {
for (let effect of beastformEffects) {
await effect.delete();
}
return true;
}
return false;
const existingEffects = beastformEffects.length > 0;
await this.actor.deleteEmbeddedDocuments(
'ActiveEffect',
beastformEffects.map(x => x.id)
);
return existingEffects;
}
}

View file

@ -22,31 +22,32 @@ export default class DHDamageAction extends DHBaseAction {
formatFormulas(formulas, systemData) {
const formattedFormulas = [];
formulas.forEach(formula => {
if (isNaN(formula.formula)) formula.formula = Roll.replaceFormulaData(formula.formula, this.getRollData(systemData));
const same = formattedFormulas.find(f => setsEqual(f.damageTypes, formula.damageTypes) && f.applyTo === formula.applyTo);
if(same)
same.formula += ` + ${formula.formula}`;
else
formattedFormulas.push(formula);
})
if (isNaN(formula.formula))
formula.formula = Roll.replaceFormulaData(formula.formula, this.getRollData(systemData));
const same = formattedFormulas.find(
f => setsEqual(f.damageTypes, formula.damageTypes) && f.applyTo === formula.applyTo
);
if (same) same.formula += ` + ${formula.formula}`;
else formattedFormulas.push(formula);
});
return formattedFormulas;
}
async rollDamage(event, data) {
const systemData = data.system ?? data;
let formulas = this.damage.parts.map(p => ({
formula: this.getFormulaValue(p, data).getFormula(this.actor),
damageTypes: p.applyTo === 'hitPoints' && !p.type.size ? new Set(['physical']) : p.type,
applyTo: p.applyTo
}));
if(!formulas.length) return;
if (!formulas.length) return;
formulas = this.formatFormulas(formulas, systemData);
const config = {
title: game.i18n.format('DAGGERHEART.UI.Chat.damageRoll.title', { damage: this.name }),
title: game.i18n.format('DAGGERHEART.UI.Chat.damageRoll.title', { damage: game.i18n.localize(this.name) }),
roll: formulas,
targets: systemData.targets.filter(t => t.hit) ?? data.targets,
hasSave: this.hasSave,

View file

@ -16,11 +16,13 @@ export default class DHHealingAction extends DHBaseAction {
async rollHealing(event, data) {
const systemData = data.system ?? data;
let formulas = [{
formula: this.getFormulaValue(data).getFormula(this.actor),
applyTo: this.healing.applyTo
}];
let formulas = [
{
formula: this.getFormulaValue(data).getFormula(this.actor),
applyTo: this.healing.applyTo
}
];
const config = {
title: game.i18n.format('DAGGERHEART.UI.Chat.healingRoll.title', {
healing: game.i18n.localize(CONFIG.DH.GENERAL.healingTypes[this.healing.applyTo].label)