Fix: protection sur actions sans acteur/propriété

Cas rencontré une fois, un jet de chance d'un autre
joueur, pouvait être tenté.

Cas plus étrange, un jet de chance alors que le jet sauvegardé
n'avait pas d'actorId
This commit is contained in:
2025-12-09 23:35:27 +01:00
parent 894161c0bf
commit 697247e931
4 changed files with 65 additions and 44 deletions

View File

@@ -9,7 +9,7 @@ import { ReglesOptionnelles } from "./settings/regles-optionnelles.js";
import { RdDSheetUtility } from "./rdd-sheet-utility.js";
import { MAINS_DIRECTRICES } from "./actor.js";
import { RdDBaseActorReveSheet } from "./actor/base-actor-reve-sheet.js";
import { ITEM_TYPES } from "./constants.js";
import { ACTOR_TYPES, ITEM_TYPES } from "./constants.js";
import { RdDItem } from "./item.js";
import { RdDItemCompetence } from "./item-competence.js";
import { RdDItemBlessure } from "./item/blessure.js";
@@ -58,7 +58,7 @@ export class RdDActorSheet extends RdDBaseActorSangSheet {
this.timerRecherche = undefined;
if (formData.type == 'personnage') {
if (formData.type == ACTOR_TYPES.personnage) {
formData.options.mainsDirectrices = MAINS_DIRECTRICES;
formData.byCateg = Misc.classify(formData.competences, it => it.system.categorie)
formData.calc.comptageArchetype = RdDItemCompetence.computeResumeArchetype(formData.competences);

View File

@@ -233,16 +233,16 @@ export class Misc {
if (Misc.isOwnerPlayer(document)) {
return await action(document)
} else {
return await orElse(document)
return await orElse(document ?? {name: '<aucune sélection>'})
}
}
static isOwnerPlayer(document) {
return document.testUserPermission && document.testUserPermission(game.user, CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER)
return document && document.testUserPermission && document.testUserPermission(game.user, CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER)
}
static isFirstOwnerPlayer(document) {
if (!document.testUserPermission) {
if (!document?.testUserPermission) {
return false
}
return game.users.find(u => document.testUserPermission(u, CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER)) == game.user

View File

@@ -1084,7 +1084,7 @@ export class RdDCombat {
}
async defenseV2(attackerRoll, callbacks = []) {
// this._prepareParade(attackerRoll, arme, competence);
await this.doRollDefense({
ids: {
actorId: this.defender.id,

View File

@@ -162,12 +162,18 @@ export default class ChatRollResult {
return undefined
}
getActiveActor(roll) {
return roll.active?.actor ?? (roll.ids?.actorId ? game.actors.get(roll.ids.actorId) : undefined)
}
async saveChatMessageRoll(chatMessage, savedRoll) {
await ChatUtility.setMessageData(chatMessage, 'rollData', savedRoll)
}
loadChatMessageRoll(chatMessage) {
return ChatUtility.getMessageData(chatMessage, 'rollData')
const savedRoll = ChatUtility.getMessageData(chatMessage, 'rollData')
RollBasicParts.restore(savedRoll)
return savedRoll
}
async updateChatMessage(chatMessage, savedRoll) {
@@ -184,7 +190,7 @@ export default class ChatRollResult {
event.preventDefault()
const chatMessage = ChatUtility.getChatMessage(event)
const savedRoll = this.loadChatMessageRoll(chatMessage)
const actor = game.actors.get(savedRoll.ids.actorId)
const actor = this.getActiveActor(savedRoll)
Misc.doIfOwner(actor, it => it.rollAppelChance(
() => this.onAppelChanceSuccess(savedRoll, chatMessage),
() => this.onAppelChanceEchec(savedRoll, chatMessage))
@@ -193,7 +199,6 @@ export default class ChatRollResult {
async onAppelChanceSuccess(savedRoll, chatMessage) {
const reRoll = foundry.utils.duplicate(savedRoll)
console.log('onAppelChanceSuccess savedRoll', savedRoll)
reRoll.type.retry = true
await this.updateChatMessage(chatMessage, reRoll)
const callbacks = [ChatUtility.remover(chatMessage)]
@@ -222,7 +227,7 @@ export default class ChatRollResult {
const chatMessage = ChatUtility.getChatMessage(event)
const savedRoll = this.loadChatMessageRoll(chatMessage)
const actor = game.actors.get(savedRoll.ids.actorId)
const actor = this.getActiveActor(savedRoll)
Misc.doIfOwner(actor, it => it.appelDestinee(async () => {
const reRoll = foundry.utils.duplicate(savedRoll)
@@ -235,36 +240,41 @@ export default class ChatRollResult {
async onClickDefense(event) {
const chatMessage = ChatUtility.getChatMessage(event)
const savedRoll = this.loadChatMessageRoll(chatMessage)
RollBasicParts.restore(savedRoll)
const actor = this.getActiveActor(savedRoll)
Misc.doIfOwner(actor, it => {
const attackerRoll = savedRoll.attackerRoll
RollDialog.loadRollData(attackerRoll)
this.getCombat(attackerRoll)?.defenseV2(attackerRoll,
[ChatUtility.remover(chatMessage)]
)
})
}
async onClickDefensePossession(event) {
const chatMessage = ChatUtility.getChatMessage(event)
const savedRoll = this.loadChatMessageRoll(chatMessage)
await RdDPossessionV2.rollDefensePossession(savedRoll, chatMessage)
const actor = this.getActiveActor(savedRoll)
Misc.doIfOwner(actor, it => RdDPossessionV2.rollDefensePossession(savedRoll, chatMessage))
}
async onClickMarquerPointPossession(event) {
const chatMessage = ChatUtility.getChatMessage(event)
const savedRoll = this.loadChatMessageRoll(chatMessage)
RollBasicParts.restore(savedRoll)
const actor = this.getActiveActor(savedRoll)
Misc.doIfOwner(actor, async it => {
await RdDPossessionV2.onMarquerPointPossession(savedRoll)
ChatUtility.remover(chatMessage)()
})
}
async onClickEncaissement(event) {
const chatMessage = ChatUtility.getChatMessage(event)
const isMessageDemande = ChatUtility.getMessageData(chatMessage, 'demande-defense')
const savedRoll = this.loadChatMessageRoll(chatMessage)
const actor = this.getActiveActor(savedRoll)
Misc.doIfOwner(actor, async defender => {
const defenderToken = savedRoll.active.token
const attaque = savedRoll.attackerRoll
const defenderToken = savedRoll.ids.actorTokenId ? canvas.tokens.get(savedRoll.ids.actorTokenId) : undefined
const defender = defenderToken?.actor ?? game.actors.get(savedRoll.ids.actorId)
Misc.doIfOwner(defender, async defender => {
const attackerToken = savedRoll.ids.opponentTokenId ? canvas.tokens.get(savedRoll.ids.opponentTokenId) : undefined
const attacker = attackerToken?.actor ?? game.actors.get(savedRoll.ids.opponentId)
switch (attaque.dmg.mortalite) {
@@ -290,9 +300,8 @@ export default class ChatRollResult {
async onClickRecul(event) {
const chatMessage = ChatUtility.getChatMessage(event)
const savedRoll = this.loadChatMessageRoll(chatMessage)
// TODO: gestion sur token non liés?
const defender = game.actors.get(savedRoll.ids.actorId)
Misc.doIfOwner(defender, async defender => {
const actor = this.getActiveActor(savedRoll)
Misc.doIfOwner(actor, async defender => {
const attacker = game.actors.get(savedRoll.ids.opponentId)
savedRoll.done.recul = await defender.encaisserRecul(attacker.getForce(), savedRoll.attackerRoll.dmg.dmgArme)
await this.updateChatMessage(chatMessage, savedRoll)
@@ -303,42 +312,54 @@ export default class ChatRollResult {
const choix = event.currentTarget.attributes['data-particuliere'].value
const chatMessage = ChatUtility.getChatMessage(event)
const savedRoll = this.loadChatMessageRoll(chatMessage)
const actor = this.getActiveActor(savedRoll)
Misc.doIfOwner(actor, async it => {
savedRoll.particuliere = choix
savedRoll.particulieres = [RDD_CONFIG.particuliere[choix]]
await this.updateChatMessage(chatMessage, savedRoll)
await this.getCombat(savedRoll)?.onAttaqueV2(savedRoll)
})
}
async onClickFaireGouter(event) {
const chatMessage = ChatUtility.getChatMessage(event)
const savedRoll = this.loadChatMessageRoll(chatMessage)
const actor = this.getActiveActor(savedRoll)
Misc.doIfOwner(actor, async it => {
if (!savedRoll.type.retry) {
savedRoll.type.retry = true
await this.updateChatMessage(chatMessage, savedRoll)
}
await new RollTypeCuisine().onFaireGouter(savedRoll)
})
}
async onClickApprecier(event) {
const chatMessage = ChatUtility.getChatMessage(event)
const savedRoll = this.loadChatMessageRoll(chatMessage)
await Apprecier.onClickApprecier(savedRoll)
Apprecier.onClickApprecier(savedRoll)
}
async onClickMonteeTMR(event, mode) {
const chatMessage = ChatUtility.getChatMessage(event)
const savedRoll = this.loadChatMessageRoll(chatMessage)
const actor = this.getActiveActor(savedRoll)
Misc.doIfOwner(actor, async it => {
if (await new RollTypeMeditation().onMonteeTMR(savedRoll, mode)) {
savedRoll.done.meditation = true
await this.updateChatMessage(chatMessage, savedRoll)
}
})
}
async onClickTirerMaladresse(event) {
const chatMessage = ChatUtility.getChatMessage(event)
const typeMaladresse = event.currentTarget.attributes['data-maladresse'].value
const savedRoll = this.loadChatMessageRoll(chatMessage)
const actor = this.getActiveActor(savedRoll)
Misc.doIfOwner(actor, async it => {
savedRoll.maladresse = await RdDRollTables.getMaladresse({ arme: typeMaladresse == 'avec-arme', toChat: false })
savedRoll.type.retry = true
await this.updateChatMessage(chatMessage, savedRoll)
})
}
}