mirror of
https://github.com/Foundryborne/daggerheart.git
synced 2026-01-12 19:51:08 +01:00
* Added CountdownEdit view * Added countdowns UI element * . * Fixed migration of countdowns * . * . * style countdown interface, application and ownership dialog * fix buttons height in ownsership selection * . * Added coloured pips to UI cooldowns to signify player visibility if not every player has it * . * Added max-height and overflow * Sync countdown current with max when equal (#1221) * Update module/applications/ui/countdownEdit.mjs Co-authored-by: Carlos Fernandez <CarlosFdez@users.noreply.github.com> * . --------- Co-authored-by: moliloo <dev.murilobrito@gmail.com> Co-authored-by: Carlos Fernandez <CarlosFdez@users.noreply.github.com>
185 lines
7 KiB
JavaScript
185 lines
7 KiB
JavaScript
export default class DhCombatTracker extends foundry.applications.sidebar.tabs.CombatTracker {
|
|
static DEFAULT_OPTIONS = {
|
|
actions: {
|
|
requestSpotlight: this.requestSpotlight,
|
|
toggleSpotlight: this.toggleSpotlight,
|
|
setActionTokens: this.setActionTokens,
|
|
openCountdowns: this.openCountdowns
|
|
}
|
|
};
|
|
|
|
static PARTS = {
|
|
header: {
|
|
template: 'systems/daggerheart/templates/ui/combatTracker/combatTrackerHeader.hbs'
|
|
},
|
|
tracker: {
|
|
template: 'systems/daggerheart/templates/ui/combatTracker/combatTracker.hbs'
|
|
},
|
|
footer: {
|
|
template: 'systems/daggerheart/templates/ui/combatTracker/combatTrackerFooter.hbs'
|
|
}
|
|
};
|
|
|
|
async _prepareCombatContext(context, options) {
|
|
await super._prepareCombatContext(context, options);
|
|
|
|
Object.assign(context, {
|
|
fear: game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Resources.Fear)
|
|
});
|
|
}
|
|
|
|
async _prepareTrackerContext(context, options) {
|
|
await super._prepareTrackerContext(context, options);
|
|
|
|
const adversaries = context.turns?.filter(x => x.isNPC) ?? [];
|
|
const characters = context.turns?.filter(x => !x.isNPC) ?? [];
|
|
|
|
const spotlightRequests = characters
|
|
?.filter(x => !x.isNPC)
|
|
.filter(x => x.system.spotlight.requestOrderIndex > 0)
|
|
.sort((a, b) => {
|
|
const valueA = a.system.spotlight.requestOrderIndex;
|
|
const valueB = b.system.spotlight.requestOrderIndex;
|
|
|
|
return valueA - valueB;
|
|
});
|
|
|
|
Object.assign(context, {
|
|
actionTokens: game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.variantRules).actionTokens,
|
|
adversaries,
|
|
characters: characters?.filter(x => !x.isNPC).filter(x => x.system.spotlight.requestOrderIndex == 0),
|
|
spotlightRequests
|
|
});
|
|
}
|
|
|
|
_getCombatContextOptions() {
|
|
return [
|
|
{
|
|
name: 'COMBAT.ClearMovementHistories',
|
|
icon: '<i class="fa-solid fa-shoe-prints"></i>',
|
|
condition: () => game.user.isGM && this.viewed?.combatants.size > 0,
|
|
callback: () => this.viewed.clearMovementHistories()
|
|
},
|
|
{
|
|
name: 'COMBAT.Delete',
|
|
icon: '<i class="fa-solid fa-trash"></i>',
|
|
condition: () => game.user.isGM && !!this.viewed,
|
|
callback: () => this.viewed.endCombat()
|
|
}
|
|
];
|
|
}
|
|
|
|
getDefeatedId(combatant) {
|
|
if (!combatant.actor) return CONFIG.specialStatusEffects.DEFEATED;
|
|
|
|
const settings = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation).defeated;
|
|
return settings[`${combatant.actor.type}Default`];
|
|
}
|
|
|
|
/** @inheritdoc */
|
|
async _onToggleDefeatedStatus(combatant) {
|
|
const isDefeated = !combatant.isDefeated;
|
|
await combatant.update({ defeated: isDefeated });
|
|
await combatant.actor?.toggleStatusEffect(this.getDefeatedId(combatant), { overlay: true, active: isDefeated });
|
|
}
|
|
|
|
/** @inheritdoc */
|
|
async _prepareTurnContext(combat, combatant, index) {
|
|
const { id, name, isOwner, isDefeated, hidden, initiative, permission } = combatant;
|
|
const resource = permission >= CONST.DOCUMENT_OWNERSHIP_LEVELS.OBSERVER ? combatant.resource : null;
|
|
const hasDecimals = Number.isFinite(initiative) && !Number.isInteger(initiative);
|
|
const turn = {
|
|
hasDecimals,
|
|
hidden,
|
|
id,
|
|
isDefeated,
|
|
initiative,
|
|
isOwner,
|
|
name,
|
|
resource,
|
|
active: index === combat.turn,
|
|
canPing: combatant.sceneId === canvas.scene?.id && game.user.hasPermission('PING_CANVAS'),
|
|
img: await this._getCombatantThumbnail(combatant)
|
|
};
|
|
|
|
turn.css = [turn.active ? 'active' : null, hidden ? 'hide' : null, isDefeated ? 'defeated' : null].filterJoin(
|
|
' '
|
|
);
|
|
|
|
const defeatedId = this.getDefeatedId(combatant);
|
|
const effects = [];
|
|
for (const effect of combatant.actor?.temporaryEffects ?? []) {
|
|
if (effect.statuses.has(defeatedId)) turn.isDefeated = true;
|
|
else if (effect.img) effects.push({ img: effect.img, name: effect.name });
|
|
}
|
|
turn.effects = {
|
|
icons: effects,
|
|
tooltip: this._formatEffectsTooltip(effects)
|
|
};
|
|
|
|
return { ...turn, isNPC: combatant.isNPC, system: combatant.system.toObject() };
|
|
}
|
|
|
|
async setCombatantSpotlight(combatantId) {
|
|
const update = {
|
|
system: {
|
|
'spotlight.requesting': false,
|
|
'spotlight.requestOrderIndex': 0
|
|
}
|
|
};
|
|
const combatant = this.viewed.combatants.get(combatantId);
|
|
|
|
const toggleTurn = this.viewed.combatants.contents
|
|
.sort(this.viewed._sortCombatants)
|
|
.map(x => x.id)
|
|
.indexOf(combatantId);
|
|
|
|
if (this.viewed.turn !== toggleTurn) {
|
|
const { updateCountdowns } = game.system.api.applications.ui.DhCountdowns;
|
|
await updateCountdowns(CONFIG.DH.GENERAL.countdownTypes.spotlight.id);
|
|
|
|
const autoPoints = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation).actionPoints;
|
|
if (autoPoints) {
|
|
update.system.actionTokens = Math.max(combatant.system.actionTokens - 1, 0);
|
|
}
|
|
}
|
|
|
|
await this.viewed.update({
|
|
turn: this.viewed.turn === toggleTurn ? null : toggleTurn,
|
|
round: this.viewed.round + 1
|
|
});
|
|
await combatant.update(update);
|
|
}
|
|
|
|
static async requestSpotlight(_, target) {
|
|
const characters = this.viewed.turns?.filter(x => !x.isNPC) ?? [];
|
|
const orderValues = characters.map(character => character.system.spotlight.requestOrderIndex);
|
|
const maxRequestIndex = Math.max(...orderValues);
|
|
const { combatantId } = target.closest('[data-combatant-id]')?.dataset ?? {};
|
|
const combatant = this.viewed.combatants.get(combatantId);
|
|
await combatant.update({
|
|
'system.spotlight': {
|
|
requesting: !combatant.system.spotlight.requesting,
|
|
requestOrderIndex: !combatant.system.spotlight.requesting ? maxRequestIndex + 1 : 0
|
|
}
|
|
});
|
|
|
|
this.render();
|
|
}
|
|
|
|
static async toggleSpotlight(_, target) {
|
|
const { combatantId } = target.closest('[data-combatant-id]')?.dataset ?? {};
|
|
await this.setCombatantSpotlight(combatantId);
|
|
}
|
|
|
|
static async setActionTokens(_, target) {
|
|
const { combatantId, tokenIndex } = target.closest('[data-combatant-id]')?.dataset ?? {};
|
|
|
|
const combatant = this.viewed.combatants.get(combatantId);
|
|
const changeIndex = Number(tokenIndex);
|
|
const newIndex = combatant.system.actionTokens > changeIndex ? changeIndex : changeIndex + 1;
|
|
|
|
await combatant.update({ 'system.actionTokens': newIndex });
|
|
this.render();
|
|
}
|
|
}
|