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); } }