275 lines
9.4 KiB
JavaScript
275 lines
9.4 KiB
JavaScript
|
import { MAX_ENDURANCE_FATIGUE, RdDUtility } from "../rdd-utility.js";
|
||
|
import { ReglesOptionnelles } from "../settings/regles-optionnelles.js";
|
||
|
import { STATUSES } from "../settings/status-effects.js";
|
||
|
import { TYPES } from "../item.js";
|
||
|
import { RdDBaseActorReve } from "./base-actor-reve.js";
|
||
|
import { RdDDice } from "../rdd-dice.js";
|
||
|
import { RdDItemBlessure } from "../item/blessure.js";
|
||
|
|
||
|
/**
|
||
|
* Classe de base pour les acteurs qui peuvent subir des blessures
|
||
|
* - créatures
|
||
|
* - humanoides
|
||
|
*/
|
||
|
export class RdDBaseActorSang extends RdDBaseActorReve {
|
||
|
|
||
|
|
||
|
getForce() { return Number(this.system.carac.force?.value ?? 0) }
|
||
|
|
||
|
getBonusDegat() { return Number(this.system.attributs?.plusdom?.value ?? 0) }
|
||
|
getProtectionNaturelle() { return Number(this.system.attributs?.protection?.value ?? 0) }
|
||
|
getSConst() { return 0 }
|
||
|
|
||
|
getEnduranceMax() {
|
||
|
return Math.max(1, Math.min(this.system.sante.endurance.max, MAX_ENDURANCE_FATIGUE));
|
||
|
}
|
||
|
|
||
|
getFatigueActuelle() {
|
||
|
if (ReglesOptionnelles.isUsing("appliquer-fatigue")) {
|
||
|
return Math.max(0, Math.min(this.getFatigueMax(), this.system.sante.fatigue?.value));
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
getFatigueRestante() {
|
||
|
return this.getFatigueMax() - this.getFatigueActuelle();
|
||
|
}
|
||
|
|
||
|
getFatigueMin() {
|
||
|
return this.system.sante.endurance.max - this.system.sante.endurance.value;
|
||
|
}
|
||
|
|
||
|
getFatigueMax() { return this.getEnduranceMax() * 2 }
|
||
|
|
||
|
malusFatigue() {
|
||
|
if (ReglesOptionnelles.isUsing("appliquer-fatigue")) {
|
||
|
return RdDUtility.calculMalusFatigue(this.getFatigueActuelle(), this.getEnduranceMax())
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/* -------------------------------------------- */
|
||
|
getEncombrementMax() { return Number(this.system.attributs?.encombrement?.value ?? 0) }
|
||
|
isSurenc() { return this.computeMalusSurEncombrement() < 0 }
|
||
|
|
||
|
computeMalusSurEncombrement() {
|
||
|
return Math.min(0, Math.floor(this.getEncombrementMax() - this.encTotal));
|
||
|
}
|
||
|
|
||
|
isDead() {
|
||
|
return this.system.sante.vie.value < -this.getSConst()
|
||
|
}
|
||
|
|
||
|
/* -------------------------------------------- */
|
||
|
computeResumeBlessure() {
|
||
|
const blessures = this.filterItems(it => it.system.gravite > 0, 'blessure')
|
||
|
|
||
|
const nbLegeres = blessures.filter(it => it.isLegere()).length;
|
||
|
const nbGraves = blessures.filter(it => it.isGrave()).length;
|
||
|
const nbCritiques = blessures.filter(it => it.isCritique()).length;
|
||
|
|
||
|
if (nbLegeres + nbGraves + nbCritiques == 0) {
|
||
|
return "Aucune blessure";
|
||
|
}
|
||
|
let resume = "Blessures:";
|
||
|
if (nbLegeres > 0) {
|
||
|
resume += " " + nbLegeres + " légère" + (nbLegeres > 1 ? "s" : "");
|
||
|
}
|
||
|
if (nbGraves > 0) {
|
||
|
if (nbLegeres > 0)
|
||
|
resume += ",";
|
||
|
resume += " " + nbGraves + " grave" + (nbGraves > 1 ? "s" : "");
|
||
|
}
|
||
|
if (nbCritiques > 0) {
|
||
|
if (nbGraves > 0 || nbLegeres > 0)
|
||
|
resume += ",";
|
||
|
resume += " une CRITIQUE !";
|
||
|
}
|
||
|
return resume;
|
||
|
}
|
||
|
|
||
|
blessuresASoigner() { return [] }
|
||
|
getEtatGeneral(options = { ethylisme: false }) { return 0 }
|
||
|
|
||
|
async computeArmure(attackerRoll) { return this.getProtectionNaturelle() }
|
||
|
async remiseANeuf() { }
|
||
|
async appliquerAjoutExperience(rollData, hideChatMessage = 'show') { }
|
||
|
|
||
|
/* -------------------------------------------- */
|
||
|
|
||
|
async onAppliquerJetEncaissement(encaissement, attacker) {
|
||
|
const santeOrig = duplicate(this.system.sante);
|
||
|
const blessure = await this.ajouterBlessure(encaissement, attacker); // Will update the result table
|
||
|
const perteVie = await this.santeIncDec("vie", -encaissement.vie);
|
||
|
const perteEndurance = await this.santeIncDec("endurance", -encaissement.endurance, blessure?.isCritique());
|
||
|
|
||
|
mergeObject(encaissement, {
|
||
|
resteEndurance: perteEndurance.newValue,
|
||
|
sonne: perteEndurance.sonne,
|
||
|
jetEndurance: perteEndurance.jetEndurance,
|
||
|
endurance: perteEndurance.perte,
|
||
|
vie: santeOrig.vie.value - perteVie.newValue,
|
||
|
blessure: blessure
|
||
|
});
|
||
|
}
|
||
|
/* -------------------------------------------- */
|
||
|
async santeIncDec(name, inc, isCritique = false) {
|
||
|
if (name == 'fatigue' && !ReglesOptionnelles.isUsing("appliquer-fatigue")) {
|
||
|
return;
|
||
|
}
|
||
|
const sante = duplicate(this.system.sante)
|
||
|
let compteur = sante[name];
|
||
|
if (!compteur) {
|
||
|
return;
|
||
|
}
|
||
|
let result = {
|
||
|
sonne: false,
|
||
|
};
|
||
|
|
||
|
let minValue = name == "vie" ? -this.getSConst() - 1 : 0;
|
||
|
|
||
|
result.newValue = Math.max(minValue, Math.min(compteur.value + inc, compteur.max));
|
||
|
//console.log("New value ", inc, minValue, result.newValue);
|
||
|
let fatigue = 0;
|
||
|
if (name == "endurance") {
|
||
|
if (result.newValue == 0 && inc < 0 && !isCritique) { // perte endurance et endurance devient 0 (sauf critique) -> -1 vie
|
||
|
sante.vie.value--;
|
||
|
result.perteVie = true;
|
||
|
}
|
||
|
result.newValue = Math.max(0, result.newValue);
|
||
|
if (inc > 0) { // le max d'endurance s'applique seulement à la récupération
|
||
|
result.newValue = Math.min(result.newValue, this._computeEnduranceMax())
|
||
|
}
|
||
|
const perte = compteur.value - result.newValue;
|
||
|
result.perte = perte;
|
||
|
if (perte > 1) {
|
||
|
// Peut-être sonné si 2 points d'endurance perdus d'un coup
|
||
|
mergeObject(result, await this.jetEndurance(result.newValue));
|
||
|
} else if (inc > 0) {
|
||
|
await this.setSonne(false);
|
||
|
}
|
||
|
if (sante.fatigue && inc < 0) { // Each endurance lost -> fatigue lost
|
||
|
fatigue = perte;
|
||
|
}
|
||
|
}
|
||
|
compteur.value = result.newValue;
|
||
|
// If endurance lost, then the same amount of fatigue cannot be recovered
|
||
|
if (ReglesOptionnelles.isUsing("appliquer-fatigue") && sante.fatigue && fatigue > 0) {
|
||
|
sante.fatigue.value = Math.max(sante.fatigue.value + fatigue, this.getFatigueMin());
|
||
|
}
|
||
|
await this.update({ "system.sante": sante })
|
||
|
if (this.isDead()) {
|
||
|
await this.setEffect(STATUSES.StatusComma, true);
|
||
|
}
|
||
|
return result
|
||
|
}
|
||
|
|
||
|
/* -------------------------------------------- */
|
||
|
|
||
|
/* -------------------------------------------- */
|
||
|
async ajouterBlessure(encaissement, attacker = undefined) {
|
||
|
if (encaissement.gravite < 0) return;
|
||
|
if (encaissement.gravite > 0) {
|
||
|
while (this.countBlessures(it => it.system.gravite == encaissement.gravite) >= RdDItemBlessure.maxBlessures(encaissement.gravite) && encaissement.gravite <= 6) {
|
||
|
// Aggravation
|
||
|
encaissement.gravite += 2
|
||
|
if (encaissement.gravite > 2) {
|
||
|
encaissement.vie += 2;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
const endActuelle = this.getEnduranceActuelle();
|
||
|
const blessure = await RdDItemBlessure.createBlessure(this, encaissement.gravite, encaissement.dmg.loc.label, attacker);
|
||
|
if (blessure.isCritique()) {
|
||
|
encaissement.endurance = endActuelle;
|
||
|
}
|
||
|
|
||
|
if (blessure.isMort()) {
|
||
|
this.setEffect(STATUSES.StatusComma, true);
|
||
|
encaissement.mort = true;
|
||
|
ChatMessage.create({
|
||
|
content: `<img class="chat-icon" src="icons/svg/skull.svg" alt="charge" />
|
||
|
<strong>${this.name} vient de succomber à une seconde blessure critique ! Que les Dragons gardent son Archétype en paix !</strong>`
|
||
|
});
|
||
|
}
|
||
|
return blessure;
|
||
|
}
|
||
|
|
||
|
async supprimerBlessures(filterToDelete) {
|
||
|
const toDelete = this.filterItems(filterToDelete, TYPES.blessure)
|
||
|
.map(it => it.id);
|
||
|
await this.deleteEmbeddedDocuments('Item', toDelete);
|
||
|
}
|
||
|
|
||
|
countBlessures(filter = it => !it.isContusion()) {
|
||
|
return this.filterItems(filter, 'blessure').length
|
||
|
}
|
||
|
|
||
|
/* -------------------------------------------- */
|
||
|
async jetVie() {
|
||
|
let roll = await RdDDice.roll("1d20");
|
||
|
let msgText = "Jet de Vie : " + roll.total + " / " + this.system.sante.vie.value + "<br>";
|
||
|
if (roll.total <= this.system.sante.vie.value) {
|
||
|
msgText += "Jet réussi, pas de perte de point de vie (prochain jet dans 1 round pour 1 critique, SC minutes pour une grave)";
|
||
|
if (roll.total == 1) {
|
||
|
msgText += "La durée entre 2 jets de vie est multipliée par 20 (20 rounds pour une critique, SCx20 minutes pour une grave)";
|
||
|
}
|
||
|
} else {
|
||
|
msgText += "Jet échoué, vous perdez 1 point de vie";
|
||
|
await this.santeIncDec("vie", -1);
|
||
|
if (roll.total == 20) {
|
||
|
msgText += "Votre personnage est mort !!!!!";
|
||
|
}
|
||
|
}
|
||
|
const message = {
|
||
|
content: msgText,
|
||
|
whisper: ChatMessage.getWhisperRecipients(this.name)
|
||
|
};
|
||
|
ChatMessage.create(message);
|
||
|
}
|
||
|
|
||
|
/* -------------------------------------------- */
|
||
|
async jetEndurance(resteEndurance = undefined) {
|
||
|
const jetEndurance = (await RdDDice.roll("1d20")).total;
|
||
|
const sonne = jetEndurance == 20 || jetEndurance > (resteEndurance ?? this.system.sante.endurance.value)
|
||
|
if (sonne) {
|
||
|
await this.setSonne();
|
||
|
}
|
||
|
return { jetEndurance, sonne }
|
||
|
}
|
||
|
|
||
|
|
||
|
async finDeRoundBlessures() {
|
||
|
const nbGraves = this.filterItems(it => it.isGrave(), 'blessure').length;
|
||
|
if (nbGraves > 0) {
|
||
|
// Gestion blessure graves : -1 pt endurance par blessure grave
|
||
|
await this.santeIncDec("endurance", -nbGraves);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
async setSonne(sonne = true) {
|
||
|
if (!game.combat && sonne) {
|
||
|
ui.notifications.info(`${this.name} est hors combat, il ne reste donc pas sonné`);
|
||
|
return;
|
||
|
}
|
||
|
await this.setEffect(STATUSES.StatusStunned, sonne);
|
||
|
}
|
||
|
|
||
|
getSonne() {
|
||
|
return this.getEffect(STATUSES.StatusStunned);
|
||
|
}
|
||
|
|
||
|
/* -------------------------------------------- */
|
||
|
async computeEtatGeneral() {
|
||
|
this.system.compteurs.etat.value = this.malusVie() + this.malusFatigue() + this.malusEthylisme();
|
||
|
}
|
||
|
|
||
|
malusVie() {
|
||
|
return Math.min(this.system.sante.vie.value - this.system.sante.vie.max, 0);
|
||
|
}
|
||
|
|
||
|
malusEthylisme() { return 0 }
|
||
|
|
||
|
|
||
|
}
|