feature/v13-corrections #788
14
changelog.md
14
changelog.md
@@ -1,5 +1,19 @@
|
||||
# 13.0
|
||||
|
||||
## 13.0.23 - Le marché d'Illysis
|
||||
|
||||
- Améliorations
|
||||
- lors de la consommation suite à un achat, les jets d'appréciation/éthylisme
|
||||
sont faits par l'acheteur. Du coup, c'est lui qui lance le jet d'appréciation
|
||||
(pour un service ou un plat de qualité), et ses dés sont utilisés avec dice-so-nice
|
||||
- les créatures ont le statut Inconscient quand leur endurance est à 0
|
||||
- Fenêtre de jets V2
|
||||
- les soins de blessures sont correctement appliqués
|
||||
- correction d'affichage jet sans compétence/avec compétence
|
||||
- correction de la prise en compte des tactiques
|
||||
- correction du filtrage des défenses selon l'attaque
|
||||
- lorsque le mode de visibilité des jets général est changé, les fenêtres de jets suivent ce changement
|
||||
|
||||
## 13.0.22 - Les reflets d'Illysis
|
||||
|
||||
- Améliorations
|
||||
|
||||
@@ -40,17 +40,21 @@ export class ChatVente {
|
||||
|
||||
static async diminuerQuantiteAchatVente(chatMessageId, quantite) {
|
||||
const chatMessage = game.messages.get(chatMessageId)
|
||||
const vente = ChatVente.getDetailVente(chatMessageId)
|
||||
vente.nbLots = Math.max(0, vente.nbLots - quantite)
|
||||
await chatMessage.setFlag(SYSTEM_RDD, NB_LOTS, vente.nbLots)
|
||||
|
||||
const html = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-vente-item.hbs', vente);
|
||||
chatMessage.update({ content: html });
|
||||
chatMessage.render(true);
|
||||
const vente = ChatVente.getDetailVente(chatMessageId)
|
||||
if (vente.nbLots <= quantite) {
|
||||
ChatUtility.removeChatMessageId(chatMessageIdVente);
|
||||
}
|
||||
else {
|
||||
vente.nbLots = vente.nbLots - quantite
|
||||
await chatMessage.setFlag(SYSTEM_RDD, NB_LOTS, vente.nbLots)
|
||||
const html = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-vente-item.hbs', vente)
|
||||
await chatMessage.update({ content: html }, { render: true })
|
||||
}
|
||||
}
|
||||
|
||||
static async displayAchatVente(vente) {
|
||||
const html = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-vente-item.hbs', vente);
|
||||
const html = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-vente-item.hbs', vente)
|
||||
const chatMessage = await ChatMessage.create(RdDUtility.chatDataSetup(html))
|
||||
await chatMessage.setFlag(SYSTEM_RDD, NB_LOTS, vente.nbLots)
|
||||
await chatMessage.setFlag(SYSTEM_RDD, DETAIL_VENTE, {
|
||||
|
||||
130
module/actor.js
130
module/actor.js
@@ -220,7 +220,7 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
initiative: RdDInitiative.getRollInitiative(caracValue, niveau, ajustement)
|
||||
};
|
||||
attaque.isDistance = Distance.typeAttaqueDistance(attaque),
|
||||
actions.push(attaque)
|
||||
actions.push(attaque)
|
||||
}
|
||||
|
||||
addAttaque(RdDItemArme.empoignade(this), ATTAQUE_TYPE.CORPS_A_CORPS)
|
||||
@@ -1092,7 +1092,7 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
}
|
||||
|
||||
$createSortReserve(sort) {
|
||||
const ptReve = Number.isInteger(sort.system.ptreve) ? Number(sort.system.ptreve) :Number(sort.system.ptreve.match(/\d+/))
|
||||
const ptReve = Number.isInteger(sort.system.ptreve) ? Number(sort.system.ptreve) : Number(sort.system.ptreve.match(/\d+/))
|
||||
this.createEmbeddedDocuments("Item",
|
||||
[{
|
||||
type: ITEM_TYPES.sortreserve,
|
||||
@@ -1316,14 +1316,6 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async consommerNourritureboisson(itemId, choix = { doses: 1, seForcer: false, supprimerSiZero: false }) {
|
||||
if (!this.isOwner) {
|
||||
RdDBaseActor.remoteActorCall({
|
||||
tokenId: this.token?.id,
|
||||
actorId: this.id,
|
||||
method: 'consommerNourritureboisson', args: [itemId, choix]
|
||||
})
|
||||
return
|
||||
}
|
||||
const item = this.getItem(itemId)
|
||||
if (!item.getUtilisationCuisine()) {
|
||||
return
|
||||
@@ -1333,26 +1325,36 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
return
|
||||
}
|
||||
|
||||
const onManger = [
|
||||
async () => await this.manger(item, choix.doses, { diminuerQuantite: false }),
|
||||
async () => await this.boire(item, choix.doses, { diminuerQuantite: false }),
|
||||
async () => await item.diminuerQuantite(choix.doses, choix)
|
||||
]
|
||||
if (!this.isOwner) {
|
||||
RdDBaseActor.remoteActorCall({
|
||||
tokenId: this.token?.id,
|
||||
actorId: this.id,
|
||||
method: 'consommerNourritureboisson', args: [itemId, choix]
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if (await this._surmonterExotisme(item)) {
|
||||
const appreciation = item.system.appreciation;
|
||||
new Apprecier(this, appreciation, item.system.qualite)
|
||||
.apprecier(onManger)
|
||||
if (item.system.qualite > 0) {
|
||||
new Apprecier(this, item.system.appreciation, item.system.qualite).apprecier()
|
||||
}
|
||||
await this.onConsommerNourritureboisson(item, choix)
|
||||
}
|
||||
else if (choix.seForcer) {
|
||||
await this.jetDeMoral(MORAL.MALHEUREUX)
|
||||
await Promise.all(onManger.map(async callback => await callback()))
|
||||
await this.onConsommerNourritureboisson(item, choix)
|
||||
}
|
||||
else {
|
||||
ui.notifications.info(`${this.name} ne n'arrive pas à manger de ${item.name}`)
|
||||
}
|
||||
}
|
||||
|
||||
async onConsommerNourritureboisson(item, choix) {
|
||||
await this.manger(item, choix.doses, { diminuerQuantite: false })
|
||||
await this.boire(item, choix.doses, { diminuerQuantite: false })
|
||||
await item.diminuerQuantite(choix.doses, choix)
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async _surmonterExotisme(item) {
|
||||
const qualite = Math.min(item.system.qualite, 0)
|
||||
@@ -1363,7 +1365,7 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
const rolled = await this.doRollCaracCompetence(CARACS.VOLONTE, competence, difficulte, { title: `tente de surmonter l'exotisme de ${item.name}` })
|
||||
return rolled.isSuccess
|
||||
}
|
||||
return true;
|
||||
return true
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
@@ -1934,7 +1936,7 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
async getTacheBlessure(blesse, blessure) {
|
||||
const gravite = blessure?.system.gravite ?? 0;
|
||||
if (gravite > 0) {
|
||||
const tache = this.itemTypes['tache'].find(it => it.system.itemId == blessure.id)
|
||||
const tache = this.itemTypes[ITEM_TYPES.tache].find(it => it.system.itemId == blessure.id)
|
||||
?? await RdDItemBlessure.createTacheSoinBlessure(this, gravite);
|
||||
await blessure?.updateTacheSoinBlessure(tache);
|
||||
return tache
|
||||
@@ -1988,7 +1990,7 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
selected: { tache: { key: tache.id, forced: options.forced } },
|
||||
type: { allowed: [PART_TACHE], current: PART_TACHE }
|
||||
}
|
||||
return await RollDialog.create(rollData)
|
||||
return await RollDialog.create(rollData, options)
|
||||
}
|
||||
|
||||
const compData = this.getCompetence(tache.system.competence)
|
||||
@@ -2032,8 +2034,8 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
await this.santeIncDec("fatigue", rollData.tache.system.fatigue);
|
||||
|
||||
await RdDRollResult.displayRollData(rollData, this, 'chat-resultat-tache.hbs');
|
||||
if (options?.onRollAutomate) {
|
||||
options.onRollAutomate(rollData);
|
||||
if (options?.callbacks) {
|
||||
await Promise.all(callbacks.map(callback => callback(rollData)))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2504,77 +2506,16 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
if (!blessure.system.premierssoins.done) {
|
||||
const tache = await this.getTacheBlessure(blesse, blessure);
|
||||
return await this.rollTache(tache.id, {
|
||||
onRollAutomate: async r => blesse.onRollTachePremiersSoins(blessureId, r),
|
||||
title: 'Premiers soins',
|
||||
forced: true
|
||||
callbacks: [async r => await blesse.onRollTachePremiersSoins(blessureId, r, this.id)],
|
||||
title: 'Premiers soins', forced: true
|
||||
});
|
||||
}
|
||||
else if (!blessure.system.soinscomplets.done) {
|
||||
const diff = blessure.system.difficulte + (blessure.system.premierssoins.bonus ?? 0);
|
||||
return await this.rollCaracCompetence(CARACS.DEXTERITE, "Chirurgie", diff, {
|
||||
title: "Soins complets",
|
||||
onRollAutomate: r => blesse.onRollSoinsComplets(blessureId, r),
|
||||
forced: true
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async onRollTachePremiersSoins(blessureId, rollData) {
|
||||
if (!this.isOwner) {
|
||||
return RdDBaseActor.remoteActorCall({
|
||||
tokenId: this.token?.id,
|
||||
actorId: this.id,
|
||||
method: 'onRollTachePremiersSoins', args: [blessureId, rollData]
|
||||
})
|
||||
}
|
||||
const blessure = this.getItem(blessureId, 'blessure')
|
||||
|
||||
if (blessure && !blessure.system.premierssoins.done) {
|
||||
const tache = rollData.tache;
|
||||
if (rollData.rolled.isETotal) {
|
||||
await blessure.update({
|
||||
'system.difficulte': blessure.system.difficulte - 1,
|
||||
'system.premierssoins.tache': Math.max(0, tache.system.points_de_tache_courant)
|
||||
})
|
||||
}
|
||||
else {
|
||||
const bonus = tache.system.points_de_tache_courant - tache.system.points_de_tache
|
||||
await blessure.update({
|
||||
'system.premierssoins': {
|
||||
done: (bonus >= 0),
|
||||
bonus: Math.max(0, bonus),
|
||||
tache: Math.max(0, tache.system.points_de_tache_courant)
|
||||
}
|
||||
})
|
||||
if (bonus >= 0) {
|
||||
await this.deleteEmbeddedDocuments('Item', [tache.id])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async onRollSoinsComplets(blessureId, rollData) {
|
||||
if (!this.isOwner) {
|
||||
return RdDBaseActor.remoteActorCall({
|
||||
tokenId: this.token?.id,
|
||||
actorId: this.id,
|
||||
method: 'onRollSoinsComplets', args: [blessureId, rollData]
|
||||
})
|
||||
}
|
||||
const blessure = this.getItem(blessureId, 'blessure')
|
||||
if (blessure && blessure.system.premierssoins.done && !blessure.system.soinscomplets.done) {
|
||||
// TODO: update de la blessure: passer par le MJ!
|
||||
if (rollData.rolled.isETotal) {
|
||||
await blessure.setSoinsBlessure({
|
||||
difficulte: blessure.system.difficulte - 1,
|
||||
premierssoins: { done: false, bonus: 0 }, soinscomplets: { done: false, bonus: 0 },
|
||||
})
|
||||
}
|
||||
else {
|
||||
// soins complets finis
|
||||
await blessure.setSoinsBlessure({
|
||||
soinscomplets: { done: true, bonus: Math.max(0, rollData.rolled.ptTache) },
|
||||
callbacks: [async r => await blesse.onRollSoinsComplets(blessureId, r, this.id)],
|
||||
onRollDone: RollDialog.onRollDoneClose,
|
||||
title: "Soins complets", forced: true
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -2990,15 +2931,6 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
await this.diminuerQuantiteObjet(potion.id, 1, { supprimerSiZero: potion.supprimer });
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async onUpdateActor(update, options, actorId) {
|
||||
const updatedEndurance = update?.system?.sante?.endurance
|
||||
if (updatedEndurance && options.diff) {
|
||||
await this.setEffect(STATUSES.StatusUnconscious, updatedEndurance.value == 0)
|
||||
}
|
||||
await super.onUpdateActor(update, options, actorId)
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async onPreUpdateItem(item, change, options, id) {
|
||||
if (item.isCompetencePersonnage() && item.system.defaut_carac && item.system.xp) {
|
||||
|
||||
@@ -26,7 +26,7 @@ import { BASE_CORPS_A_CORPS, BASE_ESQUIVE, CATEGORIES_COMPETENCES_CREATURES } fr
|
||||
import { RollDataAjustements } from "../rolldata-ajustements-v1.js";
|
||||
import { MappingCreatureArme } from "../item/mapping-creature-arme.mjs";
|
||||
import RollDialog from "../roll/roll-dialog.mjs";
|
||||
import { ATTAQUE_ROLL_TYPES, DEFAULT_ROLL_TYPES, DIFF, ROLL_TYPE_ATTAQUE} from "../roll/roll-constants.mjs";
|
||||
import { ATTAQUE_ROLL_TYPES, DEFAULT_ROLL_TYPES, DIFF, ROLL_TYPE_ATTAQUE } from "../roll/roll-constants.mjs";
|
||||
import { OptionsAvancees, ROLL_DIALOG_V2 } from "../settings/options-avancees.js";
|
||||
import { PART_COMP } from "../roll/roll-part-comp.mjs";
|
||||
import { RdDInitiative } from "../initiative.mjs";
|
||||
@@ -208,7 +208,7 @@ export class RdDBaseActorReve extends RdDBaseActor {
|
||||
.map(async it => await RdDEmpoignade.onImmobilisation(this, it)))
|
||||
}
|
||||
|
||||
async finDeRoundPossession(){
|
||||
async finDeRoundPossession() {
|
||||
await Promise.all(this.itemTypes[ITEM_TYPES.possession]
|
||||
.map(async it => await RdDPossessionV2.onPossession(this, it)))
|
||||
}
|
||||
@@ -348,7 +348,10 @@ export class RdDBaseActorReve extends RdDBaseActor {
|
||||
competence: competence,
|
||||
show: { title: options?.title ?? '' }
|
||||
},
|
||||
callbacks: [async r => this.$onRollCompetence(r, options)]
|
||||
callbacks: [
|
||||
async r => this.$onRollCompetence(r, options),
|
||||
...(options?.callbacks ?? [])
|
||||
]
|
||||
});
|
||||
}
|
||||
/**
|
||||
|
||||
@@ -7,6 +7,7 @@ import { RdDDice } from "../rdd-dice.js";
|
||||
import { RdDItemBlessure } from "../item/blessure.js";
|
||||
import { ChatUtility } from "../chat-utility.js";
|
||||
import { Misc } from "../misc.js";
|
||||
import { RdDBaseActor } from "./base-actor.js";
|
||||
|
||||
/**
|
||||
* Classe de base pour les acteurs qui peuvent subir des blessures
|
||||
@@ -120,16 +121,14 @@ export class RdDBaseActorSang extends RdDBaseActorReve {
|
||||
/* -------------------------------------------- */
|
||||
async santeIncDec(name, inc, isCritique = false) {
|
||||
if (name == 'fatigue' && !ReglesOptionnelles.isUsing("appliquer-fatigue")) {
|
||||
return;
|
||||
return
|
||||
}
|
||||
if (!this.system.sante[name]) {
|
||||
return
|
||||
}
|
||||
const sante = foundry.utils.duplicate(this.system.sante)
|
||||
let compteur = sante[name];
|
||||
if (!compteur) {
|
||||
return;
|
||||
}
|
||||
let result = {
|
||||
sonne: false,
|
||||
};
|
||||
const compteur = sante[name]
|
||||
const result = { sonne: false }
|
||||
let perteEndurance = 0
|
||||
let minValue = name == "vie" ? -this.getSConst() - 1 : 0;
|
||||
|
||||
@@ -171,6 +170,67 @@ export class RdDBaseActorSang extends RdDBaseActorReve {
|
||||
return result
|
||||
}
|
||||
|
||||
async onRollTachePremiersSoins(blessureId, rollData, soigneurId) {
|
||||
if (!this.isOwner) {
|
||||
return RdDBaseActor.remoteActorCall({
|
||||
tokenId: this.token?.id,
|
||||
actorId: this.id,
|
||||
method: 'onRollTachePremiersSoins', args: [blessureId, rollData, soigneurId]
|
||||
})
|
||||
}
|
||||
|
||||
const blessure = this.getItem(blessureId, 'blessure')
|
||||
if (blessure && !blessure.system.premierssoins.done) {
|
||||
const tache = rollData.v2 ? rollData.current.tache.tache : rollData.tache
|
||||
if (rollData.rolled.isETotal) {
|
||||
await blessure.update({
|
||||
'system.difficulte': blessure.system.difficulte - 1,
|
||||
'system.premierssoins.tache': Math.max(0, tache.system.points_de_tache_courant)
|
||||
})
|
||||
}
|
||||
else {
|
||||
const bonus = tache.system.points_de_tache_courant - tache.system.points_de_tache
|
||||
await blessure.update({
|
||||
'system.premierssoins': {
|
||||
done: (bonus >= 0),
|
||||
bonus: Math.max(0, bonus),
|
||||
tache: Math.max(0, tache.system.points_de_tache_courant)
|
||||
}
|
||||
})
|
||||
if (bonus >= 0 && soigneurId) {
|
||||
const soigneur = game.actors.get(soigneurId)
|
||||
await soigneur.deleteEmbeddedDocuments('Item', [tache.id], { render: true })
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async onRollSoinsComplets(blessureId, rollData) {
|
||||
if (!this.isOwner) {
|
||||
return RdDBaseActor.remoteActorCall({
|
||||
tokenId: this.token?.id,
|
||||
actorId: this.id,
|
||||
method: 'onRollSoinsComplets', args: [blessureId, rollData]
|
||||
})
|
||||
}
|
||||
const blessure = this.getItem(blessureId, 'blessure')
|
||||
if (blessure && blessure.system.premierssoins.done && !blessure.system.soinscomplets.done) {
|
||||
// TODO: update de la blessure: passer par le MJ!
|
||||
if (rollData.rolled.isETotal) {
|
||||
await blessure.setSoinsBlessure({
|
||||
difficulte: blessure.system.difficulte - 1,
|
||||
premierssoins: { done: false, bonus: 0 }, soinscomplets: { done: false, bonus: 0 },
|
||||
})
|
||||
}
|
||||
else {
|
||||
// soins complets finis
|
||||
await blessure.setSoinsBlessure({
|
||||
soinscomplets: { done: true, bonus: Math.max(0, rollData.rolled.ptTache) },
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
_computeEnduranceMax() {
|
||||
const diffVie = this.system.sante.vie.max - this.system.sante.vie.value;
|
||||
@@ -182,6 +242,14 @@ export class RdDBaseActorSang extends RdDBaseActorReve {
|
||||
return Math.max(0, Math.min(maxEndVie, maxEndGraves, maxEndCritiques));
|
||||
}
|
||||
|
||||
async onUpdateActor(update, options, actorId) {
|
||||
const updatedEndurance = update?.system?.sante?.endurance
|
||||
if (updatedEndurance && options.diff) {
|
||||
await this.setEffect(STATUSES.StatusUnconscious, updatedEndurance.value == 0)
|
||||
}
|
||||
await super.onUpdateActor(update, options, actorId)
|
||||
}
|
||||
|
||||
async onCreateItem(item, options, id) {
|
||||
await this.changeItemEffects(item)
|
||||
await super.onCreateItem(item, options, id)
|
||||
|
||||
@@ -23,7 +23,7 @@ export class RdDBaseActor extends Actor {
|
||||
}
|
||||
|
||||
static $findCaracByName(carac, name) {
|
||||
const caracList = Object.entries(carac);
|
||||
const caracList = Object.entries(carac)
|
||||
let entry = Misc.findFirstLike(name, caracList, { mapper: it => it[0], description: 'caractéristique', onMessage: m => { } });
|
||||
if (!entry || entry.length == 0) {
|
||||
entry = Misc.findFirstLike(name, caracList, { mapper: it => it[1].label, description: 'caractéristique' });
|
||||
@@ -62,14 +62,14 @@ export class RdDBaseActor extends Actor {
|
||||
}
|
||||
}
|
||||
|
||||
static remoteActorCall(callData) {
|
||||
static remoteActorCall(callData, userId = undefined) {
|
||||
if (game.user.isGM) {
|
||||
RdDBaseActor.onRemoteActorCall(callData, game.user.id)
|
||||
return false
|
||||
}
|
||||
else {
|
||||
const gmUserId = Misc.firstConnectedGMId()
|
||||
if (gmUserId){
|
||||
if (gmUserId) {
|
||||
game.socket.emit(SYSTEM_SOCKET_ID, {
|
||||
msg: "msg_remote_actor_call",
|
||||
data: callData,
|
||||
@@ -166,14 +166,22 @@ export class RdDBaseActor extends Actor {
|
||||
return this.system.sante.vie
|
||||
}
|
||||
|
||||
const carac = this.system.carac;
|
||||
const carac = {}
|
||||
foundry.utils.mergeObject(carac, this.system.carac, { overwrite: false })
|
||||
foundry.utils.mergeObject(carac, this.getCaracCompetenceCreature(), { overwrite: false })
|
||||
return RdDBaseActor.$findCaracByName(carac, name);
|
||||
}
|
||||
|
||||
getCaracCompetenceCreature() {
|
||||
return this.isCreatureOuEntite()
|
||||
? Object.fromEntries(this.itemTypes[ITEM_TYPES.competencecreature].map(it => [Grammar.toLowerCaseNoAccent(it.name), { label: it.name, value: it.system.carac_value }]))
|
||||
: {}
|
||||
}
|
||||
|
||||
mapCarac(caracCode) { return caracCode }
|
||||
|
||||
getCaracByName(name) {
|
||||
name = this.mapCarac(Grammar.toLowerCaseNoAccent(name))
|
||||
name = this.mapCarac(Grammar.toLowerCaseNoAccent(name)) ?? name
|
||||
switch (name) {
|
||||
case 'reve-actuel': case 'reve actuel':
|
||||
return this.getCaracReveActuel();
|
||||
@@ -417,6 +425,14 @@ export class RdDBaseActor extends Actor {
|
||||
}
|
||||
|
||||
async depenserSols(sols) {
|
||||
if (!this.isOwner) {
|
||||
return RdDBaseActor.remoteActorCall({
|
||||
userId: Misc.connectedGMOrUser(),
|
||||
tokenId: this.token?.id,
|
||||
actorId: this.id,
|
||||
method: 'depenserSols', args: [sols]
|
||||
})
|
||||
}
|
||||
let reste = this.getFortune() - Number(sols);
|
||||
if (reste >= 0) {
|
||||
await Monnaie.optimiserFortune(this, reste);
|
||||
@@ -425,32 +441,31 @@ export class RdDBaseActor extends Actor {
|
||||
}
|
||||
|
||||
async ajouterSols(sols, fromActorId = undefined) {
|
||||
sols = Number(sols);
|
||||
sols = Number(sols)
|
||||
if (sols == 0) {
|
||||
return;
|
||||
return
|
||||
}
|
||||
if (sols < 0) {
|
||||
ui.notifications.error(`Impossible d'ajouter un gain de ${sols} <0`);
|
||||
return;
|
||||
ui.notifications.error(`Impossible d'ajouter un gain de ${sols} <0`)
|
||||
return
|
||||
}
|
||||
if (fromActorId && !this.isOwner) {
|
||||
RdDBaseActor.remoteActorCall({
|
||||
return RdDBaseActor.remoteActorCall({
|
||||
userId: Misc.connectedGMOrUser(),
|
||||
tokenId: this.token?.id,
|
||||
actorId: this.id,
|
||||
method: 'ajouterSols', args: [sols, fromActorId]
|
||||
});
|
||||
})
|
||||
}
|
||||
else {
|
||||
const fromActor = game.actors.get(fromActorId)
|
||||
await Monnaie.optimiserFortune(this, sols + this.getFortune());
|
||||
|
||||
RdDAudio.PlayContextAudio("argent"); // Petit son
|
||||
ChatMessage.create({
|
||||
whisper: ChatUtility.getOwners(this),
|
||||
content: `Vous avez reçu <strong>${sols} Sols</strong> ${fromActor ? " de " + fromActor.name : ''}, qui ont été ajoutés à votre argent.`
|
||||
});
|
||||
}
|
||||
const fromActor = game.actors.get(fromActorId)
|
||||
await Monnaie.optimiserFortune(this, sols + this.getFortune());
|
||||
|
||||
RdDAudio.PlayContextAudio("argent"); // Petit son
|
||||
ChatMessage.create({
|
||||
whisper: ChatUtility.getOwners(this),
|
||||
content: `Vous avez reçu <strong>${sols} Sols</strong> ${fromActor ? " de " + fromActor.name : ''}, qui ont été ajoutés à votre argent.`
|
||||
})
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
@@ -462,24 +477,28 @@ export class RdDBaseActor extends Actor {
|
||||
/* -------------------------------------------- */
|
||||
async achatVente(achat) {
|
||||
if (achat.vendeurId == achat.acheteurId) {
|
||||
ui.notifications.info("Inutile de se vendre à soi-même");
|
||||
return;
|
||||
ui.notifications.info("Inutile de se vendre à soi-même")
|
||||
return
|
||||
}
|
||||
if (!game.user.isGM) {
|
||||
const cout = Number(achat.prixTotal ?? 0)
|
||||
const acheteur = achat.acheteurId ? game.actors.get(achat.acheteurId) : undefined
|
||||
|
||||
if (acheteur && !acheteur.isOwner) {
|
||||
ui.notifications.warn(`${game.user.id} n'est pas propriétaire de ${this.name} et effectue un achat pour lui!`)
|
||||
RdDBaseActor.remoteActorCall({
|
||||
actorId: achat.vendeurId ?? achat.acheteurId,
|
||||
actorId: achat.acheteurId,
|
||||
method: 'achatVente', args: [achat]
|
||||
});
|
||||
return
|
||||
}
|
||||
const cout = Number(achat.prixTotal ?? 0);
|
||||
const vendeur = achat.vendeurId ? game.actors.get(achat.vendeurId) : undefined;
|
||||
const acheteur = achat.acheteurId ? game.actors.get(achat.acheteurId) : undefined;
|
||||
|
||||
|
||||
const vendeur = achat.vendeurId ? game.actors.get(achat.vendeurId) : undefined
|
||||
const quantite = (achat.choix.nombreLots ?? 1) * (achat.vente.tailleLot);
|
||||
const itemVendu = vendeur?.getItem(achat.vente.item._id) ?? game.items.get(achat.vente.item._id);
|
||||
if (!itemVendu) {
|
||||
ChatUtility.notifyUser(achat.userId, 'warn', vendeur ? `Le vendeur n'a pas plus de ${achat.vente.item.name} !` : `Impossible de retrouver: ${achat.vente.item.name} !`);
|
||||
return;
|
||||
return
|
||||
}
|
||||
if (vendeur && !vendeur.verifierQuantite(itemVendu, quantite)) {
|
||||
ChatUtility.notifyUser(achat.userId, 'warn', `Le vendeur n'a pas assez de ${itemVendu.name} !`);
|
||||
@@ -487,10 +506,10 @@ export class RdDBaseActor extends Actor {
|
||||
}
|
||||
if (acheteur && !acheteur.verifierFortune(cout)) {
|
||||
ChatUtility.notifyUser(achat.userId, 'warn', `Vous n'avez pas assez d'argent pour payer ${Math.ceil(cout / 100)} sols !`);
|
||||
return;
|
||||
return
|
||||
}
|
||||
await vendeur?.vendre(itemVendu, quantite, cout);
|
||||
await acheteur?.acheter(itemVendu, quantite, cout, achat)
|
||||
await vendeur?.vendre(itemVendu, quantite, cout, acheteur);
|
||||
await acheteur?.acheter(itemVendu, quantite, cout, achat, vendeur)
|
||||
|
||||
if (cout > 0) {
|
||||
RdDAudio.PlayContextAudio("argent");
|
||||
@@ -505,22 +524,32 @@ export class RdDBaseActor extends Actor {
|
||||
});
|
||||
|
||||
if (!achat.vente.quantiteIllimite) {
|
||||
if (achat.vente.nbLots <= achat.choix.nombreLots) {
|
||||
ChatUtility.removeChatMessageId(achat.chatMessageIdVente);
|
||||
}
|
||||
else if (achat.chatMessageIdVente) {
|
||||
await ChatVente.diminuerQuantiteAchatVente(achat.chatMessageIdVente, achat.choix.nombreLots)
|
||||
}
|
||||
await this.updateMessageVente(achat.chatMessageIdVente, achat.choix.nombreLots);
|
||||
}
|
||||
}
|
||||
|
||||
async vendre(item, quantite, cout) {
|
||||
await this.ajouterSols(cout);
|
||||
await this.decrementerQuantiteItem(item, quantite);
|
||||
async updateMessageVente(chatMessageIdVente, nombreLots) {
|
||||
const chatMessage = game.messages.get(chatMessageIdVente)
|
||||
if (!chatMessage.isOwner) {
|
||||
return RdDBaseActor.remoteActorCall({
|
||||
userId: Misc.firstConnectedGMId(),
|
||||
actorId: this.id,
|
||||
method: 'updateMessageVente', args: [chatMessageIdVente, nombreLots]
|
||||
})
|
||||
}
|
||||
await ChatVente.diminuerQuantiteAchatVente(chatMessageIdVente, nombreLots);
|
||||
}
|
||||
|
||||
async vendre(item, quantite, cout, acheteur) {
|
||||
await this.ajouterSols(cout, acheteur?.id)
|
||||
await this.decrementerQuantiteItem(item.id, quantite)
|
||||
}
|
||||
|
||||
async acheter(item, quantite, cout, achat) {
|
||||
await this.depenserSols(cout)
|
||||
if (!this.isOwner) {
|
||||
ui.notifications.warn(`${game.user.id} n'est pas propriétaire de ${this.name} et effectue un achat!`)
|
||||
}
|
||||
const createdItemId = await this.creerQuantiteItem(item, quantite)
|
||||
if (item.type == ITEM_TYPES.nourritureboisson && achat.choix.consommer && createdItemId != undefined) {
|
||||
achat.choix.doses = achat.choix.nombreLots;
|
||||
@@ -542,43 +571,46 @@ export class RdDBaseActor extends Actor {
|
||||
|
||||
async consommerNourritureboisson(itemId, choix, userId) { }
|
||||
|
||||
async decrementerQuantiteItem(item, quantite, options = { supprimerSiZero: true }) {
|
||||
async decrementerQuantiteItem(itemId, quantite, options = { supprimerSiZero: true }) {
|
||||
const item = this.items.get(itemId)
|
||||
if (item.isService()) {
|
||||
return;
|
||||
return
|
||||
}
|
||||
const itemId = item.id;
|
||||
let resteQuantite = (item.system.quantite ?? 1) - quantite;
|
||||
if (resteQuantite <= 0) {
|
||||
if (options.supprimerSiZero) {
|
||||
await this.deleteEmbeddedDocuments("Item", [item.id]);
|
||||
}
|
||||
else {
|
||||
await this.updateEmbeddedDocuments("Item", [{ _id: itemId, 'system.quantite': 0 }]);
|
||||
}
|
||||
if (resteQuantite < 0) {
|
||||
ui.notifications.warn(`La quantité de ${item.name} était insuffisante, l'objet a donc été supprimé`)
|
||||
}
|
||||
|
||||
if (!this.isOwner) {
|
||||
return RdDBaseActor.remoteActorCall({
|
||||
userId: Misc.connectedGMOrUser(),
|
||||
tokenId: this.token?.id,
|
||||
actorId: this.id,
|
||||
method: 'decrementerQuantiteItem', args: [itemId, quantite, options]
|
||||
})
|
||||
}
|
||||
else if (resteQuantite > 0) {
|
||||
const realItem = this.getItem(item.id)
|
||||
realItem.update({ 'system.quantite': resteQuantite });
|
||||
await this.updateEmbeddedDocuments("Item", [{ _id: item.id, 'system.quantite': resteQuantite }]);
|
||||
|
||||
const resteQuantite = Math.max((item.system.quantite ?? 1) - quantite, 0)
|
||||
if (resteQuantite <= 0 && options.supprimerSiZero) {
|
||||
await this.deleteEmbeddedDocuments("Item", [itemId]);
|
||||
}
|
||||
else {
|
||||
await this.updateEmbeddedDocuments("Item", [{ _id: itemId, 'system.quantite': resteQuantite }])
|
||||
}
|
||||
}
|
||||
|
||||
async creerQuantiteItem(item, quantite) {
|
||||
if (this.canReceive(item)) {
|
||||
const isItemEmpilable = "quantite" in item.system;
|
||||
const baseItem = {
|
||||
type: item.type,
|
||||
img: item.img,
|
||||
name: item.name,
|
||||
system: foundry.utils.mergeObject(item.system, { quantite: isItemEmpilable ? quantite : undefined }, { inplace: false })
|
||||
};
|
||||
const newItems = isItemEmpilable ? [baseItem] : Array.from({ length: quantite }, (_, i) => baseItem);
|
||||
const items = await this.createEmbeddedDocuments("Item", newItems);
|
||||
return items.length > 0 ? items[0].id : undefined;
|
||||
if (!this.canReceive(item)) {
|
||||
return
|
||||
}
|
||||
|
||||
const isItemEmpilable = "quantite" in item.system;
|
||||
const baseItem = {
|
||||
type: item.type,
|
||||
img: item.img,
|
||||
name: item.name,
|
||||
system: foundry.utils.mergeObject(item.system, { quantite: isItemEmpilable ? quantite : undefined }, { inplace: false })
|
||||
}
|
||||
|
||||
const newItems = isItemEmpilable ? [baseItem] : Array.from({ length: quantite }, (_, i) => baseItem);
|
||||
const items = await this.createEmbeddedDocuments("Item", newItems);
|
||||
return newItems.length > 0 ? items[0].id : undefined;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
@@ -866,4 +898,5 @@ export class RdDBaseActor extends Actor {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
@@ -28,11 +28,11 @@ export class RdDCommerce extends RdDBaseActor {
|
||||
await super.depenserSols(cout)
|
||||
}
|
||||
|
||||
async decrementerQuantiteItem(item, quantite) {
|
||||
async decrementerQuantiteItem(itemId, quantite) {
|
||||
if (this.system.illimite) {
|
||||
return;
|
||||
}
|
||||
await super.decrementerQuantiteItem(item, quantite, { supprimerSiZero: false });
|
||||
await super.decrementerQuantiteItem(itemId, quantite, { supprimerSiZero: false });
|
||||
}
|
||||
|
||||
calculerPrix(item) {
|
||||
|
||||
@@ -233,4 +233,25 @@ export class ChatUtility {
|
||||
static async setTimestamp(chatMessage) {
|
||||
await chatMessage.setFlag(SYSTEM_RDD, 'rdd-timestamp', game.system.rdd.calendrier.getTimestamp());
|
||||
}
|
||||
// TODO: find ChatLog to change the action for data-action flush
|
||||
|
||||
// async flush() {
|
||||
// const question = game.i18n.localize("AreYouSure");
|
||||
// const warning = game.i18n.localize("CHAT.FlushWarning");
|
||||
// return foundry.applications.api.DialogV2.confirm({
|
||||
// window: {title: "CHAT.FlushTitle"},
|
||||
// content: `<p><strong>${question}</strong> ${warning}</p>`,
|
||||
// position: {
|
||||
// top: window.innerHeight - 150,
|
||||
// left: window.innerWidth - 720
|
||||
// },
|
||||
// yes: {
|
||||
// callback: async () => {
|
||||
// await this.documentClass.deleteDocuments([], {deleteAll: true});
|
||||
// const jumpToBottomElement = document.querySelector(".jump-to-bottom");
|
||||
// jumpToBottomElement.hidden = true;
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ export class RdDItemArme extends RdDItem {
|
||||
isParade() { return this.system.resistance > 0 && this.system.categorie_parade }
|
||||
isBouclier() { return RdDItemArme.getCategorieParade(this).includes('bouclier') }
|
||||
|
||||
|
||||
|
||||
getCompetenceAction(main) {
|
||||
switch (main) {
|
||||
case ATTAQUE_TYPE.UNE_MAIN: return this.competence1Mains()
|
||||
@@ -174,24 +174,30 @@ export class RdDItemArme extends RdDItem {
|
||||
|
||||
static defenseArmeParade(armeAttaque, armeParade) {
|
||||
const defCategory = RdDItemArme.getCategorieParade(armeParade)
|
||||
if (defCategory == 'boucliers') {
|
||||
return 'norm'
|
||||
switch (defCategory) {
|
||||
case 'boucliers':
|
||||
return 'norm'
|
||||
case '':
|
||||
return 'impossible'
|
||||
}
|
||||
if (armeAttaque?.system?.competence?.toLowerCase().match(/(fléau)/)) {
|
||||
return ''
|
||||
}
|
||||
if (armeParade.system?.tir) {
|
||||
return ''
|
||||
if (RdDItemArme.$isFleau(armeAttaque)) {
|
||||
return 'impossible'
|
||||
}
|
||||
|
||||
const attCategory = RdDItemArme.getCategorieParade(armeAttaque)
|
||||
switch (attCategory) {
|
||||
case 'armes-naturelles': case 'sans-armes':
|
||||
return defCategory == 'sans-armes' ? 'norm' : ''
|
||||
case 'sans-armes':
|
||||
case 'armes-naturelles':
|
||||
return defCategory == attCategory ? 'norm' : 'impossible'
|
||||
default:
|
||||
return RdDItemArme.needParadeSignificative(armeAttaque, armeParade) ? 'sign' : 'norm'
|
||||
}
|
||||
}
|
||||
|
||||
static $isFleau(armeAttaque) {
|
||||
return armeAttaque?.system?.competence?.toLowerCase().match(/(fléau)/);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static needParadeSignificative(armeAttaque, armeParade) {
|
||||
if (!armeAttaque || !armeParade) {
|
||||
|
||||
@@ -104,7 +104,7 @@ export class Apprecier {
|
||||
|
||||
apprecier(callbacks = []) {
|
||||
if (this.qualite <= 0) {
|
||||
this.raisons.push(`la qualité ${this.qualite} est négative.`)
|
||||
this.raisons.push(`la qualité ${this.qualite} est insuffisante.`)
|
||||
}
|
||||
if (this.qualite <= this.actor.getMoralTotal()) {
|
||||
this.raisons.push(`la qualité de ${this.qualite} est inférieure au moral de ${this.actor.getMoralTotal()}.`)
|
||||
|
||||
@@ -775,7 +775,7 @@ export class RdDCombat {
|
||||
/* -------------------------------------------- */
|
||||
_prepareAttaque(competence, arme) {
|
||||
let rollData = {
|
||||
mode: ROLL_TYPE_ATTAQUE,
|
||||
mode: 'attaque',
|
||||
alias: this.attacker?.getAlias(),
|
||||
passeArme: foundry.utils.randomID(16),
|
||||
mortalite: arme?.system.mortalite,
|
||||
@@ -1378,6 +1378,7 @@ export class RdDCombat {
|
||||
return
|
||||
}
|
||||
const alias = token?.name ?? actor.getAlias();
|
||||
const blessuresGraves = actor.countBlessures(it => it.isGrave());
|
||||
const formData = {
|
||||
combatId: combat._id,
|
||||
alias: alias,
|
||||
@@ -1388,7 +1389,7 @@ export class RdDCombat {
|
||||
actorId: actor.id,
|
||||
actor: actor,
|
||||
tokenId: token.id,
|
||||
isGrave: actor.countBlessures(it => it.isGrave()) > 0,
|
||||
blessuresGraves: blessuresGraves,
|
||||
isCritique: actor.countBlessures(it => it.isCritique()) > 0
|
||||
}
|
||||
await ChatMessage.create({
|
||||
|
||||
@@ -49,9 +49,8 @@ export default class ChatRollResult {
|
||||
roll.active.actor,
|
||||
roll.current?.rollmode?.key
|
||||
)
|
||||
const save = RollDialog.saveParts(roll, impacts)
|
||||
|
||||
await this.saveChatMessageRoll(chatMessage, save)
|
||||
await this.saveChatMessageRoll(chatMessage, roll, impacts)
|
||||
return chatMessage
|
||||
}
|
||||
|
||||
@@ -166,8 +165,20 @@ export default class ChatRollResult {
|
||||
return roll.active?.actor ?? (roll.ids?.actorId ? game.actors.get(roll.ids.actorId) : undefined)
|
||||
}
|
||||
|
||||
async saveChatMessageRoll(chatMessage, savedRoll) {
|
||||
await ChatUtility.setMessageData(chatMessage, 'rollData', savedRoll)
|
||||
async updateChatMessage(chatMessage, savedRoll) {
|
||||
RollDialog.loadRollData(savedRoll)
|
||||
savedRoll.dmg = savedRoll.current.attaque?.dmg
|
||||
|
||||
await this.saveChatMessageRoll(chatMessage, savedRoll)
|
||||
|
||||
this.prepareDisplay(savedRoll)
|
||||
chatMessage.update({ content: await this.buildRollHtml(savedRoll) })
|
||||
chatMessage.render(true)
|
||||
}
|
||||
|
||||
async saveChatMessageRoll(chatMessage, roll, impacts = undefined) {
|
||||
const save = RollDialog.saveParts(roll, impacts)
|
||||
await ChatUtility.setMessageData(chatMessage, 'rollData', save)
|
||||
}
|
||||
|
||||
loadChatMessageRoll(chatMessage) {
|
||||
@@ -176,16 +187,6 @@ export default class ChatRollResult {
|
||||
return savedRoll
|
||||
}
|
||||
|
||||
async updateChatMessage(chatMessage, savedRoll) {
|
||||
await this.saveChatMessageRoll(chatMessage, savedRoll)
|
||||
const copy = foundry.utils.duplicate(savedRoll)
|
||||
RollDialog.loadRollData(copy)
|
||||
savedRoll.dmg = copy.current.attaque?.dmg
|
||||
this.prepareDisplay(copy)
|
||||
chatMessage.update({ content: await this.buildRollHtml(copy) })
|
||||
chatMessage.render(true)
|
||||
}
|
||||
|
||||
onClickAppelChance(event) {
|
||||
event.preventDefault()
|
||||
const chatMessage = ChatUtility.getChatMessage(event)
|
||||
@@ -197,28 +198,28 @@ export default class ChatRollResult {
|
||||
)
|
||||
}
|
||||
|
||||
async onAppelChanceSuccess(reRoll, chatMessage) {
|
||||
reRoll.type.retry = true
|
||||
await this.updateChatMessage(chatMessage, reRoll)
|
||||
async onAppelChanceSuccess(roll, chatMessage) {
|
||||
roll.type.retry = true
|
||||
await this.updateChatMessage(chatMessage, roll)
|
||||
|
||||
const callbacks = [ChatUtility.remover(chatMessage)]
|
||||
// TODO: annuler les effets...
|
||||
switch (reRoll.type.current) {
|
||||
switch (roll.type.current) {
|
||||
case ROLL_TYPE_DEFENSE:
|
||||
this.getCombat(reRoll)?.doRollDefense(reRoll, callbacks)
|
||||
this.getCombat(roll)?.doRollDefense(roll, callbacks)
|
||||
break
|
||||
case ROLL_TYPE_ATTAQUE:
|
||||
this.getCombat(reRoll)?.doRollAttaque(reRoll, callbacks)
|
||||
this.getCombat(roll)?.doRollAttaque(roll, callbacks)
|
||||
break
|
||||
default: {
|
||||
await RollDialog.create(reRoll, { onRollDone: RollDialog.onRollDoneClose, callbacks })
|
||||
await RollDialog.create(roll, { onRollDone: RollDialog.onRollDoneClose, callbacks })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async onAppelChanceEchec(reRoll, chatMessage) {
|
||||
reRoll.type.retry = true
|
||||
await this.updateChatMessage(chatMessage, reRoll)
|
||||
async onAppelChanceEchec(roll, chatMessage) {
|
||||
roll.type.retry = true
|
||||
await this.updateChatMessage(chatMessage, roll)
|
||||
}
|
||||
|
||||
onClickAppelDestinee(event) {
|
||||
@@ -229,10 +230,9 @@ export default class ChatRollResult {
|
||||
const actor = this.getActiveActor(savedRoll)
|
||||
|
||||
Misc.doIfOwner(actor, it => it.appelDestinee(async () => {
|
||||
const reRoll = foundry.utils.duplicate(savedRoll)
|
||||
reRoll.type.retry = true
|
||||
RdDResolutionTable.significativeRequise(reRoll.rolled)
|
||||
await this.updateChatMessage(chatMessage, reRoll)
|
||||
savedRoll.type.retry = true
|
||||
RdDResolutionTable.significativeRequise(savedRoll.rolled)
|
||||
await this.updateChatMessage(chatMessage, savedRoll)
|
||||
}))
|
||||
}
|
||||
|
||||
|
||||
@@ -42,7 +42,6 @@ import ChatRollResult from "./chat-roll-result.mjs";
|
||||
import { renderTemplate } from "../constants.js";
|
||||
import { RollTypeCuisine } from "./roll-type-cuisine.mjs";
|
||||
import { RollPartCuisine } from "./roll-part-cuisine.mjs";
|
||||
import { OptionsAvancees, ROLL_DIALOG_V2_TEST } from "../settings/options-avancees.js";
|
||||
import { ActorImpacts } from "../technical/actor-impacts.mjs";
|
||||
import { RollPartEmpoignade } from "./roll-part-empoignade.mjs";
|
||||
import { RollPartEmpoignadeTaille } from "./roll-part-empoignade-taille.mjs";
|
||||
@@ -199,9 +198,7 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2
|
||||
}
|
||||
|
||||
static onRollDoneClose(dialog, roll) {
|
||||
if (roll.type.retry || !OptionsAvancees.isUsing(ROLL_DIALOG_V2_TEST)) {
|
||||
dialog.close()
|
||||
}
|
||||
dialog.close()
|
||||
}
|
||||
|
||||
static init() { }
|
||||
@@ -289,6 +286,13 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2
|
||||
// rien pour l'instant
|
||||
}
|
||||
|
||||
static getAllowedParts(rollData) {
|
||||
return rollData.type?.allowed
|
||||
? ROLL_PARTS.filter(p => RollDialog.$isIntersecting(rollData.type.allowed, p.rollTypes))
|
||||
: ROLL_PARTS
|
||||
|
||||
}
|
||||
|
||||
/** pre-configure les paramètres des différentes parties de la fenêtre (par exemple, prépare les listes de caractéristiques/compétences */
|
||||
static $prepareRollData(rollData) {
|
||||
rollData.current = rollData.current ?? {}
|
||||
@@ -302,17 +306,17 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2
|
||||
? [potential]
|
||||
: (rollData.type.allowed ?? ALL_ROLL_TYPES.filter(m => m.isAllowed(rollData) && m.visible(rollData)).map(m => m.code) ?? [ROLL_TYPE_COMP])
|
||||
const rollType = allowed.find(c => c == rollData.type.current) ?? allowed[0]
|
||||
const allowedRollParts = RollDialog.getAllowedParts(rollData)
|
||||
|
||||
rollData.type.allowed = allowed
|
||||
rollData.type.current = rollType
|
||||
ALL_ROLL_TYPES.find(m => m.code == rollType).setRollDataType(rollData)
|
||||
|
||||
rollData.refs = foundry.utils.mergeObject(rollData.refs ?? {}, Object.fromEntries(ROLL_PARTS.map(p => [p.code, {}])));
|
||||
rollData.refs = foundry.utils.mergeObject(rollData.refs ?? {}, Object.fromEntries(allowedRollParts.map(p => [p.code, {}])));
|
||||
rollData.options = rollData.options ?? { rollMode: game.settings.get("core", "rollMode") }
|
||||
|
||||
ROLL_PARTS.forEach(p => RollDialog.$initializeRollPart(rollData, p.code))
|
||||
ROLL_PARTS
|
||||
.filter(p => RollDialog.$isIntersecting(allowed, p.rollTypes))
|
||||
allowedRollParts.forEach(p => RollDialog.$initializeRollPart(rollData, p.code))
|
||||
allowedRollParts
|
||||
.filter(p => p.isValid(rollData))
|
||||
.forEach(p => {
|
||||
p.restore(rollData)
|
||||
@@ -350,11 +354,13 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2
|
||||
}
|
||||
if (from.current) {
|
||||
// stockage de current
|
||||
ROLL_PARTS.filter(p => p.isActive(from))
|
||||
RollDialog.getAllowedParts(from)
|
||||
.filter(p => p.isActive(from))
|
||||
.forEach(p => p.storeClean(from, target))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const target = RollBasicParts.initFrom(rollData)
|
||||
saveBasics(rollData, target)
|
||||
if (impacts) {
|
||||
@@ -382,12 +388,14 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2
|
||||
onClose: rollOptions.onClose ?? RollDialog.onCloseDoNothing
|
||||
}
|
||||
this.chatRollResult = new ChatRollResult()
|
||||
this.rollParts = RollDialog.getAllowedParts(rollData)
|
||||
|
||||
this.selectType()
|
||||
this.registerHooks(rollData)
|
||||
}
|
||||
|
||||
registerHooks(rollData) {
|
||||
ROLL_PARTS.filter(p => p.isValid(rollData))
|
||||
this.rollParts.filter(p => p.isValid(rollData))
|
||||
.forEach(p => p.getHooks(this).forEach(h => {
|
||||
const hook = h.hook;
|
||||
const id = Hooks.on(hook, h.fn)
|
||||
@@ -407,13 +415,12 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2
|
||||
selectedType.onSelect(this.rollData)
|
||||
this.rollData.type.label = selectedType.title(this.rollData)
|
||||
|
||||
ROLL_PARTS.find(it => it.code == PART_CARAC).filterCaracs(this.rollData)
|
||||
ROLL_PARTS.find(it => it.code == PART_COMP).filterComps(this.rollData)
|
||||
this.rollParts.find(it => it.code == PART_CARAC).filterCaracs(this.rollData)
|
||||
this.rollParts.find(it => it.code == PART_COMP).filterComps(this.rollData)
|
||||
}
|
||||
|
||||
|
||||
static getActiveParts(rollData) {
|
||||
return ROLL_PARTS.filter(p => p.isActive(rollData))
|
||||
getActiveParts() {
|
||||
return this.rollParts.filter(p => p.isActive(this.rollData))
|
||||
}
|
||||
|
||||
rollTitle(rollData) {
|
||||
@@ -448,12 +455,13 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2
|
||||
))
|
||||
|
||||
Promise.all(
|
||||
RollDialog.getActiveParts(this.rollData).map(async p => await p._onRender(this, context, options))
|
||||
this.getActiveParts().map(async p => await p._onRender(this, context, options))
|
||||
)
|
||||
}
|
||||
|
||||
static getAjustements(rollData) {
|
||||
return RollDialog.getActiveParts(rollData)
|
||||
return RollDialog.getAllowedParts(rollData)
|
||||
.filter(p => p.isActive(rollData))
|
||||
.map(p => p.getAjustements(rollData))
|
||||
.reduce((a, b) => a.concat(b))
|
||||
.sort((a, b) => a.value == undefined ? 1 : b.value == undefined ? -1 : 0)
|
||||
@@ -470,8 +478,8 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2
|
||||
.map(m => m.toTypeData(rollData))
|
||||
RollBasicParts.loadSurprises(rollData, this.getSelectedType().code)
|
||||
rollData.type.label = this.getSelectedType()?.title(rollData)
|
||||
//TOCHECK: set type.label ?
|
||||
const visibleRollParts = RollDialog.getActiveParts(rollData)
|
||||
|
||||
const visibleRollParts = this.getActiveParts()
|
||||
visibleRollParts.forEach(p => p.applyExternalImpacts(visibleRollParts, rollData))
|
||||
|
||||
this.setSpecialComp(visibleRollParts);
|
||||
@@ -480,7 +488,7 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2
|
||||
|
||||
RollDialog.calculAjustement(rollData)
|
||||
|
||||
const templates = RollDialog.getActiveParts(rollData).map(p => p.toTemplateData())
|
||||
const templates = visibleRollParts.map(p => p.toTemplateData())
|
||||
const context = await super._prepareContext()
|
||||
return foundry.utils.mergeObject(
|
||||
{
|
||||
@@ -494,8 +502,7 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2
|
||||
const specialComp = visibleRollParts.map(p => p.getSpecialComp(this.rollData))
|
||||
.reduce((a, b) => a.concat(b))
|
||||
if (specialComp.length > 0) {
|
||||
const rollPartComp = RollDialog.getActiveParts(this.rollData)
|
||||
.find(it => it.code == PART_COMP);
|
||||
const rollPartComp = this.getActiveParts().find(it => it.code == PART_COMP)
|
||||
rollPartComp?.setSpecialComp(this.rollData, specialComp)
|
||||
}
|
||||
}
|
||||
@@ -535,12 +542,15 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2
|
||||
roll.result = selectedRollType.getResult(roll, impacts)
|
||||
|
||||
console.info('RollDialog.roll:', roll)
|
||||
|
||||
const callbacks = [
|
||||
...this.rollOptions.callbacks,
|
||||
...selectedRollType.callbacks(this.rollOptions),
|
||||
...this.rollOptions.callbacks,
|
||||
]
|
||||
|
||||
await Promise.all(callbacks.map(async callback => await callback(roll)))
|
||||
for (let callback of callbacks) {
|
||||
await callback(roll)
|
||||
}
|
||||
|
||||
await impacts.applyImpacts()
|
||||
selectedRollType.onApplyImpacts(roll, impacts)
|
||||
|
||||
@@ -46,19 +46,25 @@ export class RollPartAttaque extends RollPartSelect {
|
||||
return it.arme.isEmpoignade()
|
||||
}
|
||||
|
||||
store(rollData, targetData) {
|
||||
super.store(rollData, targetData)
|
||||
this.getSaved(targetData).dmg = this.getCurrent(rollData).dmg
|
||||
restore(rollData) {
|
||||
const saved = this.getSaved(rollData) ?? {}
|
||||
this.setCurrent(rollData, {
|
||||
key: saved.key,
|
||||
tactique: saved.tactique,
|
||||
dmg: saved.dmg
|
||||
})
|
||||
}
|
||||
|
||||
restore(rollData) {
|
||||
const saved = this.getSaved(rollData)
|
||||
super.restore(rollData)
|
||||
if (saved.dmg != undefined) {
|
||||
this.getCurrent(rollData).dmg = this.getSaved(rollData).dmg
|
||||
}
|
||||
store(rollData, targetData) {
|
||||
const current = this.getCurrent(rollData)
|
||||
this.setSaved(targetData, {
|
||||
key: current.key,
|
||||
tactique: current.tactique,
|
||||
dmg: current.dmg
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
findAttaque(attaques, saved) {
|
||||
return attaques.find(at => at.arme.id == saved?.arme?.id &&
|
||||
at.comp.id == saved?.comp?.id
|
||||
@@ -102,7 +108,11 @@ export class RollPartAttaque extends RollPartSelect {
|
||||
|
||||
|
||||
$selectAttaque(rollData, key) {
|
||||
const tactique = this.getCurrent(rollData).tactique
|
||||
this.selectByKey(rollData, key)
|
||||
if (tactique) {
|
||||
this.getCurrent(rollData).tactique = tactique
|
||||
}
|
||||
}
|
||||
|
||||
async _onRender(rollDialog, context, options) {
|
||||
|
||||
@@ -36,7 +36,7 @@ export class RollPartDefense extends RollPartSelect {
|
||||
: defenseur.getCompetencesEsquive()
|
||||
const parades = isEmpoignade
|
||||
? [RdDItemArme.empoignade(defenseur)]
|
||||
: defenseur.items.filter(it => it.isParade() && (!refs.distance || it.isBouclier()))
|
||||
: this.$getParades(defenseur, attackerRoll, refs.distance)
|
||||
|
||||
refs.defenses = [
|
||||
...esquives.map(it => RollPartDefense.$extractEsquive(it, defenseur, attackerRoll)),
|
||||
@@ -45,6 +45,14 @@ export class RollPartDefense extends RollPartSelect {
|
||||
this.$selectDefense(rollData)
|
||||
}
|
||||
|
||||
$getParades(defenseur, attackerRoll, distance) {
|
||||
const parades = defenseur.items.filter(it => it.isParade() && (!distance || it.isBouclier()))
|
||||
const armeAttaque = attackerRoll?.current?.attaque?.arme
|
||||
return armeAttaque
|
||||
? parades.filter(armeDefense => RdDItemArme.defenseArmeParade(armeAttaque, armeDefense) != 'impossible')
|
||||
: parades
|
||||
}
|
||||
|
||||
static $extractEsquive(esquive, defenseur, attackerRoll) {
|
||||
const defense = {
|
||||
key: esquive.id,
|
||||
@@ -124,19 +132,19 @@ export class RollPartDefense extends RollPartSelect {
|
||||
case PART_CARAC: return part.filterCaracs(rollData, refs.defenses.length > 0 ? [current.carac] : ['impossible'])
|
||||
case PART_COMP: return part.filterComps(rollData, refs.defenses.length > 0 ? [current.comp?.name] : ['impossible'])
|
||||
case PART_DIFF: return part.setDiff(rollData, this.getDiffDefense(rollData))
|
||||
case PART_SIGN: return part.setArme(rollData, this.isArmeDisparate(rollData), current.forceRequise)
|
||||
case PART_SIGN: return part.setArme(rollData, this.getArmeDisparate(rollData), current.forceRequise)
|
||||
}
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
|
||||
isArmeDisparate(rollData) {
|
||||
getArmeDisparate(rollData) {
|
||||
const armeDefense = this.getCurrent(rollData).arme
|
||||
if (armeDefense) {
|
||||
const armeAttaque = rollData.attackerRoll?.current.attaque.arme
|
||||
return RdDItemArme.defenseArmeParade(armeAttaque, armeDefense) == 'sign'
|
||||
return RdDItemArme.defenseArmeParade(armeAttaque, armeDefense)
|
||||
}
|
||||
return false
|
||||
return 'norm'
|
||||
}
|
||||
|
||||
getDiffDefense(rollData) {
|
||||
|
||||
@@ -29,4 +29,17 @@ export class RollPartRollMode extends RollPart {
|
||||
rollDialog.render()
|
||||
}))
|
||||
}
|
||||
|
||||
getHooks(rollDialog) {
|
||||
return [
|
||||
{ hook: "clientSettingChanged", fn: (setting, update, options, id) => this.onUpdateSetting(rollDialog, setting, update, options, id) },
|
||||
]
|
||||
}
|
||||
|
||||
async onUpdateSetting(rollDialog, setting, update, options, id) {
|
||||
if (setting == 'core.rollMode') {
|
||||
this.setCurrent(rollDialog.rollData, { key: game.settings.get("core", "rollMode") })
|
||||
rollDialog.render()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ export class RollPartSign extends RollPart {
|
||||
const actor = rollData.active.actor;
|
||||
const isCombat = this.isCombat(rollData)
|
||||
const current = this.getCurrent(rollData)
|
||||
current.armeDisparate = isCombat && current.armeDisparate
|
||||
current.armeDisparate = isCombat ? current.armeDisparate : 'norm'
|
||||
current.surprise = actor.getSurprise(isCombat, current.forceRequise ?? 0)
|
||||
current.reasons = actor.getEffects(it => StatusEffects.niveauSurprise(it, isCombat) > 0, current.forceRequise ?? 0)
|
||||
.map(it => { return { img: it.img, label: game.i18n.localize(it.name) } })
|
||||
@@ -81,7 +81,7 @@ export class RollPartSign extends RollPart {
|
||||
}
|
||||
|
||||
isParadeArmeDisparate(current) {
|
||||
return current.armeDisparate
|
||||
return current.armeDisparate == 'sign'
|
||||
}
|
||||
|
||||
getAjustements(rollData) {
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { ITEM_TYPES } from "../constants.js"
|
||||
import { ReglesOptionnelles } from "../settings/regles-optionnelles.js"
|
||||
import { DIFF, ROLL_TYPE_TACHE } from "./roll-constants.mjs"
|
||||
import { PART_TACHE } from "./roll-part-tache.mjs"
|
||||
@@ -19,25 +18,22 @@ export class RollTypeTache extends RollType {
|
||||
this.setDiffType(rollData, DIFF.AUCUN)
|
||||
}
|
||||
|
||||
callbacks(rollOptions) { return [ async r => await RollTypeTache.$onRollTache(r, rollOptions)] }
|
||||
callbacks(rollOptions) { return [async r => await RollTypeTache.$onRollTache(r)] }
|
||||
|
||||
static async $onRollTache(rollData, rollOptions) {
|
||||
static async $onRollTache(rollData) {
|
||||
const actor = rollData.active.actor
|
||||
const tache = rollData.current[PART_TACHE].tache
|
||||
if (ReglesOptionnelles.isUsing("appliquer-fatigue")) {
|
||||
await actor.santeIncDec("fatigue", tache.system.fatigue)
|
||||
}
|
||||
|
||||
rollData.current[PART_TACHE].tache = await tache.update({
|
||||
'system.points_de_tache_courant': tache.system.points_de_tache_courant + rollData.rolled.ptTache,
|
||||
'system.nb_jet_succes': tache.system.nb_jet_succes + (rollData.rolled.isSuccess ? 1 : 0),
|
||||
'system.nb_jet_echec': tache.system.nb_jet_echec + (rollData.rolled.isSuccess ? 0 : 1),
|
||||
'system.difficulte': tache.system.difficulte - (rollData.rolled.isETotal ? 1 : 0),
|
||||
}, {render:true})
|
||||
}, { render: true })
|
||||
|
||||
|
||||
if (rollOptions?.onRollAutomate) {
|
||||
await rollOptions.onRollAutomate(rollData)
|
||||
if (ReglesOptionnelles.isUsing("appliquer-fatigue")) {
|
||||
await actor.santeIncDec("fatigue", tache.system.fatigue)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -63,5 +63,5 @@ export class RollType {
|
||||
* @returns undefined ou une structure contenant les informations requise pour afficher
|
||||
*/
|
||||
getResult(rollData, impacts) { return { messages: [] } }
|
||||
onApplyImpacts(roll, impacts) { }
|
||||
onApplyImpacts(rollData, impacts) { }
|
||||
}
|
||||
|
||||
@@ -3,11 +3,9 @@ import { Misc } from "../misc.js"
|
||||
|
||||
export const EXPORT_CSV_SCRIPTARIUM = 'export-csv-scriptarium'
|
||||
export const ROLL_DIALOG_V2 = 'roll-dialog-v2'
|
||||
export const ROLL_DIALOG_V2_TEST = 'roll-dialog-v2-test'
|
||||
|
||||
const OPTIONS_AVANCEES = [
|
||||
{ group: 'Fenêtres', name: ROLL_DIALOG_V2, descr: "Utiliser les nouvelles fenêtres de jet", default: false },
|
||||
{ group: 'Fenêtres', name: ROLL_DIALOG_V2_TEST, descr: "Mode de test des nouvelles fenêtres", default: false },
|
||||
{ group: 'Menus', name: EXPORT_CSV_SCRIPTARIUM, descr: "Proposer le menu d'export csv Scriptarium", default: false },
|
||||
]
|
||||
|
||||
|
||||
@@ -3,11 +3,12 @@
|
||||
</h4>
|
||||
<p data-combatid="{{combatId}}" data-combatmessage="actor-turn-summary">{{blessuresStatus}}</p>
|
||||
<p>Son état général est de : {{etatGeneral}} {{#if isSonne}} et est <strong>sonné</strong>{{/if}}</p>
|
||||
{{#if isGrave}}
|
||||
<p>{{alias}} souffre de Blessure(s) Grave(s) : n'oubliez pas de faire un Jet de Vie toutes les SC ({{SConst}}) minutes. Un point d'Endurance a été retiré automatiquement.</p>
|
||||
{{#if blessuresGraves}}
|
||||
<p>{{alias}} souffre {{#if (eq blessuresGraves 1)}}d'une <strong>blessure grave</strong>{{else}}
|
||||
de {{blessuresGraves}} <strong>blessures graves</strong>{{/if}} : n'oubliez pas de faire un Jet de Vie toutes les SC ({{SConst}}) minutes. Les pertes d'endurance sont automatiques à la fin du round.</p>
|
||||
{{/if}}
|
||||
{{#if isCritique}}
|
||||
<p>{{alias}} souffre d'une <strong>Blessure Critique</strong> : faites un
|
||||
<p>{{alias}} souffre d'une <strong>blessure critique</strong> : faites un
|
||||
<a class="chat-card-button chat-jet-vie"
|
||||
data-tokenId="{{tokenId}}"
|
||||
data-actorId="{{actorId}}">Jet de Vie.<a></p>
|
||||
|
||||
@@ -11,8 +11,13 @@
|
||||
{{#if (eq active.surprise.key 'totale')}}
|
||||
<span><strong>{{active.name}}</strong> est totalement surpris</span>
|
||||
{{else}}
|
||||
{{log 'attackerRoll' attackerRoll}}
|
||||
<span><strong>{{active.name}}</strong> doit se défendre
|
||||
{{~#if (eq active.surprise.key 'demi')}} avec une significative {{/if}} d'une attaque
|
||||
{{~#if (eq active.surprise.key 'demi')}} avec une significative {{/if}} d'une
|
||||
{{#if (eq attackerRoll.current.attaque.tactique.key 'charge')}}charge
|
||||
{{else if (eq attackerRoll.current.attaque.tactique.key 'feinte')}}feinte
|
||||
{{else}}attaque
|
||||
{{/if}}
|
||||
{{~#if attackerRoll.particuliere}} <strong>particulière en
|
||||
{{~#if (eq attackerRoll.particuliere 'finesse')}} finesse
|
||||
{{else if (eq attackerRoll.particuliere 'force')}} force
|
||||
|
||||
@@ -8,9 +8,9 @@
|
||||
<hr>
|
||||
<span>
|
||||
{{#if jetVie.rolled.isSuccess}}
|
||||
{{alias}} a réussi son jet d'éthylisme, il a consommé {{doses}} doses sans effet.
|
||||
{{alias}} a réussi son jet d'éthylisme, {{doses}} doses ont été consommées sans effet.
|
||||
{{else}}
|
||||
{{alias}} a échoué son jet d'éthylisme, il est maintenant {{nomEthylisme}} ({{ajustementEthylique}}).
|
||||
{{alias}} a échoué son jet d'éthylisme et est maintenant {{nomEthylisme}} ({{ajustementEthylique}}).
|
||||
{{/if}}
|
||||
</span>
|
||||
{{#if jetVie.rolled.isEchec}}
|
||||
@@ -19,8 +19,8 @@
|
||||
{{alias}} perd {{perteEndurance.perte}} points d'endurance. {{#if perteEndurance.perteVie}}<br/>Il tombe inconscient et perd un point de vie.{{/if}}
|
||||
{{#if jetMoral}}
|
||||
<br/>Jet de moral {{#if jetMoral.succes}}réussi{{else}}manqué{{/if}} en situation heureuse ({{jetMoral.jet}}/{{jetMoral.difficulte}}).
|
||||
{{#if (gt jetMoral.ajustement 0)}}L'alcool met {{alias}} en joie. Il gagne un point de moral.
|
||||
{{else if (lt jetMoral.ajustement 0)}}{{alias}} a l'alcool triste. Il perd un point de moral.
|
||||
{{#if (gt jetMoral.ajustement 0)}}L'alcool met en joie {{alias}} qui gagne un point de moral.
|
||||
{{else if (lt jetMoral.ajustement 0)}}{{alias}} a l'alcool triste et perd un point de moral.
|
||||
{{else}}{{alias}} garde son moral.{{/if}}
|
||||
{{/if}}
|
||||
</span>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
{{active.name}} fait un jet
|
||||
{{#if current.comp.key}}de {{current.comp.label}}{{/if}}
|
||||
{{#if type.appreciation}}d'appréciation
|
||||
{{else if (ne current.comp.key '')}}sans compétence
|
||||
{{else if (eq current.comp.key '')}}sans compétence
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user