diff --git a/lang/fr.json b/lang/fr.json
index 6d5cbe9b..94d60c4a 100644
--- a/lang/fr.json
+++ b/lang/fr.json
@@ -40,5 +40,19 @@
"TypeOmbre": "Ombre de Thanatos",
"TypeSouffle": "Souffle de Dragon",
"TypeTete": "Tête de Dragon"
+ },
+ "EFFECT": {
+ "StatusStunned": "Sonné",
+ "StatusUnconscious": "Inconscient",
+ "StatusBlind": "Aveugle",
+ "StatusBleeding": "Saigne",
+ "StatusProne": "Au sol",
+ "StatusUnarmed": "Désarmé",
+ "StatusGrappling": "Empoignade",
+ "StatusGrappled": "Empoigné",
+ "StatusRestrained": "Immobilisé",
+ "StatusComma": "Comma",
+ "StatusDead": "Mort",
+ "StatusDemiReve": "Demi-rêve"
}
-}
+}
\ No newline at end of file
diff --git a/module/actor-sheet.js b/module/actor-sheet.js
index 8ebde729..5f02626f 100644
--- a/module/actor-sheet.js
+++ b/module/actor-sheet.js
@@ -103,7 +103,7 @@ export class RdDActorSheet extends ActorSheet {
formData.difficultesLibres = CONFIG.RDD.difficultesLibres;
formData.hautreve = {
- isDemiReve: this.actor.listeEffets( it => it.label == "Demi-rêve").length > 0,
+ isDemiReve: this.actor.getEffectByLabel("Demi-rêve"),
sortsReserve: formData.data.reve.reserve.list,
rencontres: duplicate(formData.data.reve.rencontre.list),
casesTmr: formData.itemsByType.casetmr,
@@ -384,6 +384,10 @@ export class RdDActorSheet extends ActorSheet {
html.find('.repos').click(async event => {
await DialogRepos.create(this.actor);
});
+ html.find('.delete-active-effect').click(async event => {
+ let id = $(event.currentTarget).parents(".active-effect").data('id');
+ this.actor.enleverActiveEffectById(id);
+ });
html.find('.enlever-tous-effets').click(async event => {
this.actor.enleverTousLesEffets();
});
diff --git a/module/actor.js b/module/actor.js
index 14654f01..d52d29eb 100644
--- a/module/actor.js
+++ b/module/actor.js
@@ -32,7 +32,6 @@ import { DialogFabriquerPotion } from "./dialog-fabriquer-potion.js";
import { RollDataAjustements } from "./rolldata-ajustements.js";
import { DialogItemAchat } from "./dialog-item-achat.js";
import { RdDItem } from "./item.js";
-
/* -------------------------------------------- */
/**
* Extend the base Actor entity by defining a custom roll data structure which is ideal for the Simple system.
@@ -42,7 +41,6 @@ export class RdDActor extends Actor {
/* -------------------------------------------- */
static init() {
Hooks.on("deleteActiveEffect", (effect, options, userId) => RdDActor.getParentActor(effect)?.onDeleteActiveEffect(effect, options));
- Hooks.on("createActiveEffect", (effect, options, userId) => RdDActor.getParentActor(effect)?.onCreateActiveEffect(effect, options));
Hooks.on("preUpdateItem", (item, change, options, id) => RdDActor.getParentActor(item)?.onPreUpdateItem(item, change, options, id));
Hooks.on("createItem", (item, options, id) => RdDActor.getParentActor(item)?.onCreateItem(item, options, id));
@@ -424,7 +422,7 @@ export class RdDActor extends Actor {
/* -------------------------------------------- */
getSurprise(isCombat = undefined) {
- let niveauSurprise = Array.from(this.effects?.values() ?? [])
+ let niveauSurprise = this.getActiveEffects()
.map(effect => StatusEffects.valeurSurprise(effect.data, isCombat))
.reduce(Misc.sum(), 0);
if (niveauSurprise > 1) {
@@ -1507,13 +1505,12 @@ export class RdDActor extends Actor {
/* -------------------------------------------- */
getSonne() {
- let data = Misc.templateData(this);
- return !this.isEntiteCauchemar() && (data.sante?.sonne?.value ?? false);
+ return this.getEffectByLabel("EFFECT.StatusStunned");
}
/* -------------------------------------------- */
getSonneRound() {
- return !this.isEntiteCauchemar() && (Misc.templateData(this).sante.sonne?.round ?? false);
+ return Misc.templateData(this).sante.sonne?.round ?? -1;
}
/* -------------------------------------------- */
@@ -1528,23 +1525,12 @@ export class RdDActor extends Actor {
/* -------------------------------------------- */
async setSonne(sonne = true) {
- if (this.isEntiteCauchemar()) {
+ if (!game.combat || this.isEntiteCauchemar()) {
return;
}
- let round = (sonne && game.combat) ? game.combat.current.round : -1; // Sauvegarde du round de sonné en cas de combat
- await this.setStatusSonne(sonne);
- await this.setStateSonne(sonne, round);
- }
-
- /* -------------------------------------------- */
- async setStateSonne(sonne, round = -1) {
- if (this.isEntiteCauchemar()) {
- return;
- }
- let sonneData = duplicate(Misc.templateData(this).sante.sonne);
- sonneData.value = sonne;
- sonneData.round = round;
- await this.update({ "data.sante.sonne": sonneData });
+ await this.setStatusEffect("EFFECT.StatusStunned", sonne, {
+ duration: (sonne && game.combat) ? { rounds: 2 } : undefined
+ });
}
/* -------------------------------------------- */
@@ -1695,7 +1681,7 @@ export class RdDActor extends Actor {
}
await this.update({ "data.sante": sante });
if (this.isDead()) {
- await this.addStatusEffectById('dead');
+ await this.setStatusEffect("EFFECT.StatusComma", true);
}
return result;
}
@@ -3078,7 +3064,7 @@ export class RdDActor extends Actor {
ui.notifications.warn("Vous êtes déja dans les TMR....");
return
}
- let demiReve = this.listeEffets(it => it.label == "Demi-rêve");
+ let demiReve = this.getActiveEffects(it => it.data.label == "Demi-rêve");
if (mode != 'visu' && demiReve.length > 0) {
ui.notifications.warn("Le joueur ou le MJ est déja dans les Terres Médianes avec ce personnage ! Visualisation uniquement");
mode = "visu"; // bascule le mode en visu automatiquement
@@ -3094,7 +3080,7 @@ export class RdDActor extends Actor {
});
return;
}
- await this.setStatusDemiReve(true);
+ await this.setStatusEffect("EFFECT.StatusDemiReve", true);
}
const actorData = Misc.data(this);
@@ -3351,7 +3337,7 @@ export class RdDActor extends Actor {
count--;
} else {
// TODO: status effect dead
- this.addStatusEffectById('dead');
+ this.setStatusEffect("EFFECT.StatusComma", true);
ChatMessage.create({
content: `
${this.name} vient de succomber à une seconde blessure critique ! Que les Dragons gardent son Archétype en paix !`
@@ -3990,109 +3976,64 @@ export class RdDActor extends Actor {
async onUpdateActor(update, options, actorId) {
const updatedEndurance = update?.data?.sante?.endurance;
if (updatedEndurance && options.diff) {
- this.forceStatusEffectId('unconscious', updatedEndurance.value == 0);
- }
- }
- /* -------------------------------------------- */
- async onCreateActiveEffect(effect, options) {
- switch (StatusEffects.statusId(effect)) {
- case 'sonne':
- await this.setStateSonne(true);
- return;
+ await this.setStatusEffect("EFFECT.StatusUnconscious", updatedEndurance.value == 0);
}
}
/* -------------------------------------------- */
async onDeleteActiveEffect(effect, options) {
- switch (StatusEffects.statusId(effect)) {
- case 'sonne':
- await this.setStateSonne(false);
+ switch (effect.label) {
+ case 'EFFECT.StatusStunned':
return;
}
}
/* -------------------------------------------- */
- enleverTousLesEffets() {
- const ids = Array.from(this.effects?.keys() ?? []);
- this.deleteEmbeddedDocuments('ActiveEffect', ids);
+ getActiveEffects(matching = it => true) {
+ return Array.from(this.getEmbeddedCollection("ActiveEffect").values()).filter(it => matching(it));
}
/* -------------------------------------------- */
- listeEffets(matching = it => true) {
- const all = Array.from(this.effects?.values() ?? []);
- const filtered = all.filter(it => matching(it.data));
- return filtered;
+ getEffectByLabel(label) {
+ return this.getActiveEffects().find(it => it.data.label == label);
}
/* -------------------------------------------- */
- async setStatusDemiReve(status) {
- const demiReve = StatusEffects.demiReve();
- if (status) {
- await this.addStatusEffect(demiReve)
- } else {
- await this.deleteStatusEffect(demiReve)
- }
+ getEffectById(id) {
+ return this.getActiveEffects().find(it => it.id == id);
}
/* -------------------------------------------- */
- async setStatusSonne(sonne) {
- if (this.isEntiteCauchemar()) {
+ async setStatusEffect(label, status, updates = {}) {
+ if (this.isEntiteCauchemar() || this.data.type == 'vehicule') {
return;
}
- await this.forceStatusEffectId('sonne', sonne);
- }
-
- /* -------------------------------------------- */
- async forceStatusEffectId(statusId, isSet) {
- if (isSet) {
- await this.addStatusEffectById(statusId);
+ console.log("setStatusEffect", label, status, updates)
+ const existing = this.getEffectByLabel(label);
+ if (existing) {
+ existing.delete();
}
- else {
- await this.deleteStatusEffectById(statusId);
+ if (status) {
+ const statusEffect = mergeObject(duplicate(StatusEffects.status(label)), updates);
+ await this.createEmbeddedDocuments("ActiveEffect", [statusEffect]);
}
}
- /* -------------------------------------------- */
- async deleteStatusEffectById(id) {
-
- const ids = Array.from(this.effects?.values())
- .filter(it => it.data.flags.core?.statusId == id)
- .map(it => it.id);
- console.log("Delete effect IDS1: ", this.effects, ids);
- if (ids.length > 0) {
- await this.deleteEmbeddedDocuments('ActiveEffect', ids);
+ enleverActiveEffectById(id) {
+ if (game.user.isGM){
+ const existing = this.getEffectById(id);
+ if (existing) {
+ existing.delete();
+ }
}
}
-
/* -------------------------------------------- */
- async deleteStatusEffect(effect) {
- const ids = Array.from(this.effects?.values())
- .filter(it => StatusEffects.statusId(it.data) == StatusEffects.statusId(effect))
- .map(it => it.id);
- console.log("Delete effect 1: ", this.effects, ids);
- if (ids.length > 0) {
- await this.deleteEmbeddedDocuments('ActiveEffect', ids);
+ enleverTousLesEffets() {
+ if (game.user.isGM){
+ this.deleteEmbeddedDocuments('ActiveEffect', this.getActiveEffects().map(it => it.id));
}
}
- /* -------------------------------------------- */
- async addStatusEffectById(id) {
- const statusEffect = CONFIG.statusEffects.find(it => it.id == id);
- await this.addStatusEffect(statusEffect);
- }
-
- /* -------------------------------------------- */
- async addStatusEffect(statusEffect) {
- const effet = Misc.data(statusEffect);
- await this.deleteStatusEffectById(effet.id);
- effet.flags = effet.flags ?? { core: {} };
- effet.flags.core.statusId = effet.id;
- let effectArray = await this.createEmbeddedDocuments('ActiveEffect', [effet]);
- //if (effectArray[0]) {
- //await effectArray[0].setFlag('core', 'statusId', effet.id);
- //}
- }
-
/* -------------------------------------------- */
async onPreUpdateItem(item, change, options, id) {
const itemData = Misc.data(item);
diff --git a/module/rdd-combat.js b/module/rdd-combat.js
index 7b5f7ccd..b7904ac6 100644
--- a/module/rdd-combat.js
+++ b/module/rdd-combat.js
@@ -1217,7 +1217,7 @@ export class RdDCombat {
defenderRoll.show.recul = 'encaisse';
} else if (rollRecul.rolled.isETotal || this._isReculCauseChute(impact)) {
defenderRoll.show.recul = 'chute';
- await this.defender.addStatusEffectById('prone');
+ await this.defender.setStatusEffect("EFFECT.StatusProne", true);
}
else {
defenderRoll.show.recul = 'recul';
diff --git a/module/rdd-tmr-dialog.js b/module/rdd-tmr-dialog.js
index 48770b48..41c3ac73 100644
--- a/module/rdd-tmr-dialog.js
+++ b/module/rdd-tmr-dialog.js
@@ -274,7 +274,7 @@ export class RdDTMRDialog extends Dialog {
if ( this.actor.tmrApp ) {
this.actor.tmrApp = undefined; // Cleanup reference
if ( !this.viewOnly ) {
- this.actor.setStatusDemiReve(false);
+ this.actor.setStatusEffect("EFFECT.StatusDemiReve", false);
this._tellToGM(this.actor.name + " a quitté les terres médianes");
}
this.actor.santeIncDec("fatigue", this.cumulFatigue).then(super.close()); // moving 1 cell costs 1 fatigue
diff --git a/module/rdd-utility.js b/module/rdd-utility.js
index 6de5f96c..40f64b44 100644
--- a/module/rdd-utility.js
+++ b/module/rdd-utility.js
@@ -115,6 +115,7 @@ export class RdDUtility {
'systems/foundryvtt-reve-de-dragon/templates/actor-vehicule-sheet.html',
'systems/foundryvtt-reve-de-dragon/templates/actor-sheet-competence-partial.html',
'systems/foundryvtt-reve-de-dragon/templates/actor-sheet-categorie-competences-partial.html',
+ 'systems/foundryvtt-reve-de-dragon/templates/actor-sheet-effects-partial.html',
'systems/foundryvtt-reve-de-dragon/templates/actor-sheet-oeuvre-partial.html',
'systems/foundryvtt-reve-de-dragon/templates/actor-liste-blessures-partial.html',
'systems/foundryvtt-reve-de-dragon/templates/actor-blessure-partial.html',
diff --git a/module/status-effects.js b/module/status-effects.js
index 5b05324b..59319ab1 100644
--- a/module/status-effects.js
+++ b/module/status-effects.js
@@ -1,23 +1,31 @@
-const demiReveStatusEffect = { id: 'demi-reve', rdd: true, label: 'Demi-rêve', icon: 'systems/foundryvtt-reve-de-dragon/icons/heures/hd12.svg' };
const rddStatusEffects = [
- { id: 'sonne', rdd: true, label: 'Sonné', icon: 'icons/svg/stoned.svg' },
- demiReveStatusEffect
+ { rdd: true, id: 'stun', label: 'EFFECT.StatusStunned', icon: 'icons/svg/stoned.svg' },
+ { rdd: true, id: 'bleeding', label: 'EFFECT.StatusBleeding', icon: 'icons/svg/blood.svg' },
+ { rdd: true, id: 'prone', label: 'EFFECT.StatusProne', icon: 'icons/svg/falling.svg' },
+ { rdd: true, id: 'grappling', tint: '#33cc33', label: 'EFFECT.StatusGrappling', icon: 'systems/foundryvtt-reve-de-dragon/icons/competence_corps_a_corps.webp' },
+ { rdd: true, id: 'grappled', tint: '#ff9900', label: 'EFFECT.StatusGrappled', icon: 'systems/foundryvtt-reve-de-dragon/icons/competence_corps_a_corps.webp' },
+ { rdd: true, id: 'restrain', label: 'EFFECT.StatusRestrained', icon: 'icons/svg/net.svg' },
+ { rdd: true, id: 'unconscious', label: 'EFFECT.StatusUnconscious', icon: 'icons/svg/unconscious.svg' },
+ { rdd: true, id: 'blind', label: 'EFFECT.StatusBlind', icon: 'icons/svg/blind.svg' },
+ { rdd: true, id: 'comma', label: 'EFFECT.StatusComma', icon: 'icons/svg/skull.svg' },
+ { rdd: true, id: 'dead', label: 'EFFECT.StatusDead', icon: 'icons/svg/skull.svg' },
+ { rdd: true, id: 'demi-reve', label: 'EFFECT.StatusDemiReve', icon: 'systems/foundryvtt-reve-de-dragon/icons/heures/hd12.svg' }
];
-const statusDemiSurprise = new Set(['sonne', 'prone', 'restrain']);
-const statusSurpriseTotale = new Set(['unconscious', 'blind', 'dead']);
+const demiReveStatusEffect = rddStatusEffects.find(it => it.label == 'EFFECT.StatusDemiReve');
+
+const statusDemiSurprise = new Set(['EFFECT.StatusStunned', 'EFFECT.StatusProne', 'EFFECT.StatusRestrain']);
+const statusSurpriseTotale = new Set(['EFFECT.StatusUnconscious', 'EFFECT.StatusBlind', 'EFFECT.StatusComma']);
export class StatusEffects {
static onReady() {
- StatusEffects.setCoreStatusId([demiReveStatusEffect]);
- StatusEffects.setCoreStatusId(rddStatusEffects);
- StatusEffects.setMandatoryRdd();
- const defaultUseStatusEffect = CONFIG.statusEffects.map(it => it.id).join();
+ const rddStatusIds = rddStatusEffects.map(it => it.id);
+ const defaultStatusEffectIds = CONFIG.statusEffects.map(it => it.id);
game.settings.register("foundryvtt-reve-de-dragon", "use-status-effects", {
name: "use-status-effects",
scope: "world",
config: false,
- default: defaultUseStatusEffect,
+ default: defaultStatusEffectIds.join(),
type: String
});
@@ -29,30 +37,21 @@ export class StatusEffects {
type: StatusEffectsSettings,
restricted: true
});
- CONFIG.RDD.allEffects = rddStatusEffects.concat(CONFIG.statusEffects);
-
+
+ CONFIG.RDD.allEffects = rddStatusEffects.concat(CONFIG.statusEffects.filter(it => !rddStatusIds.includes(it.id)));
+
StatusEffects._setUseStatusEffects(StatusEffects._getUseStatusEffects());
console.log('statusEffects', CONFIG.statusEffects);
}
static valeurSurprise(effect, isCombat) {
- const id = StatusEffects.statusId(effect);
- if (statusSurpriseTotale.has(id)) {
+ // const id = StatusEffects.statusId(effect);
+ if (statusSurpriseTotale.has(effect.label)) {
return 2;
}
- return statusDemiSurprise.has(id) || (isCombat && id == demiReveStatusEffect.id) ? 1 : 0;
+ return statusDemiSurprise.has(effect.label) || (isCombat && effect.label == demiReveStatusEffect.label) ? 1 : 0;
}
- static statusId(effectData) {
- return effectData.flags?.core?.statusId ?? effectData["flags.core.statusId"];
- }
-
- static setCoreStatusId(list) {
- list.forEach(it => {
- it.flags = { core: { statusId: it.id } };
- it["flags.core.statusId"] = it.id;
- });
- }
static setMandatoryRdd() {
CONFIG.statusEffects.filter(it => statusDemiSurprise.has(it.id) || statusSurpriseTotale.has(it.id))
.forEach(it => it.rdd = true);
@@ -78,6 +77,9 @@ export class StatusEffects {
return Array.from(useStatusEffects).join();
}
+ static status(label) {
+ return rddStatusEffects.find(it => it.label == label) ?? { label: label };
+ }
static demiReve() {
return demiReveStatusEffect;
}
diff --git a/styles/simple.css b/styles/simple.css
index ff9b32a0..e925f788 100644
--- a/styles/simple.css
+++ b/styles/simple.css
@@ -271,6 +271,11 @@ table {border: 1px solid #7a7971;}
height: 16;
border-width: 0;
}
+.button-effect-img:hover {
+ color: rgba(255, 255, 128, 0.7);
+ border: 1px solid rgba(255, 128, 0, 0.8);
+ cursor: pointer;
+}
.small-button-container {
height: 16px;
diff --git a/templates/actor-creature-sheet.html b/templates/actor-creature-sheet.html
index 70b233a5..c7f2395e 100644
--- a/templates/actor-creature-sheet.html
+++ b/templates/actor-creature-sheet.html
@@ -18,19 +18,7 @@
{{calc.resumeBlessures}}