From 40147ae8d35249022332a468a204313323347772 Mon Sep 17 00:00:00 2001 From: Vlyan Date: Sun, 31 Jul 2022 18:41:50 +0200 Subject: [PATCH] Added props in actor object : isCharacter, isAdversary, isMinion, isArmy, canDoInitiativeRoll Minion ignore now the DP in init roll --- system/scripts/actor.js | 56 ++++++++++++++++--- system/scripts/actors/army-sheet.js | 2 +- system/scripts/actors/base-character-sheet.js | 19 ++++++- system/scripts/combat.js | 10 ++-- system/scripts/dice/dice-picker-dialog.js | 8 +-- system/scripts/dice/roll-n-keep-dialog.js | 4 +- system/scripts/gm/gm-monitor.js | 6 +- system/scripts/gm/gm-toolbox.js | 4 +- system/scripts/items/army-cohort-sheet.js | 2 +- 9 files changed, 83 insertions(+), 28 deletions(-) diff --git a/system/scripts/actor.js b/system/scripts/actor.js index f3d33f6..5013ff5 100644 --- a/system/scripts/actor.js +++ b/system/scripts/actor.js @@ -130,11 +130,11 @@ export class ActorL5r5e extends Actor { prepareData() { super.prepareData(); - if (this.isCharacter) { + if (this.isCharacterType) { const system = this.system; // No automation for npc as they cheat in stats - if (this.type === "character") { + if (this.isCharacter) { ActorL5r5e.computeDerivedAttributes(system); } @@ -242,10 +242,50 @@ export class ActorL5r5e extends Actor { * Return true if this actor is a PC or NPC * @return {boolean} */ - get isCharacter() { + get isCharacterType() { return ["character", "npc"].includes(this.type); } + /** + * Return true if this actor is a Character + * @return {boolean} + */ + get isCharacter() { + return this.type === "character"; + } + + /** + * Return true if this actor is an Adversary + * @return {boolean} + */ + get isAdversary() { + return this.type === "npc" && this.system.type === "adversary"; + } + + /** + * Return true if this actor is a Minion + * @return {boolean} + */ + get isMinion() { + return this.type === "npc" && this.system.type === "minion"; + } + + /** + * Return true if this actor is an Army + * @return {boolean} + */ + get isArmy() { + return this.type === "army"; + } + + /** + * Return true if this actor can do a initiative roll + * @returns {boolean} + */ + get canDoInitiativeRoll() { + return game.combat?.combatants.some((c) => c.tokenId === this.token?._id && !c.initiative); + } + /** * Return true if a weapon is equipped * @return {boolean} @@ -275,7 +315,7 @@ export class ActorL5r5e extends Actor { * @return {boolean} */ get isPrepared() { - if (!this.isCharacter) { + if (!this.isCharacterType) { return false; } @@ -286,7 +326,7 @@ export class ActorL5r5e extends Actor { }; // Prepared is a boolean or if null we get the info in the actor - let isPrepared = this.type === "character" ? cfg.character : cfg[this.system.type]; + let isPrepared = this.isCharacter ? cfg.character : cfg[this.system.type]; if (isPrepared === "null") { isPrepared = this.system.prepared ? "true" : "false"; } @@ -299,7 +339,7 @@ export class ActorL5r5e extends Actor { * @return {number|null} */ get statusRank() { - if (!this.isCharacter) { + if (!this.isCharacterType) { return null; } return Math.floor(this.system.social.status / 10); @@ -310,7 +350,7 @@ export class ActorL5r5e extends Actor { * @return {number|null} */ get intrigueRank() { - if (!this.isCharacter) { + if (!this.isCharacterType) { return null; } return this.type === "npc" ? this.system.conflict_rank.social : this.system.identity.school_rank; @@ -321,7 +361,7 @@ export class ActorL5r5e extends Actor { * @return {number|null} */ get martialRank() { - if (!this.isCharacter) { + if (!this.isCharacterType) { return null; } return this.type === "npc" ? this.system.conflict_rank.martial : this.system.identity.school_rank; diff --git a/system/scripts/actors/army-sheet.js b/system/scripts/actors/army-sheet.js index 9c2c91d..076aa9f 100644 --- a/system/scripts/actors/army-sheet.js +++ b/system/scripts/actors/army-sheet.js @@ -220,7 +220,7 @@ export class ArmySheetL5r5e extends BaseSheetL5r5e { * @private */ async _updateLinkedActorData(type, actor, isInit = false) { - if (!actor || actor.documentName !== "Actor" || !actor.isCharacter) { + if (!actor || actor.documentName !== "Actor" || !actor.isCharacterType) { console.warn("L5R5E | Wrong actor type", actor?.type, actor); return; } diff --git a/system/scripts/actors/base-character-sheet.js b/system/scripts/actors/base-character-sheet.js index 73f0734..95afbe2 100644 --- a/system/scripts/actors/base-character-sheet.js +++ b/system/scripts/actors/base-character-sheet.js @@ -621,12 +621,29 @@ export class BaseCharacterSheetL5r5e extends BaseSheetL5r5e { event.stopPropagation(); const li = $(event.currentTarget); const weapon = this._getWeaponInfos(li.data("weapon-id") || null); + const isInitiative = li.data("initiative") || false; + + if (isInitiative) { + if (!game.combat) { + ui.notifications.warn(game.i18n.localize("COMBAT.NoneActive")); + return; + } + if (!this.actor.canDoInitiativeRoll) { + ui.notifications.error(game.i18n.localize("l5r5e.conflict.initiative.already_set")); + return; + } + // Minion specific + if (this.actor.isMinion) { + this.actor.rollInitiative().then(); + return; + } + } new game.l5r5e.DicePickerDialog({ ringId: li.data("ring") || null, skillId: weapon?.skill || li.data("skill") || null, skillCatId: li.data("skillcat") || null, - isInitiativeRoll: li.data("initiative") || false, + isInitiativeRoll: isInitiative, actor: this.actor, itemUuid: weapon?.uuid, }).render(true); diff --git a/system/scripts/combat.js b/system/scripts/combat.js index 5dfab6d..ed18503 100644 --- a/system/scripts/combat.js +++ b/system/scripts/combat.js @@ -44,7 +44,7 @@ export class CombatL5r5e extends Combat { } // Skip non character types (army) - if (!combatant.actor.isCharacter) { + if (!combatant.actor.isCharacterType) { updatedCombatants.push({ _id: combatant.id, initiative: 0, @@ -53,7 +53,7 @@ export class CombatL5r5e extends Combat { } // Prepared is a boolean or if null we get the info in the actor sheet - const isPc = combatant.actor.type === "character"; + const isPc = combatant.actor.isCharacter; const isPrepared = combatant.actor.isPrepared; const actorSystem = combatant.actor.system; @@ -65,7 +65,7 @@ export class CombatL5r5e extends Combat { isPrepared === "true" ? actorSystem.focus : actorSystem.is_compromised ? 1 : actorSystem.vigilance; // Roll only for PC and Adversary - if (isPc || actorSystem.type === "adversary") { + if (isPc || combatant.actor.isAdversary) { // DicePicker management // formula is empty on the fist call (combat tab buttons) if (!formula && !combatant.initiative) { @@ -174,14 +174,14 @@ export class CombatL5r5e extends Combat { /** * Define how the array of Combatants is sorted in the displayed list of the tracker. * This method can be overridden by a system or module which needs to display combatants in an alternative order. - * By default sort by initiative, falling back to name + * By default, sort by initiative, falling back to name * @private */ _sortCombatants(a, b) { // if tie : sort by honor, less honorable first if (a.initiative === b.initiative) { // skip if no actor or if armies - if (!a.actor || !b.actor || a.actor.type === "army" || b.actor.type === "army") { + if (!a.actor || !b.actor || a.actor.isArmy || b.actor.isArmy) { return 0; } diff --git a/system/scripts/dice/dice-picker-dialog.js b/system/scripts/dice/dice-picker-dialog.js index 27932d9..afdd789 100644 --- a/system/scripts/dice/dice-picker-dialog.js +++ b/system/scripts/dice/dice-picker-dialog.js @@ -403,7 +403,7 @@ export class DicePickerDialog extends FormApplication { canUseVoidPoint: this.object.difficulty.addVoidPoint || !this._actor || - (this._actor.isCharacter && this._actor.system.void_points.value > 0), + (this._actor.isCharacterType && this._actor.system.void_points.value > 0), disableSubmit: this.object.skill.value < 1 && this.object.ring.value < 1, difficultyHiddenIsLock: this._difficultyHiddenIsLock.gm || this._difficultyHiddenIsLock.option, }; @@ -536,8 +536,8 @@ export class DicePickerDialog extends FormApplication { ui.notifications.warn(game.i18n.localize("COMBAT.NoneActive")); return this.close(); } - const combatant = game.combat.combatants.find((c) => c.actor.id === this._actor.id && c.initiative > 0); - if (combatant) { + + if (!this._actor.canDoInitiativeRoll) { ui.notifications.error(game.i18n.localize("l5r5e.conflict.initiative.already_set")); return this.close(); } @@ -721,7 +721,7 @@ export class DicePickerDialog extends FormApplication { const targetGrp = Array.from(game.user.targets).reduce( (acc, tgt) => { const targetActor = tgt.document.actor; - if (!targetActor.isCharacter) { + if (!targetActor.isCharacterType) { return acc; } diff --git a/system/scripts/dice/roll-n-keep-dialog.js b/system/scripts/dice/roll-n-keep-dialog.js index 610b198..b3e911b 100644 --- a/system/scripts/dice/roll-n-keep-dialog.js +++ b/system/scripts/dice/roll-n-keep-dialog.js @@ -250,7 +250,7 @@ export class RollnKeepDialog extends FormApplication { ...(await super.getData(options)), isGM: game.user.isGM, showChoices: options.editable && !rollData.rnkEnded, - showStrifeBt: options.editable && rollData.summary.strife > 0 && rollData.actor?.isCharacter, + showStrifeBt: options.editable && rollData.summary.strife > 0 && rollData.actor?.isCharacterType, cssClass: this.options.classes.join(" "), data: this.object, l5r5e: rollData, @@ -713,7 +713,7 @@ export class RollnKeepDialog extends FormApplication { // Apply strife to actor const strifeApplied = Math.min(this.roll.l5r5e.summary.strife, Math.max(0, formData.strifeApplied)); const actorMod = strifeApplied - this.roll.l5r5e.strifeApplied; - if (actorMod !== 0 && this.roll.l5r5e.actor?.isCharacter) { + if (actorMod !== 0 && this.roll.l5r5e.actor?.isCharacterType) { await this.roll.l5r5e.actor.update({ system: { strife: { diff --git a/system/scripts/gm/gm-monitor.js b/system/scripts/gm/gm-monitor.js index 02b57c2..038ce27 100644 --- a/system/scripts/gm/gm-monitor.js +++ b/system/scripts/gm/gm-monitor.js @@ -125,9 +125,7 @@ export class GmMonitor extends FormApplication { ...(await super.getData(options)), data: { ...this.object, - actors: this.object.actors.filter((e) => - this.object.view === "armies" ? e.type === "army" : e.type !== "army" - ), + actors: this.object.actors.filter((a) => (this.object.view === "armies" ? a.isArmy : !a.isArmy)), }, }; } @@ -178,7 +176,7 @@ export class GmMonitor extends FormApplication { case "weapons": return this._getTooltipWeapons(actor); case "global": - return actor.type === "army" ? this._getTooltipArmiesGlobal(actor) : this._getTooltipGlobal(actor); + return actor.isArmy ? this._getTooltipArmiesGlobal(actor) : this._getTooltipGlobal(actor); } }); } diff --git a/system/scripts/gm/gm-toolbox.js b/system/scripts/gm/gm-toolbox.js index c7a9dba..f12f393 100644 --- a/system/scripts/gm/gm-toolbox.js +++ b/system/scripts/gm/gm-toolbox.js @@ -197,12 +197,12 @@ export class GmToolbox extends FormApplication { for await (const actor of game.actors.contents) { // Only characters types - if (!actor.isCharacter) { + if (!actor.isCharacterType) { continue; } // Manage left/right button - if (!isAll && (actor.type !== "character" || !actor.hasPlayerOwner)) { + if (!isAll && (!actor.isCharacter || !actor.hasPlayerOwner)) { continue; } diff --git a/system/scripts/items/army-cohort-sheet.js b/system/scripts/items/army-cohort-sheet.js index b89b91b..72f708c 100644 --- a/system/scripts/items/army-cohort-sheet.js +++ b/system/scripts/items/army-cohort-sheet.js @@ -110,7 +110,7 @@ export class ArmyCohortSheetL5r5e extends ItemSheetL5r5e { * @private */ async _updateLinkedActorData(actor) { - if (!actor || actor.documentName !== "Actor" || !actor.isCharacter) { + if (!actor || actor.documentName !== "Actor" || !actor.isCharacterType) { console.warn("L5R5E | Wrong actor type", actor?.type, actor); return; }