Compare commits

...

16 Commits

Author SHA1 Message Date
17cb8a2e06 13.0.45
All checks were successful
Release Creation / build (release) Successful in 1m23s
2026-06-16 23:02:39 +02:00
933256da66 Nouvelle correction du manifest
Some checks failed
Release Creation / build (release) Has been cancelled
Le manifest versionné, téléchargé dans le système, pointe maintenant
sur le manifest latest.

Le lien manifest foundry est celui du manifest de la version.
2026-06-16 22:59:36 +02:00
a58b171fb4 13.0.44 - Le dépôt d'Illisys
All checks were successful
Release Creation / build (release) Successful in 1m5s
- le manifest pointe maintenant toujours vers la dernière version
- changement des liens dans le system.json
2026-06-15 21:26:03 +02:00
2eac969261 Update system.json
even if not necessary, it was referencing previous repository
2026-06-14 22:41:04 +02:00
fabres
e6612fe024 Make default release as latest 2026-06-14 21:57:55 +02:00
fabres
18b9e4c7a8 Updte gitignore 2026-06-14 21:55:48 +02:00
fcaebe6334 Correction des jets impossibles
All checks were successful
Release Creation / build (release) Successful in 1m58s
2026-06-12 00:26:54 +02:00
c4033707be macro signe draconique
All checks were successful
Release Creation / build (release) Successful in 1m48s
2026-06-03 00:56:52 +02:00
8b83369d5a On peut choisir la difficulté de résistance
La difficulté des jets de résistance est libre
2026-06-03 00:46:15 +02:00
e9183df59c le Guerrier Sorde n'est pas joueur 2026-06-03 00:46:15 +02:00
45ccac3489 Mineur - rendu monnaies 2026-06-03 00:39:12 +02:00
c41db974ff Corrections description aléatoire 2026-06-03 00:39:12 +02:00
875e121a09 Merge pull request '13.0.41 -mode de visibilité des jets' (#808) from feature/v13-corrections into v13
All checks were successful
Release Creation / build (release) Successful in 1m0s
Reviewed-on: https, #808
2026-05-29 02:08:11 +02:00
12e0e6397c mode de visibilité des jets 2026-05-29 02:01:30 +02:00
93b74574ad pas de stress/sommeil pour personnage non lié
All checks were successful
Release Creation / build (release) Successful in 1m32s
2026-05-29 01:53:35 +02:00
1765cb2ef9 Mode de visibilité des jets 2026-05-29 01:53:35 +02:00
21 changed files with 284 additions and 219 deletions

View File

@@ -32,7 +32,7 @@ jobs:
env:
version: ${{steps.get_version.outputs.version-without-v}}
url: https://gitea.scriptarium.org/${{gitea.repository}}
manifest: https://gitea.scriptarium.org/${{gitea.repository}}/releases/download/${{github.event.release.tag_name}}/system.json
manifest: "https://gitea.scriptarium.org/Scriptarium/foundryvtt-reve-de-dragon/releases/download/latest/system.json"
download: https://gitea.scriptarium.org/${{gitea.repository}}/releases/download/${{github.event.release.tag_name}}/rddsystem.zip
- name: Set up Node.js
@@ -69,7 +69,7 @@ jobs:
token: ${{ secrets.RDD_PUBLISH_RELEASE_FOUNDRY }}
id: "foundryvtt-reve-de-dragon"
version: ${{github.event.release.tag_name}}
manifest: "https://gitea.scriptarium.org/${{gitea.repository}}/releases/download/${{github.event.release.tag_name}}/system.json"
manifest: https://gitea.scriptarium.org/${{gitea.repository}}/releases/download/${{github.event.release.tag_name}}/system.json
notes: "https://gitea.scriptarium.org/Scriptarium/foundryvtt-reve-de-dragon/raw/branch/v13/changelog.md"
compatibility-minimum: "13"
compatibility-verified: "13"

1
.gitignore vendored
View File

@@ -12,3 +12,4 @@ todo.md
/packs/*/CURRENT
/packs/*/LOG
/packs/*/LOCK
.github/

View File

@@ -1,5 +1,34 @@
# 13.0
## 13.0.45 - L'endépôté d'Illisys
- nouvelle correction du manifest
## 13.0.44 - Le dépôt d'Illisys
- le manifest pointe maintenant toujours vers la dernière version
- changement des liens dans le system.json
## 13.0.43 - L'urgence d'Illisys
- correction urgente des jets
## 13.0.42 - La rebellion d'Illisys
- on peut choisir la difficulté des jets de résistances
- la macro signe draconique fonctionne de nouveau (ajout et suppression)
- le Guerrier Sorde n'est pas joueur et ne cuisine pas (pas de message si compétence Jeu / Cuisine manquent)
- Corrections V14
- Les descriptions aléatoires fonctionnent de nouveau
## 13.0.41 - Le miroir d'Illisys
- les mode de visibilité des jets sont bien pris en compte
## 13.0.40 - Le miroir d'Illisys
- pas de stress ou de sommeil pour les personnage non liés
## 13.0.39 - La défense d'Illisys
- mise à jour de version foundry-cli

View File

@@ -949,7 +949,7 @@ export class RdDActor extends RdDBaseActorSang {
/* -------------------------------------------- */
async distribuerStress(compteur, valeur, motif) {
if (game.user.isGM && this.hasPlayerOwner) {
if (game.user.isGM && this.isPersonnageJoueur()) {
switch (compteur) {
case 'stress': case 'experience':
await this.addCompteurValue(compteur, valeur, motif);

View File

@@ -5,25 +5,80 @@ import { RdDDice } from "../../rdd-dice.js";
import { RdDNameGen } from "../../rdd-namegen.js";
import { RdDTimestamp } from "../../time/rdd-timestamp.js";
const PATHS = [
'name',
'system.sexe',
'system.age',
'system.taille',
'system.poids',
'system.main',
'system.heure',
'system.cheveux',
'system.yeux'
]
const RANDOM_VALUES = {
'system.sexe': { 'masculin': 1, 'féminin': 1 },
'system.main': { 'droitier': 51, 'gaucher': 15, 'ambidextre': 6 },
'system.cheveux': { 'noirs': 2, 'bruns': 5, 'châtains': 3, 'châtain clair': 5, 'blonds': 4, 'blond platine': 1, 'roux carotte': 1, 'roux cuivré': 3, 'chauve': 1 },
'system.yeux': { 'noirs': 2, 'noisette': 3, 'brun-vert': 4, 'verts': 3, 'bleu clair': 3, 'bleu gris': 2, 'gris': 1, 'mauves': 1, 'indigos': 1 },
async function randomFrom(values) {
const max = Object.values(values).reduce(Misc.sum(), 0)
const total = await RdDDice.rollTotal(`1d${max}`)
let sum = 0
for (let entry of Object.entries(values)) {
sum = sum + entry[1]
if (sum >= total) {
return entry[0]
}
}
return Object.keys(values)[0]
}
async function randomTailleCm(taille) {
const infoTaille = RdDCarac.getCaracDerivee(taille)
const infoTailleSup = RdDCarac.getCaracDerivee(taille + 1)
const variation = (infoTailleSup.taille - infoTaille.taille) + Math.floor((infoTaille.poidsMax - infoTaille.poidsMin) / 2)
const base = infoTaille.taille
const total = await RdDDice.rollTotal(`1d${variation} -1d ${variation} + ${base}`)
const cm = total % 100
const dm = cm < 10 ? '0' : ''
const m = (total - cm) / 100
return `${m}m${dm}${cm}`
}
async function randomPoidsKg(taille) {
const infoTaille = RdDCarac.getCaracDerivee(taille)
const range = infoTaille.poidsMax - infoTaille.poidsMin + 1
const total = await RdDDice.rollTotal(`1d${range} + ${infoTaille.poidsMin}`)
return total + ' kg'
}
async function randomHeure() {
return RdDTimestamp.defHeure(await RdDDice.rollHeure({ rollMode: "selfroll", showDice: SHOW_DICE })).key
}
const CONTROL_UNKNOWN = { name: 'unknown', path: '', getter: (act) => { undefined }, random: async act => undefined }
const TABLE_SEXES = { 'masculin': 1, 'féminin': 1 };
const TABLE_MAINS = { 'droitier': 51, 'gaucher': 15, 'ambidextre': 6 };
const TABLE_COULEURS_CHEVEUX = {
'noirs': 2,
'bruns': 5,
'châtains': 3,
'châtain clair': 5,
'blonds': 4,
'blond platine': 1,
'roux carotte': 1,
'roux cuivré': 3,
'chauve': 1
};
const TABLE_COULEURS_YEUX = {
'noirs': 2,
'noisette': 3,
'brun-vert': 4,
'verts': 3,
'bleu clair': 3,
'bleu gris': 2,
'gris': 1,
'mauves': 1,
'indigos': 1
};
const CONTROLS = [
{ name: 'name', path: 'name', getter: (act) => act.name, random: async act => await RdDNameGen.generate() },
{ name: 'sexe', path: 'system.sexe', getter: act => act.system.sexe, random: async act => await randomFrom(TABLE_SEXES) },
{ name: 'age', path: 'system.age', getter: act => act.system.age, random: async act => await RdDDice.rollTotal('(2d4kl)*10 + 1d7xo + 2d20kl') },
{ name: 'taille', path: 'system.taille', getter: act => act.system.taille, random: async act => await randomTailleCm(act.system.carac.taille.value) },
{ name: 'poids', path: 'system.poids', getter: act => act.system.poids, random: async act => await randomPoidsKg(act.system.carac.taille.value) },
{ name: 'main', path: 'system.main', getter: act => act.system.main, random: async act => await randomFrom(TABLE_MAINS) },
{ name: 'heure', path: 'system.heure', getter: act => act.system.heure, random: async act => await randomHeure() },
{ name: 'cheveux', path: 'system.cheveux', getter: act => act.system.cheveux, random: async act => await randomFrom(TABLE_COULEURS_CHEVEUX) },
{ name: 'yeux', path: 'system.yeux', getter: act => act.system.yeux, random: async act => await randomFrom(TABLE_COULEURS_YEUX) },
]
export class AppPersonnageAleatoire extends FormApplication {
static preloadHandlebars() {
foundry.applications.handlebars.loadTemplates([
@@ -47,18 +102,12 @@ export class AppPersonnageAleatoire extends FormApplication {
constructor(actor) {
super({})
this.actor = actor
this.current = foundry.utils.duplicate(actor)
this.checked = {
'name': false,
'system.sexe': (this.actor.system.sexe ?? '') == '',
'system.age': this.actor.system.age == 0,
'system.taille': (this.actor.system.taille ?? '') == '',
'system.poids': (this.actor.system.poids ?? '') == '',
'system.main': (this.actor.system.main ?? '') == '',
'system.heure': (this.actor.system.heure ?? '') == '',
'system.cheveux': (this.actor.system.cheveux ?? '') == '',
'system.yeux': (this.actor.system.yeux ?? '') == '',
this.current = AppPersonnageAleatoire.getActorValues()
this.checked = Object.fromEntries(CONTROLS.map(it => [it.name, [0, '', undefined].includes(it.getter(this.current))]))
}
static getActorValues() {
return Object.fromEntries(CONTROLS.map(it => [it.name, it.getter(this.actor)]));
}
async getData(options) {
@@ -73,124 +122,84 @@ export class AppPersonnageAleatoire extends FormApplication {
activateListeners(html) {
super.activateListeners(html)
this.html = html
this.html.find("button.button-cancel").click(async event => await this.close())
this.html.find("button.button-apply").click(async event => await this.onApply())
this.html.find("input.current-value").change(async event => await this.onChange(event))
this.html.find("div.random-field[data-path='system.heure'] select.current-value").change(async event => await this.onChange(event))
this.html.find('a[data-action="sexe-masculin"]').click(async event => await this.onSexe('masculin'))
this.html.find('a[data-action="sexe-feminin"]').click(async event => await this.onSexe('féminin'))
this.html.find("a.random").click(async event => await this.onRandom(event))
this.html.find("a.reset").click(async event => await this.onReset(event))
this.html.find("a.randomize-selected").click(async event => await this.onRandomizeSelected())
this.html.find("input.check-for-random").click(async event => await this.onCheckForRandom(event))
this.html.find("div.random-field[data-field-name='heure'] select.current-value").change(async event => await this.onChange(event))
this.html.find('a[data-action="sexe-masculin"]').click(async event => await this.onSexe('masculin'))
this.html.find('a[data-action="sexe-feminin"]').click(async event => await this.onSexe('féminin'))
this.html.find("button.button-cancel").click(async event => await this.close())
this.html.find("button.button-apply").click(async event => await this.onApply())
}
async _updateObject(event, formData) { }
async onApply() {
const updates = Object.fromEntries(
PATHS.filter(path => game.user.isGM || path != 'name')
.map(path => [path, this.current[path]])
CONTROLS.filter(control => game.user.isGM || control.name != 'name')
.map(control => [control.path, control.getter(this.current)])
)
await this.actor.update(updates)
await this.close()
}
getPath(selector) {
getName(selector) {
const fields = this.html.find(selector).parents("div.random-field:first")
return fields[0].attributes['data-path'].value
return fields[0].attributes['data-field-name'].value
}
getControl(name) {
return CONTROLS.find(it => it.name == name) ?? CONTROL_UNKNOWN
}
async onSexe(sexe) {
this.current['system.sexe'] = sexe
this.current['sexe'] = sexe
this.render()
}
async onChange(event) {
const path = this.getPath(event.currentTarget)
this.current[path] = event.currentTarget.value
const name = this.getName(event.currentTarget)
const control = this.getControl(name)
this.current[control.name] = event.currentTarget.value
this.render()
}
async onRandom(event) {
const path = this.getPath(event.currentTarget)
await this.setRandom(path);
const name = this.getName(event.currentTarget)
const control = this.getControl(name)
await this.randomControl(control)
this.render()
}
async onReset(event) {
const path = this.getPath(event.currentTarget)
this.current[path] = this.actor[path]
const name = this.getName(event.currentTarget)
const control = this.getControl(name)
this.current[control.name] = control.getter(this.actor)
await this.render()
}
async onCheckForRandom(event) {
const path = this.getPath(event.currentTarget)
this.checked[path] = event.currentTarget.checked
const name = this.getName(event.currentTarget)
this.checked[name] = event.currentTarget.checked
this.render()
}
async onRandomizeSelected() {
const paths = this.html.find("input.check-for-random:checked")
const controls = this.html.find("input.check-for-random:checked")
.parents("div.random-field")
.toArray()
.map(it => it.attributes['data-path'].value)
await Promise.all(paths.map(path => this.setRandom(path)))
.map(it => this.getControl(it.attributes['data-field-name'].value))
await Promise.all(controls.map(it => this.randomControl(it)))
this.render()
}
async setRandom(path) {
this.current[path] = await this.random(path);
async randomControl(control) {
this.current[control.name] = await control.random(this.current)
}
async random(path) {
switch (path) {
case 'name':
return await RdDNameGen.generate()
case 'system.sexe':
case 'system.main':
case 'system.cheveux':
case 'system.yeux':
return await this.randomFromMap(RANDOM_VALUES[path])
case 'system.poids':
return await this.randomPoids()
case 'system.taille':
return await this.randomTaille()
case 'system.age':
return await RdDDice.rollTotal('(2d4kl)*10 + 1d7xo + 2d20kl')
case 'system.heure':
return RdDTimestamp.defHeure(await RdDDice.rollHeure({ rollMode: "selfroll", showDice: SHOW_DICE })).key
}
return 'unknown'
}
async randomFromMap(valuesMap) {
const max = Object.values(valuesMap).reduce(Misc.sum(), 0)
const total = await RdDDice.rollTotal(`1d${max}`)
let sum = 0
for (let entry of Object.entries(valuesMap)) {
sum = sum + entry[1]
if (sum >= total) {
return entry[0]
}
}
return Object.keys(valuesMap)[0]
}
async randomPoids() {
const caracTaille = RdDCarac.getCaracDerivee(this.current.system.carac.taille.value)
const range = caracTaille.poidsMax - caracTaille.poidsMin + 1
const total = await RdDDice.rollTotal(`1d${range} + ${caracTaille.poidsMin}`)
return total + ' kg'
}
async randomTaille() {
const caracTaille = RdDCarac.getCaracDerivee(this.current.system.carac.taille.value)
const base = this.current.system.carac.taille.value * 2 + 60 + caracTaille.poidsMin
const variation = Math.floor((caracTaille.poidsMax - caracTaille.poidsMin + base / 5) / 2)
const total = await RdDDice.rollTotal(`2d${variation} + ${base}`)
const cm = total % 100
const dm = cm < 10 ? '0' : ''
const m = (total - cm) / 100
return `${m}m${dm}${cm}`
}
}

View File

@@ -48,7 +48,7 @@ export class DialogCreateSigneDraconique extends Dialog {
async _createSigneForActor(actor, signe) {
await actor.createEmbeddedDocuments("Item", [signe]);
await ChatMessage.createChatMessage.create({
await ChatMessage.create({
whisper: ChatUtility.getOwners(actor),
content: await renderTemplate("systems/foundryvtt-reve-de-dragon/templates/chat-signe-draconique-actor.hbs", {
signe: signe,

View File

@@ -3,38 +3,38 @@ import { Misc } from "./misc.js";
const TABLE_CARACTERISTIQUES_DERIVEES = {
// xp: coût pour passer du niveau inférieur à ce niveau
1: { xp: 3, niveau: -5, poids: "moins de 1kg", poidsMin: 0, poidsMax: 1, plusdom: -5, sconst: 0.5, sust: 0.1 },
2: { xp: 3, niveau: -4, poids: "1-5", poidsMin: 1, poidsMax: 5, plusdom: -4, sconst: 0.5, sust: 0.3 },
3: { xp: 4, niveau: -3, poids: "6-10", poidsMin: 6, poidsMax: 10, plusdom: -3, sconst: 1, sust: 0.5, beaute: 'hideux' },
4: { xp: 4, niveau: -2, poids: "11-20", poidsMin: 11, poidsMax: 20, plusdom: -3, sconst: 1, sust: 1, beaute: 'repoussant' },
5: { xp: 5, niveau: -1, poids: "21-30", poidsMin: 21, poidsMax: 30, plusdom: -2, sconst: 1, sust: 1, beaute: 'franchement très laid' },
6: { xp: 5, niveau: 0, poids: "31-40", poidsMin: 31, poidsMax: 40, plusdom: -1, sconst: 2, sust: 2, beaute: 'laid' },
7: { xp: 6, niveau: 0, poids: "41-50", poidsMin: 41, poidsMax: 50, plusdom: -1, sconst: 2, sust: 2, beaute: 'très désavantagé' },
8: { xp: 6, niveau: 0, poids: "51-60", poidsMin: 51, poidsMax: 60, plusdom: 0, sconst: 2, sust: 2, beaute: 'désavantagé' },
9: { xp: 7, niveau: 0, poids: "61-65", poidsMin: 61, poidsMax: 65, plusdom: 0, sconst: 3, sust: 2, beaute: 'pas terrible' },
10: { xp: 7, niveau: 0, poids: "66-70", poidsMin: 66, poidsMax: 70, plusdom: 0, sconst: 3, sust: 3, beaute: 'commun' },
11: { xp: 8, niveau: 1, poids: "71-75", poidsMin: 71, poidsMax: 75, plusdom: 0, sconst: 3, sust: 3, beaute: 'pas mal' },
12: { xp: 8, niveau: 1, poids: "76-80", poidsMin: 76, poidsMax: 80, plusdom: +1, sconst: 4, sust: 3, beaute: 'avantagé' },
13: { xp: 9, niveau: 2, poids: "81-90", poidsMin: 81, poidsMax: 90, plusdom: +1, sconst: 4, sust: 3, beaute: 'mignon' },
14: { xp: 9, niveau: 2, poids: "91-100", poidsMin: 91, poidsMax: 100, plusdom: +2, sconst: 4, sust: 4, beaute: 'beau' },
15: { xp: 10, niveau: 3, poids: "101-110", poidsMin: 101, poidsMax: 110, plusdom: +2, sconst: 5, sust: 4, beaute: 'très beau' },
16: { xp: 20, niveau: 3, poids: "111-120", poidsMin: 111, poidsMax: 120, plusdom: +3, sconst: 5, sust: 4, beaute: 'éblouissant' },
17: { xp: 30, niveau: 4, poids: "121-131", poidsMin: 121, poidsMax: 131, plusdom: +3, sconst: 5, sust: 5 },
18: { xp: 40, niveau: 4, poids: "131-141", poidsMin: 131, poidsMax: 141, plusdom: +4, sconst: 6, sust: 5 },
19: { xp: 50, niveau: 5, poids: "141-150", poidsMin: 141, poidsMax: 150, plusdom: +4, sconst: 6, sust: 5 },
20: { xp: 60, niveau: 5, poids: "151-160", poidsMin: 151, poidsMax: 160, plusdom: +4, sconst: 6, sust: 6 },
21: { xp: 70, niveau: 6, poids: "161-180", poidsMin: 161, poidsMax: 180, plusdom: +5, sconst: 7, sust: 6 },
22: { xp: 80, niveau: 6, poids: "181-200", poidsMin: 181, poidsMax: 200, plusdom: +5, sconst: 7, sust: 7 },
23: { xp: 90, niveau: 7, poids: "201-300", poidsMin: 201, poidsMax: 300, plusdom: +6, sconst: 7, sust: 8 },
24: { xp: 100, niveau: 7, poids: "301-400", poidsMin: 301, poidsMax: 400, plusdom: +6, sconst: 8, sust: 9 },
25: { xp: 110, niveau: 8, poids: "401-500", poidsMin: 401, poidsMax: 500, plusdom: +7, sconst: 8, sust: 10 },
26: { xp: 120, niveau: 8, poids: "501-600", poidsMin: 501, poidsMax: 600, plusdom: +7, sconst: 8, sust: 11 },
27: { xp: 130, niveau: 9, poids: "601-700", poidsMin: 601, poidsMax: 700, plusdom: +8, sconst: 9, sust: 12 },
28: { xp: 140, niveau: 9, poids: "701-800", poidsMin: 701, poidsMax: 800, plusdom: +8, sconst: 9, sust: 13 },
29: { xp: 150, niveau: 10, poids: "801-900", poidsMin: 801, poidsMax: 900, plusdom: +9, sconst: 9, sust: 14 },
30: { xp: 160, niveau: 10, poids: "901-1000", poidsMin: 901, poidsMax: 1000, plusdom: +9, sconst: 10, sust: 15 },
31: { xp: 170, niveau: 11, poids: "1001-1500", poidsMin: 1001, poidsMax: 1500, plusdom: +10, sconst: 10, sust: 16 },
32: { xp: 180, niveau: 11, poids: "1501-2000", poidsMin: 1501, poidsMax: 2000, plusdom: +11, sconst: 10, sust: 17 }
1: { xp: 3, niveau: -5, taille: 40, poids: "moins de 1kg", poidsMin: 0, poidsMax: 1, plusdom: -5, sconst: 0.5, sust: 0.1 },
2: { xp: 3, niveau: -4, taille: 70, poids: "1-5", poidsMin: 1, poidsMax: 5, plusdom: -4, sconst: 0.5, sust: 0.3 },
3: { xp: 4, niveau: -3, taille: 100, poids: "6-10", poidsMin: 6, poidsMax: 10, plusdom: -3, sconst: 1, sust: 0.5, beaute: 'hideux' },
4: { xp: 4, niveau: -2, taille: 120, poids: "11-20", poidsMin: 11, poidsMax: 20, plusdom: -3, sconst: 1, sust: 1, beaute: 'repoussant' },
5: { xp: 5, niveau: -1, taille: 135, poids: "21-30", poidsMin: 21, poidsMax: 30, plusdom: -2, sconst: 1, sust: 1, beaute: 'franchement très laid' },
6: { xp: 5, niveau: 0, taille: 145, poids: "31-40", poidsMin: 31, poidsMax: 40, plusdom: -1, sconst: 2, sust: 2, beaute: 'laid' },
7: { xp: 6, niveau: 0, taille: 150, poids: "41-50", poidsMin: 41, poidsMax: 50, plusdom: -1, sconst: 2, sust: 2, beaute: 'très désavantagé' },
8: { xp: 6, niveau: 0, taille: 155, poids: "51-60", poidsMin: 51, poidsMax: 60, plusdom: 0, sconst: 2, sust: 2, beaute: 'désavantagé' },
9: { xp: 7, niveau: 0, taille: 160, poids: "61-65", poidsMin: 61, poidsMax: 65, plusdom: 0, sconst: 3, sust: 2, beaute: 'pas terrible' },
10: { xp: 7, niveau: 0, taille: 170, poids: "66-70", poidsMin: 66, poidsMax: 70, plusdom: 0, sconst: 3, sust: 3, beaute: 'commun' },
11: { xp: 8, niveau: 1, taille: 175, poids: "71-75", poidsMin: 71, poidsMax: 75, plusdom: 0, sconst: 3, sust: 3, beaute: 'pas mal' },
12: { xp: 8, niveau: 1, taille: 180, poids: "76-80", poidsMin: 76, poidsMax: 80, plusdom: +1, sconst: 4, sust: 3, beaute: 'avantagé' },
13: { xp: 9, niveau: 2, taille: 185, poids: "81-90", poidsMin: 81, poidsMax: 90, plusdom: +1, sconst: 4, sust: 3, beaute: 'mignon' },
14: { xp: 9, niveau: 2, taille: 190, poids: "91-100", poidsMin: 91, poidsMax: 100, plusdom: +2, sconst: 4, sust: 4, beaute: 'beau' },
15: { xp: 10, niveau: 3, taille: 200, poids: "101-110", poidsMin: 101, poidsMax: 110, plusdom: +2, sconst: 5, sust: 4, beaute: 'très beau' },
16: { xp: 20, niveau: 3, taille: 210, poids: "111-120", poidsMin: 111, poidsMax: 120, plusdom: +3, sconst: 5, sust: 4, beaute: 'éblouissant' },
17: { xp: 30, niveau: 4, taille: 220, poids: "121-131", poidsMin: 121, poidsMax: 131, plusdom: +3, sconst: 5, sust: 5 },
18: { xp: 40, niveau: 4, taille: 230, poids: "131-141", poidsMin: 131, poidsMax: 141, plusdom: +4, sconst: 6, sust: 5 },
19: { xp: 50, niveau: 5, taille: 240, poids: "141-150", poidsMin: 141, poidsMax: 150, plusdom: +4, sconst: 6, sust: 5 },
20: { xp: 60, niveau: 5, taille: 250, poids: "151-160", poidsMin: 151, poidsMax: 160, plusdom: +4, sconst: 6, sust: 6 },
21: { xp: 70, niveau: 6, taille: 260, poids: "161-180", poidsMin: 161, poidsMax: 180, plusdom: +5, sconst: 7, sust: 6 },
22: { xp: 80, niveau: 6, taille: 270, poids: "181-200", poidsMin: 181, poidsMax: 200, plusdom: +5, sconst: 7, sust: 7 },
23: { xp: 90, niveau: 7, taille: 280, poids: "201-300", poidsMin: 201, poidsMax: 300, plusdom: +6, sconst: 7, sust: 8 },
24: { xp: 100, niveau: 7, taille: 290, poids: "301-400", poidsMin: 301, poidsMax: 400, plusdom: +6, sconst: 8, sust: 9 },
25: { xp: 110, niveau: 8, taille: 300, poids: "401-500", poidsMin: 401, poidsMax: 500, plusdom: +7, sconst: 8, sust: 10 },
26: { xp: 120, niveau: 8, taille: 310, poids: "501-600", poidsMin: 501, poidsMax: 600, plusdom: +7, sconst: 8, sust: 11 },
27: { xp: 130, niveau: 9, taille: 320, poids: "601-700", poidsMin: 601, poidsMax: 700, plusdom: +8, sconst: 9, sust: 12 },
28: { xp: 140, niveau: 9, taille: 330, poids: "701-800", poidsMin: 701, poidsMax: 800, plusdom: +8, sconst: 9, sust: 13 },
29: { xp: 150, niveau: 10, taille: 340, poids: "801-900", poidsMin: 801, poidsMax: 900, plusdom: +9, sconst: 9, sust: 14 },
30: { xp: 160, niveau: 10, taille: 350, poids: "901-1000", poidsMin: 901, poidsMax: 1000, plusdom: +9, sconst: 10, sust: 15 },
31: { xp: 170, niveau: 11, taille: 360, poids: "1001-1500", poidsMin: 1001, poidsMax: 1500, plusdom: +10, sconst: 10, sust: 16 },
32: { xp: 180, niveau: 11, taille: 370, poids: "1501-2000", poidsMin: 1501, poidsMax: 2000, plusdom: +11, sconst: 10, sust: 17 },
};
export const CARACS = {

View File

@@ -466,7 +466,10 @@ export class RdDCommands {
async supprimerSignesDraconiquesEphemeres() {
if (game.user.isGM) {
game.actors.forEach(actor => actor.supprimerSignesDraconiques(it => it.system.ephemere))
await Promise.all(
game.actors.filter(actor => actor.isHautRevant())
.map(actor => actor.supprimerSignesDraconiques(it => it.system.ephemere))
)
}
else {
ui.notifications.warn("Seul le MJ est autorisé à utiliser la commande /signe");

View File

@@ -47,8 +47,10 @@ export default class ChatRollResult {
{
content: await this.buildRollHtml(roll)
},
roll.active.actor,
roll.current?.rollmode?.key
{
actor: roll.active.actor,
rollMode: roll.current?.rollmode?.key
}
))
await this.saveChatMessageRoll(chatMessage, roll, impacts)

View File

@@ -35,3 +35,10 @@ export const DIFFS = {
[DIFF.AUCUN]: { key: DIFF.AUCUN, label: "", libre: false, visible: false, max: 0 },
}
export class RollConstants {
static findCompetence(rollData, name) {
return rollData.active.actor.getCompetence(name, { onMessage: message => { } })
}
}

View File

@@ -1,6 +1,6 @@
import { ITEM_TYPES } from "../constants.js"
import { CARACS } from "../rdd-carac.js"
import { ROLL_TYPE_CUISINE } from "./roll-constants.mjs"
import { ROLL_TYPE_CUISINE, RollConstants } 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"
@@ -18,7 +18,11 @@ export class RollPartCuisine extends RollPartSelect {
get rollTypes() { return [ROLL_TYPE_CUISINE] }
isValid(rollData) { return rollData.active.actor.isPersonnage() }
isValid(rollData) {
return rollData.active.actor.isPersonnage()
&& RollConstants.findCompetence(rollData, 'Cuisine')
}
visible(rollData) { return RollPart.isRollType(rollData, ROLL_TYPE_CUISINE) }
restore(rollData) {
@@ -38,14 +42,18 @@ export class RollPartCuisine extends RollPartSelect {
loadRefs(rollData) {
const refs = this.getRefs(rollData)
const actor = rollData.active.actor
refs.cuisine = actor.getCompetence('Cuisine')
refs.cuisine = RollConstants.findCompetence(rollData, 'Cuisine')
const recettes = actor.items
if (!refs.cuisine) {
refs.preparations = []
return
}
const recettes = rollData.active.actor.items
.filter(it => it.type == ITEM_TYPES.recettecuisine)
.map(it => RollPartCuisine.$extractPreparationRecette(refs.cuisine, it))
const ingredientsBruts = actor.items
const ingredientsBruts = rollData.active.actor.items
.filter(it => it.getUtilisationCuisine() == 'brut')
.map(it => RollPartCuisine.$extractPreparationBrut(refs.cuisine, it))

View File

@@ -1,13 +1,12 @@
import { ITEM_TYPES } from "../constants.js"
import { CARACS } from "../rdd-carac.js"
import { ROLL_TYPE_JEU } from "./roll-constants.mjs"
import { ROLL_TYPE_JEU, RollConstants } from "./roll-constants.mjs"
import { PART_CARAC } from "./roll-part-carac.mjs"
import { PART_COMP, RollPartComp } from "./roll-part-comp.mjs"
import { RollPartSelect } from "./roll-part-select.mjs"
import { ROLLDIALOG_SECTION, RollPart } from "./roll-part.mjs"
import { RdDItem } from "../item.js"
import { Misc } from "../misc.js"
import { Grammar } from "../grammar.js"
export const PART_JEU = "jeu"
@@ -19,15 +18,21 @@ export class RollPartJeu extends RollPartSelect {
get section() { return ROLLDIALOG_SECTION.CHOIX }
get rollTypes() { return [ROLL_TYPE_JEU] }
isValid(rollData) { return rollData.active.actor.isPersonnage() }
isValid(rollData) {
return rollData.active.actor.isPersonnage()
&& RollConstants.findCompetence(rollData, 'Jeu')
}
visible(rollData) { return RollPart.isRollType(rollData, ROLL_TYPE_JEU) }
loadRefs(rollData) {
const refs = this.getRefs(rollData)
const actor = rollData.active.actor
const compJeu = actor.getCompetence(COMPETENCE_JEU)
refs.jeux = actor.itemTypes[ITEM_TYPES.jeu]
const compJeu = RollConstants.findCompetence(rollData, 'Jeu')
if (!compJeu) {
refs.jeux = []
return
}
refs.jeux = rollData.active.actor.itemTypes[ITEM_TYPES.jeu]
.map(it => RollPartJeu.$extractJeu(it, compJeu))
if (refs.jeux.length > 0) {
@@ -51,22 +56,22 @@ export class RollPartJeu extends RollPartSelect {
}
}
static $getJeuBase(jeu, comp, caracs) {
if (jeu.system.base < comp.system.niveau) {
static $getJeuBase(jeu, compJeu, caracs) {
if (jeu.system.base < compJeu.system.niveau) {
return undefined
}
return new RdDItem({
id: comp.id,
id: compJeu.id,
name: `Jeu ${Misc.lowerFirst(jeu.name)}`,
type: ITEM_TYPES.competence,
img: comp.img,
img: compJeu.img,
system: foundry.utils.mergeObject(
{
niveau: jeu.system.base,
base: jeu.system.base,
default_carac: caracs.length > 0 ? caracs[0] : CARACS.CHANCE
},
comp.system,
compJeu.system,
{ overwrite: false }
)
})
@@ -90,7 +95,7 @@ export class RollPartJeu extends RollPartSelect {
static forceCompJeu(rollData) {
const jeu = rollData.current[PART_JEU].base ?? rollData.current[PART_JEU].comp
if (jeu){
if (jeu) {
rollData.refs[PART_COMP].comps = [jeu].map(it => RollPartComp.extractComp(it))
}
else {

View File

@@ -1,7 +1,7 @@
import { ITEM_TYPES } from "../constants.js"
import { APPRECIATION } from "../moral/apprecier.mjs"
import { RollBasicParts } from "./roll-basic-parts.mjs"
import { DIFF, ROLL_TYPE_CUISINE } from "./roll-constants.mjs"
import { DIFF, ROLL_TYPE_CUISINE, RollConstants } from "./roll-constants.mjs"
import { PART_CUISINE } from "./roll-part-cuisine.mjs"
import { RollType } from "./roll-type.mjs"
@@ -9,8 +9,11 @@ export class RollTypeCuisine extends RollType {
get code() { return ROLL_TYPE_CUISINE }
get name() { return `Cuisiner un plat` }
visible(rollData) { return rollData.active.actor.isPersonnage()
&& rollData.active.actor.getCompetence('Cuisine') != undefined }
visible(rollData) {
return rollData.active.actor.isPersonnage()
&& RollConstants.findCompetence(rollData, 'Cuisine')
}
title(rollData) {
const current = rollData.current[PART_CUISINE]
return current.recette ? `prépare une recette: ${current.label}` : `prépare: ${current.label}`

View File

@@ -1,6 +1,6 @@
import { PART_JEU, RollPartJeu } from "./roll-part-jeu.mjs"
import { RollType } from "./roll-type.mjs"
import { DIFF, ROLL_TYPE_JEU } from "./roll-constants.mjs"
import { DIFF, ROLL_TYPE_JEU, RollConstants } from "./roll-constants.mjs"
import { Apprecier } from "../moral/apprecier.mjs"
@@ -10,8 +10,9 @@ export class RollTypeJeu extends RollType {
visible(rollData) {
return rollData.active.actor.isPersonnage()
&& rollData.active.actor.getCompetence('Jeu') != undefined
&& RollConstants.findCompetence(rollData, 'Jeu')
}
title(rollData) {
if (rollData.opponent) {
return `joue contre`

View File

@@ -16,7 +16,7 @@ export class RollTypeReveResistance extends RollType {
foundry.utils.mergeObject(rollData, {
selected: {
carac: { key: CARACS.REVE_ACTUEL, forced: true },
diff: { value: -8, type: '' },
diff: { value: -8, type: DIFF.LIBRE },
comp: { key: '', forced: true },
conditions: { hide: true }
}
@@ -25,7 +25,7 @@ export class RollTypeReveResistance extends RollType {
}
onSelect(rollData) {
this.setDiffType(rollData, DIFF.DEFAUT)
this.setDiffType(rollData, DIFF.LIBRE)
}
}

View File

@@ -8,7 +8,7 @@ export class DialogRepos extends Dialog {
if (!actor.isPersonnage()) {
return
}
if (!ReglesOptionnelles.isUsing("chateau-dormant-gardien") || !actor.hasPlayerOwner) {
if (!ReglesOptionnelles.isUsing("chateau-dormant-gardien") || !actor.isPersonnageJoueur()) {
foundry.utils.mergeObject(actor.system.sommeil, {
"nouveaujour": true,
"insomnie": EffetsDraconiques.isSujetInsomnie(actor),

View File

@@ -1,10 +1,10 @@
{
"id": "foundryvtt-reve-de-dragon",
"title": "Rêve de Dragon",
"version": "13.0.36",
"download": "https://www.uberwald.me/gitea/public/foundryvtt-reve-de-dragon/releases/download/13.0.36/rddsystem.zip",
"manifest": "https://www.uberwald.me/gitea/public/foundryvtt-reve-de-dragon/releases/download/13.0.36/system.json",
"changelog": "https://www.uberwald.me/gitea/public/foundryvtt-reve-de-dragon/raw/branch/v11/changelog.md",
"version": "13.0.43",
"download": "https://gitea.scriptarium.org/Scriptarium/foundryvtt-reve-de-dragon/releases/download/13.0.43/rddsystem.zip",
"manifest": "https://gitea.scriptarium.org/Scriptarium/foundryvtt-reve-de-dragon/releases/download/latest/system.json",
"changelog": "https://gitea.scriptarium.org/Scriptarium/foundryvtt-reve-de-dragon/raw/branch/v13/changelog.md",
"compatibility": {
"minimum": "13",
"verified": "14"

View File

@@ -4,23 +4,20 @@
{{#each monnaies as |piece id|}}
<li class="item flexrow list-item" data-item-id="{{piece._id}}">
<img class="sheet-competence-img" src="{{piece.img}}" data-tooltip="{{piece.name}}"/>
<span class="equipement-nom">{{piece.name}}</span>
<span class="equipement-valeur {{#unless (gt piece.system.cout 0)}}field-error{{/unless}}">
({{piece.system.cout}} Sols)
<span class="equipement-nom {{#unless (gt piece.system.cout 0)}}field-error{{/unless}}">
{{piece.name}} ({{piece.system.cout}} Sols)
</span>
<span class="equipement-detail">
{{#if @root.options.isOwner}}
<span class="item-controls">
<a class="item-quantite-moins"><i class="fa-solid fa-square-minus"></i></a>
</span>
{{/if}}
<span>
<span>{{piece.system.quantite}}</span>
</span>
{{#if @root.options.isOwner}}
<span class="equipement-detail">{{piece.system.quantite}}</span>
<span class="item-controls">
<a class="item-quantite-plus"><i class="fa-solid fa-square-plus"></i></a>
</span>
{{else}}
{{piece.system.quantite}}
{{/if}}
</span>
{{#if @root.options.isOwner}}

View File

@@ -3,40 +3,40 @@
<div class="flex-group-left">
{{#if options.isGM}}
{{>"systems/foundryvtt-reve-de-dragon/templates/actor/random/champ-aleatoire.hbs"
label="Nom" path="name" type="text" value=current.name checked=checked.name
label="Nom" fieldname="name" type="text" value=current.name checked=checked.name
}}
{{/if}}
{{>"systems/foundryvtt-reve-de-dragon/templates/actor/random/sexe-aleatoire.hbs"
label="Sexe" path="system.sexe" type="text"
value=current.system.sexe checked=checked.system.sexe
label="Sexe" fieldname="sexe" type="text"
value=current.system.sexe checked=checked.sexe
}}
{{>"systems/foundryvtt-reve-de-dragon/templates/actor/random/champ-aleatoire.hbs"
label="Age" path="system.age" type="entier" min=10 max=100
value=current.system.age checked=checked.system.age
label="Age" fieldname="age" type="entier" min=10 max=100
value=current.system.age checked=checked.age
}}
{{>"systems/foundryvtt-reve-de-dragon/templates/actor/random/champ-aleatoire.hbs"
label="Taille" path="system.taille" type="text"
value=current.system.taille checked=checked.system.taille
label="Taille" fieldname="taille" type="text"
value=current.system.taille checked=checked.taille
}}
{{>"systems/foundryvtt-reve-de-dragon/templates/actor/random/champ-aleatoire.hbs"
label="Poids" path="system.poids" type="text"
value=current.system.poids checked=checked.system.poids
label="Poids" fieldname="poids" type="text"
value=current.system.poids checked=checked.poids
}}
{{>"systems/foundryvtt-reve-de-dragon/templates/actor/random/champ-aleatoire.hbs"
label="Main directrice" path="system.main" type="text"
value=current.system.main checked=checked.system.main
label="Main directrice" fieldname="main" type="text"
value=current.system.main checked=checked.main
}}
{{>"systems/foundryvtt-reve-de-dragon/templates/actor/random/champ-aleatoire.hbs"
label="Heure de naissance" path="system.heure" type="heure"
value=current.system.heure checked=checked.system.heure
label="Heure de naissance" fieldname="heure" type="heure"
value=current.system.heure checked=checked.heure
}}
{{>"systems/foundryvtt-reve-de-dragon/templates/actor/random/champ-aleatoire.hbs"
label="Cheveux" path="system.cheveux" type="text"
value=current.system.cheveux checked=checked.system.cheveux
label="Cheveux" fieldname="cheveux" type="text"
value=current.system.cheveux checked=checked.cheveux
}}
{{>"systems/foundryvtt-reve-de-dragon/templates/actor/random/champ-aleatoire.hbs"
label="Yeux" path="system.yeux" type="text"
value=current.system.yeux checked=checked.system.yeux
label="Yeux" fieldname="yeux" type="text"
value=current.system.yeux checked=checked.yeux
}}
</div>
<hr>

View File

@@ -1,15 +1,15 @@
<div class="flexrow random-field" data-path="{{path}}">
<label for="{{path}}">{{label}}:</label>
<div class="flexrow random-field" data-field-name="{{fieldname}}">
<label for="{{fieldname}}">{{label}}:</label>
{{#if (eq type 'entier')}}
<input name="current.{{path}}" class="current-value" type="number" data-dtype="Number" placeholder="{{label}}" value="{{value}}" min="{{min}}" max="{{max}}"/>
<input name="current.{{fieldname}}" class="current-value" type="number" data-dtype="Number" placeholder="{{label}}" value="{{value}}" min="{{min}}" max="{{max}}"/>
{{else if (eq type 'heure')}}
<select class="current-value" name="current.{{path}}" value="{{value}}" type="text" data-dtype="String">
<select class="current-value" name="current.{{fieldname}}" value="{{value}}" type="text" data-dtype="String">
{{#select value}}
{{> "systems/foundryvtt-reve-de-dragon/templates/enum-heures.hbs"}}
{{/select}}
</select>
{{else}}
<input name="current.{{path}}" class="current-value" type="text" data-dtype="String" value="{{value}}" placeholder="{{label}}"/>
<input name="current.{{fieldname}}" class="current-value" type="text" data-dtype="String" value="{{value}}" placeholder="{{label}}"/>
{{/if}}
<div class="item-controls">
<input class="check-for-random" type="checkbox" data-tooltip="Sélectionné pour génération automatique" {{#if checked}}checked{{/if}}/>

View File

@@ -1,6 +1,6 @@
<div class="flexrow random-field" data-path="{{path}}">
<label for="{{path}}">{{label}}:</label>
<input class="current-value" name="current.{{path}}" value="{{value}}" placeholder="{{label}}" type="text" data-dtype="String"/>
<div class="flexrow random-field" data-field-name="{{fieldname}}">
<label for="{{fieldname}}">{{label}}:</label>
<input class="current-value" name="current.{{fieldname}}" value="{{value}}" placeholder="{{label}}" type="text" data-dtype="String"/>
<div class="item-controls">
<input class="check-for-random" type="checkbox" data-tooltip="Sélectionné pour génération automatique" {{#if checked}}checked{{/if}}/>
<a data-action="sexe-feminin" data-tooltip="sexe féminin"><i class="fa-solid fa-venus"></i></a>