Avancement messages défense & oeuvres

This commit is contained in:
2025-09-27 01:43:49 +02:00
parent d26ab59c51
commit 2741fc3fbf
31 changed files with 954 additions and 220 deletions

View File

@@ -3049,7 +3049,7 @@ export class RdDActor extends RdDBaseActorSang {
/* -------------------------------------------- */
async _rollArtV2(oeuvreId, callbackAction = async (actor, rd) => await actor._resultArtV2(rd)) {
async _rollArtV2(oeuvreId, callbackAction = async (rd) => await this._resultArtV2(rd)) {
const oeuvre = this.items.get(oeuvreId)
const rollData = {
title: `Interpretation de ${oeuvre.name} par ${this.name}`,
@@ -3074,15 +3074,16 @@ export class RdDActor extends RdDBaseActorSang {
})
}
// TODO: move vers ChatRollResult
async _resultArtV2(artData) {
const niveau = artData.oeuvre.system.niveau ?? 0;
const baseQualite = (artData.rolled.isSuccess ? niveau : artData.competence.system.niveau);
artData.qualiteFinale = Math.min(baseQualite, niveau) + artData.rolled.ptQualite;
await RdDRollResult.displayRollData(artData, this.name, `chat-resultat-${artData.art}.hbs`);
const niveau = artData.oeuvre.system.niveau ?? 0
const baseQualite = (artData.rolled.isSuccess ? niveau : artData.competence.system.niveau)
artData.qualiteFinale = Math.min(baseQualite, niveau) + artData.rolled.ptQualite
//this.$onRollCompetence(artData)
await RdDRollResult.displayRollData(artData, this.name, `chat-resultat-${artData.art}.hbs`)
}
/* -------------------------------------------- */
/* -------------------------------------------- */
async rollOeuvre(id) {
if (OptionsAvancees.isUsing(ROLL_DIALOG_V2)) {
return await this._rollArtV2(id)
@@ -3168,7 +3169,7 @@ export class RdDActor extends RdDBaseActorSang {
async _resultArt(artData) {
const niveau = artData.oeuvre.system.niveau ?? 0;
const baseQualite = (artData.rolled.isSuccess ? niveau : artData.competence.system.niveau);
artData.qualiteFinale = Math.min(baseQualite, niveau) + artData.rolled.ptQualite;
artData.qualiteFinale = Math.min(baseQualite, niveau) + artData.rolled.ptQualite
await RdDRollResult.displayRollData(artData, this.name, `chat-resultat-${artData.art}.hbs`);
}
@@ -3189,7 +3190,7 @@ export class RdDActor extends RdDBaseActorSang {
async _resultRecetteCuisine(cuisine) {
const niveauRecette = cuisine.oeuvre.system.niveau ?? 0;
const baseQualite = (cuisine.rolled.isSuccess ? niveauRecette : cuisine.competence.system.niveau);
cuisine.qualiteFinale = Math.min(baseQualite, niveauRecette) + cuisine.rolled.ptQualite;
cuisine.qualiteFinale = Math.min(baseQualite, niveauRecette) + cuisine.rolled.ptQualite
cuisine.exotismeFinal = Math.min(Math.min(cuisine.qualiteFinale, cuisine.oeuvre.system.exotisme ?? 0), 0);
cuisine.sust = cuisine.oeuvre.system.sust * Math.min(cuisine.proportions, cuisine.proportionsMax ?? cuisine.proportions)
const platCuisine = {

View File

@@ -17,9 +17,8 @@ import { RdDItemCompetenceCreature } from "./item-competencecreature.js";
import { RdDInitiative } from "./initiative.mjs";
import RollDialog from "./roll/roll-dialog.mjs";
import { PART_DEFENSE } from "./roll/roll-part-defense.mjs";
import { PART_ATTAQUE } from "./roll/roll-part-attaque.mjs";
import { RollDialogAdapter } from "./roll/roll-dialog-adapter.mjs";
import { ROLL_TYPE_ATTAQUE, ROLL_TYPE_DEFENSE } from "./roll/roll-constants.mjs";
import { DIFF, ROLL_TYPE_ATTAQUE, ROLL_TYPE_DEFENSE } from "./roll/roll-constants.mjs";
/* -------------------------------------------- */
const premierRoundInit = [
@@ -413,6 +412,9 @@ export class RdDCombat {
'.appel-chance-attaque',
'.appel-destinee-attaque',
'.echec-total-attaque',
'.appel-chance',
'.chat-encaissement',
'.resister-recul',
]) {
$(html).on("click", button, event => {
const rddCombat = RdDCombat.rddCombatForAttackerAndDefender(
@@ -807,8 +809,6 @@ export class RdDCombat {
/* -------------------------------------------- */
async _sendMessageDefense(attackerRoll, defenderRoll, essaisPrecedents = undefined) {
console.log("RdDCombat._sendMessageDefense", attackerRoll, defenderRoll, essaisPrecedents, " / ", this.attacker, this.target, this.attackerId, attackerRoll.competence.system.categorie);
this.removeChatMessageActionsPasseArme(attackerRoll.passeArme);
if (essaisPrecedents) {
foundry.utils.mergeObject(attackerRoll.essais, essaisPrecedents, { overwrite: true });
@@ -980,18 +980,21 @@ export class RdDCombat {
opponentId: this.attackerId,
},
type: { allowed: ['defense'], current: 'defense' },
attaque: RollDialogAdapter.mapActionAttaque(attackerRoll),
attackerRoll: RollDialogAdapter.mapActionAttaque(attackerRoll),
passeArme: attackerRoll.passeArme,
}
await RollDialog.create(rollData, {
onRollDone: (dialog) => { dialog.close() },
onRollDone: (dialog) => {
// dialog.close()
},
customChatMessage: true,
callbacks: [async (roll) => {
this.removeChatMessageActionsPasseArme(roll.passeArme)
// defense: esquive / arme de parade / competence de défense
if (!RdDCombat.isParticuliere(roll))
if (!RdDCombat.isParticuliere(roll)) {
await roll.active.actor.incDecItemUse(roll.current[PART_DEFENSE].defense?.id,)
}
await this._onDefense(roll)
}]
})
@@ -1025,57 +1028,49 @@ export class RdDCombat {
}
async _onDefense(rollData) {
console.log("RdDCombat._onDefense >>>", rollData)
const isEsquive = rollData.current[PART_DEFENSE].isEsquive
const isParade = !isEsquive
if (RdDCombat.isReussite(rollData)) {
await this._onDefenseNormale(rollData)
if (isParade) {
await this.computeRecul(rollData)
await this.computeDeteriorationArme(rollData)
}
if (RdDCombat.isParticuliere(rollData)) {
await this._onDefenseParticuliere(rollData)
await this._onDefenseParticuliere(rollData, isEsquive)
}
}
else {
await this._onDefenseEchec(dialog, rollData)
//await this._sendMessageDefense(rollData.attackerRoll, rollData, { defense: true })
}
// TODO: modify chat message
this.removeChatMessageActionsPasseArme(rollData.passeArme)
}
async _onDefenseParticuliere(rollData) {
console.log("RdDCombat._onDefenseParticuliere >>>", rollData);
if (/*TODO: parade?*/!rollData.attackerRoll?.isPart) {
async _onDefenseParticuliere(rollData, isEsquive) {
if (isEsquive) {
ChatUtility.createChatWithRollMode(
{ content: "<strong>Vous pouvez esquiver une deuxième fois!</strong>" },
this.defender)
}
else if (/*TODO: parade?*/!rollData.attackerRoll?.particuliere) {
// TODO: attaquant doit jouer résistance et peut être désarmé p132
ChatUtility.createChatWithRollMode(
{ content: `(à gérer) L'attaquant doit jouer résistance et peut être désarmé (p132)` },
this.defender)
}
ChatUtility.createChatWithRollMode(
{ content: "<strong>Vous pouvez esquiver une deuxième fois!</strong>" },
this.defender);
}
async _onDefenseNormale(rollData) {
console.log("RdDCombat._onDefenseNormale >>>", rollData);
// console.log("RdDCombat._onEsquiveNormal >>>", rollData);
// await RdDRollResult.displayRollData(rollData, this.defender, 'chat-resultat-esquive.hbs');
// this.removeChatMessageActionsPasseArme(rollData.passeArme);
//TODO
await this.computeRecul(rollData);
await this.computeDeteriorationArme(rollData);
await RdDRollResult.displayRollData(rollData, this.defender, 'chat-resultat-parade.hbs');
this.removeChatMessageActionsPasseArme(rollData.passeArme);
}
async _onDefenseEchec(rollData) {
console.log("RdDCombat._onDefenseEchec >>>", rollData);
// console.log("RdDCombat._onEsquiveEchec >>>", rollData);
// await RdDRollResult.displayRollData(rollData, this.defender, 'chat-resultat-esquive.hbs');
// this.removeChatMessageActionsPasseArme(rollData.passeArme);
// this._sendMessageDefense(rollData.attackerRoll, rollData, { defense: true })
await RdDRollResult.displayRollData(rollData, this.defender, 'chat-resultat-parade.hbs');
this.removeChatMessageActionsPasseArme(rollData.passeArme);
this._sendMessageDefense(rollData.attackerRoll, rollData, { defense: true });
}
@@ -1214,7 +1209,7 @@ export class RdDCombat {
// Est-ce une parade normale?
if (defenderRoll.arme && attackerRoll && !defenderRoll.rolled.isPart) {
// Est-ce que l'attaque est une particulière en force ou une charge
if (defenderRoll.needResist || this._isForceOuCharge(attackerRoll)) {
if (defenderRoll.needResist || this._isForceOuCharge(attackerRoll, defenderRoll.v2)) {
defenderRoll.show = defenderRoll.show || {}
@@ -1262,7 +1257,7 @@ export class RdDCombat {
finalLevel: Misc.toInt(defenderRoll.competence.system.niveau) - dmg,
showDice: HIDE_DICE
});
defenderRoll.show.desarme = desarme.rolled.isEchec;
defenderRoll.show.desarme = desarme.rolled.isEchec
}
}
}
@@ -1270,39 +1265,47 @@ export class RdDCombat {
/* -------------------------------------------- */
async computeRecul(defenderRoll) { // Calcul du recul (p. 132)
const attackerRoll = defenderRoll.attackerRoll;
if (ReglesOptionnelles.isUsing('recul') && this._isForceOuCharge(attackerRoll)) {
const impact = this._computeImpactRecul(attackerRoll);
const rollRecul = await RdDResolutionTable.rollData({ caracValue: 10, finalLevel: impact });
if (rollRecul.rolled.isSuccess) {
defenderRoll.show.recul = 'encaisse';
} else if (rollRecul.rolled.isETotal || this._isReculCauseChute(impact)) {
defenderRoll.show.recul = 'chute';
await this.defender.setEffect(STATUSES.StatusProne, true);
}
else {
defenderRoll.show.recul = 'recul';
}
if (!ReglesOptionnelles.isUsing('recul')) {
return
}
const attackerRoll = defenderRoll.attackerRoll;
if (this._isForceOuCharge(attackerRoll, defenderRoll.v2)) {
const impact = this._computeImpactRecul(attackerRoll);
const rollRecul = await RdDResolutionTable.roll(10, impact)
defenderRoll.show.recul = await this.gererRecul(rollRecul, impact)
}
}
async gererRecul(rolled, impact) {
if (rolled.isSuccess) {
return 'encaisse'
}
if (rolled.isETotal || this._isReculCauseChute(impact)) {
await this.defender.setEffect(STATUSES.StatusProne, true)
return 'chute'
}
return 'recul'
}
/* -------------------------------------------- */
async _isReculCauseChute(impact) {
const agilite = this.defender.getAgilite();
const chute = await RdDResolutionTable.rollData({ caracValue: agilite, finalLevel: impact });
return chute.rolled.isEchec;
const agilite = this.defender.getAgilite()
const chute = await RdDResolutionTable.rollData({ caracValue: agilite, finalLevel: impact })
return chute.rolled.isEchec
}
_isForceOuCharge(attaque, isRollV2 = false /* TODO: delete roll V1 */) {
return attaque.particuliere == 'force' || 'charge' == (isRollV2 ? attaque.tactique?.key : attaque.tactique)
}
/* -------------------------------------------- */
_isForceOuCharge(attaque) {
return attaque.particuliere == 'force' || attaque.tactique == 'charge';
}
/* -------------------------------------------- */
_computeImpactRecul(attaque) {
const taille = this.defender.getTaille();
const force = this.attacker.getForce();
const dommages = attaque.arme.system.dommagesReels ?? attaque.arme.system.dommages;
_computeImpactRecul(attackerRoll) {
const taille = this.defender.getTaille()
const force = this.attacker.getForce()
const dommages = attackerRoll.dmg /* TODO: delete roll V1 */
? attackerRoll.dmg.dmgArme
: attackerRoll.arme.system.dommagesReels ?? attaque.arme.system.dommages;
return taille - (force + dommages);
}

View File

@@ -0,0 +1,59 @@
import { ChatUtility } from "../chat-utility.js"
import RollDialog from "./roll-dialog.mjs"
import { RdDCarac } from "../rdd-carac.js";
export class ChatRollResult {
static onReady() {
foundry.applications.handlebars.loadTemplates({
'partial-appel-chance': 'systems/foundryvtt-reve-de-dragon/templates/roll/result/partial-appel-chance.hbs',
'partial-encaissement': 'systems/foundryvtt-reve-de-dragon/templates/roll/result/partial-encaissement.hbs',
'partial-recul-choc': 'systems/foundryvtt-reve-de-dragon/templates/roll/result/partial-recul-choc.hbs',
'partial-info-appel-moral': 'systems/foundryvtt-reve-de-dragon/templates/roll/result/partial-info-appel-moral.hbs',
})
}
async display(roll) {
roll.show = roll.show || {};
roll.show.chance = this.isAppelChancePossible(roll)
roll.show.encaissement = this.isShowEncaissement(roll)
roll.show.recul = this.isShowReculChoc(roll)
const chatMessage = await ChatUtility.createChatWithRollMode(
{
content: await this.buildRollHtml(roll)
},
roll.active.actor,
roll.current?.rollmode?.key
)
if (roll.show.chance) {
const save = RollDialog.saveParts(roll)
console.log("Store message roll", save)
ChatUtility.setMessageData(chatMessage, 'rollData', save)
}
return chatMessage
}
isAppelChancePossible(roll) {
return roll.active.actor.isPersonnage() &&
roll.rolled.isEchec &&
RdDCarac.isActionPhysique(roll.current.carac?.key)
}
isShowEncaissement(roll) {
return roll.rolled.isEchec &&
roll.attackerRoll?.dmg.mortalite != 'empoignade'
}
isShowReculChoc(roll) {
return roll.rolled.isEchec &&
roll.attackerRoll &&
!roll.current.defense.isEsquive &&
(roll.attackerRoll.particuliere == 'force' || 'charge' == attackerRoll.tactique?.key)
}
async buildRollHtml(roll) {
const template = `systems/foundryvtt-reve-de-dragon/templates/roll/result/chat-${roll.type.current}.hbs`
return await foundry.applications.handlebars.renderTemplate(template, roll)
}
}

View File

@@ -1,15 +0,0 @@
export class RollChatResult {
constructor(rollType) {
this.rollType = rollType
}
async display(rollData) {
const template = this.rollType.chatResultTemplate()
const chatContent = await renderTemplate(template, rollData)
ChatMessage.create({
whisper: ChatUtility.getOwners(this),
content: chatContent
})
}
}

View File

@@ -6,13 +6,12 @@ import { ReglesOptionnelles } from "../settings/regles-optionnelles.js";
import { PART_OEUVRE } from "./roll-part-oeuvre.mjs";
import { RdDItemArme } from "../item/arme.js";
import { RdDBonus } from "../rdd-bonus.js";
import { ROLL_TYPE_ATTAQUE } from "./roll-constants.mjs";
/* -------------------------------------------- */
export class RollDialogAdapter {
async rollDice(rollData, rollTitle) {
const chances = this.computeChances({
static async rollDice(rollData, rollTitle) {
const chances = RollDialogAdapter.computeChances({
carac: rollData.current.carac.value,
diff: rollData.current.totaldiff,
bonus: rollData.current.bonus,
@@ -21,13 +20,13 @@ export class RollDialogAdapter {
rollMode: rollData.current.rollmode.key
})
const rolled = await this.rollChances(rollData, chances)
this.adjustRollDataForV1(rollData, rolled, rollTitle)
const rolled = await RollDialogAdapter.rollChances(rollData, chances)
RollDialogAdapter.adjustRollDataForV1(rollData, rolled, rollTitle)
return rolled
}
computeChances({ carac, diff, bonus, sign, showDice, rollMode }) {
static computeChances({ carac, diff, bonus, sign, showDice, rollMode }) {
const chances = foundry.utils.duplicate(RdDResolutionTable.computeChances(carac, diff))
RdDResolutionTable._updateChancesWithBonus(chances, bonus, diff)
RdDResolutionTable._updateChancesFactor(chances, sign)
@@ -36,7 +35,7 @@ export class RollDialogAdapter {
return chances
}
async rollChances(rollData, chances) {
static async rollChances(rollData, chances) {
const rolled = await RdDResolutionTable.rollChances(chances,
rollData.current.sign,
rollData.current.resultat)
@@ -47,7 +46,7 @@ export class RollDialogAdapter {
return rolled
}
adjustRollDataForV1(rollData, rolled, rollTitle) {
static adjustRollDataForV1(rollData, rolled, rollTitle) {
// temporaire pour être homogène roll v1
rollData.alias = rollData.active.actor.getAlias()
// pour experience

View File

@@ -38,7 +38,8 @@ import { RollPartDefense } from "./roll-part-defense.mjs";
import { RollDialogAdapter } from "./roll-dialog-adapter.mjs";
import { ROLLDIALOG_SECTION } from "./roll-part.mjs";
import { ROLL_TYPE_COMP } from "./roll-constants.mjs";
import { RollChatResult } from "./roll-chat-result.mjs";
import { ChatRollResult } from "./chat-roll-result.mjs";
const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api
const doNothing = (dialog) => { }
@@ -48,11 +49,12 @@ const ALL_ROLL_TYPES = [
new RollTypeTache(),
new RollTypeAttaque(),
new RollTypeDefense(),
// new RollTypeResistance ??
new RollTypeSort(),
new RollTypeMeditation(),
new RollTypeOeuvre(),
new RollTypeJeu(),
// new RollTypeResistance ??
// new RollTypeFixedCarac ??
]
const BASIC_PARTS = new RollBasicParts()
@@ -182,6 +184,8 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2
'roll-button': 'systems/foundryvtt-reve-de-dragon/templates/roll/roll-button.hbs',
})
ChatRollResult.onReady()
foundry.applications.handlebars.loadTemplates(ALL_ROLL_TYPES.map(m => m.template))
foundry.applications.handlebars.loadTemplates(ROLL_PARTS.map(p => p.template))
ROLL_PARTS.forEach(p => p.onReady())
@@ -246,9 +250,49 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2
// rien pour l'instant
}
/** 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 ?? {}
rollData.selected = rollData.selected ?? {}
rollData.type = rollData.type ?? {}
rollData.type.retry = rollData.type.retry ?? false
BASIC_PARTS.restore(rollData)
const potential = ALL_ROLL_TYPES.find(m => m.code == rollData.type.current)?.code
const allowed = rollData.type.retry && potential
? [potential]
: (rollData.type.allowed ?? ALL_ROLL_TYPES.filter(m => m.isAllowed(rollData) && m.visible(rollData)).map(m => m.code))
const rollType = allowed.find(c => c == rollData.type.current) ?? (allowed.length > 0 ? allowed[0].code : ROLL_TYPE_COMP);
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.options = rollData.options ?? { rollMode: game.settings.get("core", "rollMode") }
ROLL_PARTS.forEach(p => p.initialize(rollData))
ROLL_PARTS.forEach(p => p.restore(rollData))
ROLL_PARTS.filter(p => p.isValid(rollData))
.forEach(p => {
p.loadRefs(rollData)
p.prepareContext(rollData)
})
return rollData
}
static saveParts(rollData) {
const target = BASIC_PARTS.initFrom(rollData)
ROLL_PARTS.filter(p => p.isActive(rollData))
.forEach(p => p.storeClean(rollData, target))
target.attackerRoll = rollData.attackerRoll
return target
}
constructor(rollData, rollOptions) {
super()
this.rollData = rollData
this.rollData = RollDialog.$prepareRollData(rollData)
this.rollOptions = {
callbacks: [
async r => await r.active.actor.appliquerAjoutExperience(r),
@@ -258,37 +302,8 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2
customChatMessage: rollOptions.customChatMessage,
onRollDone: rollOptions.onRollDone ?? doNothing
}
this.$loadParts()
}
/** pre-configure les paramètres des différentes parties de la fenêtre (par exemple, prépare les listes de caractéristiques/compétences */
$loadParts() {
const rollData = this.rollData;
rollData.current = rollData.current ?? {}
rollData.selected = rollData.selected ?? {}
rollData.type = rollData.type ?? {}
rollData.type.retry = rollData.type.retry ?? false
BASIC_PARTS.restore(rollData)
const loadedType = ALL_ROLL_TYPES.find(m => m.code == rollData.type?.current)?.code
const allowedTypes = ALL_ROLL_TYPES.filter(m => m.isAllowed(rollData) && m.visible(rollData)).map(m => m.code)
rollData.type.allowed = rollData.type.retry ? [loadedType] : rollData.type.allowed ?? ALL_ROLL_TYPES.map(m => m.code)
rollData.type.current = allowedTypes.find(m => m == rollData.type?.current) ?? (allowedTypes.length > 0 ? allowedTypes[0] : ROLL_TYPE_COMP)
this.getSelectedType().setRollDataType(rollData)
rollData.refs = this.$prepareRefs(rollData)
rollData.options = rollData.options ?? { showDice: true, rollMode: game.settings.get("core", "rollMode") }
ROLL_PARTS.forEach(p => p.initialize(rollData))
ROLL_PARTS.forEach(p => p.restore(rollData))
ROLL_PARTS.filter(p => p.isValid(rollData))
.forEach(p => {
p.loadRefs(rollData)
p.prepareContext(rollData)
})
this.selectType();
this.chatRollResult = new ChatRollResult();
this.selectType()
}
selectType() {
@@ -301,23 +316,21 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2
ROLL_PARTS.find(it => it.code == PART_COMP).filterComps(this.rollData)
}
$prepareRefs(rollData) {
return foundry.utils.mergeObject(rollData.refs ?? {}, Object.fromEntries(ROLL_PARTS.map(p => [p.code, {}])));
}
$saveParts() {
const target = BASIC_PARTS.initFrom(this.rollData)
ROLL_PARTS.filter(p => p.isActive(this.rollData))
.forEach(p => p.store(this.rollData, target))
return target
}
getActiveParts() {
return ROLL_PARTS.filter(p => p.isActive(this.rollData))
}
get title() {
return this.rollData.title ?? `Jet de dés de ${this.rollData.active.actor.name}`
// get title() {
// return this.rollData.title ?? `Jet de dés de ${this.rollData.active.actor.name}`
// }
rollTitle(rollData) {
return rollData.label ?? ROLL_PARTS
.filter(it => it.section == ROLLDIALOG_SECTION.ACTION)
.filter(it => it.isActive(rollData))
.map(it => it.title(rollData))
.reduce(Misc.joining(' '))
}
async _onRender(context, options) {
@@ -344,9 +357,9 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2
)
}
getAjustements() {
getAjustements(rollData = this.rollData) {
return this.getActiveParts()
.map(p => p.getAjustements(this.rollData))
.map(p => p.getAjustements(rollData))
.reduce((a, b) => a.concat(b))
.sort((a, b) => a.diff == undefined ? 1 : b.diff == undefined ? -1 : 0)
}
@@ -392,10 +405,10 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2
}
}
calculAjustements() {
this.rollData.ajustements = this.getAjustements()
this.rollData.ajustements.forEach(it => it.isDiff = it.diff != undefined)
this.rollData.current.totaldiff = this.rollData.ajustements
calculAjustements(rollData = this.rollData) {
rollData.ajustements = this.getAjustements(rollData)
rollData.ajustements.forEach(it => it.isDiff = it.diff != undefined)
rollData.current.totaldiff = rollData.ajustements
.map(adj => adj.diff)
.filter(d => d != undefined)
.reduce(Misc.sum(), 0)
@@ -406,36 +419,27 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2
}
async roll() {
this.calculAjustements()
const rollData = this.rollData
console.info('Roll parts:', this.$saveParts())
const rolled = await this.$rollDice(rollData)
rollData.rolled = rolled
Promise.all(this.rollOptions.callbacks.map(async callback => await callback(rollData)))
if (!this.rollOptions.customChatMessage) {
const rollChatResult = new RollChatResult(this.getSelectedType())
await rollChatResult.display(this.rollData)
rollData.active.actor.$onRollCompetence(this.rollData)
}
const roll = RollDialog.saveParts(this.rollData)
RollDialog.$prepareRollData(roll)
this.calculAjustements(roll)
roll.current.resultat = this.rollData.current.resultat
roll.v2 = true
roll.rolled = await this.$rollDice(roll)
roll.result = this.getSelectedType(roll).getResult(roll)
console.info('RollDialog.roll:', roll)
await Promise.all(this.rollOptions.callbacks.map(async callback => await callback(roll)))
await this.chatRollResult.display(roll)
this.rollOptions.onRollDone(this)
}
async defaultCallback(rollData, rolled) {
await rollData.active.actor.appliquerAjoutExperience(rollData)
await rollData.active.actor.appliquerAppelMoral(rollData)
}
async $rollDice(rollData) {
const adapter = new RollDialogAdapter(ROLL_PARTS);
return await adapter.rollDice(rollData, this.rollTitle(rollData));
}
rollTitle(rollData) {
return ROLL_PARTS
.filter(it => it.section == ROLLDIALOG_SECTION.ACTION)
.filter(it => it.isActive(rollData))
.map(it => it.title(rollData))
.reduce(Misc.joining(' '))
return await RollDialogAdapter.rollDice(rollData, this.rollTitle(rollData));
}
}

View File

@@ -1,10 +1,8 @@
import { RdDBonus } from "../rdd-bonus.js"
import { StatusEffects } from "../settings/status-effects.js"
import { ROLL_TYPE_ATTAQUE } from "./roll-constants.mjs"
import { PART_CARAC } from "./roll-part-carac.mjs"
import { PART_COMP } from "./roll-part-comp.mjs"
import { RollPartSelect } from "./roll-part-select.mjs"
import { PART_SIGN } from "./roll-part-sign.mjs"
import { ROLLDIALOG_SECTION } from "./roll-part.mjs"
export const PART_ATTAQUE = 'attaque'
@@ -28,6 +26,16 @@ export class RollPartAttaque extends RollPartSelect {
}
}
store(rollData, targetData) {
super.store(rollData, targetData)
this.getSaved(targetData).dmg = this.getCurrent(rollData).dmg
}
restore(rollData) {
super.restore(rollData)
this.getCurrent(rollData).dmg = this.getSaved(rollData).dmg
}
choices(refs) { return refs.attaques }
static $extractAttaque(attaque, actor) {

View File

@@ -43,6 +43,7 @@ export class RollPartCarac extends RollPartSelect {
// ? refs.all.filter(it => allowed.includes(Grammar.toLowerCaseNoAccent(it.key)))
? refs.all.filter(it => allowed.includes(it.key))
: refs.all
this.$selectCarac(rollData)
}
prepareContext(rollData) {

View File

@@ -52,6 +52,7 @@ export class RollPartComp extends RollPartSelect {
// ? refs.all.filter(it => allowed.includes(Grammar.toLowerCaseNoAccent(it.label)))
? refs.all.filter(it => allowed.includes(it.label))
: refs.all
this.$selectComp(rollData)
}
prepareContext(rollData) {

View File

@@ -27,14 +27,14 @@ export class RollPartDefense extends RollPartSelect {
loadRefs(rollData) {
const refs = this.getRefs(rollData)
const attaque = rollData.attaque
const attackerRoll = rollData.attackerRoll
const defenseur = rollData.active.actor
refs.isDistance = [ATTAQUE_TYPE.TIR, ATTAQUE_TYPE.LANCER].find(it => it == attaque?.main)
refs.isDistance = [ATTAQUE_TYPE.TIR, ATTAQUE_TYPE.LANCER].find(it => it == attackerRoll?.main)
const esquives = refs.isDistance == ATTAQUE_TYPE.TIR ? [] : defenseur.getCompetencesEsquive()
.map(it => RollPartDefense.$extractEsquive(it, defenseur))
const parades = defenseur.items.filter(it => it.isParade() && (!refs.isDistance || it.isBouclier()))
.map(it => RollPartDefense.$extractParade(it, attaque?.attaque.arme, defenseur))
.map(it => RollPartDefense.$extractParade(it, attackerRoll?.attaque.arme, defenseur))
refs.defenses = [...esquives, ...parades].filter(it => it != undefined)
this.$selectDefense(rollData)
@@ -48,7 +48,8 @@ export class RollPartDefense extends RollPartSelect {
// TODO: carac pour créatures
carac: defenseur.isPersonnage() ? CARACS.DEROBEE : esquive.name,
verb: "esquive",
comp: esquive
comp: esquive,
isEsquive: true
}
}
@@ -66,7 +67,8 @@ export class RollPartDefense extends RollPartSelect {
comp: comp,
arme: armeDefense,
forceRequise: armeDefense ? RdDItemArme.valeurMain(armeDefense.system.force ?? 0, RdDItemArme.getMainAttaque(comp)) : 0,
typeParade: armeAttaque ? RdDItemArme.defenseArmeParade(armeDefense, armeAttaque) : 'norm'
typeParade: armeAttaque ? RdDItemArme.defenseArmeParade(armeDefense, armeAttaque) : 'norm',
isEsquive: false
}
}
@@ -111,7 +113,7 @@ export class RollPartDefense extends RollPartSelect {
isArmeDisparate(rollData) {
const armeDefense = this.getCurrent(rollData).arme
if (armeDefense) {
const armeAttaque = rollData.attaque?.attaque.arme
const armeAttaque = rollData.attackerRoll?.attaque.arme
return RdDItemArme.defenseArmeParade(armeAttaque, armeDefense) == 'sign'
}
return false
@@ -120,12 +122,12 @@ export class RollPartDefense extends RollPartSelect {
getDiffDefense(rollData) {
const current = this.getCurrent(rollData)
const refs = this.getRefs(rollData)
if (refs.isDistance || !rollData.attaque) {
if (refs.isDistance || !rollData.attackerRoll) {
// Déterminer la difficulté de parade
return { diff: 0, type: DIFF.LIBRE }
}
else {
return { diff: rollData.attaque.diff ?? 0, type: DIFF.DEFENSE }
return { diff: rollData.attackerRoll.diff ?? 0, type: DIFF.DEFENSE }
}
}
}

View File

@@ -1,5 +1,4 @@
import { ITEM_TYPES } from "../constants.js"
import { Grammar } from "../grammar.js"
import { Misc } from "../misc.js"
import { CARACS } from "../rdd-carac.js"
import { ROLL_TYPE_OEUVRE } from "./roll-constants.mjs"
@@ -59,6 +58,7 @@ export class RollPartOeuvre extends RollPartSelect {
label: oeuvre.name,
art: art,
caracs: art.caracs(oeuvre),
qualite: oeuvre.system.niveau,
value: -oeuvre.system.niveau,
oeuvre: oeuvre,
comp: actor.getCompetence(art.competence(oeuvre))

View File

@@ -1,6 +1,6 @@
import { ROLLDIALOG_SECTION, RollPart } from "./roll-part.mjs"
const PART_TRICHER = "tricher"
export const PART_TRICHER = "tricher"
export class RollPartTricher extends RollPart {

View File

@@ -53,7 +53,23 @@ export class RollPart {
}
restore(rollData) { }
store(rollData, targetData) { }
storeClean(rollData, targetData) {
this.store(rollData, targetData)
if (rollData.selected[this.code]) {
const toDelete = Object.entries(rollData.selected[this.code])
.map(([k, v]) => v == undefined ? k : undefined)
.filter(k => k != undefined)
toDelete.forEach(k => delete rollData.selected[this.code][k])
if (Object.keys(rollData.selected[this.code]).length == 0) {
delete rollData.selected[this.code]
}
}
}
store(rollData, targetData) {
this.setSaved(targetData, { key: this.getCurrent(rollData).key })
}
/**
* le texte à ajouter dans la barre de titre
@@ -92,4 +108,14 @@ export class RollPart {
async _onRender(rollDialog, context, options) { }
addResult(rollData) {
const result = this.getResult(rollData)
if (result){
rollData.result[this.code] = result
}
}
getResult(rollData){
return undefined
}
}

View File

@@ -15,5 +15,14 @@ export class RollTypeOeuvre extends RollType {
onSelect(rollData) {
this.setDiffType(rollData, DIFF.AUCUN)
}
getResult(rollData){
const current = rollData.current[PART_OEUVRE]
const qualite = rollData.rolled.isSuccess ? current.qualite : Math.min(current.qualite, current.comp.system.niveau)
return {
qualite: qualite + rollData.rolled.ptQualite
}
}
}

View File

@@ -52,4 +52,8 @@ export class RollType {
rollData.current[PART_DIFF].type = type
this.setRollDataType(rollData)
}
getResult(rollData){
return undefined
}
}