import { SHOW_DICE } from "../../constants.js"; import { Misc } from "../../misc.js"; import { RdDCarac } from "../../rdd-carac.js"; import { RdDDice } from "../../rdd-dice.js"; import { RdDNameGen } from "../../rdd-namegen.js"; import { RdDTimestamp } from "../../time/rdd-timestamp.js"; 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: "self", 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) }, ] const { HandlebarsApplicationMixin } = foundry.applications.api; export class AppPersonnageAleatoire extends HandlebarsApplicationMixin(foundry.applications.api.ApplicationV2) { static PARTS = { main: { template: "systems/foundryvtt-reve-de-dragon/templates/actor/random/app-personnage-aleatoire.hbs" } } static DEFAULT_OPTIONS = { classes: ['app-personnage-aleatoire'], window: { title: "Génération aléatoire", controls: [] }, position: { width: 600, height: 600 } } static preloadHandlebars() { foundry.applications.handlebars.loadTemplates([ 'systems/foundryvtt-reve-de-dragon/templates/actor/random/champ-aleatoire.hbs', 'systems/foundryvtt-reve-de-dragon/templates/actor/random/sexe-aleatoire.hbs', ]) } constructor(actor) { super({}) this.actor = actor this.current = Object.fromEntries(CONTROLS.map(it => [it.name, it.getter(this.actor)])); this.checked = Object.fromEntries(CONTROLS.map(it => [it.name, [0, '', undefined].includes(this.current[it.name])])) } _prepareContext() { return { actor: this.actor, current: this.current, checked: this.checked, options: { isGM: game.user.isGM } } } _onRender(context, options) { super._onRender(context, options) this.html = $(this.element) this.html.find("input.current-value").change(async event => await this.onChange(event)) 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 onApply() { const updates = Object.fromEntries( CONTROLS.filter(control => game.user.isGM || control.name != 'name') .map(control => [control.path, this.current[control.name]]) ) await this.actor.update(updates) await this.close() } getName(selector) { const fields = this.html.find(selector).parents("div.random-field:first") return fields[0].attributes['data-field-name'].value } getControl(name) { return CONTROLS.find(it => it.name == name) ?? CONTROL_UNKNOWN } async onSexe(sexe) { this.current['sexe'] = sexe this.render({ force: true }) } async onChange(event) { const name = this.getName(event.currentTarget) const control = this.getControl(name) this.current[control.name] = event.currentTarget.value this.render({ force: true }) } async onRandom(event) { const name = this.getName(event.currentTarget) const control = this.getControl(name) await this.randomControl(control) this.render({ force: true }) } async onReset(event) { const name = this.getName(event.currentTarget) const control = this.getControl(name) this.current[control.name] = control.getter(this.actor) this.render({ force: true }) } async onCheckForRandom(event) { const name = this.getName(event.currentTarget) this.checked[name] = event.currentTarget.checked this.render({ force: true }) } async onRandomizeSelected() { const controls = this.html.find("input.check-for-random:checked") .parents("div.random-field") .toArray() .map(it => this.getControl(it.attributes['data-field-name'].value)) await Promise.all(controls.map(it => this.randomControl(it))) this.render({ force: true }) } async randomControl(control) { this.current[control.name] = await control.random(this.actor) } }