From be1d109def67419a6fd43eb3de8cc43990d48146 Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Wed, 6 Nov 2024 23:24:53 +0100 Subject: [PATCH] =?UTF-8?q?Corrections=20actions=20combat=20cr=C3=A9atures?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Les actions de combat des créatures et leurs défenses sont correctement filtrées --- module/actor.js | 23 +- module/actor/base-actor-reve.js | 26 ++- module/actor/base-actor.js | 15 ++ module/actor/export-scriptarium/mapping.js | 4 +- module/item-arme.js | 22 +- module/item-competencecreature.js | 23 +- module/rdd-combat.js | 242 ++++++++------------- module/rdd-token-hud.js | 2 +- 8 files changed, 180 insertions(+), 177 deletions(-) diff --git a/module/actor.js b/module/actor.js index 75eec4e8..848368ac 100644 --- a/module/actor.js +++ b/module/actor.js @@ -36,6 +36,8 @@ import { ITEM_TYPES } from "./item.js"; import { RdDBaseActorSang } from "./actor/base-actor-sang.js"; import { RdDCoeur } from "./coeur/rdd-coeur.js"; import { DialogChoixXpCarac } from "./dialog-choix-xp-carac.js"; +import { RdDItemArme } from "./item-arme.js"; +import { RdDCombatManager } from "./rdd-combat.js"; export const MAINS_DIRECTRICES = ['Droitier', 'Gaucher', 'Ambidextre'] @@ -130,6 +132,23 @@ export class RdDActor extends RdDBaseActorSang { .reduce(Misc.sum(), 0); } + listActionsCombat() { + // Recupération des armes + const actions = RdDCombatManager.listActionsArmes( + this.itemTypes[ITEM_TYPES.arme] + .filter(it => RdDItemArme.isAttaque(it)) + .concat(RdDItemArme.empoignade(this)) + .concat(RdDItemArme.mainsNues(this)) + , + this.itemTypes[ITEM_TYPES.competence], + this.system.carac) + + if (this.system.attributs.hautrevant.value) { + actions.push({ name: "Draconic", action: 'haut-reve', system: { initOnly: true, competence: "Draconic" } }); + } + return actions + } + /* -------------------------------------------- */ getTache(id) { return this.findItemLike(id, 'tache') } getMeditation(id) { return this.findItemLike(id, 'meditation') } @@ -1548,7 +1567,7 @@ export class RdDActor extends RdDBaseActorSang { /* -------------------------------------------- */ async appliquerAjoutExperience(rollData, hideChatMessage = 'show') { - if (!Misc.isFirstConnectedGM()){ + if (!Misc.isFirstConnectedGM()) { return } hideChatMessage = hideChatMessage == 'hide' || (Misc.isRollModeHiddenToPlayer() && !game.user.isGM) @@ -3067,7 +3086,7 @@ export class RdDActor extends RdDBaseActorSang { incarnation.name = 'Réincarnation de ' + incarnation.name incarnation.system = { carac: foundry.utils.duplicate(this.system.carac), - heure: RdDTimestamp.defHeure(await RdDDice.rollHeure( { rollMode: "selfroll", showDice: SHOW_DICE })).key, + heure: RdDTimestamp.defHeure(await RdDDice.rollHeure({ rollMode: "selfroll", showDice: SHOW_DICE })).key, age: 18, biographie: '', notes: '', diff --git a/module/actor/base-actor-reve.js b/module/actor/base-actor-reve.js index 53b5604b..50680bb4 100644 --- a/module/actor/base-actor-reve.js +++ b/module/actor/base-actor-reve.js @@ -15,7 +15,7 @@ import { StatusEffects } from "../settings/status-effects.js"; import { ITEM_TYPES } from "../item.js"; import { Targets } from "../targets.js"; import { RdDPossession } from "../rdd-possession.js"; -import { RdDCombat } from "../rdd-combat.js"; +import { RdDCombat, RdDCombatManager } from "../rdd-combat.js"; import { RdDConfirm } from "../rdd-confirm.js"; import { ENTITE_INCARNE, SHOW_DICE, SYSTEM_RDD } from "../constants.js"; import { RdDItemArme } from "../item-arme.js"; @@ -83,6 +83,23 @@ export class RdDBaseActorReve extends RdDBaseActor { getEtatGeneral(options = { ethylisme: false }) { return 0 } isActorCombat() { return true } + getCaracInit(competence) { + if (!competence){ + return 0 + } + if (competence.type == ITEM_TYPES.competencecreature) { + return competence.system.carac_value + } + return this.system.carac[competence.system.defaut_carac].value; + } + listActionsCombat() { + return this.itemTypes[ITEM_TYPES.competencecreature] + .filter(it => RdDItemCompetenceCreature.isAttaque(it)) + .map(it => RdDItemCompetenceCreature.armeCreature(it)) + .filter(it => it != undefined); + } + + async computeArmure(attackerRoll) { return this.getProtectionNaturelle() } async remiseANeuf() { } async appliquerAjoutExperience(rollData, hideChatMessage = 'show') { } @@ -155,9 +172,6 @@ export class RdDBaseActorReve extends RdDBaseActor { getPossession(possessionId) { return this.itemTypes[ITEM_TYPES.possession].find(it => it.system.possessionid == possessionId); } - getPossessions() { - return this.itemTypes[ITEM_TYPES.possession]; - } getEmpoignades() { return this.itemTypes[ITEM_TYPES.empoignade]; } @@ -370,7 +384,7 @@ export class RdDBaseActorReve extends RdDBaseActor { rollArme(arme, categorieArme, token) { token = token ?? RdDUtility.getSelectedToken(this) const compToUse = this.$getCompetenceArme(arme, categorieArme) - if (!RdDItemArme.isArmeUtilisable(arme)) { + if (!RdDItemArme.isUtilisable(arme)) { ui.notifications.warn(`Arme inutilisable: ${arme.name} a une résistance de 0 ou moins`) return } @@ -452,7 +466,7 @@ export class RdDBaseActorReve extends RdDBaseActor { alias: defenderToken?.name ?? this.name, hasPlayerOwner: this.hasPlayerOwner, show: show ?? {} - }, {overwrite: false}); + }, { overwrite: false }); await ChatUtility.createChatWithRollMode( { diff --git a/module/actor/base-actor.js b/module/actor/base-actor.js index 7d8b64ab..d84a9a20 100644 --- a/module/actor/base-actor.js +++ b/module/actor/base-actor.js @@ -710,4 +710,19 @@ export class RdDBaseActor extends Actor { getItemUse(itemId) { return 0; } async finDeRound(options = { terminer: false }) { } isActorCombat() { return false } + getCaracInit(competence) { return 0 } + listActionsCombat() { return [] } + listActionsPossessions() { + return this.itemTypes[ITEM_TYPES.possession] + .map(p => { + return { + name: p.name, + action: 'possession', + system: { + competence: p.name, + possessionid: p.system.possessionid, + } + } + }) + } } \ No newline at end of file diff --git a/module/actor/export-scriptarium/mapping.js b/module/actor/export-scriptarium/mapping.js index 8a4cd515..6d1fc29b 100644 --- a/module/actor/export-scriptarium/mapping.js +++ b/module/actor/export-scriptarium/mapping.js @@ -152,8 +152,8 @@ export class Mapping { } static prepareArme(actor, arme, maniement) { - const nameCompArme = RdDItemArme.getCompetenceArme(arme, maniement) - const competence = actor.getCompetence(nameCompArme) + const nameCompetenceArme = RdDItemArme.getCompetenceArme(arme, maniement) + const competence = actor.getCompetence(nameCompetenceArme) if (RdDItemCompetence.isNiveauBase(competence)) { return undefined } diff --git a/module/item-arme.js b/module/item-arme.js index 86255aa6..6d9c7a17 100644 --- a/module/item-arme.js +++ b/module/item-arme.js @@ -206,7 +206,7 @@ export class RdDItemArme extends Item { return arme.system.competence.replace(" 1 main", " 2 mains"); } - static isArmeUtilisable(arme) { + static isUtilisable(arme) { switch (arme.type) { case ITEM_TYPES.arme: return arme.system.equipe && (arme.system.resistance > 0 || arme.system.portee_courte > 0) case ITEM_TYPES.competencecreature: return true @@ -214,6 +214,26 @@ export class RdDItemArme extends Item { return false } + static isAttaque(arme) { + switch (arme.type) { + case ITEM_TYPES.arme: + return arme.system.equipe && (arme.system.resistance > 0 || arme.system.portee_courte > 0) + case ITEM_TYPES.competencecreature: + return arme.system.iscombat && RdDItemCompetenceCreature.isAttaque(item) + } + return false + } + + static isParade(arme) { + switch (arme.type) { + case ITEM_TYPES.arme: + return arme.system.equipe && arme.system.resistance > 0 && true/* TODO: regarder la categorie d'arme?*/ + case ITEM_TYPES.competencecreature: + return arme.system.iscombat && RdDItemCompetenceCreature.isParade(arme) + } + return false + } + static ajoutCorpsACorps(armes, actor) { armes.push(RdDItemArme.mainsNues(actor)); armes.push(RdDItemArme.empoignade(actor)); diff --git a/module/item-competencecreature.js b/module/item-competencecreature.js index 7e1ab4b5..6828fd48 100644 --- a/module/item-competencecreature.js +++ b/module/item-competencecreature.js @@ -27,29 +27,28 @@ export class RdDItemCompetenceCreature extends Item { static armeCreature(item) { const categorieAttaque = RdDItemCompetenceCreature.getCategorieAttaque(item) if (categorieAttaque != undefined) { - // si c'est un Item compétence: cloner pour ne pas modifier la compétence - let arme = item.clone(); - return foundry.utils.mergeObject(arme, { + // cloner pour ne pas modifier la compétence + return foundry.utils.mergeObject(item, { action: item.isCompetencePossession() ? 'possession' : 'attaque', system: { - competence: arme.name, + competence: item.name, cac: categorieAttaque == "naturelle" ? "naturelle" : "", niveau: item.system.niveau, initiative: RdDCombatManager.calculInitiative(item.system.niveau, item.system.carac_value), equipe: true, resistance: 100, - dommagesReels: arme.system.dommages, + dommagesReels: item.system.dommages, penetration: 0, force: 0, rapide: true, } - }, { inplace: false }); + }, { inplace: false, }); } return undefined; } /* -------------------------------------------- */ - static isCompetenceAttaque(item) { + static isAttaque(item) { if (item.type == ITEM_TYPES.competencecreature) { switch (item.system.categorie) { case "melee": @@ -60,7 +59,7 @@ export class RdDItemCompetenceCreature extends Item { return true } } - return undefined + return false } static getCategorieAttaque(item) { @@ -77,6 +76,7 @@ export class RdDItemCompetenceCreature extends Item { } return undefined } + static isDommages(item) { if (item.type == ITEM_TYPES.competencecreature) { switch (item.system.categorie) { @@ -89,6 +89,7 @@ export class RdDItemCompetenceCreature extends Item { } return false } + static isParade(item) { if (item.type == ITEM_TYPES.competencecreature) { switch (item.system.categorie) { @@ -101,8 +102,4 @@ export class RdDItemCompetenceCreature extends Item { return false } - /* -------------------------------------------- */ - static isCompetenceParade(item) { - return item.type == 'competencecreature' && item.system.categorie_parade !== ""; - } -} +} diff --git a/module/rdd-combat.js b/module/rdd-combat.js index 35b6bf9f..e02260ae 100644 --- a/module/rdd-combat.js +++ b/module/rdd-combat.js @@ -72,19 +72,24 @@ export class RdDCombatManager extends Combat { /* -------------------------------------------- */ async finDeRound(options = { terminer: false }) { + this.combatants.map(it => RdDCombatManager.getActorCombatant(it)) + .filter(it => it != undefined) + .forEach(async actor => { + await actor.finDeRound(options) + await actor.resetItemUse() + }) + } - for (let combatant of this.combatants) { - if (!combatant.actor) { - ui.notifications.warn(`Le combatant ${combatant.name} n'est pas associé à un acteur!`) - } - else if (!combatant.actor.isActorCombat()) { - ui.notifications.warn(`Le combatant ${combatant.name} ne peut pas combattre!`) - } - else { - await combatant.actor.finDeRound(options) - await combatant.actor.resetItemUse() - } + static getActorCombatant(combatant) { + if (!combatant.actor) { + ui.notifications.warn(`Le combatant ${combatant.name} n'est pas associé à un acteur!`) + return undefined } + else if (!combatant.actor.isActorCombat()) { + ui.notifications.warn(`${combatant.name} ne peut pas combattre!`) + return undefined + } + return combatant.actor } static calculAjustementInit(actor, arme) { @@ -107,7 +112,7 @@ export class RdDCombatManager extends Combat { if (!formula) { if (combatant.actor.type == 'creature' || combatant.actor.type == 'entite') { - const competence = combatant.actor.items.find(it => RdDItemCompetenceCreature.isCompetenceAttaque(it)) + const competence = combatant.actor.items.find(it => RdDItemCompetenceCreature.isAttaque(it)) if (competence) { rollFormula = RdDCombatManager.formuleInitiative(2, competence.system.carac_value, competence.system.niveau, etatGeneral); } @@ -156,7 +161,7 @@ export class RdDCombatManager extends Combat { alias: combatant.token.name, sound: CONFIG.sounds.dice, }, - flavor: `${combatant.token.name} a fait son jet d'Initiative (${messageOptions.initInfo})
`, + flavor: `${combatant.token.name} a fait son jet d'Initiative (${messageOptions.info})
`, }, messageOptions); roll.toMessage(messageData, { rollMode, create: true }); @@ -247,61 +252,6 @@ export class RdDCombatManager extends Combat { return attaque; } - /* -------------------------------------------- */ - static listActionsCombat(combatant) { - const actor = combatant.actor; - if (!actor.isActorCombat()) { - return - } - let actions = RdDCombatManager.listActionsPossessions(actor); - if (actions.length > 0) { - return actions; - } - if (actor.isCreatureEntite()) { - actions = RdDCombatManager.listActionsCreature(actor.itemTypes['competencecreature']); - } else if (actor.isPersonnage()) { - // Recupération des items 'arme' - const competences = actor.itemTypes['competence']; - const armes = actor.itemTypes['arme'].filter(it => RdDItemArme.isArmeUtilisable(it)) - .concat(RdDItemArme.empoignade(actor)) - .concat(RdDItemArme.mainsNues(actor)); - actions = RdDCombatManager.listActionsArmes(armes, competences, actor.system.carac); - - if (actor.system.attributs.hautrevant.value) { - actions.push({ name: "Draconic", action: 'haut-reve', system: { initOnly: true, competence: "Draconic" } }); - } - } - - return RdDCombatManager._indexActions(actions); - } - - static listActionsCreature(competences) { - return competences - .filter(it => RdDItemCompetenceCreature.isCompetenceAttaque(it)) - .map(it => RdDItemCompetenceCreature.armeCreature(it)) - .filter(it => it != undefined); - } - - static listActionsPossessions(actor) { - return RdDCombatManager._indexActions(actor.getPossessions().map(p => { - return { - name: p.name, - action: 'possession', - system: { - competence: p.name, - possessionid: p.system.possessionid, - } - } - })); - } - - static _indexActions(actions) { - for (let index = 0; index < actions.length; index++) { - actions[index].index = index; - } - return actions; - } - /* -------------------------------------------- */ static processPremierRoundInit() { // Check if we have the whole init ! @@ -339,13 +289,13 @@ export class RdDCombatManager extends Combat { /* -------------------------------------------- */ static pushInitiativeOptions(html, options) { for (let i = 0; i < options.length; i++) { - let option = options[i]; + let option = options[i] if (option.name == 'COMBAT.CombatantReroll') { // Replace ! - option.name = "Sélectionner l'initiative..."; - option.condition = true; - option.icon = ''; + option.name = "Sélectionner l'initiative..." + option.condition = true + option.icon = '' option.callback = target => { - RdDCombatManager.displayInitiativeMenu(html, target.data('combatant-id')); + RdDCombatManager.displayInitiativeMenu(html, target.data('combatant-id')) } } } @@ -356,96 +306,84 @@ export class RdDCombatManager extends Combat { } /* -------------------------------------------- */ static rollInitiativeAction(combatantId, action) { - const combatant = game.combat.combatants.get(combatantId); - if (combatant.actor == undefined) { - ui.notifications.warn(`Le combatant ${combatant.name} n'est pas associé à un acteur, impossible de déterminer ses actions de combat!`) - return []; - } - let initInfo = ""; - let initOffset = 0; - let caracForInit = 0; - let compNiveau = 0; - let compData = { name: "Aucune" }; - if (combatant.actor.getSurprise() == "totale") { - initOffset = -1; // To force 0 - initInfo = "Surprise Totale" - } else if (combatant.actor.getSurprise() == "demi") { - initOffset = 0; - initInfo = "Demi Surprise" - } else if (action.action == 'possession') { - initOffset = 10; - caracForInit = combatant.actor.getReveActuel(); - initInfo = "Possession" - } else if (action.action == 'autre') { - initOffset = 2; - initInfo = "Autre Action" - } else if (action.action == 'haut-reve') { - initOffset = 9; - initInfo = "Draconic" - } else { - compData = RdDItemCompetence.findCompetence(combatant.actor.items, action.system.competence); - compNiveau = compData.system.niveau; - initInfo = action.name + " / " + action.system.competence; + const combatant = game.combat.combatants.get(combatantId) + const actor = RdDCombatManager.getActorCombatant(combatant) + if (actor == undefined) { return [] } - if (combatant.actor.type == 'creature' || combatant.actor.type == 'entite') { - caracForInit = compData.system.carac_value; - } else { - caracForInit = combatant.actor.system.carac[compData.system.defaut_carac].value; - } - initOffset = RdDCombatManager._baseInitOffset(compData.system.categorie, action); - } - - // Cas des créatures et entités vs personnages - const ajustement = RdDCombatManager.calculAjustementInit(combatant.actor, action) - let rollFormula = RdDCombatManager.formuleInitiative(initOffset, caracForInit, compNiveau, ajustement); - // Garder la trace de l'arme/compétence utilisée pour l'iniative combatant.initiativeData = { arme: action } // pour reclasser l'init au round 0 - game.combat.rollInitiative(combatantId, rollFormula, { initInfo: initInfo }); + + const init = RdDCombatManager.getInitData(actor, action) + const ajustement = RdDCombatManager.calculAjustementInit(actor, action) + const rollFormula = RdDCombatManager.formuleInitiative(init.offset, init.carac, init.niveau, ajustement); + + game.combat.rollInitiative(combatantId, rollFormula, init); } - /* -------------------------------------------- */ - static _baseInitOffset(categorie, arme) { - if (categorie == "tir") { // Offset de principe pour les armes de jet - return 8; + static getInitData(actor, action) { + if (actor.getSurprise() == "totale") { return { offset: -1, info: "Surprise Totale", carac: 0, niveau: 0 } } + if (actor.getSurprise() == "demi") { return { offset: 0, info: "Demi Surprise", carac: 0, niveau: 0 } } + if (action.action == 'autre') { return { offset: 2, info: "Autre Action", carac: 0, niveau: 0 } } + if (action.action == 'possession') { return { offset: 10, info: "Possession", carac: actor.getReveActuel(), niveau: 0 } } + if (action.action == 'haut-reve') { return { offset: 9, info: "Draconic", carac: actor.getReveActuel(), niveau: 0 } } + + const comp = RdDItemCompetence.findCompetence(actor.items, action.system.competence); + return { + offset: RdDCombatManager.initOffset(comp?.system.categorie, action), + info: action.name + " / " + action.system.competence, + carac: actor.getCaracInit(comp), + niveau: comp?.system.niveau ?? -8 } - if (categorie == "lancer") { // Offset de principe pour les armes de jet - return 7; + } + + static initOffset(categorie, arme) { + switch (categorie) { + case "tir": return 8 + case "lancer": return 7 + default: + switch (arme.system.cac) { + case "empoignade": return 3 + case "pugilat": return 4 + case "naturelle": return 4 + default: return 5 + } } - switch (arme.system.cac) { - case "empoignade": - return 3; - case "pugilat": - case "naturelle": - return 4; - } - return 5; } /* -------------------------------------------- */ static displayInitiativeMenu(html, combatantId) { - console.log("Combatant ; ", combatantId); - const combatant = game.combat.combatants.get(combatantId); - if (!(combatant?.actor)) { - ui.notifications.warn(`Le combatant ${combatant.name ?? combatantId} n'est pas associé à un acteur, impossible de déterminer ses actions de combat!`) - return; - } - - let actions = RdDCombatManager.listActionsCombat(combatant); - + const combatant = game.combat.combatants.get(combatantId) + const actions = RdDCombatManager.listActionsCombatant(combatant); // Build the relevant submenu - if (actions) { - let menuItems = []; - for (let action of actions) { - menuItems.push({ - name: action.system.competence, - icon: "", - callback: target => { RdDCombatManager.rollInitiativeAction(combatantId, action) } - }); + const menuItems = actions.map(action => { + return { + name: action.system.competence, + icon: "", + callback: target => { RdDCombatManager.rollInitiativeAction(combatantId, action) } } + }) + if (menuItems.length > 0) { new ContextMenu(html, ".directory-list", menuItems).render(); } } + /* -------------------------------------------- */ + static listActionsCombatant(combatant) { + const actor = RdDCombatManager.getActorCombatant(combatant) + if (actor) { + const possessions = actor.listActionsPossessions() + const actions = possessions.length > 0 + ? possessions + : actor.listActionsCombat() + + for (let index = 0; index < actions.length; index++) { + actions[index].index = index + } + return actions + } + return [] + } + + } /* -------------------------------------------- */ @@ -992,13 +930,13 @@ export class RdDCombat { } /* -------------------------------------------- */ - _filterArmesParade(defender, competence, arme) { - let defenses = defender.items.filter(it => RdDItemArme.isArmeUtilisable(it) || RdDItemCompetenceCreature.isCompetenceParade(it)) + _filterArmesParade(defender, competence, armeAttaque) { + let defenses = defender.items.filter(it => RdDItemArme.isParade(it)) defenses = foundry.utils.duplicate(defenses) defenses.forEach(armeDefense => { // Ajout du # d'utilisation ce round armeDefense.nbUsage = defender.getItemUse(armeDefense.id) - armeDefense.typeParade = RdDItemArme.defenseArmeParade(arme, armeDefense) + armeDefense.typeParade = RdDItemArme.defenseArmeParade(armeAttaque, armeDefense) }) switch (competence.system.categorie) { @@ -1353,7 +1291,7 @@ export class RdDCombat { if (!actor?.isActorCombat()) { return } - let formData = { + const formData = { combatId: combat._id, alias: token.name ?? actor.name, etatGeneral: actor.getEtatGeneral(), @@ -1374,6 +1312,6 @@ export class RdDCombat { content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-actor-turn-sante.hbs`, formData), whisper: ChatUtility.getOwners(actor), alias: token.name ?? actor.name - }); + }) } } \ No newline at end of file diff --git a/module/rdd-token-hud.js b/module/rdd-token-hud.js index a230f8ee..d0040f0b 100644 --- a/module/rdd-token-hud.js +++ b/module/rdd-token-hud.js @@ -33,7 +33,7 @@ export class RdDTokenHud { ui.notifications.warn(`Le combatant ${token.name} n'est pas associé à un acteur, impossible de déterminer ses actions de combat!`) return; } - let actions = RdDCombatManager.listActionsCombat(combatant); + let actions = RdDCombatManager.listActionsCombatant(combatant); // initiative await RdDTokenHud.addExtensionHudInit(html, combatant, actions); // combat