/* -------------------------------------------- */ export class LethalFantasyCombatTracker extends foundry.applications.sidebar.tabs.CombatTracker { static PARTS = { "header": { "template": "systems/fvtt-lethal-fantasy/templates/combat-tracker-header-v2.hbs" }, "tracker": { "template": "systems/fvtt-lethal-fantasy/templates/combat-tracker-v2.hbs" }, "footer": { "template": "systems/fvtt-lethal-fantasy/templates/combat-tracker-footer-v2.hbs" } } static DEFAULT_OPTIONS = foundry.utils.mergeObject(super.DEFAULT_OPTIONS, { actions: { initiativePlus: LethalFantasyCombatTracker.#initiativePlus, initiativeMinus: LethalFantasyCombatTracker.#initiativeMinus, }, }); async _prepareContext(options) { let data = await super._prepareContext(options); console?.log("Combat Tracker Data", data); /*for (let u of data.turns) { let c = game.combat.combatants.get(u.id); u.progressionCount = c.system.progressionCount u.isMonster = c.actor.type === "monster" } console.log("Combat Data", data);*/ return data; } static #initiativePlus(ev) { ev.preventDefault(); let cId = ev.target.closest(".combatant").dataset.combatantId; let c = game.combat.combatants.get(cId); c.update({ 'initiative': c.initiative + 1 }); console.log("Initiative Plus"); } static #initiativeMinus(ev) { ev.preventDefault(); let cId = ev.target.closest(".combatant").dataset.combatantId; let c = game.combat.combatants.get(cId); let newInit = Math.max(c.initiative - 1, 0); c.update({ 'initiative': newInit }); } activateListeners(html) { super.activateListeners(html); // Display Combat settings html.find(".initiative-plus").click(ev => { ev.preventDefault(); let cId = ev.currentTarget.closest(".combatant").dataset.combatantId; let c = game.combat.combatants.get(cId); c.update({ 'initiative': c.initiative + 1 }); }); html.find(".initiative-minus").click(ev => { ev.preventDefault(); let cId = ev.currentTarget.closest(".combatant").dataset.combatantId; let c = game.combat.combatants.get(cId); c.update({ 'initiative': c.initiative - 1 }); console.log("Initiative Minus"); }); } /* -------------------------------------------- */ static get defaultOptions() { let path = "systems/fvtt-lethal-fantasy/templates/combat-tracker.hbs"; return foundry.utils.mergeObject(super.defaultOptions, { template: path, }); } } export class LethalFantasyCombat extends Combat { /** * Return the Array of combatants sorted into initiative order, breaking ties alphabetically by name. * @returns {Combatant[]} */ setupTurns() { console?.log("Setup Turns...."); this.turns ||= []; // Determine the turn order and the current turn const turns = this.combatants.contents.sort(this.sortCombatantsLF); if (this.turn !== null) this.turn = Math.clamp(this.turn, 0, turns.length - 1); // Update state tracking let c = turns[this.turn]; this.current = this._getCurrentState(c); if (!this.previous) this.previous = this.current; // Return the array of prepared turns return this.turns = turns; } async rollInitiative(ids, options) { console.log("%%%%%%%%% Roll Initiative", ids, options); ids = typeof ids === "string" ? [ids] : ids; let messages = []; let rollMode = game.settings.get("core", "rollMode"); let updates = []; for (let cId of ids) { const c = this.combatants.get(cId); let user = game.users.find(u => u.active && u.character && u.character.id === c.actor.id); if (user?.hasPlayerOwner) { console.log("Rolling initiative for", c.actor.name); game.socket.emit(`system.${SYSTEM.id}`, { type: "rollInitiative", actorId: c.actor.id, combatId: this.id, combatantId: c.id }); } else { user = game.users.find(u => u.active && u.isGM); c.actor.system.rollInitiative(this.id, c.id); } } return this; } resetProgression(cId) { let c = this.combatants.get(cId); c.update({ 'system.progressionCount': 0 }); } setCasting(cId) { let c = this.combatants.get(cId); c.setFlag(SYSTEM.id, "casting", true); } resetCasting(cId) { let c = this.combatants.get(cId); c.setFlag(SYSTEM.id, "casting", false); } isCasting(cId) { let c = this.combatants.get(cId); return c.getFlag(SYSTEM.id, "casting"); } async nextTurn() { console.log("NEXT TURN"); let turn = this.turn ?? -1; let skipDefeated = this.settings.skipDefeated; // Determine the next turn number let next = null; for (let [i, t] of this.turns.entries()) { console.log("Turn", t); if (i <= turn) continue; if (skipDefeated && t.isDefeated) continue; next = i; break; } // Maybe advance to the next round let round = this.round; if ((this.round === 0) || (next === null) || (next >= this.turns.length)) { return this.nextRound(); } // Update the document, passing data through a hook first const updateData = { round, turn: next }; const updateOptions = { advanceTime: CONFIG.time.turnTime, direction: 1 }; Hooks.callAll("combatTurn", this, updateData, updateOptions); return this.update(updateData, updateOptions); } async nextRound() { this.turnsDone = false let turn = this.turn === null ? null : 0; // Preserve the fact that it's no-one's turn currently. console.log("ROUND", this); let advanceTime = Math.max(this.turns.length - this.turn, 0) * CONFIG.time.turnTime; advanceTime += CONFIG.time.roundTime; let nextRound = this.round + 1; let initOK = true; for (let c of this.combatants) { if (c.initiative === null) { initOK = false; break; } } if (!initOK) { ui.notifications.error("All combatants must have initiative rolled before the round can advance."); return this; } for (let c of this.combatants) { if (nextRound >= c.initiative) { let user = game.users.find(u => u.active && u.character && u.character.id === c.actor.id); if (user?.hasPlayerOwner) { game.socket.emit(`system.${SYSTEM.id}`, { type: "rollProgressionDice", progressionCount: c.system.progressionCount + 1, actorId: c.actor.id, combatId: this.id, combatantId: c.id }); } else { user = game.users.find(u => u.active && u.isGM); c.actor.system.rollProgressionDice(this.id, c.id); } } } // Update the document, passing data through a hook first const updateData = { round: nextRound, turn }; const updateOptions = { advanceTime, direction: 1 }; Hooks.callAll("combatRound", this, updateData, updateOptions); return this.update(updateData, updateOptions); } sortCombatantsLF(a, b) { return a.initiative - b.initiative; } }