Améliorations combat #532
@ -1,5 +1,7 @@
|
||||
import { Misc } from "./misc.js";
|
||||
import { SYSTEM_SOCKET_ID } from "./constants.js";
|
||||
import { SYSTEM_RDD, SYSTEM_SOCKET_ID } from "./constants.js";
|
||||
|
||||
export const MESSAGE_DATA = 'message-data';
|
||||
|
||||
/**
|
||||
* Class providing helper methods to get the list of users, and
|
||||
@ -160,4 +162,20 @@ export class ChatUtility {
|
||||
}
|
||||
}
|
||||
|
||||
static async setMessageData(chatMessage, key, data) {
|
||||
if (data) {
|
||||
await chatMessage.setFlag(SYSTEM_RDD, key, JSON.stringify(data));
|
||||
}
|
||||
}
|
||||
|
||||
static getMessageData(chatMessage, key) {
|
||||
const json = chatMessage.getFlag(SYSTEM_RDD, key);
|
||||
return json ? JSON.parse(json) : undefined;
|
||||
}
|
||||
|
||||
static getChatMessage(event) {
|
||||
const chatMessageId = $(event.currentTarget).closest('.chat-message').attr('data-message-id');
|
||||
return game.messages.get(chatMessageId);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -371,19 +371,10 @@ export class RdDCombatManager extends Combat {
|
||||
export class RdDCombat {
|
||||
|
||||
static init() {
|
||||
this.initStorePasseArmes();
|
||||
Hooks.on("updateCombat", (combat, change, options, userId) => { RdDCombat.onUpdateCombat(combat, change, options, userId) });
|
||||
Hooks.on("preDeleteCombat", (combat, options, userId) => { RdDCombat.onPreDeleteCombat(combat, options, userId); });
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static initStorePasseArmes() {
|
||||
game.system.rdd.combatStore = {
|
||||
attaques: {},
|
||||
defenses: {}
|
||||
};
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static onSocketMessage(sockmsg) {
|
||||
switch (sockmsg.msg) {
|
||||
@ -391,8 +382,6 @@ export class RdDCombat {
|
||||
return RdDCombat.onMsgEncaisser(sockmsg.data);
|
||||
case "msg_defense":
|
||||
return RdDCombat.onMsgDefense(sockmsg.data);
|
||||
case "msg_combat_passearme":
|
||||
return RdDCombat.onMsgPasseArme(sockmsg.data);
|
||||
}
|
||||
}
|
||||
|
||||
@ -405,22 +394,11 @@ export class RdDCombat {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static onPreDeleteCombat(combat, options, userId) {
|
||||
if (game.user.isGM) {
|
||||
if (Misc.isUniqueConnectedGM()) {
|
||||
combat.cleanItemUse();
|
||||
ChatUtility.removeChatMessageContaining(`<div data-combatid="${combat.id}" data-combatmessage="actor-turn-summary">`)
|
||||
/*
|
||||
* TODO: support de plusieurs combats parallèles
|
||||
* il faudrait avoir un id de combat en plus de celui de passe d'armes
|
||||
*/
|
||||
for (const key in game.system.rdd.combatStore.attaques) {
|
||||
const attackerRoll = game.system.rdd.combatStore.attaques[key];
|
||||
ChatUtility.removeChatMessageContaining(`<div data-passearme="${attackerRoll.passeArme}">`);
|
||||
}
|
||||
for (const key in game.system.rdd.combatStore.defenses) {
|
||||
const defenderRoll = game.system.rdd.combatStore.defenses[key];
|
||||
ChatUtility.removeChatMessageContaining(`<div data-passearme="${defenderRoll.passeArme}">`);
|
||||
}
|
||||
RdDCombat.initStorePasseArmes();
|
||||
game.messages.filter(m => ChatUtility.getMessageData(m, 'attacker-roll') != undefined && ChatUtility.getMessageData(m, 'defender-roll') != undefined)
|
||||
.forEach(it => it.delete());
|
||||
}
|
||||
}
|
||||
|
||||
@ -471,61 +449,6 @@ export class RdDCombat {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static messagePasseArme(data) {
|
||||
// TODO: store required info for combat in the chat message presenting choices?
|
||||
game.socket.emit(SYSTEM_SOCKET_ID, { msg: "msg_combat_passearme", data: data });
|
||||
RdDCombat.onMsgPasseArme(data);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static onMsgPasseArme(data) {
|
||||
switch (data.actionPasseArme) {
|
||||
case "store-attaque":
|
||||
game.system.rdd.combatStore.attaques[data.id] = data.rollData;
|
||||
break;
|
||||
case "store-defense":
|
||||
game.system.rdd.combatStore.defenses[data.id] = data.rollData;
|
||||
break;
|
||||
case "delete-attaque":
|
||||
delete game.system.rdd.combatStore.attaques[data.id];
|
||||
break;
|
||||
case "delete-defense":
|
||||
delete game.system.rdd.combatStore.defenses[data.id];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static _storeAttaque(attackerId, attackerRoll) {
|
||||
RdDCombat.messagePasseArme({ actionPasseArme: "store-attaque", id: attackerId, rollData: attackerRoll });
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static _getAttaque(attackerId) {
|
||||
return game.system.rdd.combatStore.attaques[attackerId];
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static _deleteAttaque(attackerId) {
|
||||
RdDCombat.messagePasseArme({ actionPasseArme: "delete-attaque", id: attackerId });
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static _storeDefense(passeArme, defenderRoll) {
|
||||
RdDCombat.messagePasseArme({ actionPasseArme: "store-defense", id: passeArme, rollData: defenderRoll });
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static _getDefense(passeArme) {
|
||||
return game.system.rdd.combatStore.defenses[passeArme];
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static _deleteDefense(passeArme) {
|
||||
RdDCombat.messagePasseArme({ actionPasseArme: "delete-defense", id: passeArme });
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static create(attacker, defender, defenderTokenId, target = undefined) {
|
||||
return new RdDCombat(attacker, defender, defenderTokenId, target)
|
||||
@ -547,7 +470,7 @@ export class RdDCombat {
|
||||
static onMsgEncaisser(data) {
|
||||
let defender = canvas.tokens.get(data.defenderTokenId).actor;
|
||||
if (Misc.isOwnerPlayerOrUniqueConnectedGM()) {
|
||||
let attackerRoll = RdDCombat._getAttaque(data.attackerId); // Retrieve the rolldata from the store
|
||||
let attackerRoll = data.attackerRoll;
|
||||
let attacker = data.attackerId ? game.actors.get(data.attackerId) : null;
|
||||
|
||||
defender.encaisserDommages(attackerRoll, attacker);
|
||||
@ -563,10 +486,8 @@ export class RdDCombat {
|
||||
const rddCombat = RdDCombat.createForAttackerAndDefender(msg.attackerId, msg.defenderTokenId);
|
||||
if (rddCombat) {
|
||||
const defenderRoll = msg.defenderRoll;
|
||||
RdDCombat._storeAttaque(msg.attackerId, defenderRoll.attackerRoll);
|
||||
RdDCombat._storeDefense(defenderRoll.passeArme, defenderRoll);
|
||||
rddCombat.removeChatMessageActionsPasseArme(defenderRoll.passeArme);
|
||||
rddCombat._chatMessageDefense(msg.paramChatDefense);
|
||||
rddCombat._chatMessageDefense(msg.paramChatDefense, msg.defenderRoll);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -621,12 +542,10 @@ export class RdDCombat {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async onEvent(button, event) {
|
||||
const attackerRoll = RdDCombat._getAttaque(this.attackerId);
|
||||
if (!attackerRoll) {
|
||||
ui.notifications.warn("Action automatisée impossible, le jet de l'attaquant a été perdu (suite à un raffraichissement?)")
|
||||
return;
|
||||
}
|
||||
const defenderRoll = game.system.rdd.combatStore.defenses[attackerRoll.passeArme];
|
||||
const chatMessage = ChatUtility.getChatMessage(event);
|
||||
const defenderRoll = ChatUtility.getMessageData(chatMessage, 'defender-roll');
|
||||
const attackerRoll = defenderRoll?.attackerRoll ?? ChatUtility.getMessageData(chatMessage, 'attacker-roll') ;
|
||||
console.log('RdDCombat', attackerRoll, defenderRoll);
|
||||
const defenderTokenId = event.currentTarget.attributes['data-defenderTokenId']?.value;
|
||||
|
||||
const armeParadeId = event.currentTarget.attributes['data-armeid']?.value;
|
||||
@ -637,7 +556,7 @@ export class RdDCombat {
|
||||
case '#particuliere-attaque': return await this.choixParticuliere(attackerRoll, event.currentTarget.attributes['data-mode'].value);
|
||||
case '#parer-button': return this.parade(attackerRoll, armeParadeId);
|
||||
case '#esquiver-button': return this.esquive(attackerRoll, compId, competence);
|
||||
case '#encaisser-button': return this.encaisser(attackerRoll, defenderTokenId);
|
||||
case '#encaisser-button': return this.encaisser(attackerRoll, defenderRoll, defenderTokenId);
|
||||
case '#echec-total-attaque': return this._onEchecTotal(attackerRoll);
|
||||
|
||||
case '#appel-chance-attaque': return this.attacker.rollAppelChance(
|
||||
@ -650,7 +569,7 @@ export class RdDCombat {
|
||||
() => this.attaqueSignificative(attackerRoll),
|
||||
() => { });
|
||||
case '#appel-destinee-defense': return this.defender.appelDestinee(
|
||||
() => this.defenseDestinee(attackerRoll),
|
||||
() => this.defenseDestinee(defenderRoll),
|
||||
() => { });
|
||||
}
|
||||
}
|
||||
@ -680,8 +599,7 @@ export class RdDCombat {
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
defenseDestinee(attackerRoll) {
|
||||
let defenderRoll = RdDCombat._getDefense(attackerRoll.passeArme);
|
||||
defenseDestinee(defenderRoll) {
|
||||
if (defenderRoll) {
|
||||
ui.notifications.info('Défense significative grâce à la destinée')
|
||||
RdDResolutionTable.significativeRequise(defenderRoll.rolled);
|
||||
@ -819,8 +737,7 @@ export class RdDCombat {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async _onAttaqueParticuliere(rollData) {
|
||||
RdDCombat._storeAttaque(this.attackerId, rollData);
|
||||
|
||||
|
||||
const isMeleeDiffNegative = (rollData.competence.type == 'competencecreature' || rollData.selectedCarac.label == "Mêlée") && rollData.diffLibre < 0;
|
||||
// force toujours, sauf empoignade
|
||||
// finesse seulement en mélée, pour l'empoignade, ou si la difficulté libre est de -1 minimum
|
||||
@ -838,8 +755,8 @@ export class RdDCombat {
|
||||
else if (!isForce && !isFinesse && isRapide) {
|
||||
return await this.choixParticuliere(rollData, "rapidite");
|
||||
}
|
||||
|
||||
ChatMessage.create({
|
||||
|
||||
const choixParticuliere = await ChatMessage.create({
|
||||
alias: this.attacker.name,
|
||||
whisper: ChatUtility.getWhisperRecipientsAndGMs(this.attacker.name),
|
||||
content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-demande-attaque-particuliere.html', {
|
||||
@ -852,6 +769,7 @@ export class RdDCombat {
|
||||
passeArme: rollData.passeArme
|
||||
})
|
||||
});
|
||||
ChatUtility.setMessageData(choixParticuliere, 'attacker-roll', rollData);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
@ -860,10 +778,6 @@ export class RdDCombat {
|
||||
|
||||
attackerRoll.dmg = RdDBonus.dmg(attackerRoll, this.attacker.getBonusDegat(), this.defender.isEntiteCauchemar());
|
||||
let defenderRoll = { attackerRoll: attackerRoll, passeArme: attackerRoll.passeArme, show: {} }
|
||||
// Save rollData for defender
|
||||
RdDCombat._storeAttaque(this.attackerId, attackerRoll);
|
||||
RdDCombat._storeDefense(defenderRoll.passeArme, defenderRoll);
|
||||
|
||||
attackerRoll.show = {
|
||||
cible: this.target ? this.defender.data.name : 'la cible',
|
||||
isRecul: (attackerRoll.particuliere == 'force' || attackerRoll.tactique == 'charge')
|
||||
@ -918,7 +832,7 @@ export class RdDCombat {
|
||||
};
|
||||
|
||||
if (Misc.isUniqueConnectedGM()) {
|
||||
await this._chatMessageDefense(paramChatDefense);
|
||||
await this._chatMessageDefense(paramChatDefense, defenderRoll);
|
||||
}
|
||||
else {
|
||||
this._socketSendMessageDefense(paramChatDefense, defenderRoll);
|
||||
@ -926,14 +840,16 @@ export class RdDCombat {
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async _chatMessageDefense(paramDemandeDefense) {
|
||||
ChatMessage.create({
|
||||
async _chatMessageDefense(paramDemandeDefense, defenderRoll) {
|
||||
const choixDefense = await ChatMessage.create({
|
||||
// message privé: du défenseur à lui même (et aux GMs)
|
||||
speaker: ChatMessage.getSpeaker(this.defender, canvas.tokens.get(this.defenderTokenId)),
|
||||
alias: this.attacker.name,
|
||||
whisper: ChatUtility.getWhisperRecipientsAndGMs(this.defender.name),
|
||||
content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-demande-defense.html', paramDemandeDefense),
|
||||
});
|
||||
// flag pour garder les jets d'attaque/defense
|
||||
ChatUtility.setMessageData(choixDefense, 'defender-roll', defenderRoll);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
@ -974,10 +890,7 @@ export class RdDCombat {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async _onAttaqueEchecTotal(attackerRoll) {
|
||||
|
||||
RdDCombat._storeAttaque(this.attackerId, attackerRoll);
|
||||
|
||||
ChatMessage.create({
|
||||
const choixEchecTotal = await ChatMessage.create({
|
||||
whisper: ChatUtility.getWhisperRecipientsAndGMs(this.attacker.name),
|
||||
content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-demande-attaque-etotal.html', {
|
||||
attackerId: this.attackerId,
|
||||
@ -986,6 +899,7 @@ export class RdDCombat {
|
||||
essais: attackerRoll.essais
|
||||
})
|
||||
});
|
||||
ChatUtility.setMessageData(choixEchecTotal, 'attacker-roll', attackerRoll);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
@ -1105,7 +1019,6 @@ export class RdDCombat {
|
||||
|
||||
this.removeChatMessageActionsPasseArme(defenderRoll.passeArme);
|
||||
this._sendMessageDefense(defenderRoll.attackerRoll, defenderRoll, { defense: true });
|
||||
RdDCombat._storeDefense(defenderRoll.passeArme, defenderRoll);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
@ -1177,7 +1090,6 @@ export class RdDCombat {
|
||||
|
||||
this.removeChatMessageActionsPasseArme(defenderRoll.passeArme);
|
||||
this._sendMessageDefense(defenderRoll.attackerRoll, defenderRoll, { defense: true })
|
||||
RdDCombat._storeDefense(defenderRoll.passeArme, defenderRoll);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
@ -1282,15 +1194,10 @@ export class RdDCombat {
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async encaisser(attackerRoll, defenderTokenId) {
|
||||
async encaisser(attackerRoll, defenderRoll, defenderTokenId) {
|
||||
defenderTokenId = defenderTokenId || this.defenderTokenId;
|
||||
console.log("RdDCombat.encaisser >>>", attackerRoll, defenderTokenId);
|
||||
|
||||
let defenderRoll = RdDCombat._getDefense(attackerRoll.passeArme);
|
||||
if (!defenderRoll) {
|
||||
ui.notifications.warn("Cette passe d'arme est déjà terminée!")
|
||||
return;
|
||||
}
|
||||
if (defenderRoll?.rolled && RdDCombat.isEchecTotal(defenderRoll)) {
|
||||
this._onEchecTotal(defenderRoll);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user