mirror of
https://github.com/Foundryborne/daggerheart.git
synced 2026-01-16 23:26:28 +01:00
Added BP calculation and tooltip breakdown of BP sources
This commit is contained in:
parent
630ba5ab7d
commit
51a0fb82eb
12 changed files with 251 additions and 12 deletions
16
lang/en.json
16
lang/en.json
|
|
@ -682,6 +682,14 @@
|
||||||
"description": "Enemies that enhance their allies and/or disrupt their opponents."
|
"description": "Enemies that enhance their allies and/or disrupt their opponents."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"AdversaryTypeCost": {
|
||||||
|
"minion": "for each group of Minions equal to the size of the party.",
|
||||||
|
"support": "for each Social or Support adversary.",
|
||||||
|
"standard": "for each Horde, Ranged, Skulk, or Standard adversary.",
|
||||||
|
"leader": "for each Leader adversary.",
|
||||||
|
"bruiser": "for each Bruiser adversary.",
|
||||||
|
"solo": "for each Solo adversary."
|
||||||
|
},
|
||||||
"ArmorFeature": {
|
"ArmorFeature": {
|
||||||
"burning": {
|
"burning": {
|
||||||
"name": "Burning",
|
"name": "Burning",
|
||||||
|
|
@ -905,6 +913,14 @@
|
||||||
"evolved": "Evolved",
|
"evolved": "Evolved",
|
||||||
"hybrid": "Hybrid"
|
"hybrid": "Hybrid"
|
||||||
},
|
},
|
||||||
|
"BPModifiers": {
|
||||||
|
"increaseDamage": "if you add +1d4 (or a static +2) to all adversaries' damage rolls (to increase the challenge without lengthening the battle)",
|
||||||
|
"lessDifficult": "if the fight should be less difficult or shorter.",
|
||||||
|
"lowerTier": "if you choose an adversary from a lower tier.",
|
||||||
|
"manySolos": "if you're using 2 or more Solo adversaries.",
|
||||||
|
"moreDangerous": "if the fight should be more dangerous or last longer",
|
||||||
|
"noToughies": "if you don't include any Bruisers, Hordes, Leaders, or Solos"
|
||||||
|
},
|
||||||
"Burden": {
|
"Burden": {
|
||||||
"oneHanded": "One-Handed",
|
"oneHanded": "One-Handed",
|
||||||
"twoHanded": "Two-Handed"
|
"twoHanded": "Two-Handed"
|
||||||
|
|
|
||||||
|
|
@ -20,11 +20,53 @@ export default class DhCombatTracker extends foundry.applications.sidebar.tabs.C
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** @inheritDoc */
|
||||||
|
async _preparePartContext(_partId, context, _options) {
|
||||||
|
return context;
|
||||||
|
}
|
||||||
|
|
||||||
|
async _prepareContext(options) {
|
||||||
|
const context = await super._prepareContext(options);
|
||||||
|
|
||||||
|
await this._prepareTrackerContext(context, options);
|
||||||
|
await this._prepareCombatContext(context, options);
|
||||||
|
|
||||||
|
return context;
|
||||||
|
}
|
||||||
|
|
||||||
async _prepareCombatContext(context, options) {
|
async _prepareCombatContext(context, options) {
|
||||||
await super._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);
|
||||||
|
|
||||||
Object.assign(context, {
|
Object.assign(context, {
|
||||||
fear: game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Resources.Fear)
|
fear: game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Resources.Fear),
|
||||||
|
battlepoints: { max: maxBP, current: currentBP }
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -99,6 +141,7 @@ export default class DhCombatTracker extends foundry.applications.sidebar.tabs.C
|
||||||
resource,
|
resource,
|
||||||
active: index === combat.turn,
|
active: index === combat.turn,
|
||||||
canPing: combatant.sceneId === canvas.scene?.id && game.user.hasPermission('PING_CANVAS'),
|
canPing: combatant.sceneId === canvas.scene?.id && game.user.hasPermission('PING_CANVAS'),
|
||||||
|
type: combatant.actor.system.type,
|
||||||
img: await this._getCombatantThumbnail(combatant)
|
img: await this._getCombatantThumbnail(combatant)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ export * as actionConfig from './actionConfig.mjs';
|
||||||
export * as actorConfig from './actorConfig.mjs';
|
export * as actorConfig from './actorConfig.mjs';
|
||||||
export * as domainConfig from './domainConfig.mjs';
|
export * as domainConfig from './domainConfig.mjs';
|
||||||
export * as effectConfig from './effectConfig.mjs';
|
export * as effectConfig from './effectConfig.mjs';
|
||||||
|
export * as encounterConfig from './encounterConfig.mjs';
|
||||||
export * as flagsConfig from './flagsConfig.mjs';
|
export * as flagsConfig from './flagsConfig.mjs';
|
||||||
export * as generalConfig from './generalConfig.mjs';
|
export * as generalConfig from './generalConfig.mjs';
|
||||||
export * as itemConfig from './itemConfig.mjs';
|
export * as itemConfig from './itemConfig.mjs';
|
||||||
|
|
|
||||||
|
|
@ -108,52 +108,63 @@ export const adversaryTypes = {
|
||||||
bruiser: {
|
bruiser: {
|
||||||
id: 'bruiser',
|
id: 'bruiser',
|
||||||
label: 'DAGGERHEART.CONFIG.AdversaryType.bruiser.label',
|
label: 'DAGGERHEART.CONFIG.AdversaryType.bruiser.label',
|
||||||
description: 'DAGGERHEART.ACTORS.Adversary.bruiser.description'
|
description: 'DAGGERHEART.ACTORS.Adversary.bruiser.description',
|
||||||
|
bpCost: 4
|
||||||
},
|
},
|
||||||
horde: {
|
horde: {
|
||||||
id: 'horde',
|
id: 'horde',
|
||||||
label: 'DAGGERHEART.CONFIG.AdversaryType.horde.label',
|
label: 'DAGGERHEART.CONFIG.AdversaryType.horde.label',
|
||||||
description: 'DAGGERHEART.ACTORS.Adversary.horde.description'
|
description: 'DAGGERHEART.ACTORS.Adversary.horde.description',
|
||||||
|
bpCost: 2
|
||||||
},
|
},
|
||||||
leader: {
|
leader: {
|
||||||
id: 'leader',
|
id: 'leader',
|
||||||
label: 'DAGGERHEART.CONFIG.AdversaryType.leader.label',
|
label: 'DAGGERHEART.CONFIG.AdversaryType.leader.label',
|
||||||
description: 'DAGGERHEART.ACTORS.Adversary.leader.description'
|
description: 'DAGGERHEART.ACTORS.Adversary.leader.description',
|
||||||
|
bpCost: 3
|
||||||
},
|
},
|
||||||
minion: {
|
minion: {
|
||||||
id: 'minion',
|
id: 'minion',
|
||||||
label: 'DAGGERHEART.CONFIG.AdversaryType.minion.label',
|
label: 'DAGGERHEART.CONFIG.AdversaryType.minion.label',
|
||||||
description: 'DAGGERHEART.ACTORS.Adversary.minion.description'
|
description: 'DAGGERHEART.ACTORS.Adversary.minion.description',
|
||||||
|
bpCost: 1,
|
||||||
|
partyAmountPerBP: true
|
||||||
},
|
},
|
||||||
ranged: {
|
ranged: {
|
||||||
id: 'ranged',
|
id: 'ranged',
|
||||||
label: 'DAGGERHEART.CONFIG.AdversaryType.ranged.label',
|
label: 'DAGGERHEART.CONFIG.AdversaryType.ranged.label',
|
||||||
description: 'DAGGERHEART.ACTORS.Adversary.ranged.description'
|
description: 'DAGGERHEART.ACTORS.Adversary.ranged.description',
|
||||||
|
bpCost: 2
|
||||||
},
|
},
|
||||||
skulk: {
|
skulk: {
|
||||||
id: 'skulk',
|
id: 'skulk',
|
||||||
label: 'DAGGERHEART.CONFIG.AdversaryType.skulk.label',
|
label: 'DAGGERHEART.CONFIG.AdversaryType.skulk.label',
|
||||||
description: 'DAGGERHEART.ACTORS.Adversary.skulk.description'
|
description: 'DAGGERHEART.ACTORS.Adversary.skulk.description',
|
||||||
|
bpCost: 2
|
||||||
},
|
},
|
||||||
social: {
|
social: {
|
||||||
id: 'social',
|
id: 'social',
|
||||||
label: 'DAGGERHEART.CONFIG.AdversaryType.social.label',
|
label: 'DAGGERHEART.CONFIG.AdversaryType.social.label',
|
||||||
description: 'DAGGERHEART.ACTORS.Adversary.social.description'
|
description: 'DAGGERHEART.ACTORS.Adversary.social.description',
|
||||||
|
bpCost: 1
|
||||||
},
|
},
|
||||||
solo: {
|
solo: {
|
||||||
id: 'solo',
|
id: 'solo',
|
||||||
label: 'DAGGERHEART.CONFIG.AdversaryType.solo.label',
|
label: 'DAGGERHEART.CONFIG.AdversaryType.solo.label',
|
||||||
description: 'DAGGERHEART.ACTORS.Adversary.solo.description'
|
description: 'DAGGERHEART.ACTORS.Adversary.solo.description',
|
||||||
|
bpCost: 5
|
||||||
},
|
},
|
||||||
standard: {
|
standard: {
|
||||||
id: 'standard',
|
id: 'standard',
|
||||||
label: 'DAGGERHEART.CONFIG.AdversaryType.standard.label',
|
label: 'DAGGERHEART.CONFIG.AdversaryType.standard.label',
|
||||||
description: 'DAGGERHEART.ACTORS.Adversary.standard.description'
|
description: 'DAGGERHEART.ACTORS.Adversary.standard.description',
|
||||||
|
bpCost: 2
|
||||||
},
|
},
|
||||||
support: {
|
support: {
|
||||||
id: 'support',
|
id: 'support',
|
||||||
label: 'DAGGERHEART.CONFIG.AdversaryType.support.label',
|
label: 'DAGGERHEART.CONFIG.AdversaryType.support.label',
|
||||||
description: 'DAGGERHEART.ACTORS.Adversary.support.description'
|
description: 'DAGGERHEART.ACTORS.Adversary.support.description',
|
||||||
|
bpCost: 1
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
79
module/config/encounterConfig.mjs
Normal file
79
module/config/encounterConfig.mjs
Normal file
|
|
@ -0,0 +1,79 @@
|
||||||
|
export const BaseBPPerEncounter = nrCharacters => 3 * nrCharacters + 2;
|
||||||
|
|
||||||
|
export const adversaryTypeCostBrackets = {
|
||||||
|
1: [
|
||||||
|
{
|
||||||
|
sort: 1,
|
||||||
|
types: ['minion'],
|
||||||
|
description: 'DAGGERHEART.CONFIG.AdversaryTypeCost.minion'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
sort: 2,
|
||||||
|
types: ['social', 'support'],
|
||||||
|
description: 'DAGGERHEART.CONFIG.AdversaryTypeCost.support'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
2: [
|
||||||
|
{
|
||||||
|
sort: 1,
|
||||||
|
types: ['horde', 'ranged', 'skulk', 'standard'],
|
||||||
|
description: 'DAGGERHEART.CONFIG.AdversaryTypeCost.standard'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
3: [
|
||||||
|
{
|
||||||
|
sort: 1,
|
||||||
|
types: ['leader'],
|
||||||
|
description: 'DAGGERHEART.CONFIG.AdversaryTypeCost.leader'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
4: [
|
||||||
|
{
|
||||||
|
sort: 1,
|
||||||
|
types: ['bruiser'],
|
||||||
|
description: 'DAGGERHEART.CONFIG.AdversaryTypeCost.bruiser'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
5: [
|
||||||
|
{
|
||||||
|
sort: 1,
|
||||||
|
types: ['solo'],
|
||||||
|
description: 'DAGGERHEART.CONFIG.AdversaryTypeCost.solo'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
export const BPModifiers = {
|
||||||
|
[-2]: {
|
||||||
|
manySolos: {
|
||||||
|
sort: 1,
|
||||||
|
description: 'DAGGERHEART.CONFIG.BPModifiers.manySolos'
|
||||||
|
},
|
||||||
|
increaseDamage: {
|
||||||
|
sort: 2,
|
||||||
|
description: 'DAGGERHEART.CONFIG.BPModifiers.increaseDamage'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[-1]: {
|
||||||
|
lessDifficult: {
|
||||||
|
sort: 2,
|
||||||
|
description: 'DAGGERHEART.CONFIG.BPModifiers.lessDifficult'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
1: {
|
||||||
|
lowerTier: {
|
||||||
|
sort: 1,
|
||||||
|
description: 'DAGGERHEART.CONFIG.BPModifiers.lowerTier'
|
||||||
|
},
|
||||||
|
noToughies: {
|
||||||
|
sort: 2,
|
||||||
|
description: 'DAGGERHEART.CONFIG.BPModifiers.noToughies'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
2: {
|
||||||
|
moreDangerous: {
|
||||||
|
sort: 2,
|
||||||
|
description: 'DAGGERHEART.CONFIG.BPModifiers.moreDangerous'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
@ -1,17 +1,19 @@
|
||||||
import * as GENERAL from './generalConfig.mjs';
|
import * as GENERAL from './generalConfig.mjs';
|
||||||
import * as DOMAIN from './domainConfig.mjs';
|
import * as DOMAIN from './domainConfig.mjs';
|
||||||
|
import * as ENCOUNTER from './encounterConfig.mjs';
|
||||||
import * as ACTOR from './actorConfig.mjs';
|
import * as ACTOR from './actorConfig.mjs';
|
||||||
import * as ITEM from './itemConfig.mjs';
|
import * as ITEM from './itemConfig.mjs';
|
||||||
import * as SETTINGS from './settingsConfig.mjs';
|
import * as SETTINGS from './settingsConfig.mjs';
|
||||||
import * as EFFECTS from './effectConfig.mjs';
|
import * as EFFECTS from './effectConfig.mjs';
|
||||||
import * as ACTIONS from './actionConfig.mjs';
|
import * as ACTIONS from './actionConfig.mjs';
|
||||||
import * as FLAGS from './flagsConfig.mjs';
|
import * as FLAGS from './flagsConfig.mjs';
|
||||||
import * as ITEMBROWSER from './itemBrowserConfig.mjs'
|
import * as ITEMBROWSER from './itemBrowserConfig.mjs';
|
||||||
|
|
||||||
export const SYSTEM_ID = 'daggerheart';
|
export const SYSTEM_ID = 'daggerheart';
|
||||||
|
|
||||||
export const SYSTEM = {
|
export const SYSTEM = {
|
||||||
id: SYSTEM_ID,
|
id: SYSTEM_ID,
|
||||||
|
ENCOUNTER,
|
||||||
GENERAL,
|
GENERAL,
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
ACTOR,
|
ACTOR,
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,53 @@ export default class DhTooltipManager extends foundry.helpers.interaction.Toolti
|
||||||
this.tooltip.innerHTML = html;
|
this.tooltip.innerHTML = html;
|
||||||
options.direction = this._determineItemTooltipDirection(element);
|
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 {
|
} else {
|
||||||
const attack = element.dataset.tooltip?.startsWith('#attack#');
|
const attack = element.dataset.tooltip?.startsWith('#attack#');
|
||||||
if (attack) {
|
if (attack) {
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,12 @@
|
||||||
|
|
||||||
.encounter-title {
|
.encounter-title {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
|
flex: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.encounter-battlepoints {
|
||||||
|
display: flex;
|
||||||
|
cursor: help;
|
||||||
}
|
}
|
||||||
|
|
||||||
.inner-controls {
|
.inner-controls {
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1,3 @@
|
||||||
@import './tooltip/tooltip.less';
|
@import './tooltip/tooltip.less';
|
||||||
|
@import './tooltip/battlepoints.less';
|
||||||
@import './autocomplete/autocomplete.less';
|
@import './autocomplete/autocomplete.less';
|
||||||
|
|
|
||||||
16
styles/less/ux/tooltip/battlepoints.less
Normal file
16
styles/less/ux/tooltip/battlepoints.less
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
.daggerheart.dh-style.tooltip {
|
||||||
|
.battlepoint-categories-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 8px;
|
||||||
|
|
||||||
|
.battlepoint-grouping-container {
|
||||||
|
display: flex;
|
||||||
|
gap: 4px;
|
||||||
|
|
||||||
|
.unselected-grouping {
|
||||||
|
opacity: 0.4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -64,6 +64,8 @@
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</strong>
|
</strong>
|
||||||
|
|
||||||
|
<div class="encounter-battlepoints" data-tooltip="#battlepoints#" data-combat-id="{{combat.id}}" data-bp-current="{{battlepoints.current}}" data-bp-max="{{battlepoints.max}}" data-nr-characters="{{characters.length}}">{{battlepoints.current}}/{{battlepoints.max}} BP</div>
|
||||||
|
|
||||||
{{!-- Combat Controls --}}
|
{{!-- Combat Controls --}}
|
||||||
<div class="inner-controls">
|
<div class="inner-controls">
|
||||||
{{#if hasCombat}}
|
{{#if hasCombat}}
|
||||||
|
|
|
||||||
15
templates/ui/tooltip/battlepoints.hbs
Normal file
15
templates/ui/tooltip/battlepoints.hbs
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
<div class="daggerheart dh-style tooltip">
|
||||||
|
<div class="battlepoint-categories-container">
|
||||||
|
{{#each categories as |category key|}}
|
||||||
|
{{#each category as |grouping index|}}
|
||||||
|
<div class="battlepoint-grouping-container">
|
||||||
|
{{#if grouping.nr}}
|
||||||
|
<label>{{key}} BP - {{concat (localize grouping.description) ' ' '('grouping.nr 'x)'}}</label>
|
||||||
|
{{else}}
|
||||||
|
<label class="unselected-grouping">{{key}}BP - {{localize grouping.description}}</label>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
{{/each}}
|
||||||
|
{{/each}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
Loading…
Add table
Add a link
Reference in a new issue