Ajouts combat #68

- gestion de la feinte (sauf initiative)
- gestion du bonus à l'attaque de la charge
- dégats de corps à corps
- bonus dégâts si surprise, début de gestion de surprise totale
This commit is contained in:
2020-12-16 23:02:15 +01:00
parent c8a2d69e0f
commit f3453a46e7
9 changed files with 287 additions and 318 deletions

View File

@ -1,11 +1,10 @@
import { RdDActor } from "./actor.js";
import { ChatUtility } from "./chat-utility.js";
import { RdDItemArme } from "./item-arme.js";
import { RdDItemCompetence } from "./item-competence.js";
import { Misc } from "./misc.js";
import { RdDBonus } from "./rdd-bonus.js";
import { RdDResolutionTable } from "./rdd-resolution-table.js";
import { RdDRoll } from "./rdd-roll.js";
import { RdDUtility } from "./rdd-utility.js";
export class RdDCombat {
@ -75,7 +74,6 @@ export class RdDCombat {
ui.notifications.warn("Action automatisée impossible, le jet de l'attaquant a été perdu (suite à un raffraichissement?)")
return;
}
// TODO: enlever le ChatMessage?
switch (button) {
case '#particuliere-attaque': return await this.choixParticuliere(rollData, event.currentTarget.attributes['data-mode'].value);
case '#parer-button': return this.parade(rollData, event.currentTarget.attributes['data-armeid'].value);
@ -84,6 +82,41 @@ export class RdDCombat {
}
}
/* -------------------------------------------- */
static isEchec(rollData) {
switch (rollData.surprise) {
case 'demi': return !rollData.rolled.isSign;
case 'totale': return true;
}
return rollData.rolled.isEchec;
}
/* -------------------------------------------- */
static isEchecTotal(rollData) {
if (rollData.arme && rollData.surprise == 'demi') {
return rollData.rolled.isEchec;
}
return rollData.rolled.isETotal;
}
/* -------------------------------------------- */
static isParticuliere(rollData) {
if (rollData.arme && rollData.surprise) {
return false;
}
return rollData.rolled.isPart;
}
/* -------------------------------------------- */
static isReussite(rollData) {
switch (rollData.surprise) {
case 'demi': return rollData.rolled.isSign;
case 'totale': return false;
}
return rollData.rolled.isSuccess;
}
/* -------------------------------------------- */
async attaque(competence, arme) {
if (!await this.accorderEntite('avant-attaque')) {
@ -99,10 +132,10 @@ export class RdDCombat {
label: 'Attaque: ' + (arme ? arme.name : competence.name),
callbacks: [
this.attacker.createCallbackExperience(),
{ condition: RdDResolutionTable.isParticuliere, action: r => this._onAttaqueParticuliere(r) },
{ condition: r => (RdDResolutionTable.isReussite(r) && !RdDResolutionTable.isParticuliere(r)), action: r => this._onAttaqueNormale(r) },
{ condition: RdDResolutionTable.isEchecTotal, action: r => this._onAttaqueEchecTotal(r) },
{ condition: RdDResolutionTable.isEchec, action: r => this._onAttaqueEchec(r) }
{ condition: RdDCombat.isParticuliere, action: r => this._onAttaqueParticuliere(r) },
{ condition: r => (RdDCombat.isReussite(r) && !RdDCombat.isParticuliere(r)), action: r => this._onAttaqueNormale(r) },
{ condition: RdDCombat.isEchecTotal, action: r => this._onAttaqueEchecTotal(r) },
{ condition: RdDCombat.isEchec, action: r => this._onAttaqueEchec(r) }
]
});
dialog.render(true);
@ -113,16 +146,21 @@ export class RdDCombat {
let rollData = {
coupsNonMortels: false,
competence: competence,
surprise: this.attacker.getSurprise()
surprise: this.attacker.getSurprise(),
surpriseDefenseur: this.defender.getSurprise()
};
if (this.attacker.isCreature()) {
this._modifieRollDataCreature(rollData, competence);
}
else {
else if (arme) {
// Usual competence
rollData.arme = RdDItemArme.armeUneOuDeuxMains(arme, RdDItemCompetence.isArmeUneMain(competence));
}
else {
// sans armes: à mains nues
rollData.arme = RdDItemArme.mainsNues();
}
return rollData;
}
@ -139,6 +177,11 @@ export class RdDCombat {
dommagesReels: competence.data.dommages
}
};
// rollData.dmg = {
// dmgArme: competence.data.dommages,
// total: competence.data.dommages
// };
}
/* -------------------------------------------- */
@ -172,13 +215,12 @@ export class RdDCombat {
whisper: ChatMessage.getWhisperRecipients(this.attacker.name)
});
}
rollData.dmg = RdDCombat.calculBonusDegats(rollData, this.attacker);
rollData.dmg = RdDBonus.dmg(rollData, this.attacker.getBonusDegat(), this.defender.isEntiteCauchemar());
if (this.target) {
rollData.mortalite = this._calculMortaliteEncaissement(rollData);
explications += "<br><strong>Cible</strong> : " + this.defender.data.name;
}
explications += "<br>Encaissement à "+ Misc.toSignedString(rollData.dmg.total)+ " (" + rollData.dmg.loc.label+")";
explications += "<br>Encaissement à " + Misc.toSignedString(rollData.dmg.total) + " (" + rollData.dmg.loc.label + ")";
// Save rollData for defender
game.system.rdd.rollDataHandler[this.attackerId] = duplicate(rollData);
@ -202,14 +244,16 @@ export class RdDCombat {
let content = "<strong>" + this.defender.name + "</strong> doit se défendre :<span class='chat-card-button-area'>";
// parades
for (const arme of this._filterArmesParade(this.defender.data.items, rollData.competence.data.categorie)) {
content += "<br><a class='chat-card-button' id='parer-button' data-attackerId='" + this.attackerId + "' data-defenderTokenId='" + this.defenderTokenId + "' data-armeid='" + arme._id + "'>Parer avec " + arme.name + "</a>";
}
// esquive
if (rollData.competence.data.categorie == 'melee' || rollData.competence.data.categorie == "lancer" || rollData.competence.data.categorie == 'competencecreature') {
content += "<br><a class='chat-card-button' id='esquiver-button' data-attackerId='" + this.attackerId + "' data-defenderTokenId='" + this.defenderTokenId + "'>Esquiver</a>";
if (this.defender.getSurprise() != 'totale') {
// parades
for (const arme of this._filterArmesParade(this.defender.data.items, rollData.competence.data.categorie)) {
content += "<br><a class='chat-card-button' id='parer-button' data-attackerId='" + this.attackerId + "' data-defenderTokenId='" + this.defenderTokenId + "' data-armeid='" + arme._id + "'>Parer avec " + arme.name + "</a>";
}
// esquive
if (rollData.competence.data.categorie == 'melee' || rollData.competence.data.categorie == "lancer" || rollData.competence.data.categorie == 'competencecreature') {
content += "<br><a class='chat-card-button' id='esquiver-button' data-attackerId='" + this.attackerId + "' data-defenderTokenId='" + this.defenderTokenId + "'>Esquiver</a>";
}
}
// encaisser
@ -257,13 +301,6 @@ export class RdDCombat {
});
}
}
/* -------------------------------------------- */
_calculMortaliteEncaissement(rollData) {
const mortalite = this.defender.isEntiteCauchemar() ? "cauchemar" : (rollData.mortalite ? rollData.mortalite : "mortel");
console.log("Mortalité : ", mortalite, this.defender.data.type);
return mortalite;
}
_onAttaqueEchecTotal(rollData) {
console.log("RdDCombat.onEchecTotal >>>", rollData);
@ -306,10 +343,10 @@ export class RdDCombat {
label: 'Parade: ' + (arme ? arme.name : rollData.competence.name),
callbacks: [
this.defender.createCallbackExperience(),
{ condition: RdDResolutionTable.isParticuliere, action: r => this._onParadeParticuliere(r) },
{ condition: RdDResolutionTable.isReussite, action: r => this._onParadeNormale(r) },
{ condition: RdDResolutionTable.isEchecTotal, action: r => this._onParadeEchecTotal(r) },
{ condition: RdDResolutionTable.isEchec, action: r => this._onParadeEchec(r) }
{ condition: RdDCombat.isParticuliere, action: r => this._onParadeParticuliere(r) },
{ condition: RdDCombat.isReussite, action: r => this._onParadeNormale(r) },
{ condition: RdDCombat.isEchecTotal, action: r => this._onParadeEchecTotal(r) },
{ condition: RdDCombat.isEchec, action: r => this._onParadeEchec(r) }
]
});
dialog.render(true);
@ -334,6 +371,7 @@ export class RdDCombat {
competence: competence,
arme: arme.data,
surprise: this.defender.getSurprise(),
surpriseDefenseur: this.defender.getSurprise(),
needSignificative: this._needSignificative(attackerRoll) || RdDItemArme.needParadeSignificative(armeAttaque, armeParade),
needResist: this._needResist(armeAttaque, armeParade),
carac: this.defender.data.data.carac
@ -401,7 +439,7 @@ export class RdDCombat {
console.log("RdDCombat._onParadeEchec >>>", rollData);
let explications = "<br><strong>Parade échouée, encaissement !</strong> ";
explications += RdDCombat.descriptionSurprise(rollData.surprise);
explications += RdDBonus.description(rollData.surprise);
if (rollData.needSignificative) {
explications += " Significative nécessaire!";
}
@ -436,10 +474,10 @@ export class RdDCombat {
label: 'Esquiver',
callbacks: [
this.defender.createCallbackExperience(),
{ condition: RdDResolutionTable.isParticuliere, action: r => this._onEsquiveParticuliere(r) },
{ condition: RdDResolutionTable.isReussite, action: r => this._onEsquiveNormale(r) },
{ condition: RdDResolutionTable.isEchecTotal, action: r => this._onEsquiveEchecTotal(r) },
{ condition: RdDResolutionTable.isEchec, action: r => this._onEsquiveEchec(r) },
{ condition: RdDCombat.isParticuliere, action: r => this._onEsquiveParticuliere(r) },
{ condition: RdDCombat.isReussite, action: r => this._onEsquiveNormale(r) },
{ condition: RdDCombat.isEchecTotal, action: r => this._onEsquiveEchecTotal(r) },
{ condition: RdDCombat.isEchec, action: r => this._onEsquiveEchec(r) },
]
});
dialog.render(true);
@ -452,6 +490,7 @@ export class RdDCombat {
attackerRoll: attackerRoll,
competence: competence,
surprise: this.defender.getSurprise(),
surpriseDefenseur: this.defender.getSurprise(),
needSignificative: this._needSignificative(attackerRoll),
carac: this.defender.data.data.carac
};
@ -497,7 +536,7 @@ export class RdDCombat {
console.log("RdDCombat._onEsquiveEchec >>>", rollData);
let explications = "<br><strong>Esquive échouée, encaissement !</strong> ";
explications += RdDCombat.descriptionSurprise(rollData.surprise);
explications += RdDBonus.description(rollData.surprise);
if (rollData.needSignificative) {
explications += " Significative nécessaire!";
}
@ -567,65 +606,4 @@ export class RdDCombat {
return rolled.isSuccess;
}
/* -------------------------------------------- */
static calculBonusDegats(rollData, actor) {
let dmg = { total: 0, loc: RdDUtility.getLocalisation() };
if (rollData.arme.name.toLowerCase() == "esquive") {
// Specific case management
ui.notifications.warn("Calcul de bonus dégats sur eswquive")
return dmg;
}
dmg.dmgArme = RdDCombat._dmgArme(rollData);
dmg.ignoreArmure = 0; // TODO: calculer pour arcs et arbaletes, gérer pour lmes créatures
dmg.dmgTactique= RdDCombat._dmgTactique(rollData);
dmg.dmgParticuliere= RdDCombat._dmgParticuliere(rollData);
dmg.dmgSurprise= RdDCombat._dmgSurprise(rollData);
dmg.dmgActor = RdDCombat._dmgActor(actor.getBonusDegat(), rollData.selectedCarac.label, dmg.dmgArme);
dmg.total = dmg.dmgSurprise + dmg.dmgTactique + dmg.dmgArme + dmg.dmgActor + dmg.dmgParticuliere;
return dmg;
}
static _dmgArme(rollData) {
return parseInt(rollData.arme.data.dommages);
}
static _dmgActor(bonusDegat, categorie, dmgArme) {
switch (categorie) {
case "Tir": return 0;
case "Lancer": return Math.max(0, Math.min(dmgArme, bonusDegat));
}
return bonusDegat;
}
static _dmgTactique(rollData) {
return rollData.isCharge ? 2 : 0;
}
static _dmgParticuliere(rollData) {
return rollData.particuliereAttaque == 'force' ? 5 : 0;
}
static _dmgSurprise(rollData) {
if (rollData.surprise) {
switch (rollData.surprise) {
case 'demi': return 1;
case 'totale': return 10;
}
}
return 0;
}
/* -------------------------------------------- */
static descriptionSurprise(surprise) {
if (surprise) {
switch (surprise) {
case 'demi': return 'demi-surprise';
case 'totale': return 'surprise totale';
}
}
return '';
}
}