mirror of
https://github.com/Foundryborne/daggerheart.git
synced 2026-01-12 03:31:07 +01:00
Added Modifiers
This commit is contained in:
parent
51a0fb82eb
commit
e32454b7c7
9 changed files with 344 additions and 205 deletions
|
|
@ -1,3 +1,5 @@
|
|||
import { AdversaryBPPerEncounter } from '../../config/encounterConfig.mjs';
|
||||
|
||||
export default class DhCombatTracker extends foundry.applications.sidebar.tabs.CombatTracker {
|
||||
static DEFAULT_OPTIONS = {
|
||||
actions: {
|
||||
|
|
@ -37,36 +39,16 @@ export default class DhCombatTracker extends foundry.applications.sidebar.tabs.C
|
|||
async _prepareCombatContext(context, options) {
|
||||
await super._prepareCombatContext(context, options);
|
||||
|
||||
const adversaryTypes = CONFIG.DH.ACTOR.allAdversaryTypes();
|
||||
const maxBP = CONFIG.DH.ENCOUNTER.BaseBPPerEncounter(context.characters.length);
|
||||
const currentBP = context.adversaries
|
||||
.reduce((acc, adversary) => {
|
||||
const existingEntry = acc.find(
|
||||
x => x.adversary.name === adversary.name && x.adversary.type === adversary.type
|
||||
);
|
||||
if (existingEntry) {
|
||||
existingEntry.nr += 1;
|
||||
} else {
|
||||
acc.push({ adversary, nr: 1 });
|
||||
}
|
||||
return acc;
|
||||
}, [])
|
||||
.reduce((acc, entry) => {
|
||||
const adversary = entry.adversary;
|
||||
const type = adversaryTypes[adversary.type];
|
||||
const bpCost = type.bpCost ?? 0;
|
||||
if (type.partyAmountPerBP) {
|
||||
acc += context.characters.length === 0 ? 0 : Math.ceil(entry.nr / context.characters.length);
|
||||
} else {
|
||||
acc += bpCost;
|
||||
}
|
||||
|
||||
return acc;
|
||||
}, 0);
|
||||
const modifierBP =
|
||||
this.combats
|
||||
.find(x => x.active)
|
||||
?.system?.battleToggles?.reduce((acc, toggle) => acc + toggle.category, 0) ?? 0;
|
||||
const maxBP = CONFIG.DH.ENCOUNTER.BaseBPPerEncounter(context.characters.length) + modifierBP;
|
||||
const currentBP = AdversaryBPPerEncounter(context.adversaries, context.characters);
|
||||
|
||||
Object.assign(context, {
|
||||
fear: game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Resources.Fear),
|
||||
battlepoints: { max: maxBP, current: currentBP }
|
||||
battlepoints: { max: maxBP, current: currentBP, hasModifierBP: Boolean(modifierBP) }
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -121,7 +121,8 @@ export const adversaryTypes = {
|
|||
id: 'leader',
|
||||
label: 'DAGGERHEART.CONFIG.AdversaryType.leader.label',
|
||||
description: 'DAGGERHEART.ACTORS.Adversary.leader.description',
|
||||
bpCost: 3
|
||||
bpCost: 3,
|
||||
bpDescription: 'DAGGERHEART.CONFIG.AdversaryType.leader.'
|
||||
},
|
||||
minion: {
|
||||
id: 'minion',
|
||||
|
|
|
|||
|
|
@ -1,5 +1,33 @@
|
|||
export const BaseBPPerEncounter = nrCharacters => 3 * nrCharacters + 2;
|
||||
|
||||
export const AdversaryBPPerEncounter = (adversaries, characters) => {
|
||||
const adversaryTypes = CONFIG.DH.ACTOR.allAdversaryTypes();
|
||||
return adversaries
|
||||
.reduce((acc, adversary) => {
|
||||
const existingEntry = acc.find(
|
||||
x => x.adversary.name === adversary.name && x.adversary.type === adversary.type
|
||||
);
|
||||
if (existingEntry) {
|
||||
existingEntry.nr += 1;
|
||||
} else {
|
||||
acc.push({ adversary, nr: 1 });
|
||||
}
|
||||
return acc;
|
||||
}, [])
|
||||
.reduce((acc, entry) => {
|
||||
const adversary = entry.adversary;
|
||||
const type = adversaryTypes[adversary.type];
|
||||
const bpCost = type.bpCost ?? 0;
|
||||
if (type.partyAmountPerBP) {
|
||||
acc += characters.length === 0 ? 0 : Math.ceil(entry.nr / characters.length);
|
||||
} else {
|
||||
acc += bpCost;
|
||||
}
|
||||
|
||||
return acc;
|
||||
}, 0);
|
||||
};
|
||||
|
||||
export const adversaryTypeCostBrackets = {
|
||||
1: [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,6 +1,13 @@
|
|||
export default class DhCombat extends foundry.abstract.TypeDataModel {
|
||||
static defineSchema() {
|
||||
const fields = foundry.data.fields;
|
||||
return {};
|
||||
return {
|
||||
battleToggles: new fields.ArrayField(
|
||||
new fields.SchemaField({
|
||||
category: new fields.NumberField({ required: true, integer: true }),
|
||||
grouping: new fields.StringField({ required: true })
|
||||
})
|
||||
)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,28 @@
|
|||
import { AdversaryBPPerEncounter, BaseBPPerEncounter } from '../config/encounterConfig.mjs';
|
||||
|
||||
export default class DhTooltipManager extends foundry.helpers.interaction.TooltipManager {
|
||||
#wide = false;
|
||||
|
||||
async activate(element, options = {}) {
|
||||
const { TextEditor } = foundry.applications.ux;
|
||||
|
||||
let html = options.html;
|
||||
if (element.dataset.tooltip?.startsWith('#battlepoints#')) {
|
||||
this.#wide = true;
|
||||
|
||||
html = await this.getBattlepointHTML(element.dataset.combatId);
|
||||
options.direction = this._determineItemTooltipDirection(element);
|
||||
super.activate(element, { ...options, html: html });
|
||||
|
||||
const lockedTooltip = this.lockTooltip();
|
||||
lockedTooltip.querySelectorAll('.battlepoint-toggle-container input').forEach(element => {
|
||||
element.addEventListener('input', this.toggleModifier.bind(this));
|
||||
});
|
||||
return;
|
||||
} else {
|
||||
this.#wide = false;
|
||||
}
|
||||
|
||||
if (element.dataset.tooltip?.startsWith('#item#')) {
|
||||
const itemUuid = element.dataset.tooltip.slice(6);
|
||||
const item = await foundry.utils.fromUuid(itemUuid);
|
||||
|
|
@ -24,53 +44,6 @@ export default class DhTooltipManager extends foundry.helpers.interaction.Toolti
|
|||
this.tooltip.innerHTML = html;
|
||||
options.direction = this._determineItemTooltipDirection(element);
|
||||
}
|
||||
} else if (element.dataset.tooltip?.startsWith('#battlepoints#')) {
|
||||
const combat = game.combats.get(element.dataset.combatId);
|
||||
const nrCharacters = Number(element.dataset.nrCharacters);
|
||||
const currentBP = element.dataset.bpCurrent;
|
||||
const maxBP = element.dataset.bpMax;
|
||||
|
||||
const categories = combat.combatants.reduce((acc, combatant) => {
|
||||
if (combatant.actor.type === 'adversary') {
|
||||
const keyData = Object.keys(acc).reduce((identifiers, categoryKey) => {
|
||||
if (identifiers) return identifiers;
|
||||
const category = acc[categoryKey];
|
||||
const groupingIndex = category.findIndex(grouping =>
|
||||
grouping.types.includes(combatant.actor.system.type)
|
||||
);
|
||||
if (groupingIndex !== -1) identifiers = { categoryKey, groupingIndex };
|
||||
|
||||
return identifiers;
|
||||
}, null);
|
||||
if (keyData) {
|
||||
const { categoryKey, groupingIndex } = keyData;
|
||||
const grouping = acc[categoryKey][groupingIndex];
|
||||
const partyAmount =
|
||||
CONFIG.DH.ACTOR.adversaryTypes[combatant.actor.system.type].partyAmountPerBP;
|
||||
grouping.individuals = (grouping.individuals ?? 0) + 1;
|
||||
|
||||
const currentNr = grouping.nr ?? 0;
|
||||
grouping.nr = partyAmount
|
||||
? Math.ceil(grouping.individuals / (nrCharacters ?? 0))
|
||||
: currentNr + 1;
|
||||
}
|
||||
}
|
||||
|
||||
return acc;
|
||||
}, foundry.utils.deepClone(CONFIG.DH.ENCOUNTER.adversaryTypeCostBrackets));
|
||||
|
||||
html = await foundry.applications.handlebars.renderTemplate(
|
||||
`systems/daggerheart/templates/ui/tooltip/battlepoints.hbs`,
|
||||
{
|
||||
categories,
|
||||
nrCharacters,
|
||||
currentBP,
|
||||
maxBP
|
||||
}
|
||||
);
|
||||
|
||||
this.tooltip.innerHTML = html;
|
||||
options.direction = this._determineItemTooltipDirection(element);
|
||||
} else {
|
||||
const attack = element.dataset.tooltip?.startsWith('#attack#');
|
||||
if (attack) {
|
||||
|
|
@ -222,4 +195,117 @@ export default class DhTooltipManager extends foundry.helpers.interaction.Toolti
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**@inheritdoc */
|
||||
_setStyle(position = {}) {
|
||||
super._setStyle(position);
|
||||
|
||||
if (this.#wide) {
|
||||
this.tooltip.classList.add('wide');
|
||||
}
|
||||
}
|
||||
|
||||
/**@inheritdoc */
|
||||
lockTooltip() {
|
||||
const clone = super.lockTooltip();
|
||||
clone.classList.add('wide');
|
||||
|
||||
return clone;
|
||||
}
|
||||
/** Get HTML for Battlepoints tooltip */
|
||||
async getBattlepointHTML(combatId) {
|
||||
const combat = game.combats.get(combatId);
|
||||
const adversaries =
|
||||
combat.turns?.filter(x => x.isNPC)?.map(x => ({ ...x.actor, type: x.actor.system.type })) ?? [];
|
||||
const characters = combat.turns?.filter(x => !x.isNPC) ?? [];
|
||||
|
||||
const nrCharacters = characters.length;
|
||||
const currentBP = AdversaryBPPerEncounter(adversaries, characters);
|
||||
const maxBP = combat.system.battleToggles.reduce(
|
||||
(acc, toggle) => acc + toggle.category,
|
||||
BaseBPPerEncounter(nrCharacters)
|
||||
);
|
||||
|
||||
const categories = combat.combatants.reduce((acc, combatant) => {
|
||||
if (combatant.actor.type === 'adversary') {
|
||||
const keyData = Object.keys(acc).reduce((identifiers, categoryKey) => {
|
||||
if (identifiers) return identifiers;
|
||||
const category = acc[categoryKey];
|
||||
const groupingIndex = category.findIndex(grouping =>
|
||||
grouping.types.includes(combatant.actor.system.type)
|
||||
);
|
||||
if (groupingIndex !== -1) identifiers = { categoryKey, groupingIndex };
|
||||
|
||||
return identifiers;
|
||||
}, null);
|
||||
if (keyData) {
|
||||
const { categoryKey, groupingIndex } = keyData;
|
||||
const grouping = acc[categoryKey][groupingIndex];
|
||||
const partyAmount = CONFIG.DH.ACTOR.adversaryTypes[combatant.actor.system.type].partyAmountPerBP;
|
||||
grouping.individuals = (grouping.individuals ?? 0) + 1;
|
||||
|
||||
const currentNr = grouping.nr ?? 0;
|
||||
grouping.nr = partyAmount ? Math.ceil(grouping.individuals / (nrCharacters ?? 0)) : currentNr + 1;
|
||||
}
|
||||
}
|
||||
|
||||
return acc;
|
||||
}, foundry.utils.deepClone(CONFIG.DH.ENCOUNTER.adversaryTypeCostBrackets));
|
||||
|
||||
const toggles = Object.keys(CONFIG.DH.ENCOUNTER.BPModifiers)
|
||||
.reduce((acc, categoryKey) => {
|
||||
const category = CONFIG.DH.ENCOUNTER.BPModifiers[categoryKey];
|
||||
acc.push(
|
||||
...Object.keys(category).reduce((acc, toggleKey) => {
|
||||
acc.push({
|
||||
...category[toggleKey],
|
||||
categoryKey: Number(categoryKey),
|
||||
toggleKey,
|
||||
checked: combat.system.battleToggles.find(
|
||||
x => x.category == categoryKey && x.grouping === toggleKey
|
||||
)
|
||||
});
|
||||
|
||||
return acc;
|
||||
}, [])
|
||||
);
|
||||
return acc;
|
||||
}, [])
|
||||
.sort((a, b) => {
|
||||
if (a.categoryKey < b.categoryKey) return -1;
|
||||
if (a.categoryKey > b.categoryKey) return 1;
|
||||
else return a.toggleKey.localeCompare(b.toggleKey);
|
||||
});
|
||||
|
||||
return await foundry.applications.handlebars.renderTemplate(
|
||||
`systems/daggerheart/templates/ui/tooltip/battlepoints.hbs`,
|
||||
{
|
||||
combatId: combat.id,
|
||||
nrCharacters,
|
||||
currentBP,
|
||||
maxBP,
|
||||
categories,
|
||||
toggles
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/** Enable/disable a BP modifier */
|
||||
async toggleModifier(event) {
|
||||
const { combatId, category, grouping } = event.target.dataset;
|
||||
const combat = game.combats.get(combatId);
|
||||
await combat.update({
|
||||
system: {
|
||||
battleToggles: combat.system.battleToggles.some(x => x.category == category && x.grouping === grouping)
|
||||
? combat.system.battleToggles.filter(x => x.category != category && x.grouping !== grouping)
|
||||
: [...combat.system.battleToggles, { category: Number(category), grouping }]
|
||||
}
|
||||
});
|
||||
|
||||
this.tooltip.innerHTML = await this.getBattlepointHTML(combatId);
|
||||
const lockedTooltip = this.lockTooltip();
|
||||
lockedTooltip.querySelectorAll('.battlepoint-toggle-container input').forEach(element => {
|
||||
element.addEventListener('input', this.toggleModifier.bind(this));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue