diff --git a/module/item-arme.js b/module/item-arme.js index bcca2358..f18bb712 100644 --- a/module/item-arme.js +++ b/module/item-arme.js @@ -138,7 +138,7 @@ export class RdDItemArme extends Item { /* -------------------------------------------- */ static armeUneOuDeuxMains(armeData, aUneMain) { armeData = Misc.data(armeData); - if (armeData) { + if (armeData && !armeData.data.cac) { armeData.data.unemain = armeData.data.unemain || !armeData.data.deuxmains; const uneOuDeuxMains = armeData.data.unemain && armeData.data.deuxmains; const containsSlash = !Number.isInteger(armeData.data.dommages) && armeData.data.dommages.includes("/"); @@ -171,11 +171,12 @@ export class RdDItemArme extends Item { let corpsACorps = competences.find(it => it.name == 'Corps à corps') ?? { data: { niveau: -6 } }; let init = RdDCombatManager.calculInitiative(corpsACorps.data.niveau, carac['melee'].value); armes.push(RdDItemArme.mainsNues({ niveau: corpsACorps.data.niveau, initiative: init })); + armes.push(RdDItemArme.empoignade({ niveau: corpsACorps.data.niveau, initiative: init })); } - static mainsNues(actorData = {}) { - const mainsNues = { - name: 'Mains nues', + static corpsACorps(actorData) { + const corpsACorps = { + name: 'Corps à corps', data: { equipe: true, rapide: true, @@ -187,9 +188,24 @@ export class RdDItemArme extends Item { categorie_parade: 'sans-armes' } }; - if (actorData) { - mergeObject(mainsNues.data, actorData, { overwrite: false }); - } + mergeObject(corpsACorps.data, actorData ??{}, { overwrite: false }); + return corpsACorps; + } + + static mainsNues(actorData) { + const mainsNues = RdDItemArme.corpsACorps(actorData); + mainsNues.name = 'Mains nues'; + mainsNues.data.cac = 'pugilat'; + mainsNues.data.baseInit = 4; return mainsNues; } + + static empoignade(actorData) { + const empoignade = RdDItemArme.corpsACorps(actorData); + empoignade.name = 'Empoignade'; + empoignade.data.cac = 'empoignade'; + empoignade.data.baseInit = 3; + empoignade.data.mortalite = 'empoignade'; + return empoignade; + } } diff --git a/module/rdd-combat.js b/module/rdd-combat.js index a7c42c3b..7b5f7ccd 100644 --- a/module/rdd-combat.js +++ b/module/rdd-combat.js @@ -11,23 +11,23 @@ import { ReglesOptionelles } from "./regles-optionelles.js"; /* -------------------------------------------- */ const premierRoundInit = [ - { pattern: 'hast', init: 3.90 }, - { pattern: 'lance', init: 3.85 }, - { pattern: 'baton', init: 3.80 }, - { pattern: 'doubledragonne', init: 3.75 }, - { pattern: 'esparlongue', init: 3.70 }, - { pattern: 'epeedragonne', init: 3.65 }, - { pattern: 'epeebatarde', init: 3.60 }, - { pattern: 'epeecyane', init: 3.55 }, - { pattern: 'epeesorde', init: 3.50 }, - { pattern: 'grandehache', init: 3.45 }, - { pattern: 'bataille', init: 3.40 }, - { pattern: 'epeegnome', init: 3.35 }, - { pattern: 'masse', init: 3.30 }, - { pattern: 'gourdin', init: 3.25 }, - { pattern: 'fléau', init: 3.20 }, - { pattern: 'dague', init: 3.15 }, - { pattern: 'autre', init: 3.10 }, + { pattern: 'hast', init: 5.90 }, + { pattern: 'lance', init: 5.85 }, + { pattern: 'baton', init: 5.80 }, + { pattern: 'doubledragonne', init: 5.75 }, + { pattern: 'esparlongue', init: 5.70 }, + { pattern: 'epeedragonne', init: 5.65 }, + { pattern: 'epeebatarde', init: 5.60 }, + { pattern: 'epeecyane', init: 5.55 }, + { pattern: 'epeesorde', init: 5.50 }, + { pattern: 'grandehache', init: 5.45 }, + { pattern: 'bataille', init: 5.40 }, + { pattern: 'epeegnome', init: 5.35 }, + { pattern: 'masse', init: 5.30 }, + { pattern: 'gourdin', init: 5.25 }, + { pattern: 'fléau', init: 5.20 }, + { pattern: 'dague', init: 5.15 }, + { pattern: 'autre', init: 5.10 }, ]; /* -------------------------------------------- */ @@ -148,7 +148,8 @@ export class RdDCombatManager extends Combat { let compData = competences.map(c => Misc.data(c)).find(c => c.name == armeData.data.competence); armesEquipe.push(armeData); - armeData.data.initiative = RdDCombatManager.calculInitiative(armeData.data.niveau, carac[compData.data.defaut_carac].value); + armeData.data.niveau = compData.data.niveau; + armeData.data.initiative = RdDCombatManager.calculInitiative(compData.data.niveau, carac[compData.data.defaut_carac].value); // Dupliquer les armes pouvant être à 1 main et 2 mains en patchant la compétence if (armeData.data.unemain && !armeData.data.deuxmains) { armeData.data.mainInfo = "(1m)"; @@ -185,7 +186,8 @@ export class RdDCombatManager extends Combat { } else { // Recupération des items 'arme' let armes = items.filter(it => RdDItemArme.isArmeUtilisable(it)) - .concat(RdDItemArme.mainsNues()); + .concat(RdDItemArme.mainsNues()) + .concat(RdDItemArme.empoignade()); let competences = items.filter(it => it.type == 'competence'); actions = actions.concat(RdDCombatManager.finalizeArmeList(armes, competences, actorData.data.carac)); @@ -277,30 +279,23 @@ export class RdDCombatManager extends Combat { initOffset = 2; initInfo = "Autre Action" } else if (arme.name == "Draconic") { - initOffset = 7; + initOffset = 9; initInfo = "Draconic" } else { - initOffset = 3; // Melée = 3.XX compData = Misc.data(RdDItemCompetence.findCompetence(combatant.actor.data.items, arme.data.competence)); compNiveau = compData.data.niveau; initInfo = arme.name + " / " + arme.data.competence; - if (combatant.actor.data.type == 'creature' || combatant.actor.data.type == 'entite') { caracForInit = compData.data.carac_value; if (compData.data.categorie == "lancer") { + initOffset = 7; + } + else { initOffset = 5; } } else { caracForInit = Misc.data(combatant.actor).data.carac[compData.data.defaut_carac].value; - if (compData.data.categorie == "lancer") { // Offset de principe pour les armes de jet - initOffset = 4; - } - if (compData.data.categorie == "tir") { // Offset de principe pour les armes de jet - initOffset = 5; - } - if (compData.data.categorie == "melee") { // Offset de principe pour les armes de jet - initOffset = 3; - } + initOffset = RdDCombatManager._baseInitOffset(compData.data.categorie, arme); } } let malus = combatant.actor.getEtatGeneral(); // Prise en compte état général @@ -311,6 +306,21 @@ export class RdDCombatManager extends Combat { game.combat.rollInitiative(combatantId, rollFormula, { initInfo: initInfo }); } + static _baseInitOffset(categorie, arme) { + if (categorie == "tir") { // Offset de principe pour les armes de jet + return 8; + } + if (categorie == "lancer") { // Offset de principe pour les armes de jet + return 7; + } + // Offset de principe pour les armes de jet + switch (arme.data.cac) { + case "empoignade": return 3; + case "pugilat": return 4; + } + return 5; + } + /* -------------------------------------------- */ static displayInitiativeMenu(html, combatantId) { console.log("Combatant ; ", combatantId); @@ -706,10 +716,21 @@ export class RdDCombat { } /* -------------------------------------------- */ - async attaque(competence, arme = undefined) { + async attaque(competence, arme) { if (!await this.accorderEntite('avant-attaque')) { return; } + if (arme.data.cac =='empoignade' && this.attacker.isCombatTouche()){ + ChatMessage.create({ + alias: this.attacker.name, + whisper: ChatUtility.getWhisperRecipientsAndGMs(this.attacker.name), + content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-actor-perte-empoignade.html', { + attacker: this.attacker, + competence: competence + }) + }); + return; + } let rollData = this._prepareAttaque(competence, arme); console.log("RdDCombat.attaque >>>", rollData); @@ -742,13 +763,14 @@ export class RdDCombat { _prepareAttaque(competence, arme) { let rollData = { passeArme: randomID(16), + mortalite: arme?.data.mortalite, coupsNonMortels: false, competence: competence, surprise: this.attacker.getSurprise(true), surpriseDefenseur: this.defender.getSurprise(true), essais: {} }; - + if (this.attacker.isCreature()) { RdDItemCompetenceCreature.setRollDataCreature(rollData); } @@ -758,7 +780,9 @@ export class RdDCombat { } else { // sans armes: à mains nues - rollData.arme = RdDItemArme.mainsNues({ niveau: competence.data.niveau }); + const niveau = competence.data.niveau; + const init = RdDCombatManager.calculInitiative(niveau, Misc.templateData(this.attacker).carac['melee'].value); + rollData.arme = RdDItemArme.mainsNues({ niveau: niveau, initiative: init }); } return rollData; } @@ -767,8 +791,24 @@ export class RdDCombat { async _onAttaqueParticuliere(rollData) { RdDCombat._storeAttaque(this.attackerId, rollData); - // Finesse et Rapidité seulement en mêlée et si la difficulté libre est de -1 minimum const isMeleeDiffNegative = (rollData.competence.type == 'competencecreature' || rollData.selectedCarac.label == "Mêlée") && rollData.diffLibre < 0; + // force toujours, sauf empoignade + // finesse seulement en mélée, pour l'empoignade, ou si la difficulté libre est de -1 minimum + // rapidité seulement en mêlée, si l'arme le permet, et si la difficulté libre est de -1 minimum + const isForce = !rollData.arme.data.empoignade; + const isFinesse = rollData.arme.data.empoignade || isMeleeDiffNegative; + const isRapide = !rollData.arme.data.empoignade && isMeleeDiffNegative && rollData.arme.data.rapide; + // si un seul choix possible, le prendre + if (isForce && !isFinesse && !isRapide) { + return await this.choixParticuliere(rollData, "force"); + } + else if (!isForce && isFinesse && !isRapide) { + return await this.choixParticuliere(rollData, "finesse"); + } + else if (!isForce && !isFinesse && isRapide) { + return await this.choixParticuliere(rollData, "rapidite"); + } + ChatMessage.create({ alias: this.attacker.name, whisper: ChatUtility.getWhisperRecipientsAndGMs(this.attacker.name), @@ -776,8 +816,9 @@ export class RdDCombat { alias: this.attacker.name, attackerId: this.attackerId, defenderTokenId: this.defenderTokenId, - isFinesse: isMeleeDiffNegative, - isRapide: isMeleeDiffNegative && rollData.arme.data.rapide, + isForce: isForce, + isFinesse: isFinesse, + isRapide: isRapide, passeArme: rollData.passeArme }) }); diff --git a/module/rdd-roll.js b/module/rdd-roll.js index 335c2082..243d5b6a 100644 --- a/module/rdd-roll.js +++ b/module/rdd-roll.js @@ -221,7 +221,7 @@ export class RdDRoll extends Dialog { console.log("RdDRollSelectDialog - Cout reve", ptreve); this.updateRollResult(); }); - html.find('#coupsNonMortels').change((event) => { + html.find("[name='coupsNonMortels']").change((event) => { this.rollData.dmg.mortalite = event.currentTarget.checked ? "non-mortel" : "mortel"; this.updateRollResult(); }); @@ -300,12 +300,14 @@ export class RdDRoll extends Dialog { rollData.dmg = rollData.attackerRoll?.dmg ?? RdDBonus.dmg(rollData, this.actor.getBonusDegat()); rollData.caracValue = parseInt(rollData.selectedCarac.value); + rollData.mortalite = rollData.attackerRoll?.dmg.mortalite ?? rollData.dmg.mortalite ?? 'mortel'; rollData.coupsNonMortels = (rollData.attackerRoll?.dmg.mortalite ?? rollData.dmg.mortalite) == 'non-mortel'; rollData.use.appelAuMoral = this.actor.isPersonnage() && RdDCarac.isActionPhysique(rollData.selectedCarac); let dmgText = Misc.toSignedString(rollData.dmg.total); - if (rollData.coupsNonMortels) { - dmgText = `(${dmgText}) non-mortel` + switch (rollData.mortalite){ + case 'non-mortel': dmgText = `(${dmgText}) non-mortel`; break; + case 'empoignade': dmgText = `empoignade`; break; } RollDataAjustements.calcul(rollData, this.actor); @@ -318,7 +320,7 @@ export class RdDRoll extends Dialog { // Mise à jour valeurs $(".dialog-roll-title").text(this._getTitle(rollData)); - $('#coupsNonMortels').prop('checked', rollData.coupsNonMortels); + $("[name='coupsNonMortels']").prop('checked', rollData.mortalite == 'non-mortel'); $(".dmg-arme-actor").text(dmgText); $('.table-ajustement').remove(); $(".table-resolution").remove(); diff --git a/templates/chat-demande-attaque-particuliere.html b/templates/chat-demande-attaque-particuliere.html index e6a32ad8..77456709 100644 --- a/templates/chat-demande-attaque-particuliere.html +++ b/templates/chat-demande-attaque-particuliere.html @@ -1,9 +1,11 @@