forked from public/foundryvtt-reve-de-dragon
Expérience des caractéristiques dérivées
Une fenêtre de répartition est ouverte quand plusieurs caractéristiques peuvent recevoir l'expérience. Sinon, l'expérience est attribuée automatiquement. L'expérience n'est plus ajoutée en Force si supérieure à Taille+4
This commit is contained in:
120
module/actor.js
120
module/actor.js
@ -35,6 +35,7 @@ import { ExperienceLog, XP_TOPIC } from "./actor/experience-log.js";
|
||||
import { 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";
|
||||
|
||||
export const MAINS_DIRECTRICES = ['Droitier', 'Gaucher', 'Ambidextre']
|
||||
|
||||
@ -56,21 +57,20 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
$computeCaracDerivee() {
|
||||
|
||||
this.system.carac.force.value = Math.min(this.system.carac.force.value, parseInt(this.system.carac.taille.value) + 4);
|
||||
|
||||
this.system.carac.derobee.value = Math.floor(parseInt(((21 - this.system.carac.taille.value)) + parseInt(this.system.carac.agilite.value)) / 2);
|
||||
let bonusDomKey = Math.floor((parseInt(this.system.carac.force.value) + parseInt(this.system.carac.taille.value)) / 2);
|
||||
let tailleData = RdDCarac.getCaracDerivee(bonusDomKey);
|
||||
this.system.attributs.plusdom.value = tailleData.plusdom;
|
||||
|
||||
this.system.attributs.sconst.value = RdDCarac.calculSConst(this.system.carac.constitution.value);
|
||||
this.system.attributs.sust.value = RdDCarac.getCaracDerivee(this.system.carac.taille.value).sust;
|
||||
|
||||
this.system.attributs.encombrement.value = (parseInt(this.system.carac.force.value) + parseInt(this.system.carac.taille.value)) / 2;
|
||||
this.system.carac.melee.value = Math.floor((parseInt(this.system.carac.force.value) + parseInt(this.system.carac.agilite.value)) / 2);
|
||||
this.system.carac.tir.value = Math.floor((parseInt(this.system.carac.vue.value) + parseInt(this.system.carac.dexterite.value)) / 2);
|
||||
this.system.carac.lancer.value = Math.floor((parseInt(this.system.carac.tir.value) + parseInt(this.system.carac.force.value)) / 2);
|
||||
this.system.carac.derobee.value = Math.floor(parseInt(((21 - this.system.carac.taille.value)) + parseInt(this.system.carac.agilite.value)) / 2);
|
||||
|
||||
let bonusDomKey = Math.floor((parseInt(this.system.carac.force.value) + parseInt(this.system.carac.taille.value)) / 2);
|
||||
let tailleData = RdDCarac.getCaracDerivee(bonusDomKey);
|
||||
this.system.attributs.plusdom.value = tailleData.plusdom;
|
||||
this.system.attributs.encombrement.value = (parseInt(this.system.carac.force.value) + parseInt(this.system.carac.taille.value)) / 2;
|
||||
|
||||
this.system.attributs.sconst.value = RdDCarac.calculSConst(this.system.carac.constitution.value);
|
||||
this.system.attributs.sust.value = RdDCarac.getCaracDerivee(this.system.carac.taille.value).sust;
|
||||
this.system.sante.vie.max = Math.ceil((parseInt(this.system.carac.taille.value) + parseInt(this.system.carac.constitution.value)) / 2);
|
||||
|
||||
this.system.sante.vie.value = Math.min(this.system.sante.vie.value, this.system.sante.vie.max)
|
||||
@ -659,7 +659,7 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
this.setPointsDeChance(to);
|
||||
}
|
||||
}
|
||||
let selectedCarac = RdDBaseActor._findCaracByName(this.system.carac, caracName);
|
||||
let selectedCarac = this.findCaracByName(caracName);
|
||||
const from = selectedCarac.value
|
||||
await this.update({ [`system.carac.${caracName}.value`]: to });
|
||||
await ExperienceLog.add(this, XP_TOPIC.CARAC, from, to, caracName);
|
||||
@ -670,7 +670,7 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
if (caracName == 'Taille') {
|
||||
return;
|
||||
}
|
||||
let selectedCarac = RdDBaseActor._findCaracByName(this.system.carac, caracName);
|
||||
let selectedCarac = this.findCaracByName(caracName);
|
||||
if (!selectedCarac.derivee) {
|
||||
const from = Number(selectedCarac.xp);
|
||||
await this.update({ [`system.carac.${caracName}.xp`]: to });
|
||||
@ -684,7 +684,7 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
if (caracName == 'Taille') {
|
||||
return;
|
||||
}
|
||||
let carac = RdDBaseActor._findCaracByName(this.system.carac, caracName);
|
||||
let carac = this.findCaracByName(caracName);
|
||||
if (carac) {
|
||||
carac = duplicate(carac);
|
||||
const fromXp = Number(carac.xp);
|
||||
@ -1472,8 +1472,14 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
isCaracMax(code) {
|
||||
if (code == 'force' && parseInt(this.system.carac.force.value) >= parseInt(this.system.carac.taille.value) + 4) {
|
||||
return true;
|
||||
}
|
||||
return false
|
||||
}
|
||||
async checkCaracXP(caracName, display = true) {
|
||||
let carac = RdDBaseActor._findCaracByName(this.system.carac, caracName);
|
||||
let carac = this.findCaracByName(caracName);
|
||||
if (carac && carac.xp > 0) {
|
||||
const niveauSuivant = Number(carac.value) + 1;
|
||||
let xpNeeded = RdDCarac.getCaracNextXp(niveauSuivant);
|
||||
@ -1534,8 +1540,11 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
async appliquerAjoutExperience(rollData, hideChatMessage = 'show') {
|
||||
hideChatMessage = hideChatMessage == 'hide' || (Misc.isRollModeHiddenToPlayer() && !game.user.isGM)
|
||||
let xpData = await this._appliquerExperience(rollData.rolled, rollData.selectedCarac.label, rollData.competence, rollData.jetResistance);
|
||||
if (xpData) {
|
||||
const content = await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-actor-gain-xp.html`, xpData);
|
||||
if (xpData.length) {
|
||||
const content = await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-actor-gain-xp.html`, {
|
||||
actor: this,
|
||||
xpData
|
||||
});
|
||||
if (hideChatMessage) {
|
||||
ChatUtility.blindMessageToGM({ content: content });
|
||||
}
|
||||
@ -1698,7 +1707,7 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
if (rollData.competence.name.includes('Thanatos')) { // Si Thanatos
|
||||
await this.update({ "system.reve.reve.thanatosused": true });
|
||||
}
|
||||
let reveActuel = this.system.reve.reve.value;
|
||||
let reveActuel = parseInt(this.system.reve.reve.value)
|
||||
if (rolled.isSuccess) { // Réussite du sort !
|
||||
if (rolled.isPart) {
|
||||
rollData.depenseReve = Math.max(Math.floor(rollData.depenseReve / 2), 1);
|
||||
@ -2265,9 +2274,7 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
});
|
||||
return undefined;
|
||||
}
|
||||
if (caracName == 'Vie') caracName = 'constitution';
|
||||
if (caracName == 'derobee') caracName = 'agilite';
|
||||
if (caracName == 'reve-actuel') caracName = 'reve';
|
||||
|
||||
let xp = Math.abs(rolled.finalLevel);
|
||||
// impair: arrondi inférieur en carac
|
||||
let xpCarac = competence ? Math.floor(xp / 2) : Math.max(Math.floor(xp / 2), 1);
|
||||
@ -2280,11 +2287,10 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
// max 1 xp sur jets de résistance
|
||||
xpCarac = Math.min(1, xpCarac);
|
||||
}
|
||||
let xpData = { alias: this.name, caracName, xpCarac, competence, xpCompetence };
|
||||
|
||||
await this._xpCompetence(xpData);
|
||||
await this._xpCarac(xpData);
|
||||
return xpData;
|
||||
return [
|
||||
...(await this._xpCompetence({ competence, xpCompetence })),
|
||||
...(await this._xpCarac({ caracName, xpCarac }))
|
||||
];
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
@ -2292,31 +2298,67 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
if (xpData.competence) {
|
||||
const from = Number(xpData.competence.system.xp);
|
||||
const to = from + xpData.xpCompetence;
|
||||
let update = { _id: xpData.competence._id, 'system.xp': to };
|
||||
await this.updateEmbeddedDocuments('Item', [update]);
|
||||
await this.updateEmbeddedDocuments('Item', [{ _id: xpData.competence._id, 'system.xp': to }]);
|
||||
xpData.checkComp = await this.checkCompetenceXP(xpData.competence.name, undefined, false);
|
||||
await ExperienceLog.add(this, XP_TOPIC.XP, from, to, xpData.competence.name);
|
||||
return [xpData]
|
||||
}
|
||||
return []
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async _xpCarac(xpData) {
|
||||
if (xpData.xpCarac > 0) {
|
||||
let carac = duplicate(this.system.carac);
|
||||
let selectedCarac = RdDBaseActor._findCaracByName(carac, xpData.caracName);
|
||||
if (!selectedCarac.derivee) {
|
||||
const from = Number(selectedCarac.xp);
|
||||
const to = from + xpData.xpCarac;
|
||||
selectedCarac.xp = to;
|
||||
await this.update({ "system.carac": carac });
|
||||
xpData.checkCarac = await this.checkCaracXP(selectedCarac.label, false);
|
||||
await ExperienceLog.add(this, XP_TOPIC.XPCARAC, from, to, xpData.caracName);
|
||||
const carac = duplicate(this.system.carac)
|
||||
const code = RdDBaseActor._findCaracNode(carac, xpData.caracName)
|
||||
const selectedCarac = carac[code]
|
||||
if (this.isCaracMax(code)) {
|
||||
ui.notifications.info(`Pas d'expérience: la caractéristique '${selectedCarac.label}' est déjà au maximum pour ${this.name}`)
|
||||
return []
|
||||
}
|
||||
if (selectedCarac && !selectedCarac.derivee) {
|
||||
const from = Number(selectedCarac.xp)
|
||||
const to = from + xpData.xpCarac
|
||||
selectedCarac.xp = to
|
||||
await this.update({ "system.carac": carac })
|
||||
xpData.checkCarac = await this.checkCaracXP(selectedCarac.label, false)
|
||||
await ExperienceLog.add(this, XP_TOPIC.XPCARAC, from, to, xpData.caracName)
|
||||
return [xpData]
|
||||
} else {
|
||||
xpData.caracRepartitionManuelle = true;
|
||||
return await this._xpCaracDerivee(xpData)
|
||||
}
|
||||
}
|
||||
return []
|
||||
}
|
||||
|
||||
async _xpCaracDerivee(xpData) {
|
||||
const caracs = RdDActor._getComposantsCaracDerivee(xpData.caracName)
|
||||
.map(c => mergeObject(this.system.carac[c], { isMax: this.isCaracMax(c) }))
|
||||
switch (caracs.filter(it => !it.isMax).length) {
|
||||
case 0:
|
||||
xpData.caracRepartitionManuelle = true;
|
||||
return [xpData]
|
||||
case 1:
|
||||
xpData.caracName = caracs.find(it => !it.isMax).label
|
||||
return this._xpCarac(xpData)
|
||||
default:
|
||||
await DialogChoixXpCarac.choix(this, xpData, caracs)
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
static _getComposantsCaracDerivee(caracName) {
|
||||
switch (Grammar.toLowerCaseNoAccent(caracName)) {
|
||||
case 'vie': return ['constitution']
|
||||
case 'tir': return ['vue', 'dexterite']
|
||||
case 'lancer': return ['force', 'dexterite', 'vue']
|
||||
case 'melee': return ['force', 'agilite']
|
||||
case 'derobee': return ['agilite']
|
||||
}
|
||||
return []
|
||||
}
|
||||
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async resetNombresAstraux() {
|
||||
const deletions = this.itemTypes['nombreastral'].map(it => it._id);
|
||||
@ -2418,7 +2460,7 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
draconic: this.getDraconicList(),
|
||||
sort: this.itemTypes['sort'],
|
||||
signes: this.itemTypes['signedraconique'],
|
||||
caracReve: this.system.carac.reve.value,
|
||||
caracReve: parseInt(this.system.carac.reve.value),
|
||||
pointsReve: this.getReveActuel(),
|
||||
isRapide: isRapide,
|
||||
isGM: game.user.isGM,
|
||||
@ -2509,7 +2551,7 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
verifierForceMin(item) {
|
||||
if (item.type == 'arme' && item.system.force > this.system.carac.force.value) {
|
||||
if (item.type == 'arme' && item.system.force > parseInt(this.system.carac.force.value)) {
|
||||
ChatMessage.create({
|
||||
content: `<strong>${this.name} s'est équipé(e) de l'arme ${item.name}, mais n'a pas une force suffisante pour l'utiliser normalement </strong>
|
||||
(${item.system.force} nécessaire pour une Force de ${this.system.carac.force.value})`
|
||||
|
Reference in New Issue
Block a user