Added automation for defeated status

This commit is contained in:
WBHarry 2025-08-13 18:16:28 +02:00
parent e2da9f8e99
commit 47403b4b39
12 changed files with 168 additions and 37 deletions

View file

@ -821,6 +821,10 @@
"name": "Dead",
"description": "The character is dead"
},
"defeated": {
"name": "Defeated",
"description": "This adversary is defeated."
},
"hidden": {
"name": "Hidden",
"description": "While Hidden, attacks cannot be made directly targeting them nd any rolls against them are at disadvantage.\nWhen a Hidden creature moves or attacks, they are no longer Hidden. However, if a creature is Hidden when they begin making an attack, the roll has advantage; the Hidden condition isnt cleared until after the attack is resolved."
@ -1870,7 +1874,8 @@
"tier3": "Tier 3",
"tier4": "tier 4",
"domains": "Domains",
"downtime": "Downtime"
"downtime": "Downtime",
"rules": "Rules"
},
"Tiers": {
"singular": "Tier",
@ -2110,6 +2115,13 @@
"label": "Damage Reduction Rules Default",
"hint": "Wether using armor and reductions has rules on by default"
},
"defeated": {
"enabled": { "label": "Enabled" },
"overlay": { "label": "Overlay Effect" },
"characterDefault": { "label": "Character Default Defeated Status" },
"adversaryDefault": { "label": "Adversary Default Defeated Status" },
"companionDefault": { "label": "Companion Default Defeated Status" }
},
"hopeFear": {
"label": "Hope & Fear",
"gm": { "label": "GM" },
@ -2141,6 +2153,9 @@
"label": "Players Can Manually Edit Character Settings",
"hint": "Players are allowed to access the manual Character Settings and change their statistics beyond the rules."
}
},
"defeated": {
"title": "Defeated Handling"
}
},
"Homebrew": {

View file

@ -31,8 +31,19 @@ export default class DhAutomationSettings extends HandlebarsApplicationMixin(App
};
static PARTS = {
tabs: { template: 'systems/daggerheart/templates/sheets/global/tabs/tab-navigation.hbs' },
header: { template: 'systems/daggerheart/templates/settings/automation-settings/header.hbs' },
general: { template: 'systems/daggerheart/templates/settings/automation-settings/general.hbs' },
rules: { template: 'systems/daggerheart/templates/settings/automation-settings/rules.hbs' },
footer: { template: 'systems/daggerheart/templates/settings/automation-settings/footer.hbs' }
};
/** @inheritdoc */
static TABS = {
main: {
template: 'systems/daggerheart/templates/settings/automation-settings.hbs'
tabs: [{ id: 'general' }, { id: 'rules' }],
initial: 'general',
labelPrefix: 'DAGGERHEART.GENERAL.Tabs'
}
};

View file

@ -164,6 +164,27 @@ export const healingTypes = {
}
};
export const defeatedConditions = {
defeated: {
id: 'defeated',
name: 'DAGGERHEART.CONFIG.Condition.defeated.name',
icon: 'icons/magic/control/fear-fright-mask-orange.webp',
description: 'DAGGERHEART.CONFIG.Condition.defeated.description'
},
unconscious: {
id: 'unconscious',
name: 'DAGGERHEART.CONFIG.Condition.unconscious.name',
icon: 'icons/magic/control/sleep-bubble-purple.webp',
description: 'DAGGERHEART.CONFIG.Condition.unconscious.description'
},
dead: {
id: 'dead',
name: 'DAGGERHEART.CONFIG.Condition.dead.name',
icon: 'icons/magic/death/grave-tombstone-glow-teal.webp',
description: 'DAGGERHEART.CONFIG.Condition.dead.description'
}
};
export const conditions = {
vulnerable: {
id: 'vulnerable',
@ -183,18 +204,7 @@ export const conditions = {
icon: 'icons/magic/control/debuff-chains-shackle-movement-red.webp',
description: 'DAGGERHEART.CONFIG.Condition.restrained.description'
},
unconscious: {
id: 'unconscious',
name: 'DAGGERHEART.CONFIG.Condition.unconscious.name',
icon: 'icons/magic/control/sleep-bubble-purple.webp',
description: 'DAGGERHEART.CONFIG.Condition.unconscious.description'
},
dead: {
id: 'dead',
name: 'DAGGERHEART.CONFIG.Condition.dead.name',
icon: 'icons/magic/death/grave-tombstone-glow-teal.webp',
description: 'DAGGERHEART.CONFIG.Condition.dead.description'
}
...defeatedConditions
};
export const defaultRestOptions = {

View file

@ -106,6 +106,28 @@ export default class BaseDataActor extends foundry.abstract.TypeDataModel {
}, []);
options.scrollingTextData = textData;
}
if (changes.system?.resources) {
const defeatedSettings = game.settings.get(
CONFIG.DH.id,
CONFIG.DH.SETTINGS.gameSettings.Automation
).defeated;
const typeForDefeated = ['character', 'adversary', 'companion'].find(x => x === this.parent.type);
if (defeatedSettings.enabled && typeForDefeated) {
const resource = typeForDefeated === 'companion' ? 'stress' : 'hitPoints';
if (changes.system.resources[resource]) {
const becameMax = changes.system.resources[resource].value === this.resources[resource].max;
const wasMax =
this.resources[resource].value === this.resources[resource].max &&
this.resources[resource].value !== changes.system.resources[resource].value;
if (becameMax) {
this.parent.toggleDefeated(true);
} else if (wasMax) {
this.parent.toggleDefeated(false);
}
}
}
}
}
_onUpdate(changes, options, userId) {

View file

@ -8,4 +8,10 @@ export default class DhCombatant extends foundry.abstract.TypeDataModel {
actionTokens: new fields.NumberField({ required: true, integer: true, initial: 3 })
};
}
get isDefeated() {
const { unconscious, defeated, dead } = CONFIG.DH.GENERAL.conditions;
const defeatedConditions = new Set([unconscious.id, defeated.id, dead.id]);
return this.defeated || this.actor?.statuses.intersection(defeatedConditions)?.size;
}
}

View file

@ -50,6 +50,36 @@ export default class DhAutomation extends foundry.abstract.DataModel {
required: true,
initial: false,
label: 'DAGGERHEART.SETTINGS.Automation.FIELDS.playerCanEditSheet.label'
}),
defeated: new fields.SchemaField({
enabled: new fields.BooleanField({
required: true,
initial: false,
label: 'DAGGERHEART.SETTINGS.Automation.FIELDS.defeated.enabled.label'
}),
overlay: new fields.BooleanField({
required: true,
initial: true,
label: 'DAGGERHEART.SETTINGS.Automation.FIELDS.defeated.overlay.label'
}),
characterDefault: new fields.StringField({
required: true,
choices: CONFIG.DH.GENERAL.defeatedConditions,
initial: CONFIG.DH.GENERAL.defeatedConditions.unconscious.id,
label: 'DAGGERHEART.SETTINGS.Automation.FIELDS.defeated.characterDefault.label'
}),
adversaryDefault: new fields.StringField({
required: true,
choices: CONFIG.DH.GENERAL.defeatedConditions,
initial: CONFIG.DH.GENERAL.defeatedConditions.defeated.id,
label: 'DAGGERHEART.SETTINGS.Automation.FIELDS.defeated.adversaryDefault.label'
}),
companionDefault: new fields.StringField({
required: true,
choices: CONFIG.DH.GENERAL.defeatedConditions,
initial: CONFIG.DH.GENERAL.defeatedConditions.defeated.id,
label: 'DAGGERHEART.SETTINGS.Automation.FIELDS.defeated.companionDefault.label'
})
})
};
}

View file

@ -225,7 +225,8 @@ export const registerRollDiceHooks = () => {
const actor = await fromUuid(config.source.actor);
let updates = [];
if (!actor) return;
if (config.roll.isCritical || config.roll.result.duality === 1) updates.push({ key: 'hope', value: 1, total: -1, enabled: true });
if (config.roll.isCritical || config.roll.result.duality === 1)
updates.push({ key: 'hope', value: 1, total: -1, enabled: true });
if (config.roll.isCritical) updates.push({ key: 'stress', value: -1, total: 1, enabled: true });
if (config.roll.result.duality === -1) updates.push({ key: 'fear', value: 1, total: -1, enabled: true });
@ -233,16 +234,15 @@ export const registerRollDiceHooks = () => {
if (config.rerolledRoll.isCritical || config.rerolledRoll.result.duality === 1)
updates.push({ key: 'hope', value: -1, total: 1, enabled: true });
if (config.rerolledRoll.isCritical) updates.push({ key: 'stress', value: 1, total: -1, enabled: true });
if (config.rerolledRoll.result.duality === -1) updates.push({ key: 'fear', value: -1, total: 1, enabled: true });
if (config.rerolledRoll.result.duality === -1)
updates.push({ key: 'fear', value: -1, total: 1, enabled: true });
}
if (updates.length) {
const target = actor.system.partner ?? actor;
if (!['dead', 'unconscious'].some(x => actor.statuses.has(x))) {
if(config.rerolledRoll)
target.modifyResource(updates);
else
config.costs = [...(config.costs ?? []), ...updates];
if (!['dead', 'defeated', 'unconscious'].some(x => actor.statuses.has(x))) {
if (config.rerolledRoll) target.modifyResource(updates);
else config.costs = [...(config.costs ?? []), ...updates];
}
}

View file

@ -718,4 +718,21 @@ export default class DhpActor extends Actor {
value: 1
});
}
async toggleDefeated(defeatedState) {
const settings = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation).defeated;
const { unconscious, defeated, dead } = CONFIG.DH.GENERAL.conditions;
const defeatedConditions = new Set([unconscious.id, defeated.id, dead.id]);
if (!defeatedState) {
for (let defeatedId of defeatedConditions) {
await this.toggleStatusEffect(defeatedId, { overlay: settings.overlay, active: defeatedState });
}
} else {
const noDefeatedConditions = this.statuses.intersection(defeatedConditions).size === 0;
if (noDefeatedConditions) {
const condition = settings[`${this.type}Default`];
await this.toggleStatusEffect(condition, { overlay: settings.overlay, active: defeatedState });
}
}
}
}

View file

@ -0,0 +1,10 @@
<footer class="form-footer">
<button data-action="reset">
<i class="fa-solid fa-arrow-rotate-left"></i>
<span>{{localize "Reset"}}</span>
</button>
<button data-action="save" >
<i class="fa-solid fa-floppy-disk"></i>
<span>{{localize "Save Changes"}}</span>
</button>
</footer>

View file

@ -1,7 +1,8 @@
<div>
<header class="dialog-header">
<h1>{{localize 'DAGGERHEART.SETTINGS.Menu.automation.name'}}</h1>
</header>
<section
class="tab {{tabs.general.cssClass}} {{tabs.general.id}}"
data-tab="{{tabs.general.id}}"
data-group="{{tabs.general.group}}"
>
<div class="form-group">
<label>{{localize "DAGGERHEART.SETTINGS.Automation.FIELDS.hopeFear.label"}}</label>
{{formGroup settingFields.schema.fields.hopeFear.fields.gm value=settingFields._source.hopeFear.gm localize=true}}
@ -15,16 +16,5 @@
{{formGroup settingFields.schema.fields.playerCanEditSheet value=settingFields._source.playerCanEditSheet localize=true}}
{{formGroup settingFields.schema.fields.damageReductionRulesDefault value=settingFields._source.damageReductionRulesDefault localize=true}}
{{formGroup settingFields.schema.fields.resourceScrollTexts value=settingFields._source.resourceScrollTexts localize=true}}
<footer class="form-footer">
<button data-action="reset">
<i class="fa-solid fa-arrow-rotate-left"></i>
<span>{{localize "Reset"}}</span>
</button>
<button data-action="save" >
<i class="fa-solid fa-floppy-disk"></i>
<span>{{localize "Save Changes"}}</span>
</button>
</footer>
</div>
</section>

View file

@ -0,0 +1,3 @@
<header class="dialog-header">
<h1>{{localize 'DAGGERHEART.SETTINGS.Menu.automation.name'}}</h1>
</header>

View file

@ -0,0 +1,17 @@
<section
class="tab {{tabs.rules.cssClass}} {{tabs.rules.id}}"
data-tab="{{tabs.rules.id}}"
data-group="{{tabs.rules.group}}"
>
<fieldset>
<legend>
{{localize "DAGGERHEART.SETTINGS.Automation.defeated.title"}}
</legend>
{{formGroup settingFields.schema.fields.defeated.fields.enabled value=settingFields._source.defeated.enabled localize=true}}
{{formGroup settingFields.schema.fields.defeated.fields.overlay value=settingFields._source.defeated.overlay localize=true}}
{{formGroup settingFields.schema.fields.defeated.fields.characterDefault value=settingFields._source.defeated.characterDefault labelAttr="name" localize=true}}
{{formGroup settingFields.schema.fields.defeated.fields.adversaryDefault value=settingFields._source.defeated.adversaryDefault labelAttr="name" localize=true}}
{{formGroup settingFields.schema.fields.defeated.fields.companionDefault value=settingFields._source.defeated.companionDefault labelAttr="name" localize=true}}
</fieldset>
</section>