From 755d15509e7b4ecfd214876547dd04e0d12df3f8 Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Thu, 23 Oct 2025 18:09:12 +0200 Subject: [PATCH] =?UTF-8?q?Ajout=20du=20StatusEffect=20surencombr=C3=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- assets/actions/surenc.svg | 65 ++++++++++++++++++++++ changelog.md | 1 + lang/fr.json | 5 +- module/actor-sheet.js | 8 --- module/actor.js | 20 +++---- module/actor/base-actor-reve-sheet.js | 10 ++-- module/actor/base-actor-reve.js | 45 +--------------- module/actor/base-actor-sang.js | 4 +- module/actor/base-actor-sheet.js | 10 +--- module/actor/base-actor.js | 77 +++++++++++++++++++++++---- module/actor/experience-log.js | 2 +- module/constants.js | 1 + module/item-sheet.js | 5 +- module/roll/roll-part-enctotal.mjs | 3 +- module/roll/roll-part-surenc.mjs | 3 +- module/settings/status-effects.js | 12 +++-- templates/actor/carac-main.hbs | 4 +- 17 files changed, 175 insertions(+), 100 deletions(-) create mode 100644 assets/actions/surenc.svg diff --git a/assets/actions/surenc.svg b/assets/actions/surenc.svg new file mode 100644 index 00000000..c9e8313a --- /dev/null +++ b/assets/actions/surenc.svg @@ -0,0 +1,65 @@ + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/changelog.md b/changelog.md index 4045f266..82f528ed 100644 --- a/changelog.md +++ b/changelog.md @@ -3,6 +3,7 @@ - Les réussites particulières en demi-surprise sont de simples réussites - Les images des scènes par défaut sont corrigées +- Ajout d'une image de status "sur-encombré" - Amélioration des entités: - l'attaquant ne sait plus que c'est une entité de cauchemar (surprise!) - l'encaissement indique une blessure dans le tchat... même si ce n'est que de l'endurance diff --git a/lang/fr.json b/lang/fr.json index 26e9a883..e44d03db 100644 --- a/lang/fr.json +++ b/lang/fr.json @@ -1,6 +1,6 @@ { "TYPES": { - "Actor": { + "Actor": { "personnage": "Personnage", "creature": "Créature", "entite": "Entité de cauchemar", @@ -67,6 +67,7 @@ "StatusComma": "Comma", "StatusDead": "Mort", "StatusDemiReve": "Demi-rêve", + "StatusSurEnc": "Sur-encombrement", "StatusForceWeak": "Force insuffisante" } -} \ No newline at end of file +} diff --git a/module/actor-sheet.js b/module/actor-sheet.js index 6fdbdc07..80d79326 100644 --- a/module/actor-sheet.js +++ b/module/actor-sheet.js @@ -375,14 +375,6 @@ export class RdDActorSheet extends RdDBaseActorSangSheet { return position; } - - /* -------------------------------------------- */ - /** @override */ - _updateObject(event, formData) { - // Update the Actor - return this.actor.update(formData); - } - async splitItem(item) { const dialog = await DialogSplitItem.create(item, (item, split) => this._onSplitItem(item, split)); dialog.render(true); diff --git a/module/actor.js b/module/actor.js index 98b67afd..97b6e228 100644 --- a/module/actor.js +++ b/module/actor.js @@ -228,7 +228,7 @@ export class RdDActor extends RdDBaseActorSang { if (arme.system.lancer && arme.system.resistance > 0) { addAttaque(arme, ATTAQUE_TYPE.LANCER) } if (arme.system.tir) { addAttaque(arme, ATTAQUE_TYPE.TIR) } }) - addAttaque(RdDItemArme.pugilat(this), ATTAQUE_TYPE.CORPS_A_CORPS) + addAttaque(RdDItemArme.pugilat(this), ATTAQUE_TYPE.CORPS_A_CORPS) return actions } @@ -755,20 +755,18 @@ export class RdDActor extends RdDBaseActorSang { let updates = {}; if (caracName == LIST_CARAC_PERSONNAGE.reve.code) { if (to > Misc.toInt(this.system.reve.seuil.value)) { - updates[`system.reve.seuil.value`] = to; // SFA : Direct and packed changes - //this.setPointsDeSeuil(to); + updates[`system.reve.seuil.value`] = to } } if (caracName == LIST_CARAC_PERSONNAGE.chance.code) { if (to > Misc.toInt(this.system.compteurs.chance.value)) { - updates[`system.compteurs.chance.value`] = to; // SFA : Direct and packed changes - //this.setPointsDeChance(to); + updates[`system.compteurs.chance.value`] = to } } let selectedCarac = this.findCaracByName(caracName); const from = selectedCarac.value updates[`system.carac.${caracName}.value`] = to; - await this.update(updates); + await this.update(updates, { noHook: true }); await ExperienceLog.add(this, XP_TOPIC.CARAC, from, to, caracName); } @@ -1753,7 +1751,7 @@ export class RdDActor extends RdDBaseActorSang { this.tmrApp?.close(); this.tmrApp = undefined; } - } ], + }], onRollDone: RollDialog.onRollDoneClose, onClose: () => { this.tmrApp?.restoreTMRAfterAction(); @@ -2607,7 +2605,7 @@ export class RdDActor extends RdDBaseActorSang { if (item?.isEquipable()) { const isEquipe = !item.system.equipe; await item.update({ "system.equipe": isEquipe }); - this.computeEncTotal(); + this.computeEncTotal() if (isEquipe) this.verifierForceMin(item); } @@ -2998,6 +2996,7 @@ export class RdDActor extends RdDBaseActorSang { if (updatedEndurance && options.diff) { await this.setEffect(STATUSES.StatusUnconscious, updatedEndurance.value == 0) } + await super.onUpdateActor(update, options, actorId) } /* -------------------------------------------- */ @@ -3039,12 +3038,13 @@ export class RdDActor extends RdDBaseActorSang { await this.onDeleteOwnedCaseTmr(item, options, id) break case ITEM_TYPES.empoignade: + await RdDEmpoignade.deleteLinkedEmpoignade(this.id, item) + // TODO: check remaining emp. await this.setEffect(STATUSES.StatusGrappled, false) await this.setEffect(STATUSES.StatusGrappling, false) - await RdDEmpoignade.deleteLinkedEmpoignade(this.id, item) break } - super.onDeleteItem(item, options, id) + await super.onDeleteItem(item, options, id) } /* -------------------------------------------- */ diff --git a/module/actor/base-actor-reve-sheet.js b/module/actor/base-actor-reve-sheet.js index 9003a3e2..bdccb641 100644 --- a/module/actor/base-actor-reve-sheet.js +++ b/module/actor/base-actor-reve-sheet.js @@ -56,13 +56,15 @@ export class RdDBaseActorReveSheet extends RdDBaseActorSheet { if (this.options.vueDetaillee) { // On carac change this.html.find('.carac-value').change(async event => { - let caracName = event.currentTarget.name.replace(".value", "").replace("system.carac.", "") - await this.actor.updateCarac(caracName, parseInt(event.target.value)) - }); + if (event.currentTarget.name.includes("carac.")) { + let caracName = event.currentTarget.name.replace("carac.", "") + await this.actor.updateCarac(caracName, parseInt(event.currentTarget.value)) + } + }) // On competence change this.html.find('.competence-value').change(async event => { let compName = event.currentTarget.attributes.compname.value - await this.actor.updateCompetence(compName, parseInt(event.target.value)) + await this.actor.updateCompetence(compName, parseInt(event.currentTarget.value)) }); } } diff --git a/module/actor/base-actor-reve.js b/module/actor/base-actor-reve.js index 92a60e9d..6f3da2ab 100644 --- a/module/actor/base-actor-reve.js +++ b/module/actor/base-actor-reve.js @@ -89,7 +89,6 @@ export class RdDBaseActorReve extends RdDBaseActor { getSConst() { return 0 } /* -------------------------------------------- */ - isSurenc() { return false } computeMalusSurEncombrement() { return 0 } ajustementAstrologique() { return 0 } @@ -126,7 +125,7 @@ export class RdDBaseActorReve extends RdDBaseActor { async remiseANeuf() { } async appliquerAjoutExperience(rollData, hideChatMessage = 'show') { } - computeResumeBlessure() {} + computeResumeBlessure() { } countBlessures(filter = it => !it.isContusion()) { return 0 } async santeIncDec(name, inc, isCritique = false) { } @@ -230,49 +229,9 @@ export class RdDBaseActorReve extends RdDBaseActor { } } - /* -------------------------------------------- */ - isEffectAllowed(effectId) { return false } - - getEffects(filter = e => true, forceRequise = undefined) { - const effects = this.getEmbeddedCollection("ActiveEffect") - const selected = effects.filter(filter) - if (forceRequise && this.isForceInsuffisante(forceRequise)) { - selected.push(StatusEffects.prepareActiveEffect(STATUSES.StatusForceWeak)) - } - return selected - } - - getEffectByStatus(statusId) { - return this.getEffects().find(it => it.statuses.has(statusId)); - } - - async setEffect(statusId, status) { - if (this.isEffectAllowed(statusId)) { - const effect = this.getEffectByStatus(statusId) - if (!status && effect) { - await this.deleteEmbeddedDocuments('ActiveEffect', [effect.id], { render: true }) - } - if (status && !effect) { - await this.createEmbeddedDocuments("ActiveEffect", [StatusEffects.prepareActiveEffect(statusId)], { render: true }) - } - } - } - - async removeEffect(id) { - this.removeEffects(it => it.id == id) - } - - async removeEffects(filter = e => true) { - if (game.user.isGM) { - const effectsToRemove = this.getEffects(filter); - const ids = effectsToRemove.map(it => it.id); - await this.deleteEmbeddedDocuments('ActiveEffect', ids); - } - } - /* -------------------------------------------- */ isDemiReve() { - return this.getEffectByStatus(STATUSES.StatusDemiReve) != undefined + return this.getEffectsByStatus(STATUSES.StatusDemiReve).length > 0 } getSurprise(isCombat = undefined, forceRequise = undefined) { diff --git a/module/actor/base-actor-sang.js b/module/actor/base-actor-sang.js index 59bdcbb5..69dda7e2 100644 --- a/module/actor/base-actor-sang.js +++ b/module/actor/base-actor-sang.js @@ -186,6 +186,7 @@ export class RdDBaseActorSang extends RdDBaseActorReve { await this.changeBleedingState() break } + await super.onCreateItem(item, options, id) } async onUpdateItem(item, options, id) { @@ -194,6 +195,7 @@ export class RdDBaseActorSang extends RdDBaseActorReve { await this.changeBleedingState() break } + await super.onUpdateItem(item, options, id) } async changeBleedingState() { @@ -313,7 +315,7 @@ export class RdDBaseActorSang extends RdDBaseActorReve { } isSonne() { - return this.getEffectByStatus(STATUSES.StatusStunned) + return this.getEffectsByStatus(STATUSES.StatusStunned).length > 0 } isEffectAllowed(effectId) { return true } diff --git a/module/actor/base-actor-sheet.js b/module/actor/base-actor-sheet.js index 8be9575a..18530449 100644 --- a/module/actor/base-actor-sheet.js +++ b/module/actor/base-actor-sheet.js @@ -49,7 +49,7 @@ export class RdDBaseActorSheet extends foundry.appv1.sheets.ActorSheet { formData.calc = { fortune: Monnaie.toSolsDeniers(this.actor.getFortune()), prixTotalEquipement: this.actor.computePrixTotalEquipement(), - encTotal: await this.actor.computeEncTotal(), + encTotal: this.actor.getEncTotal(), } this.objetVersConteneur = RdDUtility.buildArbreDeConteneurs(formData.conteneurs, formData.inventaires); @@ -229,14 +229,6 @@ export class RdDBaseActorSheet extends foundry.appv1.sheets.ActorSheet { return position; } - - /* -------------------------------------------- */ - /** @override */ - _updateObject(event, formData) { - // Update the Actor - return this.actor.update(formData); - } - async splitItem(item) { const dialog = await DialogSplitItem.create(item, (item, split) => this._onSplitItem(item, split)); dialog.render(true); diff --git a/module/actor/base-actor.js b/module/actor/base-actor.js index 8c0c9b2a..37c49a23 100644 --- a/module/actor/base-actor.js +++ b/module/actor/base-actor.js @@ -10,7 +10,7 @@ import { RdDConfirm } from "../rdd-confirm.js"; import { RdDUtility } from "../rdd-utility.js"; import { SystemCompendiums } from "../settings/system-compendiums.js"; import { RdDItem } from "../item.js"; -import { STATUSES } from "../settings/status-effects.js"; +import { StatusEffects, STATUSES } from "../settings/status-effects.js"; export class RdDBaseActor extends Actor { @@ -243,18 +243,68 @@ export class RdDBaseActor extends Actor { getMonnaie(id) { return this.findItemLike(id, 'monnaie'); } getEncombrementMax() { return 0 } + isSurenc() { return false } + + /* -------------------------------------------- */ + isEffectAllowed(effectId) { return false } + + getEffects(filter = e => true, forceRequise = undefined) { + const effects = this.getEmbeddedCollection("ActiveEffect") + const selected = effects.filter(filter) + if (forceRequise && this.isForceInsuffisante(forceRequise)) { + selected.push(StatusEffects.prepareActiveEffect(STATUSES.StatusForceWeak)) + } + return selected + } + + getEffectsByStatus(effectId) { + return this.getEffects().filter(it => it.statuses.has(effectId)) + } + + async setEffect(effectId, status) { + if (this.isEffectAllowed(effectId)) { + const effects = this.getEffectsByStatus(effectId) + if (!status && effects.length > 0) { + await this.deleteEmbeddedDocuments('ActiveEffect', effects.map(it => it.id), { render: true }) + } + if (status && effects.length == 0) { + await this.createEmbeddedDocuments("ActiveEffect", [StatusEffects.prepareActiveEffect(effectId)], { render: true }) + } + } + } + + async removeEffect(id) { + this.removeEffects(it => it.id == id) + } + + async removeEffects(filter = e => true) { + if (game.user.isGM) { + const effectsToRemove = this.getEffects(filter); + const ids = effectsToRemove.map(it => it.id); + await this.deleteEmbeddedDocuments('ActiveEffect', ids); + } + } /* -------------------------------------------- */ async updateCarac(caracName, to) { } + + async onUpdateActor(change, options, actorId) { + const updatedCarac = change?.system?.carac + if (updatedCarac && (updatedCarac.force || updatedCarac.reve || updatedCarac.taille)) { + console.log(' onUpdateActor', change, options, actorId) + await this.setEffect(STATUSES.StatusSurEnc, this.isSurenc()) + } + } + /* -------------------------------------------- */ async onPreUpdateItem(item, change, options, id) { } - async onCreateItem(item, options, id) { } + async onCreateItem(item, options, id) { + } - async onUpdateItem(item, options, id) { } - - async onUpdateActor(update, options, actorId) { } + async onUpdateItem(item, options, id) { + } async onDeleteItem(item, options, id) { if (item.isInventaire()) { @@ -262,6 +312,7 @@ export class RdDBaseActor extends Actor { } } + async _removeItemFromConteneur(item) { const updates = this.items.filter(it => it.isConteneur() && it.system.contenu.includes(item.id)) .map(conteneur => { @@ -510,16 +561,22 @@ export class RdDBaseActor extends Actor { /* -------------------------------------------- */ async computeEncTotal() { - if (!this.pack) { + if (this.pack) { + this.encTotal = 0 + } + else { + const wasSurenc = this.isSurenc() this.encTotal = this.items.filter(it => RdDItem.getItemTypesInventaire().includes(it.type)) .map(it => it.getEncTotal()).reduce(Misc.sum(), 0) - return this.encTotal; + const isSurenc = this.isSurenc() + if (isSurenc != wasSurenc) { + await this.setEffect(STATUSES.StatusSurEnc, isSurenc) + } } - return 0; } getEncTotal() { - return Math.floor(this.encTotal ?? 0); + return Math.floor(this.encTotal ?? 0) } async createItem(type, name = undefined) { @@ -570,7 +627,7 @@ export class RdDBaseActor extends Actor { } } } - await this.computeEncTotal(); + await this.computeEncTotal() return result; } diff --git a/module/actor/experience-log.js b/module/actor/experience-log.js index ad282e78..1e7e9ce0 100644 --- a/module/actor/experience-log.js +++ b/module/actor/experience-log.js @@ -29,7 +29,7 @@ export class ExperienceLog { }; console.log('ExperienceLog.add', newXpLog) const newExperienceLog = (actor.system.experiencelog ?? []).concat([newXpLog]); - await actor.update({ [`system.experiencelog`]: newExperienceLog }); + await actor.update({ [`system.experiencelog`]: newExperienceLog }, { noHook: true }); } static labelTopic(topic) { diff --git a/module/constants.js b/module/constants.js index fbd60dc0..cf8a91f1 100644 --- a/module/constants.js +++ b/module/constants.js @@ -62,6 +62,7 @@ export const RDD_CONFIG = { demiReve: 'systems/foundryvtt-reve-de-dragon/assets/actions/sort.svg', empoignade: 'systems/foundryvtt-reve-de-dragon/assets/actions/empoignade.svg', forceWeak: 'systems/foundryvtt-reve-de-dragon/assets/actions/weak.svg', + surenc: 'systems/foundryvtt-reve-de-dragon/assets/actions/surenc.svg', }, encaissement: { mortel: 'mortel', diff --git a/module/item-sheet.js b/module/item-sheet.js index 0e441d31..5b3cc994 100644 --- a/module/item-sheet.js +++ b/module/item-sheet.js @@ -260,7 +260,7 @@ export class RdDItemSheetV1 extends foundry.appv1.sheets.ItemSheet { /* -------------------------------------------- */ /** @override */ - _updateObject(event, formData) { + async _updateObject(event, formData) { switch (this.item.type) { case ITEM_TYPES.sort: formData['system.bonuscase'] = RdDItemSort.bonuscasesToString(RdDItemSheetV1._listCaseTmr( @@ -273,8 +273,7 @@ export class RdDItemSheetV1 extends foundry.appv1.sheets.ItemSheet { formData['system.niveau'] = formData['system.niveau'] ?? formData['system.base'] break } - - return this.item.update(formData) + return await super._updateObject(event, formData) } /* -------------------------------------------- */ diff --git a/module/roll/roll-part-enctotal.mjs b/module/roll/roll-part-enctotal.mjs index 5595b58a..4be5366e 100644 --- a/module/roll/roll-part-enctotal.mjs +++ b/module/roll/roll-part-enctotal.mjs @@ -1,3 +1,4 @@ +import { RDD_CONFIG } from "../constants.js" import { RdDItemCompetence } from "../item-competence.js" import { RdDCarac } from "../rdd-carac.js" import { RollPartCheckbox } from "./roll-part-checkbox.mjs" @@ -25,7 +26,7 @@ export class RollPartEncTotal extends RollPartCheckbox { }) } - getCheckboxIcon(rollData) { return '' } + getCheckboxIcon(rollData) { return `` } getCheckboxLabel(rollData) { return "Enc. total" } getCheckboxValue(rollData) { return - rollData.active.actor.getEncTotal() } } diff --git a/module/roll/roll-part-surenc.mjs b/module/roll/roll-part-surenc.mjs index 89abc579..c5be7cd8 100644 --- a/module/roll/roll-part-surenc.mjs +++ b/module/roll/roll-part-surenc.mjs @@ -1,3 +1,4 @@ +import { RDD_CONFIG } from "../constants.js" import { RdDCarac } from "../rdd-carac.js" import { RollPartCheckbox } from "./roll-part-checkbox.mjs" @@ -10,7 +11,7 @@ export class RollPartSurEnc extends RollPartCheckbox { visible(rollData) { return RdDCarac.isActionPhysique(rollData.current.carac.key) && rollData.active.actor.isSurenc() } - getCheckboxIcon(rollData) { return '' } + getCheckboxIcon(rollData) { return `` } getCheckboxLabel(rollData) { return "Sur-enc." } getCheckboxValue(rollData) { return rollData.active.actor.computeMalusSurEncombrement() } } diff --git a/module/settings/status-effects.js b/module/settings/status-effects.js index 43ce4a20..06e349e4 100644 --- a/module/settings/status-effects.js +++ b/module/settings/status-effects.js @@ -14,13 +14,14 @@ export const STATUSES = { StatusBleeding: 'bleeding', StatusDead: 'dead', StatusDemiReve: 'demi-reve', + StatusSurEnc: 'sur-encombrement', StatusForceWeak: 'force insuffisante', } export const forceWeakStatusEffect = { rdd: true, id: STATUSES.StatusForceWeak, name: 'EFFECT.StatusForceWeak', img: RDD_CONFIG.icons.forceWeak }; -export const demiReveStatusEffect = { - rdd: true, id: STATUSES.StatusDemiReve, name: 'EFFECT.StatusDemiReve', img: RDD_CONFIG.icons.demiReve -}; +export const surEncEffect = { rdd: true, id: STATUSES.StatusSurEnc, name: 'EFFECT.StatusSurEnc', img: RDD_CONFIG.icons.surenc }; +export const demiReveStatusEffect = { rdd: true, id: STATUSES.StatusDemiReve, name: 'EFFECT.StatusDemiReve', img: RDD_CONFIG.icons.demiReve }; + const rddStatusEffects = [ { rdd: true, id: STATUSES.StatusGrappling, name: 'EFFECT.StatusGrappling', img: RDD_CONFIG.icons.empoignade }, { rdd: true, id: STATUSES.StatusGrappled, tint: '#d5633d', name: 'EFFECT.StatusGrappled', img: RDD_CONFIG.icons.empoignade }, @@ -36,7 +37,8 @@ const rddStatusEffects = [ { rdd: true, id: STATUSES.StatusBleeding, name: 'EFFECT.StatusBleeding', img: 'icons/svg/blood.svg' }, { rdd: true, id: STATUSES.StatusDead, name: 'EFFECT.StatusDead', img: 'icons/svg/skull.svg' }, demiReveStatusEffect, - forceWeakStatusEffect + forceWeakStatusEffect, + surEncEffect, ]; const statusDemiSurprise = new Set([STATUSES.StatusStunned, STATUSES.StatusProne, STATUSES.StatusRestrained, STATUSES.StatusForceWeak]) @@ -136,7 +138,7 @@ export class StatusEffects extends FormApplication { } static prepareActiveEffect(effectId) { - let status = rddStatusEffects.find(it => it.id == effectId) + let status = rddStatusEffects.find(it => it.statuses.has(effectId)) if (status) { status = foundry.utils.duplicate(status) status.statuses = new Set([effectId]) diff --git a/templates/actor/carac-main.hbs b/templates/actor/carac-main.hbs index 5b26ef21..ac09cffb 100644 --- a/templates/actor/carac-main.hbs +++ b/templates/actor/carac-main.hbs @@ -4,7 +4,7 @@
  • {{#if (eq key 'taille')}} {{carac.label}} - +