Compare commits

..

7 Commits

Author SHA1 Message Date
fd96be439e Merge pull request '13.0.31 - Les choix multiples d'Illysis' (#796) from feature/v13-corrections into v13
All checks were successful
Release Creation / build (release) Successful in 1m57s
Reviewed-on: https, #796
2026-03-04 09:01:53 +01:00
238d99fa9b Fix: dommages armes 1/2 mains à deux mains 2026-03-03 18:14:58 +01:00
490de5882b Fix: valeurs par défaut après la sélection 2026-03-03 17:58:52 +01:00
4fc06a449c Merge pull request '13.0.30 - Le pansement d'Illysis' (#795) from feature/v13-corrections into v13
All checks were successful
Release Creation / build (release) Successful in 1m27s
Reviewed-on: https, #795
2026-02-18 00:43:46 +01:00
929d6af173 Saisie de valeurs négatives 2026-02-17 00:36:08 +01:00
e15ed9d05d Jet de compétence avec défauts
Utilisation de carac par défaut et difficulté par défaut à l'ouverture
de la fenêtre de jet depuis une compétence
2026-02-16 23:58:45 +01:00
3699bc19b8 Fix: soins d'un joueur à l'autre
Les données dans rollData ne pouvaient pas être serialisées
2026-02-06 13:42:27 +01:00
19 changed files with 128 additions and 101 deletions

View File

@@ -1,5 +1,16 @@
# 13.0 # 13.0
## 13.0.31 - Les choix multiples d'Illysis
- les défauts de caractéristique/difficulté des compétences ne sont pris que si aucun autre choix n'est fait
- lors d'une attaque à deux mains avec une arme à une ou deux mains, les dommages à deux mains sont bien utilisés
## 13.0.30 - Le pansement d'Illysis
- les soins d'un joueur à l'autre fonctionne de nouveau
- la fenêtre de jet de compétence s'ouvre avec la caractéristique et la difficulté par défaut
- on peut saisir des valeurs négatives au clavier en sélectionnant les conditions/difficultés
## 13.0.29 - Le tricorne d'Illysis ## 13.0.29 - Le tricorne d'Illysis
- gestion des attaques avec jets V2 depuis l'onglet de combat - gestion des attaques avec jets V2 depuis l'onglet de combat
@@ -13,7 +24,7 @@
- L'appel au moral dans le tchat ne déplace plus les boutons d'appel à la chance - L'appel au moral dans le tchat ne déplace plus les boutons d'appel à la chance
- Correction d'apparence V13 - Correction d'apparence V13
- la fenêtre de choix des status utilisés est affichée correctement - la fenêtre de choix des status utilisés est affichée correctement
- la fenêtrre d'astrologir MJ est affichée correctement - la fenêtre d'astrologie MJ est affichée correctement
## 13.0.27 - Les lunettes d'Illysis ## 13.0.27 - Les lunettes d'Illysis

View File

@@ -2504,9 +2504,9 @@ export class RdDActor extends RdDBaseActorSang {
const blessure = blesse.blessuresASoigner().find(it => it.id == blessureId); const blessure = blesse.blessuresASoigner().find(it => it.id == blessureId);
if (blessure) { if (blessure) {
if (!blessure.system.premierssoins.done) { if (!blessure.system.premierssoins.done) {
const tache = await this.getTacheBlessure(blesse, blessure); const tacheId = (await this.getTacheBlessure(blesse, blessure))?.id
return await this.rollTache(tache.id, { return await this.rollTache(tacheId, {
callbacks: [async r => await blesse.onRollTachePremiersSoins(blessureId, r, this.id)], callbacks: [async r => await blesse.callbackPremiersSoins(blessureId, r, this.id)],
title: 'Premiers soins', forced: true title: 'Premiers soins', forced: true
}); });
} }

View File

@@ -179,19 +179,24 @@ export class RdDBaseActorSang extends RdDBaseActorReve {
return result return result
} }
async onRollTachePremiersSoins(blessureId, rollData, soigneurId) { async callbackPremiersSoins(blessureId, rollData, soigneurId) {
await this.onRollTachePremiersSoins(blessureId,
rollData.v2 ? rollData.current.tache.tache : rollData.tache,
rollData.rolled.isETotal,
soigneurId)
}
async onRollTachePremiersSoins(blessureId, tache, isETotal, soigneurId) {
if (!this.isOwner) { if (!this.isOwner) {
return RdDBaseActor.remoteActorCall({ return RdDBaseActor.remoteActorCall({
tokenId: this.token?.id, tokenId: this.token?.id,
actorId: this.id, actorId: this.id,
method: 'onRollTachePremiersSoins', args: [blessureId, rollData, soigneurId] method: 'onRollTachePremiersSoins', args: [blessureId, tache, isETotal, soigneurId]
}) })
} }
const blessure = this.getItem(blessureId, 'blessure') const blessure = this.getItem(blessureId, 'blessure')
if (blessure && !blessure.system.premierssoins.done) { if (blessure && !blessure.system.premierssoins.done) {
const tache = rollData.v2 ? rollData.current.tache.tache : rollData.tache if (isETotal) {
if (rollData.rolled.isETotal) {
await blessure.update({ await blessure.update({
'system.difficulte': blessure.system.difficulte - 1, 'system.difficulte': blessure.system.difficulte - 1,
'system.premierssoins.tache': Math.max(0, tache.system.points_de_tache_courant) 'system.premierssoins.tache': Math.max(0, tache.system.points_de_tache_courant)

View File

@@ -218,7 +218,7 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2
foundry.applications.handlebars.loadTemplates(ALL_ROLL_TYPES.map(m => m.chatResultTemplate)) foundry.applications.handlebars.loadTemplates(ALL_ROLL_TYPES.map(m => m.chatResultTemplate))
foundry.applications.handlebars.loadTemplates(ROLL_PARTS.map(p => p.template)) foundry.applications.handlebars.loadTemplates(ROLL_PARTS.map(p => p.template))
ROLL_PARTS.forEach(p => p.onReady()) ROLL_PARTS.forEach(p => p.onReady(ROLL_PARTS))
Handlebars.registerHelper('roll-centered-array', (base, show) => { Handlebars.registerHelper('roll-centered-array', (base, show) => {
show = Math.abs(show) show = Math.abs(show)

View File

@@ -72,11 +72,11 @@ export class RollPartAttaque extends RollPartSelect {
findAttaque(attaques, saved) { findAttaque(attaques, saved) {
return attaques.find(at => at.arme.id == (saved?.arme?.id ?? at.arme.id) return attaques.find(it => it.key == saved.key) ??
&& at.comp.id == (saved?.comp?.id ?? at.comp.id) attaques.find(it => it.arme.id == (saved?.arme?.id ?? it.arme.id)
&& at.main == (saved?.main ?? at.main) && it.comp.id == (saved?.comp?.id ?? it.comp.id)
&& it.main == (saved?.main ?? it.main)
) )
} }
choices(refs) { return refs.attaques } choices(refs) { return refs.attaques }

View File

@@ -1,7 +1,9 @@
import { Grammar } from "../grammar.js" import { Grammar } from "../grammar.js"
import { Misc } from "../misc.js" import { Misc } from "../misc.js"
import { PART_CARAC } from "./roll-part-carac.mjs"
import { PART_DIFF } from "./roll-part-diff.mjs"
import { RollPartSelect } from "./roll-part-select.mjs" import { RollPartSelect } from "./roll-part-select.mjs"
import { ROLLDIALOG_SECTION } from "./roll-part.mjs" import { ROLLDIALOG_SECTION, RollPart } from "./roll-part.mjs"
export const PART_COMP = "comp" export const PART_COMP = "comp"
@@ -15,15 +17,21 @@ export class RollPartComp extends RollPartSelect {
get name() { return 'Compétences' } get name() { return 'Compétences' }
get section() { return ROLLDIALOG_SECTION.COMP } get section() { return ROLLDIALOG_SECTION.COMP }
onReady(rollParts) {
this.rollPartCarac = rollParts.find(it => it.code == PART_CARAC)
this.rollPartDiff = rollParts.find(it => it.code == PART_DIFF)
}
loadRefs(rollData) { loadRefs(rollData) {
const refs = this.getRefs(rollData) const refs = this.getRefs(rollData)
const selected = this.getSelected(rollData) const selected = this.getSelected(rollData)
const all = this.$getActorComps(rollData) const all = this.$getActorComps(rollData)
if (selected.forced) { const selectedComp = selected.key
refs.all = all.filter(comp => Grammar.equalsInsensitive(comp.label, selected.key)) if (selected.forced && selectedComp) {
refs.all = all.filter(comp => Grammar.equalsInsensitive(comp.label, selectedComp))
if (refs.all.length == 0) { if (refs.all.length == 0) {
if (selected.key && selected.key.length > 0) { if (selected.key && selected.key.length > 0) {
refs.all = all.filter(comp => Grammar.includesLowerCaseNoAccent(comp.label, selected.key)) refs.all = all.filter(comp => Grammar.includesLowerCaseNoAccent(comp.label, selectedComp))
} }
else { else {
refs.all = all.filter(comp => comp == SANS_COMPETENCE) refs.all = all.filter(comp => comp == SANS_COMPETENCE)
@@ -35,6 +43,13 @@ export class RollPartComp extends RollPartSelect {
} }
refs.comps = refs.all refs.comps = refs.all
this.$selectComp(rollData) this.$selectComp(rollData)
if (rollData.type.current == PART_COMP && selectedComp) {
const current = this.getCurrent(rollData)
const selectedCarac = RollPart.getSelectedPart(rollData, PART_CARAC)
const selectedDiff = RollPart.getSelectedPart(rollData, PART_DIFF)
this.rollPartCarac.selectByKey(rollData, selectedCarac?.key ?? current.comp.system.defaut_carac)
this.rollPartDiff.setDiff(rollData, selectedDiff?.value ?? current.comp.system.default_diffLibre)
}
} }
choices(refs) { return refs.comps } choices(refs) { return refs.comps }
@@ -71,6 +86,7 @@ export class RollPartComp extends RollPartSelect {
refs.comps.sort(sorting) refs.comps.sort(sorting)
} }
this.$selectComp(rollData) this.$selectComp(rollData)
} }
prepareContext(rollData) { prepareContext(rollData) {

View File

@@ -10,7 +10,7 @@ export class RollPartConditions extends RollPart {
settingMin() { return RollPart.settingKey(this, 'min') } settingMin() { return RollPart.settingKey(this, 'min') }
settingMax() { return RollPart.settingKey(this, 'max') } settingMax() { return RollPart.settingKey(this, 'max') }
onReady() { onReady(rollParts) {
game.settings.register(SYSTEM_RDD, this.settingMin(), game.settings.register(SYSTEM_RDD, this.settingMin(),
{ {
name: "Malus maximal de conditions", name: "Malus maximal de conditions",
@@ -65,12 +65,7 @@ export class RollPartConditions extends RollPart {
async _onRender(rollDialog, context, options) { async _onRender(rollDialog, context, options) {
const input = rollDialog.element.querySelector(`roll-section[name="${this.code}"] input[name="${this.code}"]`) const input = rollDialog.element.querySelector(`roll-section[name="${this.code}"] input[name="${this.code}"]`)
input?.addEventListener("input", e => this.onInputChange(e, rollDialog)) input?.addEventListener("input", e => this.onNumericInputChange(e, rollDialog))
}
onInputChange(event, rollDialog) {
this.getCurrent(rollDialog.rollData).value = parseInt(event.currentTarget.value)
rollDialog.render()
} }
} }

View File

@@ -9,7 +9,7 @@ import { ROLLDIALOG_SECTION, RollPart } from "./roll-part.mjs"
export const PART_CUISINE = "cuisine" export const PART_CUISINE = "cuisine"
export class RollPartCuisine extends RollPartSelect { export class RollPartCuisine extends RollPartSelect {
onReady() { onReady(rollParts) {
foundry.applications.handlebars.loadTemplates({ 'roll-oeuvre-recettecuisine': `systems/foundryvtt-reve-de-dragon/templates/roll/roll-oeuvre-recettecuisine.hbs` }) foundry.applications.handlebars.loadTemplates({ 'roll-oeuvre-recettecuisine': `systems/foundryvtt-reve-de-dragon/templates/roll/roll-oeuvre-recettecuisine.hbs` })
} }

View File

@@ -73,12 +73,7 @@ export class RollPartDiff extends RollPart {
async _onRender(rollDialog, context, options) { async _onRender(rollDialog, context, options) {
const input = rollDialog.element.querySelector(`roll-section[name="${this.code}"] input[name="${this.code}"]`) const input = rollDialog.element.querySelector(`roll-section[name="${this.code}"] input[name="${this.code}"]`)
input?.addEventListener("input", e => this.onInputChange(e, rollDialog)) input?.addEventListener("input", e => this.onNumericInputChange(e, rollDialog))
}
onInputChange(event, rollDialog) {
this.getCurrent(rollDialog.rollData).value = parseInt(event.currentTarget.value)
rollDialog.render()
} }
} }

View File

@@ -24,7 +24,7 @@ const ARTS = [
] ]
export class RollPartOeuvre extends RollPartSelect { export class RollPartOeuvre extends RollPartSelect {
onReady() { onReady(rollParts) {
ARTS.forEach(art => art.label = Misc.typeName('Item', art.type)) ARTS.forEach(art => art.label = Misc.typeName('Item', art.type))
ARTS.map(it => `roll-oeuvre-${it.type}`) ARTS.map(it => `roll-oeuvre-${it.type}`)
.forEach(art => .forEach(art =>

View File

@@ -12,7 +12,7 @@ export const PART_SORT = "sort"
export class RollPartSort extends RollPartSelect { export class RollPartSort extends RollPartSelect {
onReady() { onReady(rollParts) {
// TODO: utiliser un hook pour écouter les déplacements dans les TMRs? // TODO: utiliser un hook pour écouter les déplacements dans les TMRs?
} }

View File

@@ -1,5 +1,3 @@
import { ALL_ROLL_TYPES } from "./roll-dialog.mjs"
export const ROLLDIALOG_SECTION = { export const ROLLDIALOG_SECTION = {
ACTION: 'action', ACTION: 'action',
CARAC: 'carac', CARAC: 'carac',
@@ -7,12 +5,11 @@ export const ROLLDIALOG_SECTION = {
CHOIX: 'choix', CHOIX: 'choix',
CONDITIONS: 'conditions', CONDITIONS: 'conditions',
AJUSTEMENTS: 'ajustements', AJUSTEMENTS: 'ajustements',
} }
export class RollPart { export class RollPart {
static settingKey(rollPart, key) { return `roll-part-${rollPart.code}.${key}` } static settingKey(rollPart, key) { return `roll-part-${rollPart.code}.${key}` }
get code() { throw new Error(`Pas dse code définie pour ${this}`) } get code() { throw new Error(`Pas dse code définie pour ${this}`) }
get name() { return this.code } get name() { return this.code }
/** la section de la fenêtre ou le paramêtre apparaît */ /** la section de la fenêtre ou le paramêtre apparaît */
@@ -20,30 +17,37 @@ export class RollPart {
get priority() { return 0 /* TODO */ } get priority() { return 0 /* TODO */ }
/** le template handlebars pour affichage */ /** le template handlebars pour affichage */
get template() { return `systems/foundryvtt-reve-de-dragon/templates/roll/roll-part-${this.code}.hbs` } get template() { return `systems/foundryvtt-reve-de-dragon/templates/roll/roll-part-${this.code}.hbs` }
static getSelectedPart(rollData, code) {
return rollData.selected[code] ?? {}
}
static setSelectedPart(rollData, code, saved) {
rollData.selected[code] = saved
}
/** l'acteur actif du jet */ /** l'acteur actif du jet */
getActor(rollData) { return rollData.active.actor } getActor(rollData) { return rollData.active.actor }
/** le conteneur de données du RollPart */ /** le conteneur de données du RollPart */
getRefs(rollData) { getRefs(rollData) {
return rollData.refs[this.code] return rollData.refs[this.code]
} }
/** les informations de sélection du paramètre */ /** les informations de sélection du paramètre */
getCurrent(rollData) { getCurrent(rollData) {
return rollData.current[this.code] return rollData.current[this.code]
} }
setCurrent(rollData, current) { setCurrent(rollData, current) {
rollData.current[this.code] = current rollData.current[this.code] = current
} }
/** les informations minimales représentant la sélection dans le rollData permettant de restaurer la fenêtre */ /** les informations minimales représentant la sélection dans le rollData permettant de restaurer la fenêtre */
getSelected(rollData) { return this.getSaved(rollData) } getSelected(rollData) { return this.getSaved(rollData) }
getSaved(rollData) { getSaved(rollData) {
return rollData.selected[this.code] ?? {} return RollPart.getSelectedPart(rollData, this.code)
} }
setSaved(rollData, saved) { setSaved(rollData, saved) {
rollData.selected[this.code] = saved RollPart.setSelectedPart(rollData, this.code, saved)
} }
restore(rollData) { } restore(rollData) { }
@@ -75,7 +79,7 @@ export class RollPart {
isValid(rollData) { return true } isValid(rollData) { return true }
visible(rollData) { return true } visible(rollData) { return true }
onReady() { } onReady(rollParts) { }
loadRefs(rollData) { } loadRefs(rollData) { }
prepareContext(rollData) { } prepareContext(rollData) { }
@@ -103,4 +107,13 @@ export class RollPart {
async _onRender(rollDialog, context, options) { } async _onRender(rollDialog, context, options) { }
getHooks() { return [] } getHooks() { return [] }
onNumericInputChange(event, rollDialog, setValue = value => this.getCurrent(rollDialog.rollData).value = value) {
if (isNaN(event.currentTarget.value) || event.currentTarget.value == "") {
return
}
setValue(parseInt(event.currentTarget.value))
rollDialog.render()
}
} }

View File

@@ -5,8 +5,6 @@ const DEFAULT_DIFF_TYPES = [DIFF.LIBRE, DIFF.IMPOSEE, DIFF.DEFAUT]
export class RollType { export class RollType {
onReady() { }
get code() { throw new Error(`Pas de code défini pour ${this}`) } get code() { throw new Error(`Pas de code défini pour ${this}`) }
get name() { return this.code } get name() { return this.code }
get icon() { return `systems/foundryvtt-reve-de-dragon/assets/actions/${this.code}.svg` } get icon() { return `systems/foundryvtt-reve-de-dragon/assets/actions/${this.code}.svg` }

View File

@@ -1,8 +1,7 @@
<label for="{{code}}">Conditions</label> <label for="{{code}}">Conditions</label>
{{numberInput current.value <input type="number"
name=name name="{{name}}"
step=1 value="{{current.value}}"
min=current.min pattern="^(-|+)?\d+$"
max=current.max min="{{current.min}}" max="{{current.max}}" step="1"
disabled=rollData.type.retry {{#if rollData.type.retry}}disabled{{/if}}>
}}

View File

@@ -9,24 +9,23 @@
{{#if current.recette}} {{#if current.recette}}
<selected-numeric-value>{{plusMoins current.value}}</selected-numeric-value> <selected-numeric-value>{{plusMoins current.value}}</selected-numeric-value>
{{else if current.ingredient}} {{else if current.ingredient}}
{{numberInput current.value <input type="number"
name='diff-var' name='diff-var'
step=1 value="{{current.value}}"
min=-10 pattern="^(-|+)?\d+$"
max=0 min="-10" max="0" step="1"
disabled=rollData.type.retry {{#if rollData.type.retry}}disabled{{/if}}>
}}
{{/if}} {{/if}}
</subline> </subline>
<subline> <subline>
<label for="proportions">Proportions</label> <label for="proportions">Proportions</label>
{{numberInput current.proportions <input type="number"
name='proportions' name='proportions'
step=1 value="{{current.proportions}}"
min=1 pattern="^\d+$"
max=(either current.proportionsMax 10) min="1" max="{{either current.proportionsMax 10}}" step="1"
disabled=rollData.type.retry {{#if rollData.type.retry}}disabled{{/if}}>
}}
{{#if (and current.sust (ne current.sust 1))}}<span>(&times; {{current.sust}})</span>{{/if}} {{#if (and current.sust (ne current.sust 1))}}<span>(&times; {{current.sust}})</span>{{/if}}
</subline> </subline>
<subline> <subline>

View File

@@ -1,10 +1,9 @@
<subline> <subline>
<label for="{{code}}">{{current.label}}&nbsp;</label> <label for="{{code}}">{{current.label}}&nbsp;</label>
{{numberInput current.value <input type="number"
name=name name="{{name}}"
step=1 value="{{current.value}}"
min=current.min pattern="^(-|+)?\d+$"
max=current.max min="{{current.min}}" max="{{current.max}}" step="1"
disabled=(or rollData.type.retry current.disabled) {{#if (or rollData.type.retry current.disabled)}}disabled{{/if}}>
}}
</subline> </subline>

View File

@@ -6,10 +6,9 @@
{{current.label}} {{current.label}}
</label> </label>
<label for="malusenc"></label> <label for="malusenc"></label>
{{numberInput current.value <input type="number"
name='malusenc' name='malusenc'
step=1 value="{{current.value}}"
min=-30 pattern="^(-)?\d+$"
max=0 min="-30" max="0" step="1"
disabled=rollData.type.retry {{#if rollData.type.retry}}disabled{{/if}}>
}}

View File

@@ -8,13 +8,12 @@
{{selectOptions refs.sorts selected=current.key valueAttr="key" labelAttr="label"}} {{selectOptions refs.sorts selected=current.key valueAttr="key" labelAttr="label"}}
</select> </select>
{{#if current.isDiffVariable}} {{#if current.isDiffVariable}}
{{numberInput current.value <input type="number"
name='diff-var' name='diff-var'
step=1 value="{{current.value}}"
min=-20 pattern="^(-)?\d+$"
max=-1 min="-20" max="-1" step="1"
disabled=rollData.type.retry {{#if rollData.type.retry}}disabled{{/if}}>
}}
{{else}} {{else}}
<selected-numeric-value>{{plusMoins current.value}}</selected-numeric-value> <selected-numeric-value>{{plusMoins current.value}}</selected-numeric-value>
{{/if}} {{/if}}
@@ -23,13 +22,13 @@
<label for="ptreve-var">Rêve {{itemSort-coutReve current.sort}}&nbsp;</span> <label for="ptreve-var">Rêve {{itemSort-coutReve current.sort}}&nbsp;</span>
</label> </label>
{{#if current.isReveVariable}} {{#if current.isReveVariable}}
{{numberInput current.ptreve <input type="number"
name='ptreve-var' name='ptreve-var'
step=1 value="{{current.ptreve}}"
min=1 pattern="^\d+$"
max=30 min="{{1}}" max="{{60}}" step="1"
disabled=rollData.type.retry {{#if rollData.type.retry}}disabled{{/if}}>
}}
{{/if}} {{/if}}
<span>&nbsp;(actuel: {{rollData.active.actor.system.reve.reve.value}})</span> <span>&nbsp;(actuel: {{rollData.active.actor.system.reve.reve.value}})</span>
</subline> </subline>

View File

@@ -1,8 +1,7 @@
<label for="{{name}}">Forcer </label> <label for="{{name}}">Forcer </label>
<img src="systems/foundryvtt-reve-de-dragon/assets/ui/d100.svg" data-tooltip="Forcer le résultat du jet de dé"/> <img src="systems/foundryvtt-reve-de-dragon/assets/ui/d100.svg" data-tooltip="Forcer le résultat du jet de dé"/>
{{numberInput current.resultat <input type="number"
name=name name="{{name}}"
step=1 value="{{current.resultat}}"
min=-1 pattern="^(-|+)?\d+$"
max=100 min="-1" max="100" step="1">
}}