daggerheart/module/ui/combatTracker.mjs
2025-05-22 16:53:39 +02:00

200 lines
No EOL
7.8 KiB
JavaScript

import { GMUpdateEvent, socketEvent } from "../helpers/socket.mjs";
export default class DhpCombatTracker extends foundry.applications.sidebar.tabs.CombatTracker {
constructor(data, context) {
super(data, context);
Hooks.on(socketEvent.DhpFearUpdate, this.onFearUpdate);
}
get template(){
return 'systems/daggerheart/templates/ui/combatTracker.hbs';
}
activateListeners(html) {
super.activateListeners(html);
html.on("click", ".token-action-tokens .use-action-token", this.useActionToken.bind(this));
html.on("click", ".encounter-gm-resources .trade-actions", this.tradeActions.bind(this));
html.on("click", ".encounter-gm-resources .trade-fear", this.tradeFear.bind(this));
html.on("click", ".encounter-gm-resources .icon-button.up", this.increaseResource.bind(this));
html.on("click", ".encounter-gm-resources .icon-button.down", this.decreaseResource.bind(this));
}
async useActionToken(event){
event.stopPropagation();
const combatant = event.currentTarget.dataset.combatant;
await game.combat.useActionToken(combatant);
}
async tradeActions(event){
if(event.currentTarget.classList.contains('disabled')) return;
const currentFear = await game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Resources.Fear);
const value = currentFear+1;
if(value <= 6){
Hooks.callAll(socketEvent.GMUpdate,GMUpdateEvent.UpdateFear, null, value);
await game.socket.emit(`system.${SYSTEM.id}`, {
action: socketEvent.GMUpdate,
data: { action: GMUpdateEvent.UpdateFear, update: value },
});
await game.combat.update({ "system.actions": game.combat.system.actions-2 });
}
}
async tradeFear(){
if(event.currentTarget.classList.contains('disabled')) return;
const currentFear = await game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Resources.Fear);
const value = currentFear-1;
if(value >= 0){
Hooks.callAll(socketEvent.GMUpdate,GMUpdateEvent.UpdateFear, null, value);
await game.socket.emit(`system.${SYSTEM.id}`, {
action: socketEvent.GMUpdate,
data: { action: GMUpdateEvent.UpdateFear, update: value },
});
await game.combat.update({ "system.actions": game.combat.system.actions+2 });
}
}
async increaseResource(event) {
if(event.currentTarget.dataset.type === 'action'){
await game.combat.update({ "system.actions": game.combat.system.actions+1 });
}
const currentFear = await game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Resources.Fear);
const value = currentFear+1;
if(event.currentTarget.dataset.type === 'fear' && value <= 6){
Hooks.callAll(socketEvent.GMUpdate,GMUpdateEvent.UpdateFear, null, value);
await game.socket.emit(`system.${SYSTEM.id}`, {
action: socketEvent.GMUpdate,
data: { action: GMUpdateEvent.UpdateFear, update: value },
});
}
this.render();
}
async decreaseResource(event) {
if(event.currentTarget.dataset.type === 'action' && game.combat.system.actions-1 >= 0){
await game.combat.update({ "system.actions": game.combat.system.actions-1 });
}
const currentFear = await game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Resources.Fear);
const value = currentFear-1;
if(event.currentTarget.dataset.type === 'fear' && value >= 0){
Hooks.callAll(socketEvent.GMUpdate,GMUpdateEvent.UpdateFear, null, value);
await game.socket.emit(`system.${SYSTEM.id}`, {
action: socketEvent.GMUpdate,
data: { action: GMUpdateEvent.UpdateFear, update: value },
});
}
this.render();
}
async getData(options={}) {
let context = await super.getData(options);
// Get the combat encounters possible for the viewed Scene
const combat = this.viewed;
const hasCombat = combat !== null;
const combats = this.combats;
const currentIdx = combats.findIndex(c => c === combat);
const previousId = currentIdx > 0 ? combats[currentIdx-1].id : null;
const nextId = currentIdx < combats.length - 1 ? combats[currentIdx+1].id : null;
const settings = game.settings.get("core", Combat.CONFIG_SETTING);
// Prepare rendering data
context = foundry.utils.mergeObject(context, {
combats: combats,
currentIndex: currentIdx + 1,
combatCount: combats.length,
hasCombat: hasCombat,
combat,
turns: [],
previousId,
nextId,
started: this.started,
control: false,
settings,
linked: combat?.scene !== null,
labels: {}
});
context.labels.scope = game.i18n.localize(`COMBAT.${context.linked ? "Linked" : "Unlinked"}`);
if ( !hasCombat ) return context;
// Format information about each combatant in the encounter
let hasDecimals = false;
const turns = [];
for ( let [i, combatant] of combat.turns.entries() ) {
if ( !combatant.visible ) continue;
// Prepare turn data
const resource = combatant.permission >= CONST.DOCUMENT_OWNERSHIP_LEVELS.OBSERVER ? combatant.resource : null;
const turn = {
id: combatant.id,
name: combatant.name,
img: await this._getCombatantThumbnail(combatant),
active: combatant.id === combat.system.activeCombatant,
owner: combatant.isOwner,
defeated: combatant.isDefeated,
hidden: combatant.hidden,
initiative: combatant.initiative,
hasRolled: combatant.initiative !== null,
hasResource: resource !== null,
resource: resource,
canPing: (combatant.sceneId === canvas.scene?.id) && game.user.hasPermission("PING_CANVAS"),
playerCharacter: game.user?.character?.id === combatant.actor.id,
ownedByPlayer: combatant.hasPlayerOwner,
};
if ( (turn.initiative !== null) && !Number.isInteger(turn.initiative) ) hasDecimals = true;
turn.css = [
turn.active ? "active" : "",
turn.hidden ? "hidden" : "",
turn.defeated ? "defeated" : ""
].join(" ").trim();
// Actor and Token status effects
turn.effects = new Set();
if ( combatant.token ) {
combatant.token.effects.forEach(e => turn.effects.add(e));
if ( combatant.token.overlayEffect ) turn.effects.add(combatant.token.overlayEffect);
}
if ( combatant.actor ) {
for ( const effect of combatant.actor.temporaryEffects ) {
if ( effect.statuses.has(CONFIG.specialStatusEffects.DEFEATED) ) turn.defeated = true;
else if ( effect.icon ) turn.effects.add(effect.icon);
}
}
turns.push(turn);
}
// Format initiative numeric precision
const precision = CONFIG.Combat.initiative.decimals;
turns.forEach(t => {
if ( t.initiative !== null ) t.initiative = t.initiative.toFixed(hasDecimals ? precision : 0);
});
const fear = await game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Resources.Fear);
// Merge update data for rendering
return foundry.utils.mergeObject(context, {
round: combat.round,
turn: combat.turn,
turns: turns,
control: combat.combatant?.players?.includes(game.user),
fear: fear,
});
}
onFearUpdate = async () => {
this.render(true);
}
async close(options){
Hooks.off(socketEvent.DhpFearUpdate, this.onFearUpdate);
return super.close(options);
}
}