/* -------------------------------------------- */ export class LethalFantasyCombatTracker extends CombatTracker { /* -------------------------------------------- */ 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); await this.setFlag("acks", "lock-turns", true); ids = typeof ids === "string" ? [ids] : ids; let messages = []; let rollMode = game.settings.get("core", "rollMode"); // Get current groups let groups = this.getFlag('acks', 'groups') || []; let maxInit = { value: -1, cId: "" } let updates = []; for (let cId of ids) { const c = this.combatants.get(cId); //console.log("Init for combattant", cId, c, ids) let id = c._id || c.id // get the associated token let tokenId = c.token.id; // Check if the current token ID is in a group let groupData = groups.find((groupData) => groupData.tokens.includes(tokenId)); let initValue = -1; let showMessage = true let roll if (groupData && groupData.initiative > 0) { initValue = groupData.initiative; showMessage = false } else { roll = c.getInitiativeRoll(); await roll.evaluate(); initValue = roll.total; } if (groupData) { groupData.initiative = initValue } updates.push({ _id: id, initiative: initValue }); if (initValue > maxInit.value) { maxInit.value = initValue; maxInit.cId = id; } if (showMessage) { // Determine the roll mode if ((c.token.hidden || c.hidden) && (rollMode === "roll")) { rollMode = "gmroll"; } // Construct chat message data const messageData = foundry.utils.mergeObject({ speaker: { scene: canvas.scene._id, actor: c.actor?.id || null, token: c.token.id, alias: c.token.name }, flavor: game.i18n.format('ACKS.roll.individualInit', { name: c.token.name, }), }, {}); const chatData = await roll.toMessage(messageData, { rollMode, create: false, }); if (messages.length > 0) { chatData.sound = null; } messages.push(chatData); } } await CONFIG.ChatMessage.documentClass.create(messages); this.pools = AcksCombat.getCombatantsPool(); await this.processOutNumbering(); await this.setFlag("acks", "lock-turns", false); await this.updateEmbeddedDocuments("Combatant", updates); setTimeout(function () { const updateData = { turn: 0 }; game.combat.update(updateData); }, 200); return this; } async startCombat() { console.log("Start Combat 1 !") // Send chat message to all players to roll for initiative ChatMessage.create({ user: game.user.id, content: await renderTemplate(`systems/fvtt-lethal-fantasy/templates/chat-ask-initiative.hbs`, { title: "Initiative roll requested", text: text, rollType: type, }), flags: { "fvtt-lethal-fantasy": { msg: "request-initiative-roll", content: {} } }, }) ChatMessage.create({ content: message, type: CONST.CHAT_MESSAGE_TYPES.GAME }); } 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() { console.log('NEXT ROUND') 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.round, this.turns); let advanceTime = Math.max(this.turns.length - this.turn, 0) * CONFIG.time.turnTime; advanceTime += CONFIG.time.roundTime; let nextRound = this.round + 1; // 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; } }