Compare commits

..

1 Commits

Author SHA1 Message Date
f31da34461 Carte des TMR alternatives
Ajout d'une option pour choisir parmi les TMRs des 3 éditions
2024-12-08 18:55:37 +01:00
468 changed files with 12772 additions and 7959 deletions

View File

@ -1,76 +1,11 @@
# 12.0
## 12.0.36 - L'alchimie d'Astrobazzarh
- Nouveautés
- ajout d'un bouton pour enchanter les potions
- standardisation des boutons d'actions sur les items
- utilisations d'icones pour les actions de l'inventaire
- Corrections:
- la commande /tmra sans paramètres fonctionne
- les jets d'encaissement depuis le tchat fonctionnent
- affichage de la vie/endurance en cas de blessures et remise à neuf
- les queues durant 12 heures ajoutées début Vaisseau ne durent plus 24 heures
- Compendiums
- Corrections des remedes enchantables
- Corrections de descriptions pour proposer les jet de dés
## 12.0.35 - La Solution d'Astrobazzarh
- Fix problème d'initialisation des feuilles d'items
## 12.0.34 - la tête d'Astrobazzarh
- support de liens "jets de dés"
- on peut ajouter des liens "jet de dés" dans les journaux, descriptions, notes, maladresses, ...
- avec la syntaxe `@roll[...]` on peut ajouter le lien vers:
- un jet de caractéristique/compétence `@roll[carac/competence/difficulte]` / `@roll[carac/difficulte]` / `@roll[carac/competence]`
- une formule foundry `@roll[2d6]` pour lancer 2d6
- une manipulation alchimique `@roll[couleur vert-bleu]`
- les liens "jet avec caractéristiques" s'appliquent:
- à tous les tokens sélectionnés
- sinon, à l'acteur propriétaire (dans le cas d'un Item) ou à l'acteur courant
- sinon, au personnage du joueur
- on peut poster les liens dans le tchat pour proposer un jet aux joueurs
- gestion des blocs secrets dans les descriptions
## 12.0.33 - la vieillesse d'Astrobazzarh
- retour de l'expérience pour les joueurs
- suppression du message "Pas de caractéristique" sur les jets d'odorat-goût
## 12.0.32 - les rêveries d'Astrobazzarh
- Ajout des Items Race pour gérer les ajustements liés aux races
## 12.0.31 - le mausolée d'Astrobazzarh
- Correction: les automatisation de combat jouer-MJ fonctionnentde nouveau
## 12.0.30 - le cauchemar d'Astrobazzarh
- calcul automatique du niveau des entités selon leur rêve
- la description des créatures venimeuses contient un lien vers leur venin
- Correction: les messages de combats ne marchaient plus (Changement combiné Foundry + rêve de Dragon)
## 12.0.29 - L'indexation d'Astrobazzarh
- les liens dans la descriptions des sorts pointent vers les sorts du compendium
- la description du chrasme contient le lien vers son venin plutôt qu'un tableau
## 12.0.28 - Les réserves d'Astrobazzarh
- possibilité de mettre en réserve depuis un sort connu
## 12.0.27 - Les vêtements d'Astrobazzarh
- Ajout de la liste des armures dans l'onglet caractéristiques
- Ajout d'une option pour choisir une carte des TMR alternatives
- Le Gardien peut créer des sorts en réserve parmi les sorts d'un personnage
- Bouton pour ajouter des compétences aux créatures/entités
- Bouton pour ajouter un personnage accordé aux entités de cauchemar
- Correction du choix d'une cible parmi toutes les cibles pour les combats
- Correction des ajouts de blessures (prise en compte de l'endurance et des contusions)
- Correction des rituels de Détection et Lecture d'Aura des personnages prétirés
- Correction des invocations
- support de "personnages" n'ayant pas toutes les compétences
- ajout de lien entre le sort et la créature
- correction des liens vers les journaux
- limitation aux compétences listées
- acteur non lié par défaut
- Correction des compendiums
- l'import de personnages depuis un compendium respecte les acteurs liés/non-liés
- les modèles de voyageurs sont liés par défaut
- les modèles de personnages non joueurs sont non-liés par défaut
## 12.0.26 - Astrobazzarh le Haut-rêvant
- bouton pour le don de haut-rêve en un clic
@ -168,9 +103,11 @@
- encodage de l'export en windows-1252
- export de l'esquive avec armure et sans armure
## 12.0.9 - 12.0.10 - Le scriptorium d'Astrobazzarh
## 12.0.10 - Le scriptorium d'Astrobazzarh
- corrections de l'export scriptarium
- ajout d'une fonction avancée pour un exporter "scriptarium" des personnages
## 12.0.9 - Le scriptorium d'Astrobazzarh
- ajout d'une fonction avancée pour exporter les personnages dans un format csv
## 12.0.8 - La quincaillerie d'Astrobazzarh
- le propriétaire est indiqué dans les feuilles d'équipements/compétences/...

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.3 KiB

View File

@ -40,7 +40,6 @@
"possession": "Possession",
"potion": "Potion",
"queue": "Queue de Dragon",
"race": "Race",
"recettealchimique": "Recette alchimique",
"recettecuisine": "Recette de cuisine",
"rencontre": "Rencontre TMR",

View File

@ -12,19 +12,17 @@ import { RdDSheetUtility } from "./rdd-sheet-utility.js";
import { STATUSES } from "./settings/status-effects.js";
import { MAINS_DIRECTRICES } from "./actor.js";
import { RdDBaseActorReveSheet } from "./actor/base-actor-reve-sheet.js";
import { ITEM_TYPES } from "./constants.js";
import { RdDItem } from "./item.js";
import { RdDItemBlessure } from "./item/blessure.js";
import { RdDEmpoignade } from "./rdd-empoignade.js";
import { RdDBaseActorSangSheet } from "./actor/base-actor-sang-sheet.js";
import { RdDCoeur } from "./coeur/rdd-coeur.js";
import { AppPersonnageAleatoire } from "./actor/random/app-personnage-aleatoire.js";
import { RdDItemRace } from "./item/race.js";
import { RdDTextEditor } from "./apps/rdd-text-roll-editor.js";
/* -------------------------------------------- */
/**
* Extend the basic ActorSheet with some very simple modifications
* @extends {ActorSheet}
*/
export class RdDActorSheet extends RdDBaseActorSangSheet {
@ -46,8 +44,8 @@ export class RdDActorSheet extends RdDBaseActorSangSheet {
cssClass: this.isEditable ? "editable" : "locked",
limited: this.actor.limited,
owner: this.actor.isOwner,
biographie: await RdDTextEditor.enrichHTML(this.actor.system.biographie, this.actor),
notes: await RdDTextEditor.enrichHTML(this.actor.system.notes, this.actor),
biographie: await TextEditor.enrichHTML(this.actor.system.biographie, { async: true }),
notes: await TextEditor.enrichHTML(this.actor.system.notes, { async: true }),
});
foundry.utils.mergeObject(formData.calc, {
surenc: this.actor.computeMalusSurEncombrement(),
@ -85,7 +83,7 @@ export class RdDActorSheet extends RdDBaseActorSangSheet {
formData.combat.push(RdDItemArme.corpsACorps(actor));
formData.combat.push(RdDItemArme.empoignade(actor));
formData.esquives = this.actor.getCompetencesEsquive()
formData.esquives = this.actor.getCompetences("Esquive");
formData.combat = RdDCombatManager.listActionsArmes(formData.combat, formData.competences, formData.system.carac);
formData.empoignades = this.actor.getEmpoignades();
@ -100,7 +98,6 @@ export class RdDActorSheet extends RdDBaseActorSangSheet {
cacheTMR: this.actor.isTMRCache()
}
formData.race = actor.itemTypes[ITEM_TYPES.race].find(it => true)
formData.subacteurs = {
vehicules: this.actor.listeVehicules(),
montures: this.actor.listeMontures(),
@ -185,19 +182,22 @@ export class RdDActorSheet extends RdDBaseActorSangSheet {
await blessure?.setSoinsBlessure({ soinscomplets: { bonus: Number(event.currentTarget.value) } })
});
this.html.find('.roll-chance-actuelle').click(async event => this.actor.rollCarac('chance-actuelle'))
// Equip Inventory Item
this.html.find('.item-equip').click(async event => this.actor.equiperObjet(RdDSheetUtility.getItemId(event)))
this.html.find('.chance-actuelle').click(async event => this.actor.rollCarac('chance-actuelle'))
this.html.find('.button-appel-chance').click(async event => this.actor.rollAppelChance())
this.html.find('[name="jet-astrologie"]').click(async event => this.actor.astrologieNombresAstraux())
this.html.find('.action-tache').click(async event => this.actor.rollTache(RdDSheetUtility.getItemId(event)))
this.html.find('.tache-label a').click(async event => this.actor.rollTache(RdDSheetUtility.getItemId(event)))
this.html.find('.meditation-label a').click(async event => this.actor.rollMeditation(RdDSheetUtility.getItemId(event)))
this.html.find('.action-chant').click(async event => this.actor.rollChant(RdDSheetUtility.getItemId(event)))
this.html.find('.action-danse').click(async event => this.actor.rollDanse(RdDSheetUtility.getItemId(event)))
this.html.find('.action-musique').click(async event => this.actor.rollMusique(RdDSheetUtility.getItemId(event)))
this.html.find('.action-oeuvre').click(async event => this.actor.rollOeuvre(RdDSheetUtility.getItemId(event)))
this.html.find('.action-jeu').click(async event => this.actor.rollJeu(RdDSheetUtility.getItemId(event)))
this.html.find('.action-recettecuisine').click(async event => this.actor.rollRecetteCuisine(RdDSheetUtility.getItemId(event)))
this.html.find('.chant-label a').click(async event => this.actor.rollChant(RdDSheetUtility.getItemId(event)))
this.html.find('.danse-label a').click(async event => this.actor.rollDanse(RdDSheetUtility.getItemId(event)))
this.html.find('.musique-label a').click(async event => this.actor.rollMusique(RdDSheetUtility.getItemId(event)))
this.html.find('.oeuvre-label a').click(async event => this.actor.rollOeuvre(RdDSheetUtility.getItemId(event)))
this.html.find('.jeu-label a').click(async event => this.actor.rollJeu(RdDSheetUtility.getItemId(event)))
this.html.find('.recettecuisine-label a').click(async event => this.actor.rollRecetteCuisine(RdDSheetUtility.getItemId(event)))
this.html.find('.description-aleatoire').click(async event => new AppPersonnageAleatoire(this.actor).render(true))
if (game.user.isGM) {
@ -215,12 +215,13 @@ export class RdDActorSheet extends RdDBaseActorSangSheet {
// Boutons spéciaux MJs
this.html.find('.forcer-tmr-aleatoire').click(async event => this.actor.reinsertionAleatoire("Action MJ"))
this.html.find('.don-de-haut-reve').click(async event => this.actor.addDonDeHautReve())
this.html.find('.nouveau-sort-reserve').click(async event => this.actor.addSortReserve())
this.html.find('.afficher-tmr').click(async event => this.actor.changeTMRVisible())
}
// Points de reve actuel
this.html.find('.roll-reve-actuel').click(async event => this.actor.rollCarac('reve-actuel', {resistance:true}))
this.html.find('.action-empoignade').click(async event => RdDEmpoignade.onAttaqueEmpoignadeFromItem(RdDSheetUtility.getItem(event, this.actor)))
this.html.find('.roll-reve-actuel').click(async event => this.actor.rollCarac('reve-actuel', true))
this.html.find('.empoignade-label a').click(async event => RdDEmpoignade.onAttaqueEmpoignadeFromItem(RdDSheetUtility.getItem(event, this.actor)))
this.html.find('.roll-arme').click(async event => this.actor.rollArme(foundry.utils.duplicate(this._getEventArmeCombat(event)), 'competence'))
@ -284,8 +285,6 @@ export class RdDActorSheet extends RdDBaseActorSangSheet {
this.html.find('.ptreve-actuel-plus').click(async event => this.actor.reveActuelIncDec(1))
this.html.find('.ptreve-actuel-moins').click(async event => this.actor.reveActuelIncDec(-1))
this.html.find('.chance-actuelle-plus').click(async event => this.actor.chanceActuelleIncDec(1))
this.html.find('.chance-actuelle-moins').click(async event => this.actor.chanceActuelleIncDec(-1))
this.html.find('.fatigue-plus').click(async event => this.actor.santeIncDec("fatigue", 1))
this.html.find('.fatigue-moins').click(async event => this.actor.santeIncDec("fatigue", -1))
}
@ -324,7 +323,7 @@ export class RdDActorSheet extends RdDBaseActorSangSheet {
/* -------------------------------------------- */
async selectTypeOeuvreToCreate() {
let types = RdDItem.getTypesOeuvres();
let content = `<span class="generic-label">Selectionnez le type d'oeuvre</span><select class="item-type">`;
let content = `<span class="competence-label">Selectionnez le type d'oeuvre</span><select class="item-type">`;
for (let typeName of types) {
content += `<option value="${typeName}">${Misc.typeName('Item', typeName)}</option>`
}

View File

@ -17,7 +17,7 @@ import { RdDItemSigneDraconique } from "./item/signedraconique.js";
import { ReglesOptionnelles } from "./settings/regles-optionnelles.js";
import { EffetsDraconiques } from "./tmr/effets-draconiques.js";
import { Draconique } from "./tmr/draconique.js";
import { LIST_CARAC_PERSONNAGE, RdDCarac } from "./rdd-carac.js";
import { RdDCarac } from "./rdd-carac.js";
import { DialogConsommer } from "./dialog-item-consommer.js";
import { DialogFabriquerPotion } from "./dialog-fabriquer-potion.js";
import { RollDataAjustements } from "./rolldata-ajustements.js";
@ -32,20 +32,18 @@ import { RdDItemBlessure } from "./item/blessure.js";
import { AppAstrologie } from "./sommeil/app-astrologie.js";
import { RdDEmpoignade } from "./rdd-empoignade.js";
import { ExperienceLog, XP_TOPIC } from "./actor/experience-log.js";
import { ITEM_TYPES } from "./constants.js";
import { ITEM_TYPES } from "./item.js";
import { RdDBaseActorSang } from "./actor/base-actor-sang.js";
import { RdDCoeur } from "./coeur/rdd-coeur.js";
import { DialogChoixXpCarac } from "./dialog-choix-xp-carac.js";
import { RdDItemArme } from "./item-arme.js";
import { RdDCombatManager } from "./rdd-combat.js";
import { RdDItemTete } from "./item/tete.js";
import { SystemCompendiums } from "./settings/system-compendiums.js";
import { DialogSelect } from "./dialog-select.js";
import { PAS_DE_DRACONIC, POSSESSION_SANS_DRACONIC } from "./item/base-items.js";
import { RdDItemRace } from "./item/race.js";
export const MAINS_DIRECTRICES = ['Droitier', 'Gaucher', 'Ambidextre']
/* -------------------------------------------- */
/**
* Extend the base Actor entity by defining a custom roll data structure which is ideal for the Simple system.
@ -59,7 +57,7 @@ export class RdDActor extends RdDBaseActorSang {
*/
prepareActorData() {
RdDItemRace.applyRacialLimits(this)
this.system.carac.force.value = Math.min(this.system.carac.force.value, parseInt(this.system.carac.taille.value) + 4);
this.system.carac.melee.value = Math.floor((this.getForce() + parseInt(this.system.carac.agilite.value)) / 2);
this.system.carac.tir.value = Math.floor((parseInt(this.system.carac.vue.value) + parseInt(this.system.carac.dexterite.value)) / 2);
@ -96,14 +94,11 @@ export class RdDActor extends RdDBaseActorSang {
isHautRevant() { return this.system.attributs.hautrevant.value != "" }
/* -------------------------------------------- */
getAgilite() { return Misc.toInt(this.system.carac.agilite?.value ?? 0) }
getChance() { return Misc.toInt(this.system.carac.chance?.value ?? 0) }
getAgilite() { return this.system.carac.agilite?.value ?? 0 }
getChance() { return this.system.carac.chance?.value ?? 0 }
getReveActuel() { return Misc.toInt(this.system.reve?.reve?.value) ?? this.carac.reve.value ?? 0 }
getChanceActuel() {
return Number.isNumeric(this.system.compteurs.chance.value) ?
Misc.toInt(this.system.compteurs.chance.value) : this.getChance()
}
getReveActuel() { return this.system.reve?.reve?.value ?? this.carac.reve.value ?? 0 }
getChanceActuel() { return this.system.compteurs.chance?.value ?? 10 }
getMoralTotal() { return this.system.compteurs.moral?.value ?? 0 }
getEnduranceMax() { return Math.max(1, Math.max(this.getTaille() + this.getConstitution(), this.getVieMax() + this.getVolonte())) }
@ -158,31 +153,38 @@ export class RdDActor extends RdDBaseActorSang {
/* -------------------------------------------- */
getDemiReve() { return this.system.reve.tmrpos.coord }
getDraconicList() { return this.itemTypes[ITEM_TYPES.competence].filter(it => it.system.categorie == 'draconic') }
getBestDraconic() { return foundry.utils.duplicate([...this.getDraconicList(), PAS_DE_DRACONIC].sort(Misc.descending(it => it.system.niveau)).find(it => true)) }
getBestDraconic() { return foundry.utils.duplicate(this.getDraconicList().sort(Misc.descending(it => it.system.niveau)).find(it => true)) }
getDraconicOuPossession() {
return [...this.getDraconicList().filter(it => it.system.niveau >= 0), POSSESSION_SANS_DRACONIC]
return [...this.getDraconicList().filter(it => it.system.niveau >= 0),
super.getDraconicOuPossession()]
.sort(Misc.descending(it => it.system.niveau))
.find(it => true)
}
/* -------------------------------------------- */
async $perteRevePotionsEnchantees() {
const potionUpdates = this.itemTypes[ITEM_TYPES.potion].map(it => it.perteRevePotion())
.filter(it => it != undefined)
if (potionUpdates.length > 0) {
console.log('perte rêve de potions', potionUpdates)
const messageUpdates = await Promise.all(potionUpdates.map(async p => await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-potionenchantee-chateaudormant.html`, {
pr: foundry.utils.getProperty(p, 'system.pr'),
alias: this.getAlias(),
potionName: p.name,
potionImg: p.img
})))
let potions = this.itemTypes[ITEM_TYPES.potion]
.filter(it => Grammar.includesLowerCaseNoAccent(it.system.categorie, 'enchanté') && !it.system.prpermanent)
const potionUpdates = await Promise.all(potions.map(async it => {
const nouveauReve = Math.max(it.system.pr - 1, 0)
ChatMessage.create({
whisper: ChatUtility.getOwners(this),
content: messageUpdates.reduce(Misc.joining('<br>'))
content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-potionenchantee-chateaudormant.html`, {
pr: nouveauReve,
alias: this.getAlias(),
potionName: it.name,
potionImg: it.img
})
})
await this.updateEmbeddedDocuments('Item', potionUpdates);
}
return {
_id: it._id,
'system.pr': nouveauReve,
'system.quantite': nouveauReve > 0 ? it.system.quantite : 0
}
}))
await this.updateEmbeddedDocuments('Item', potionUpdates);
}
/** --------------------------------------------
@ -239,7 +241,7 @@ export class RdDActor extends RdDBaseActorSang {
}
async _recuperationSante(message) {
const maladiesPoisons = this.getMaladiesPoisons();
const maladiesPoisons = this.getMaladiePoisons();
const isMaladeEmpoisonne = maladiesPoisons.length > 0;
this._messageRecuperationMaladiePoisons(maladiesPoisons, message);
@ -247,7 +249,7 @@ export class RdDActor extends RdDBaseActorSang {
await this._recupererVie(message, isMaladeEmpoisonne);
}
getMaladiesPoisons() {
getMaladiePoisons() {
return this.items.filter(item => item.type == 'maladie' || (item.type == 'poison' && item.system.active));
}
@ -407,18 +409,19 @@ export class RdDActor extends RdDBaseActorSang {
/* -------------------------------------------- */
async remiseANeuf() {
await this.update({
ChatMessage.create({
whisper: ChatUtility.getOwners(this),
content: 'Remise à neuf de ' + this.name
});
await this.supprimerBlessures(it => true);
await this.removeEffects(e => e.id != STATUSES.StatusDemiReve);
const updates = {
'system.sante.endurance.value': this.system.sante.endurance.max,
'system.sante.vie.value': this.system.sante.vie.max,
'system.sante.fatigue.value': 0,
'system.compteurs.ethylisme': { value: 1, nb_doses: 0, jet_moral: false }
})
await this.removeEffects(e => e.id != STATUSES.StatusDemiReve);
await this.supprimerBlessures(it => true);
await ChatMessage.create({
whisper: ChatUtility.getOwners(this),
content: 'Remise à neuf de ' + this.name
});
};
await this.update(updates);
}
/* -------------------------------------------- */
@ -522,7 +525,7 @@ export class RdDActor extends RdDBaseActorSang {
jet_moral: false,
value: value
}
})
});
}
/* -------------------------------------------- */
@ -654,16 +657,18 @@ export class RdDActor extends RdDBaseActorSang {
/* -------------------------------------------- */
async updateCarac(caracName, to) {
to = Number(to)
if (!RdDItemRace.checkRacialMax(this, caracName, to)) {
return
if (caracName == "force") {
if (Number(to) > this.getTaille() + 4) {
ui.notifications.warn("Votre FORCE doit être au maximum de TAILLE+4");
return;
}
}
if (caracName == LIST_CARAC_PERSONNAGE.reve.code) {
if (caracName == "reve") {
if (to > Misc.toInt(this.system.reve.seuil.value)) {
this.setPointsDeSeuil(to);
}
}
if (caracName == LIST_CARAC_PERSONNAGE.chance.code) {
if (caracName == "chance") {
if (to > Misc.toInt(this.system.compteurs.chance.value)) {
this.setPointsDeChance(to);
}
@ -986,28 +991,21 @@ export class RdDActor extends RdDBaseActorSang {
}
}
async addSortReserve(item) {
if (item?.type == ITEM_TYPES.sort && !item.system.isrituel) {
this.$createSortReserve(item)
return
}
async addSortReserve() {
const selectSortReserve = {
title: "Créer un sort en réserve",
label: "Choisir un sort",
list: this.itemTypes[ITEM_TYPES.sort].filter(it => !it.system.isrituel)
}
DialogSelect.select(selectSortReserve, sort => this.$createSortReserve(sort))
}
$createSortReserve(sort) {
this.createEmbeddedDocuments("Item",
[{
type: ITEM_TYPES.sortreserve,
name: sort.name,
img: sort.img,
system: { sortid: sort.id, draconic: sort.system.draconic, ptreve: Number(sort.system.ptreve.match(/\d+/)), coord: 'A1', heurecible: 'Vaisseau' }
}],
{ renderSheet: true })
DialogSelect.select(selectSortReserve, sort =>
this.createEmbeddedDocuments("Item",
[{
type: ITEM_TYPES.sortreserve,
name: sort.name,
img: sort.img,
system: { sortid: sort.id, draconic: sort.system.draconic, ptreve: Number(sort.system.ptreve.match(/\d+/)), coord: 'A1', heurecible: 'Vaisseau' }
}],
{ renderSheet: true }))
}
/* -------------------------------------------- */
async reinsertionAleatoire(raison, accessible = tmr => true) {
@ -1072,11 +1070,6 @@ export class RdDActor extends RdDBaseActorSang {
await this.update({ "system.reve.reve.value": reve });
}
async chanceActuelleIncDec(value) {
const chance = Math.min(this.getChance(), Math.max(this.getChanceActuel() + value, 0));
await this.update({ "system.compteurs.chance.value": chance });
}
/* -------------------------------------------- */
async regainPointDeSeuil() {
const seuil = Misc.toInt(this.system.reve.seuil.value);
@ -1193,6 +1186,42 @@ export class RdDActor extends RdDBaseActorSang {
new RdDRollDialogEthylisme(html, rollData, this, r => this.saouler(r.forceAlcool)).render(true);
}
async actionPrincipale(item, onActionItem = async () => { }) {
let result = await super.actionPrincipale(item, onActionItem)
if (result) { return result }
result = await this.actionNourritureboisson(item, onActionItem)
if (result) { return result }
switch (item.type) {
case ITEM_TYPES.potion: return await this.consommerPotion(item, onActionItem);
case ITEM_TYPES.livre: return await this.actionLire(item);
case ITEM_TYPES.conteneur: return await item.sheet.render(true);
case ITEM_TYPES.herbe: return await this.actionHerbe(item, onActionItem);
case ITEM_TYPES.queue: case ITEM_TYPES.ombre: return await this.actionRefoulement(item);
}
return undefined
}
async actionNourritureboisson(item, onActionItem) {
switch (item.getUtilisationCuisine()) {
case 'brut': {
const utilisation = new Dialog({
title: "Nourriture brute",
content: `Que faire de votre ${item.name}`,
buttons: {
'cuisiner': { icon: '<i class="fa-solid fa-utensils"></i>', label: 'Cuisiner', callback: async () => await this.preparerNourriture(item) },
'manger': { icon: '<i class="fa-solid fa-drumstick-bite"></i>', label: 'Manger cru', callback: async () => await this.mangerNourriture(item, onActionItem) }
}
});
return utilisation.render(true);
}
case 'pret':
return await this.mangerNourriture(item, onActionItem);
}
return undefined;
}
async mangerNourriture(item, onActionItem) {
return (await DialogConsommer.create(this, item, onActionItem)).render(true);
}
@ -1341,7 +1370,7 @@ export class RdDActor extends RdDBaseActorSang {
}
await RdDResolutionTable.rollData(ethylismeData.jetVie);
this.gererExperience(ethylismeData.jetVie);
this._gererExperience(ethylismeData.jetVie);
RollDataAjustements.calcul(ethylismeData.jetVie, this);
if (ethylismeData.jetVie.rolled.isSuccess) {
ethylisme.nb_doses++;
@ -1373,7 +1402,7 @@ export class RdDActor extends RdDBaseActorSang {
finalLevel: Number(ethylisme.value) + Number(this.system.compteurs.moral.value)
}
await RdDResolutionTable.rollData(ethylismeData.jetVolonte);
this.gererExperience(ethylismeData.jetVolonte);
this._gererExperience(ethylismeData.jetVolonte);
RollDataAjustements.calcul(ethylismeData.jetVolonte, this);
}
}
@ -1484,12 +1513,13 @@ export class RdDActor extends RdDBaseActorSang {
};
}
/* -------------------------------------------- */
isCaracMax(code) {
return RdDItemRace.isRacialMax(this, code)
if (code == 'force' && parseInt(this.system.carac.force.value) >= parseInt(this.system.carac.taille.value) + 4) {
return true;
}
return false
}
async checkCaracXP(caracName, display = true) {
let carac = this.findCaracByName(caracName);
if (carac && carac.xp > 0) {
@ -1550,7 +1580,7 @@ export class RdDActor extends RdDBaseActorSang {
/* -------------------------------------------- */
async appliquerAjoutExperience(rollData, hideChatMessage = 'show') {
if (!Misc.hasConnectedGM()) {
if (!Misc.isFirstConnectedGM()) {
return
}
hideChatMessage = hideChatMessage == 'hide' || (Misc.isRollModeHiddenToPlayer() && !game.user.isGM)
@ -1616,12 +1646,10 @@ export class RdDActor extends RdDBaseActorSang {
/* -------------------------------------------- */
async rollUnSort(coord) {
if (RdDEmpoignade.checkEmpoignadeEnCours(this)) {
return
}
RdDEmpoignade.checkEmpoignadeEnCours(this)
if (EffetsDraconiques.isSortImpossible(this)) {
ui.notifications.error("Une queue ou un souffle vous empèche de lancer de sort!")
return
ui.notifications.error("Une queue ou un souffle vous empèche de lancer de sort!");
return;
}
// Duplication car les pts de reve sont modifiés dans le sort
let sorts = foundry.utils.duplicate(this.$filterSortList(this.itemTypes['sort'], coord));
@ -1753,8 +1781,38 @@ export class RdDActor extends RdDBaseActorSang {
}
}
/**
* Méthode pour faire un jet prédéterminer sans ouvrir la fenêtre de dialogue
* @param {*} caracName
* @param {*} compName
* @param {*} diff
* @param {*} options
* @returns
*/
async doRollCaracCompetence(caracName, compName, diff, options = { title: "" }) {
const carac = this.getCaracByName(caracName);
if (!carac) {
ui.notifications.warn(`${this.name} n'a pas de caractéristique correspondant à ${caracName}`)
return;
}
const competence = this.getCompetence(compName);
let rollData = {
alias: this.getAlias(),
caracValue: Number(carac.value),
selectedCarac: carac,
competence: competence,
diffLibre: diff,
show: { title: options?.title ?? '' }
};
RollDataAjustements.calcul(rollData, this);
await RdDResolutionTable.rollData(rollData);
this._gererExperience(rollData);
await RdDResolutionTable.displayRollData(rollData, this)
return rollData.rolled;
}
/* -------------------------------------------- */
gererExperience(rollData) {
_gererExperience(rollData) {
const callback = this.createCallbackExperience();
if (callback.condition(rollData)) {
callback.action(rollData);
@ -1804,6 +1862,26 @@ export class RdDActor extends RdDBaseActorSang {
return undefined;
}
async rollCaracCompetence(caracName, compName, diff, options = { title: "" }) {
RdDEmpoignade.checkEmpoignadeEnCours(this)
const competence = this.getCompetence(compName);
await this.openRollDialog({
name: 'jet-competence',
label: 'Jet ' + Grammar.apostrophe('de', competence.name),
template: 'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-competence.html',
rollData: {
alias: this.getAlias(),
carac: this.system.carac,
selectedCarac: this.getCaracByName(caracName),
selectedCaracName: caracName,
diffLibre: diff,
competence: competence,
show: { title: options?.title ?? '' }
},
callbackAction: r => this.$onRollCompetence(r, options)
});
}
/* -------------------------------------------- */
async rollTache(id, options = {}) {
RdDEmpoignade.checkEmpoignadeEnCours(this)
@ -1845,8 +1923,8 @@ export class RdDActor extends RdDBaseActorSang {
}
rollData.tache.system.tentatives = rollData.tache.system.nb_jet_succes + rollData.tache.system.nb_jet_echec;
await this.updateEmbeddedDocuments('Item', [rollData.tache]);
await this.santeIncDec("fatigue", rollData.tache.system.fatigue);
this.updateEmbeddedDocuments('Item', [rollData.tache]);
this.santeIncDec("fatigue", rollData.tache.system.fatigue);
await RdDResolutionTable.displayRollData(rollData, this, 'chat-resultat-tache.html');
if (options?.onRollAutomate) {
@ -2176,6 +2254,12 @@ export class RdDActor extends RdDBaseActorSang {
}
}
/* -------------------------------------------- */
async chanceActuelleIncDec(value) {
const chance = Math.min(this.getChance(), Math.max(this.getChanceActuel() + value, 0));
await this.updateCompteurValue("chance", chance);
}
/* -------------------------------------------- */
async appelDestinee(onSuccess = () => { }, onEchec = () => { }) {
let destinee = this.system.compteurs.destinee?.value ?? 0;
@ -2524,7 +2608,8 @@ export class RdDActor extends RdDBaseActorSang {
}
/* -------------------------------------------- */
async equiperObjet(item) {
async equiperObjet(itemID) {
let item = this.getEmbeddedDocument('Item', itemID);
if (item?.isEquipable()) {
const isEquipe = !item.system.equipe;
await item.update({ "system.equipe": isEquipe });
@ -2543,7 +2628,7 @@ export class RdDActor extends RdDBaseActorSang {
for (const armure of armures) {
protection += await RdDDice.rollTotal(armure.system.protection.toString());
if (dmg > 0 && attackerRoll.dmg.encaisserSpecial != "noarmure") {
await armure.deteriorerArmure(dmg)
armure.deteriorerArmure(dmg);
dmg = 0;
}
}
@ -2936,14 +3021,12 @@ export class RdDActor extends RdDBaseActorSang {
/* -------------------------------------------- */
async onCreateItem(item, options, id) {
switch (item.type) {
case ITEM_TYPES.tete:
case ITEM_TYPES.queue:
case ITEM_TYPES.ombre:
case ITEM_TYPES.souffle:
await this.onCreateOwnedDraconique(item, options, id)
break
case ITEM_TYPES.race:
await this.onCreateOwnedRace(item, options, id)
case 'tete':
case 'queue':
case 'ombre':
case 'souffle':
await this.onCreateOwnedDraconique(item, options, id);
break;
}
await item.onCreateItemTemporel(this);
await item.onCreateDecoupeComestible(this);
@ -2951,19 +3034,16 @@ export class RdDActor extends RdDBaseActorSang {
async onDeleteItem(item, options, id) {
switch (item.type) {
case ITEM_TYPES.tete:
case ITEM_TYPES.queue:
case ITEM_TYPES.ombre:
case ITEM_TYPES.souffle:
case 'tete':
case 'queue':
case 'ombre':
case 'souffle':
await this.onDeleteOwnedDraconique(item, options, id)
break
case ITEM_TYPES.race:
await this.onDeleteOwnedRace(item, options, id)
break
case ITEM_TYPES.casetmr:
case 'casetmr':
await this.onDeleteOwnedCaseTmr(item, options, id)
break
case ITEM_TYPES.empoignade:
case 'empoignade':
await RdDEmpoignade.deleteLinkedEmpoignade(this.id, item)
break
}
@ -2992,35 +3072,6 @@ export class RdDActor extends RdDBaseActorSang {
}
}
async onCreateOwnedRace(item, options, id) {
if (Misc.isFirstConnectedGM()) {
const raceIds = this.itemTypes[ITEM_TYPES.race].map(it => it.id).filter(id => id != item.id)
if (raceIds.length > 0) {
await this.deleteEmbeddedDocuments('Item', raceIds)
}
await this._applyRaceCaracUpdates(item, 1)
}
}
async onDeleteOwnedRace(item, options, id) {
if (Misc.isFirstConnectedGM()) {
await this._applyRaceCaracUpdates(item, -1)
}
}
async _applyRaceCaracUpdates(item, sign) {
const updates = {};
RdDCarac.caracs(it => true).forEach(c => {
const toAdd = Number(foundry.utils.getProperty(item, c.path)) * sign
if (toAdd != 0) {
updates[c.path] = Number(foundry.utils.getProperty(this, c.path)) + toAdd
}
})
if (Object.keys(updates).length > 0) {
await this.update(updates)
}
}
/* -------------------------------------------- */
async onDeleteOwnedCaseTmr(item, options, id) {
if (Misc.isFirstConnectedGM()) {

View File

@ -1,6 +1,4 @@
import { RdDTextEditor } from "../apps/rdd-text-roll-editor.js";
import { Grammar } from "../grammar.js";
import { ITEM_TYPES } from "../constants.js";
import { RdDSheetUtility } from "../rdd-sheet-utility.js";
import { RdDBaseActorSheet } from "./base-actor-sheet.js";
@ -28,7 +26,7 @@ export class RdDBaseActorReveSheet extends RdDBaseActorSheet {
this.html.find('.button-encaissement').click(async event => this.actor.encaisser())
this.html.find('.roll-carac').click(async event => {
this.actor.rollCarac(Grammar.toLowerCaseNoAccent(event.currentTarget.attributes['data-carac-name'].value))})
this.actor.rollCarac(Grammar.toLowerCaseNoAccent(event.currentTarget.attributes['data-carac-name'].value))});
this.html.find('.roll-competence').click(async event => this.actor.rollCompetence(RdDSheetUtility.getItemId(event)));
this.html.find('.endurance-plus').click(async event => this.actor.santeIncDec("endurance", 1));
this.html.find('.endurance-moins').click(async event => this.actor.santeIncDec("endurance", -1));
@ -38,33 +36,7 @@ export class RdDBaseActorReveSheet extends RdDBaseActorSheet {
this.html.find('.delete-active-effect').click(async event => this.actor.removeEffect(this.html.find(event.currentTarget).parents(".active-effect").data('effect')));
this.html.find('.enlever-tous-effets').click(async event => await this.actor.removeEffects());
}
this.html.find('.competence-add').click(async event =>
await this.actor.createEmbeddedDocuments("Item", [{
type: ITEM_TYPES.competencecreature,
name: 'Nouvelle competence',
img: 'systems/foundryvtt-reve-de-dragon/icons/compcreature-serres.webp',
system: {
carac_value: this.actor.getForce(),
}
}], { renderSheet: true })
)
this.html.find('.roll-text').click(async event => await RdDTextEditor.rollText(event, this.actor))
this.html.find('.chat-roll-text').click(async event => await RdDTextEditor.chatRollText(event))
if (this.options.vueDetaillee) {
// On carac change
this.html.find('.carac-value').change(async event => {
let caracName = event.currentTarget.name.replace(".value", "").replace("system.carac.", "");
this.actor.updateCarac(caracName, parseInt(event.target.value));
});
// On competence change
this.html.find('.competence-value').change(async event => {
let compName = event.currentTarget.attributes.compname.value;
//console.log("Competence changed :", compName);
this.actor.updateCompetence(compName, parseInt(event.target.value));
});
}
}
}

View File

@ -1,28 +1,34 @@
import { ENTITE_INCARNE, SHOW_DICE, SYSTEM_RDD } from "../constants.js";
import { ChatUtility } from "../chat-utility.js";
import { DialogValidationEncaissement } from "../dialog-validation-encaissement.js";
import { Grammar } from "../grammar.js";
import { RdDItemCompetence } from "../item-competence.js";
import { Misc } from "../misc.js";
import { RdDEmpoignade } from "../rdd-empoignade.js";
import { RdDResolutionTable } from "../rdd-resolution-table.js";
import { RdDEncaisser } from "../rdd-roll-encaisser.js";
import { RdDRoll } from "../rdd-roll.js";
import { RdDUtility } from "../rdd-utility.js";
import { ReglesOptionnelles } from "../settings/regles-optionnelles.js";
import { RdDBaseActor } from "./base-actor.js";
import { ITEM_TYPES } from "../constants.js";
import { RdDItemCompetence } from "../item-competence.js";
import { RdDItemCompetenceCreature } from "../item-competencecreature.js";
import { RdDItemArme } from "../item-arme.js";
import { StatusEffects } from "../settings/status-effects.js";
import { ITEM_TYPES } from "../item.js";
import { Targets } from "../targets.js";
import { RdDPossession } from "../rdd-possession.js";
import { RdDCombat, RdDCombatManager } from "../rdd-combat.js";
import { RdDConfirm } from "../rdd-confirm.js";
import { ENTITE_INCARNE, SHOW_DICE, SYSTEM_RDD } from "../constants.js";
import { RdDItemArme } from "../item-arme.js";
import { RdDCarac } from "../rdd-carac.js";
import { ChatUtility } from "../chat-utility.js";
import { DialogValidationEncaissement } from "../dialog-validation-encaissement.js";
import { RdDCombat } from "../rdd-combat.js";
import { RdDEmpoignade } from "../rdd-empoignade.js";
import { RdDPossession } from "../rdd-possession.js";
import { BASE_CORPS_A_CORPS, BASE_ESQUIVE, POSSESSION_SANS_DRACONIC } from "../item/base-items.js";
import { RollDataAjustements } from "../rolldata-ajustements.js";
const POSSESSION_SANS_DRACONIC = {
img: 'systems/foundryvtt-reve-de-dragon/icons/entites/possession.webp',
name: 'Sans draconic',
system: {
niveau: 0,
defaut_carac: "reve-actuel",
}
};
/**
* Classe de base pour les acteurs disposant de rêve (donc, pas des objets)
@ -38,15 +44,6 @@ export class RdDBaseActorReve extends RdDBaseActor {
this.system.sante.endurance.value = Math.min(this.system.sante.endurance.value, this.system.sante.endurance.max)
}
getCarac() {
return foundry.utils.mergeObject(this.system.carac,
{
'reve-actuel': this.getCaracReveActuel(),
'chance-actuelle': this.getCaracChanceActuelle()
},
{ inplace: false })
}
getCaracChanceActuelle() {
return {
label: 'Chance actuelle',
@ -63,6 +60,7 @@ export class RdDBaseActorReve extends RdDBaseActor {
};
}
getTaille() { return Misc.toInt(this.system.carac.taille?.value) }
getConstitution() { return this.getReve() }
getForce() { return this.getReve() }
@ -165,24 +163,24 @@ export class RdDBaseActorReve extends RdDBaseActor {
}
return RdDItemCompetence.findCompetence(this.items, idOrName, options)
}
getCompetences(name, options = { onMessage: message => { } }) {
return RdDItemCompetence.findCompetences(this.items, name, options)
getCompetences(name) {
return RdDItemCompetence.findCompetences(this.items, name)
}
getCompetenceCorpsACorps(options = { onMessage: message => { } }) {
return this.getCompetence(BASE_CORPS_A_CORPS.name, options) ?? BASE_CORPS_A_CORPS
getCompetenceCorpsACorps(options = {}) {
return this.getCompetence("Corps à corps", options)
}
getCompetencesEsquive(options = { onMessage: message => { } }) {
return this.getCompetences(BASE_ESQUIVE.name, options) ?? [BASE_ESQUIVE]
getCompetencesEsquive() {
return this.getCompetences("esquive")
}
getArmeParade(armeParadeId) {
return RdDItemArme.getArme(armeParadeId ? this.getEmbeddedDocument('Item', armeParadeId) : undefined)
const item = armeParadeId ? this.getEmbeddedDocument('Item', armeParadeId) : undefined;
return RdDItemArme.getArme(item);
}
getDraconicOuPossession() { return POSSESSION_SANS_DRACONIC }
getDraconicOuPossession() {
return POSSESSION_SANS_DRACONIC
}
getPossession(possessionId) {
return this.itemTypes[ITEM_TYPES.possession].find(it => it.system.possessionid == possessionId);
@ -294,57 +292,6 @@ export class RdDBaseActorReve extends RdDBaseActor {
createCallbackAppelAuMoral() { return this.createEmptyCallback(); }
async _onCloseRollDialog(html) { }
async rollCaracCompetence(caracName, compName, diff, options = { title: "" }) {
RdDEmpoignade.checkEmpoignadeEnCours(this)
const competence = this.getCompetence(compName);
await this.openRollDialog({
name: 'jet-competence',
label: competence? 'Jet ' + Grammar.apostrophe('de', competence.name) : `Jet sans compétence (${compName})`,
template: 'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-competence.html',
rollData: {
alias: this.getAlias(),
carac: this.system.carac,
selectedCarac: this.getCaracByName(caracName),
selectedCaracName: caracName,
diffLibre: diff,
competence: competence,
show: { title: options?.title ?? '' }
},
callbackAction: r => this.$onRollCompetence(r, options)
});
}
/**
* Méthode pour faire un jet prédéterminer sans ouvrir la fenêtre de dialogue
* @param {*} caracName code ou label de la caractéristique. On peut utiliser 'intel' pour Intellect.
* @param {*} compName nom de compétence ou nom abrégé.
* @param {*} diff difficulté (0 si undefined)
* @param {*} options
* @returns le jet effectué
*/
async doRollCaracCompetence(caracName, compName, diff, options = { title: "" }) {
const carac = this.getCaracByName(caracName);
if (!carac) {
ui.notifications.warn(`${this.name} n'a pas de caractéristique correspondant à ${caracName}`)
return
}
const competence = this.getCompetence(compName);
let rollData = {
alias: this.getAlias(),
caracValue: Number(carac.value),
selectedCarac: carac,
competence: competence,
diffLibre: diff ?? 0,
show: { title: options?.title ?? '' }
}
RollDataAjustements.calcul(rollData, this);
await RdDResolutionTable.rollData(rollData);
this.gererExperience(rollData);
await RdDResolutionTable.displayRollData(rollData, this)
return rollData.rolled;
}
gererExperience(rollData) { }
/* -------------------------------------------- */
async roll() {
RdDEmpoignade.checkEmpoignadeEnCours(this)
@ -363,14 +310,24 @@ export class RdDBaseActorReve extends RdDBaseActor {
competences: this.itemTypes['competence']
},
callbackAction: r => this.$onRollCaracResult(r)
})
});
}
getCarac() {
// TODO: le niveau d'une entité de cauchemar devrait être exclu...
return foundry.utils.mergeObject(this.system.carac,
{
'reve-actuel': this.getCaracReveActuel(),
'chance-actuelle': this.getCaracChanceActuelle()
},
{ inplace: false })
}
/* -------------------------------------------- */
async rollCarac(caracName, options = {}) {
async rollCarac(caracName, jetResistance = undefined) {
if (Grammar.equalsInsensitive(caracName, 'taille')) {
return
}
foundry.utils.mergeObject(options, { resistance: false, diff: 0 }, { overwrite: false })
RdDEmpoignade.checkEmpoignadeEnCours(this)
let selectedCarac = this.getCaracByName(caracName)
console.log("selectedCarac", selectedCarac)
@ -381,8 +338,7 @@ export class RdDBaseActorReve extends RdDBaseActor {
rollData: {
selectedCarac: selectedCarac,
competences: this.itemTypes['competence'],
diffLibre: options.diff ?? 0,
jetResistance: options.resistance ? caracName : undefined
jetResistance: jetResistance ? caracName : undefined
},
callbackAction: r => this.$onRollCaracResult(r)
});
@ -550,7 +506,7 @@ export class RdDBaseActorReve extends RdDBaseActor {
|| entite.isEntiteAccordee(this)) {
return true;
}
const rolled = await RdDResolutionTable.roll(this.getReveActuel(), - Number(entite.getNiveau()));
const rolled = await RdDResolutionTable.roll(this.getReveActuel(), - Number(entite.system.carac.niveau.value));
const rollData = {
alias: this.getAlias(),
rolled: rolled,

View File

@ -1,7 +1,7 @@
import { RdDUtility } from "../rdd-utility.js";
import { MAX_ENDURANCE_FATIGUE, RdDUtility } from "../rdd-utility.js";
import { ReglesOptionnelles } from "../settings/regles-optionnelles.js";
import { STATUSES } from "../settings/status-effects.js";
import { ITEM_TYPES } from "../constants.js";
import { ITEM_TYPES } from "../item.js";
import { RdDBaseActorReve } from "./base-actor-reve.js";
import { RdDDice } from "../rdd-dice.js";
import { RdDItemBlessure } from "../item/blessure.js";

View File

@ -3,11 +3,8 @@ import { Misc } from "../misc.js";
import { DialogSplitItem } from "../dialog-split-item.js";
import { RdDSheetUtility } from "../rdd-sheet-utility.js";
import { Monnaie } from "../item-monnaie.js";
import { ITEM_TYPES } from "../constants.js";
import { RdDItem } from "../item.js";
import { RdDItem, ITEM_TYPES } from "../item.js";
import { RdDItemCompetenceCreature } from "../item-competencecreature.js";
import { RdDTextEditor } from "../apps/rdd-text-roll-editor.js";
import { ItemAction } from "../item/item-actions.js";
/* -------------------------------------------- */
/**
@ -28,7 +25,7 @@ export class RdDBaseActorSheet extends ActorSheet {
/* -------------------------------------------- */
async getData() {
Monnaie.validerMonnaies(this.actor)
Monnaie.validerMonnaies(this.actor.itemTypes['monnaie']);
this.actor.computeEtatGeneral();
let formData = {
@ -38,13 +35,13 @@ export class RdDBaseActorSheet extends ActorSheet {
img: this.actor.img,
name: this.actor.name,
system: this.actor.system,
description: await RdDTextEditor.enrichHTML(this.actor.system.description, this.actor),
notesmj: await RdDTextEditor.enrichHTML(this.actor.system.notesmj, this.actor),
description: await TextEditor.enrichHTML(this.actor.system.description, { async: true }),
notesmj: await TextEditor.enrichHTML(this.actor.system.notesmj, { async: true }),
options: RdDSheetUtility.mergeDocumentRights(this.options, this.actor, this.isEditable),
effects: this.actor.effects
}
RdDUtility.filterItemsPerTypeForSheet(formData, this.actor.itemTypes);
RdDBaseActorSheet.filterItemsPerTypeForSheet(formData, this.actor.itemTypes);
formData.calc = {
fortune: Monnaie.toSolsDeniers(this.actor.getFortune()),
prixTotalEquipement: this.actor.computePrixTotalEquipement(),
@ -56,7 +53,6 @@ export class RdDBaseActorSheet extends ActorSheet {
formData.conteneurs = RdDUtility.conteneursRacine(formData.conteneurs);
formData.competences.filter(it => it.type == ITEM_TYPES.competencecreature)
.forEach(it => it.isdommages = RdDItemCompetenceCreature.isDommages(it))
return formData;
}
@ -80,37 +76,95 @@ export class RdDBaseActorSheet extends ActorSheet {
}
}
/* -------------------------------------------- */
static filterItemsPerTypeForSheet(formData, itemTypes) {
formData.blessures = Misc.arrayOrEmpty(itemTypes['blessure']);
formData.recettescuisine = Misc.arrayOrEmpty(itemTypes['recettecuisine']);
formData.recettesAlchimiques = Misc.arrayOrEmpty(itemTypes['recettealchimique']);
formData.maladies = Misc.arrayOrEmpty(itemTypes['maladie']);
formData.poisons = Misc.arrayOrEmpty(itemTypes['poison']);
formData.possessions = Misc.arrayOrEmpty(itemTypes['possession']);
formData.maladiesPoisons = formData.maladies.concat(formData.poisons);
formData.competences = (itemTypes['competence'] ?? []).concat(itemTypes['competencecreature'] ?? []);
formData.sortsReserve = Misc.arrayOrEmpty(itemTypes['sortreserve']);
formData.sorts = Misc.arrayOrEmpty(itemTypes['sort']);
formData.rencontres = Misc.arrayOrEmpty(itemTypes['rencontre']);
formData.casestmr = Misc.arrayOrEmpty(itemTypes['casetmr']);
formData.signesdraconiques = Misc.arrayOrEmpty(itemTypes['signedraconique']);
formData.queues = Misc.arrayOrEmpty(itemTypes['queue']);
formData.souffles = Misc.arrayOrEmpty(itemTypes['souffle']);
formData.ombres = Misc.arrayOrEmpty(itemTypes['ombre']);
formData.tetes = Misc.arrayOrEmpty(itemTypes['tete']);
formData.taches = Misc.arrayOrEmpty(itemTypes['tache']);
formData.meditations = Misc.arrayOrEmpty(itemTypes['meditation']);
formData.chants = Misc.arrayOrEmpty(itemTypes['chant']);
formData.danses = Misc.arrayOrEmpty(itemTypes['danse']);
formData.musiques = Misc.arrayOrEmpty(itemTypes['musique']);
formData.oeuvres = Misc.arrayOrEmpty(itemTypes['oeuvre']);
formData.jeux = Misc.arrayOrEmpty(itemTypes['jeu']);
formData.services = Misc.arrayOrEmpty(itemTypes['service']);
formData.conteneurs = Misc.arrayOrEmpty(itemTypes['conteneur']);
formData.materiel = Misc.arrayOrEmpty(itemTypes['objet']);
formData.armes = Misc.arrayOrEmpty(itemTypes['arme']);
formData.armures = Misc.arrayOrEmpty(itemTypes['armure']);
formData.munitions = Misc.arrayOrEmpty(itemTypes['munition']);
formData.livres = Misc.arrayOrEmpty(itemTypes['livre']);
formData.potions = Misc.arrayOrEmpty(itemTypes['potion']);
formData.plantes = Misc.arrayOrEmpty(itemTypes['plante']);
formData.ingredients = Misc.arrayOrEmpty(itemTypes['ingredient']);
formData.faunes = Misc.arrayOrEmpty(itemTypes['faune']);
formData.herbes = Misc.arrayOrEmpty(itemTypes['herbe']);
formData.nourritureboissons = Misc.arrayOrEmpty(itemTypes['nourritureboisson']);
formData.gemmes = Misc.arrayOrEmpty(itemTypes['gemme']);
formData.monnaies = Misc.arrayOrEmpty(itemTypes['monnaie']).sort(Monnaie.triValeurEntiere());
formData.objets = Misc.arrayOrEmpty(itemTypes['objet'])
formData.inventaires = RdDItem.getItemTypesInventaire('all')
.map(t => Misc.arrayOrEmpty(itemTypes[t]))
.reduce((a, b) => a.concat(b), [])
.sort(Misc.ascending(it => it.name));
}
/* -------------------------------------------- */ /** @override */
activateListeners(html) {
super.activateListeners(html);
this.html = html;
this.html.find('.actionItem').click(event => ItemAction.onActionItem(event, this.actor, this.options))
this.html.find('.item-edit').click(async event => this.itemActionEdit(event))
this.html.find('.conteneur-name a').click(async event => {
RdDUtility.toggleAfficheContenu(this.getItemId(event))
this.render(true)
})
RdDUtility.toggleAfficheContenu(this.getItemId(event));
this.render(true);
});
this.html.find('.actor-montrer').click(async event => this.actor.postActorToChat());
this.html.find('.item-edit').click(async event => this.getItem(event)?.sheet.render(true))
this.html.find('.item-montrer').click(async event => this.getItem(event)?.postItemToChat());
this.html.find('.recherche')
.each((index, field) => {
this._rechercheSelectArea(field);
})
.keyup(async event => this._rechercherKeyup(event))
.change(async event => this._rechercherKeyup(event))
this.html.find('.recherche').prop("disabled", false)
.change(async event => this._rechercherKeyup(event));
this.html.find('.recherche').prop("disabled", false);
// Everything below here is only needed if the sheet is editable
if (!this.options.editable) return;
this.html.find('.item-equip-armure').click(async event => this.actor.equiperObjet(this.getItem(event)))
this.html.find('.item-delete').click(async event => RdDUtility.confirmActorItemDelete(this.getItem(event), this.actor));
this.html.find('.item-split').click(async event => RdDSheetUtility.splitItem(this.getItem(event), this.actor))
this.html.find('.item-action').click(async event => {
const item = RdDSheetUtility.getItem(event, this.actor);
item?.actionPrincipale(this.actor, async () => this.render())
});
this.html.find('.item-split').click(async event => {
const item = this.getItem(event);
RdDSheetUtility.splitItem(item, this.actor);
});
this.html.find('.item-quantite-plus').click(async event => this.actor.itemQuantiteIncDec(this.getItemId(event), 1));
this.html.find('.item-quantite-moins').click(async event => this.actor.itemQuantiteIncDec(this.getItemId(event), -1));
this.html.find('.item-delete').click(async event => RdDUtility.confirmActorItemDelete(this, this.getItem(event)));
this.html.find('.item-vendre').click(async event => this.vendre(this.getItem(event)));
this.html.find('.creer-un-objet').click(async event => {
this.selectObjetTypeToCreate();
@ -123,11 +177,21 @@ export class RdDBaseActorSheet extends ActorSheet {
this.options.vueDetaillee = !this.options.vueDetaillee;
this.render(true);
});
}
itemActionEdit(event) {
const item = this.getItem(event);
return item?.sheet.render(true);
if (this.options.vueDetaillee) {
// On carac change
this.html.find('.carac-value').change(async event => {
let caracName = event.currentTarget.name.replace(".value", "").replace("system.carac.", "");
this.actor.updateCarac(caracName, parseInt(event.target.value));
});
// On competence change
this.html.find('.competence-value').change(async event => {
let compName = event.currentTarget.attributes.compname.value;
//console.log("Competence changed :", compName);
this.actor.updateCompetence(compName, parseInt(event.target.value));
});
}
}
_rechercherKeyup(event) {
@ -196,7 +260,7 @@ export class RdDBaseActorSheet extends ActorSheet {
/* -------------------------------------------- */
async selectObjetTypeToCreate() {
let types = this.getTypesInventaire().sort(Misc.ascending(type => Misc.typeName('Item', type)));
let content = `<span class="generic-label">Selectionnez le type d'équipement</span><select class="item-type">`;
let content = `<span class="competence-label">Selectionnez le type d'équipement</span><select class="item-type">`;
for (let typeName of types) {
content += `<option value="${typeName}">${Misc.typeName('Item', typeName)}</option>`
}

View File

@ -3,7 +3,7 @@ import { ChatUtility } from "../chat-utility.js";
import { SYSTEM_SOCKET_ID } from "../constants.js";
import { Grammar } from "../grammar.js";
import { Monnaie } from "../item-monnaie.js";
import { ITEM_TYPES } from "../constants.js";
import { ITEM_TYPES } from "../item.js";
import { Misc } from "../misc.js";
import { RdDAudio } from "../rdd-audio.js";
import { RdDConfirm } from "../rdd-confirm.js";
@ -21,7 +21,7 @@ export class RdDBaseActor extends Actor {
static $findCaracByName(carac, name) {
const caracList = Object.entries(carac);
let entry = Misc.findFirstLike(name, caracList, { mapper: it => it[0], description: 'caractéristique', onMessage: m => { } });
let entry = Misc.findFirstLike(name, caracList, { mapper: it => it[0], description: 'caractéristique' });
if (!entry || entry.length == 0) {
entry = Misc.findFirstLike(name, caracList, { mapper: it => it[1].label, description: 'caractéristique' });
}
@ -81,6 +81,7 @@ export class RdDBaseActor extends Actor {
}
}
static getRealActor(actorId, tokenId) {
if (tokenId) {
let token = canvas.tokens.get(tokenId)
@ -160,11 +161,8 @@ export class RdDBaseActor extends Actor {
return RdDBaseActor.$findCaracByName(carac, name);
}
mapCarac(caracCode) { return caracCode }
getCaracByName(name) {
name = this.mapCarac(Grammar.toLowerCaseNoAccent(name))
switch (name) {
switch (Grammar.toLowerCaseNoAccent(name)) {
case 'reve-actuel': case 'reve actuel':
return this.getCaracReveActuel();
case 'chance-actuelle': case 'chance-actuelle':
@ -178,19 +176,11 @@ export class RdDBaseActor extends Actor {
await super._preCreate(data, options, user);
// Configure prototype token settings
if (this.type === "personnage") {
this.updateSource({
sight: { enabled: true },
actorLink: options.fromCompendium ? data.prototypeToken.actorLink : true,
disposition: CONST.TOKEN_DISPOSITIONS.FRIENDLY
})
} else {
const prototypeToken = {
sight: { enabled: true },
disposition: CONST.TOKEN_DISPOSITIONS.NEUTRAL
}
this.updateSource({ prototypeToken });
}
const prototypeToken = {};
if (this.type === "personnage") Object.assign(prototypeToken, {
sight: { enabled: true }, actorLink: true, disposition: CONST.TOKEN_DISPOSITIONS.FRIENDLY
});
this.updateSource({ prototypeToken });
}
/* -------------------------------------------- */
@ -737,20 +727,25 @@ export class RdDBaseActor extends Actor {
actionImpossible(action) {
ui.notifications.info(`${this.getAlias()} ne peut pas faire cette action: ${action}`)
}
async jetEthylisme() { this.actionImpossible("jet d'éthylisme") }
async rollAppelChance() { this.actionImpossible("appel à la chance") }
async jetDeMoral() { this.actionImpossible("jet de moral") }
async actionPrincipale(item, onActionItem = async () => { }) {
switch (item.type) {
case ITEM_TYPES.conteneur: return await item.sheet.render(true);
}
return undefined
}
async resetItemUse() { }
async incDecItemUse(itemId, inc = 1) { }
getItemUse(itemId) { return 0; }
async finDeRound(options = { terminer: false }) { }
isActorCombat() { return false }
getCaracInit(competence) { return 0 }
listActionsCombat() { return [] }
listActionsPossessions() {
return this.itemTypes[ITEM_TYPES.possession]

View File

@ -45,7 +45,6 @@ export class RdDCommerceSheet extends RdDBaseActorSheet {
super.activateListeners(html);
this.html.find('a.item-acheter').click(async event => await this.vente(this.getItem(event)));
this.html.find('.service-acheter').click(async event => await this.vente(this.getItem(event)));
if (!this.options.editable) return;

View File

@ -1,6 +1,4 @@
import { Grammar } from "../grammar.js";
import { ITEM_TYPES } from "../constants.js";
import { LIST_CARAC_AUTRES } from "../rdd-carac.js";
import { ITEM_TYPES } from "../item.js";
import { RdDBaseActorSang } from "./base-actor-sang.js";
export class RdDCreature extends RdDBaseActorSang {
@ -34,16 +32,4 @@ export class RdDCreature extends RdDBaseActorSang {
}
}
mapCarac(caracCode) {
switch (caracCode) {
case 'vue': case 'ouie': case 'odoratgout': case 'empathie': case 'perception':
return 'perception'
case 'agilite':
return 'force'
case 'force': case 'constitution': case 'taille': case 'reve': case 'volonte':
return caracCode
}
return undefined
}
}

View File

@ -1,7 +1,6 @@
import { RdDBaseActorReveSheet } from "./base-actor-reve-sheet.js";
import { RdDSheetUtility } from "../rdd-sheet-utility.js";
import { RdDUtility } from "../rdd-utility.js";
import { DialogSelect } from "../dialog-select.js";
export class RdDActorEntiteSheet extends RdDBaseActorReveSheet {
@ -15,8 +14,6 @@ export class RdDActorEntiteSheet extends RdDBaseActorReveSheet {
async getData() {
let formData = await super.getData();
formData.niveau = this.actor.getNiveau()
delete formData.system.carac.niveau
formData.resonances = this.actor.system.sante.resonnance.actors.map(actorId => game.actors.get(actorId))
.map(actor => { return { id: actor.id, name: actor.name, img: actor.img } })
return formData
@ -35,30 +32,26 @@ export class RdDActorEntiteSheet extends RdDBaseActorReveSheet {
let compName = event.currentTarget.attributes.compname.value;
this.actor.updateCreatureCompetence(compName, "carac_value", parseInt(event.target.value));
});
this.html.find('.creature-niveau').change(async event => {
let compName = event.currentTarget.attributes.compname.value;
this.actor.updateCreatureCompetence(compName, "niveau", parseInt(event.target.value));
});
this.html.find('.creature-dommages').change(async event => {
let compName = event.currentTarget.attributes.compname.value;
this.actor.updateCreatureCompetence(compName, "dommages", parseInt(event.target.value));
})
this.html.find('.resonance-add').click(async event =>
DialogSelect.select({
label: "Choisir un acteur à accorder",
list: game.actors.filter(it => it.isPersonnage() && it.prototypeToken.actorLink)
},
it => this.resonanceAdd(it.id))
)
});
this.html.find('.resonance-delete').click(async event => {
const li = RdDSheetUtility.getEventElement(event);
const actorId = li.data("actor-id");
if (actorId) {
const actorResonance = game.actors.get(actorId);
RdDUtility.confirmSubActeurDelete(this, actorResonance, li, () => {
this.resonanceDelete(actorId);
console.log('Delete : ', actorId);
this.deleteSubActeur(actorId);
RdDUtility.slideOnDelete(this, li);
})
});
}
})
});
}
async _onDropActor(event, dragData) {
@ -67,13 +60,7 @@ export class RdDActorEntiteSheet extends RdDBaseActorReveSheet {
super._onDropActor(event, dragData)
}
async resonanceAdd(actorId) {
let newResonances = [...this.actor.system.sante.resonnance.actors, actorId]
await this.actor.update({ 'system.sante.resonnance.actors': newResonances });
}
async resonanceDelete(actorId) {
console.log('Delete : ', actorId);
async deleteSubActeur(actorId) {
let newResonances = this.actor.system.sante.resonnance.actors.filter(id => id != actorId);
await this.actor.update({ 'system.sante.resonnance.actors': newResonances }, { renderSheet: false });
}

View File

@ -1,7 +1,6 @@
import { ENTITE_INCARNE, ENTITE_NONINCARNE } from "../constants.js";
import { ITEM_TYPES } from "../constants.js";
import { ITEM_TYPES } from "../item.js";
import { Misc } from "../misc.js";
import { RdDCarac } from "../rdd-carac.js";
import { RdDEncaisser } from "../rdd-roll-encaisser.js";
import { STATUSES } from "../settings/status-effects.js";
import { RdDBaseActorReve } from "./base-actor-reve.js";
@ -19,23 +18,12 @@ export class RdDEntite extends RdDBaseActorReve {
isEntite(typeentite = []) {
return (typeentite.length == 0 || typeentite.includes(this.system.definition.typeentite));
}
isNonIncarnee() { return this.isEntite([ENTITE_NONINCARNE]) }
getReveActuel() {
return Misc.toInt(this.system.carac.reve?.value)
}
getCarac() {
const carac = super.getCarac()
delete carac.niveau
return carac
}
getNiveau() {
const reve = this.getReve()
return RdDCarac.getCaracDerivee(reve).niveau
}
getForce() { return this.getReve() }
getAgilite() { return this.getReve() }
getChance() { return this.getReve() }
@ -76,7 +64,6 @@ export class RdDEntite extends RdDBaseActorReve {
}
return {}
}
async encaisser() {
if (this.isNonIncarnee()) {
return
@ -117,14 +104,4 @@ export class RdDEntite extends RdDBaseActorReve {
super.setEntiteReveAccordee(actor)
}
}
mapCarac(caracCode) {
switch (caracCode) {
case 'taille':
case 'reve':
return caracCode
}
return 'reve'
}
}

View File

@ -6,8 +6,8 @@ import { ExportScriptarium } from "./export-scriptarium.js";
import { CATEGORIES_COMPETENCES, CATEGORIES_DRACONIC, Mapping } from "./mapping.js";
export class RdDActorExportSheet extends RdDActorSheet {
static init() {
loadTemplates([
static async init() {
await loadTemplates([
"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/arme.hbs",
"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/blessure.hbs",
"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/blessures.hbs",
@ -23,7 +23,6 @@ export class RdDActorExportSheet extends RdDActorSheet {
])
Actors.registerSheet(SYSTEM_RDD, RdDActorExportSheet, { types: ["personnage"], makeDefault: false, label: "Feuille simplifiée" })
}
static get defaultOptions() {
return foundry.utils.mergeObject(RdDActorSheet.defaultOptions, {
template: "systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/actor-encart-sheet.hbs",

View File

@ -1,4 +1,4 @@
import { ACTOR_TYPES } from "../../constants.js"
import { ACTOR_TYPES } from "../../item.js"
import { Misc } from "../../misc.js"
import { EXPORT_CSV_SCRIPTARIUM, OptionsAvancees } from "../../settings/options-avancees.js"
import { Mapping } from "./mapping.js"

View File

@ -2,7 +2,7 @@ import { Grammar } from "../../grammar.js"
import { RdDItemArme } from "../../item-arme.js"
import { RdDItemCompetence } from "../../item-competence.js"
import { RdDItemSort } from "../../item-sort.js"
import { ITEM_TYPES } from "../../constants.js"
import { ITEM_TYPES } from "../../item.js"
import { Misc } from "../../misc.js"
import { RdDTimestamp } from "../../time/rdd-timestamp.js"
import { RdDBonus } from "../../rdd-bonus.js"
@ -83,7 +83,6 @@ const MAPPING_BASE = [
{ column: "protectionarmure", colName: 'Protection', getter: (actor, context) => Mapping.getProtectionArmure(actor, context) },
{ column: "malus_armure", getter: (actor, context) => Mapping.getMalusArmure(actor, context) },
{ column: "reve_actuel", rollClass: 'roll-reve-actuel', colName: 'Rêve actuel', getter: (actor, context) => actor.system.reve.reve.value },
{ column: "chance_actuel", rollClass: 'roll-chance-actuelle', colName: 'Chance actuelle', getter: (actor, context) => actor.system.compteurs.chance.value },
{ column: "vie_actuel", rollClass: 'jet-vie', getter: (actor, context) => actor.system.sante.vie.value },
{ column: "endurance_actuel", rollClass: 'jet-endurance', getter: (actor, context) => actor.system.sante.endurance.value },
{ column: "esquive", getter: (actor, context) => Mapping.getEsquive(context) },
@ -279,7 +278,7 @@ export class Mapping {
const race = ['', 'humain'].includes(Grammar.toLowerCaseNoAccent(actor.system.race)) ? '' : (actor.system.race + ' ')
const heure = actor.system.heure
const hn = `${sexeFeminin} à l'heure ${RdDTimestamp.definition(heure).avecArticle}`
const age = (actor.system.age && actor.system.age >0) ? `${actor.system.age} ans` : undefined
const age = actor.system.age ? `${actor.system.age} ans` : undefined
const taille = actor.system.taille
const poids = actor.system.poids
const cheveux = actor.system.cheveux ? `cheveux ${actor.system.cheveux}` : undefined

View File

@ -6,7 +6,6 @@ import { Grammar } from "../grammar.js";
import { Misc } from "../misc.js";
import { ENTITE_INCARNE, ENTITE_NONINCARNE } from "../constants.js";
import { RdDItemTete } from "../item/tete.js";
import { ITEM_TYPES } from "../constants.js";
const WHITESPACES = "\\s+"
const NUMERIC = "[\\+\\-]?\\d+"
@ -27,13 +26,14 @@ const MANIEMENTS = {
'de lancer': (weapon) => { return { name: weapon.system.lancer, categorie: 'lancer' } },
'de jet': (weapon) => { return { name: weapon.system.lancer, categorie: 'lancer' } },
'à une main': (weapon) => { return { name: weapon.system.competence, categorie: 'melee' } },
'à deux mains': (weapon) => { return { name: weapon.system.competence.replace("à 1 main", "à 2 mains"), categorie: 'melee' } },
'à deux main': (weapon) => { return { name: weapon.system.competence.replace("à 1 main", "à 2 main"), categorie: 'melee' } },
'mêlée': (weapon) => { return { name: weapon.system.competence, categorie: 'melee' } },
}
const XREGEXP_WEAPON_MANIEMENT = "(?<maniement>(" + Misc.join(Object.keys(MANIEMENTS), '|') + "))"
const XREGEXP_SORT_VOIE = "(?<voies>[OHNT](\\/[OHNT])*)"
const XREGEXP_SORT_NAME = "(?<name>[^\\(]+)"
// const XREGEXP_SORT_CASE = "(?<coord>([A-Za-zÀ-ÖØ-öø-ÿ\\s\\-]+|[A-M]\\d{1,2})+)"
const XREGEXP_SORT_CASE = "(?<coord>([A-Za-zÀ-ÖØ-öø-ÿ\\s\\-]+|[A-M]\\d{1,2}))"
const XREGEXP_SORT = "(" + XREGEXP_SORT_VOIE
@ -164,18 +164,26 @@ export class RdDStatBlockParser {
switch (type) {
case "creature":
RdDStatBlockParser.parseCreature(statString, actorData)
await RdDStatBlockParser.parseCompetences(statString, actorData, items)
break
case "entite":
RdDStatBlockParser.parseEntite(statString, actorData)
await RdDStatBlockParser.parseCompetences(statString, actorData, items)
break
case "personnage":
await RdDStatBlockParser.parseArmors(statString, actorData, items);
await RdDStatBlockParser.parseCompetences(statString, actorData, items);
await RdDStatBlockParser.parseWeapons(statString, items);
await RdDStatBlockParser.parseHautReve(statString, actorData, items);
RdDStatBlockParser.parsePersonnage(statString, actorData);
}
if (type == "personnage") {
// Now process armors
await RdDStatBlockParser.parseArmors(statString, actorData, items);
}
// Get skills from compendium
await RdDStatBlockParser.parseCompetences(statString, actorData, items);
if (type == "personnage") {
// Now process weapons
await RdDStatBlockParser.parseWeapons(statString, items);
await RdDStatBlockParser.parseHautReve(statString, actorData, items);
RdDStatBlockParser.parsePersonnage(statString, actorData);
}
const name = RdDStatBlockParser.extractName(type, statString);
@ -185,7 +193,6 @@ export class RdDStatBlockParser {
let newActor = await RdDBaseActorReve.create({ name, type, system: actorData, items });
await newActor.remiseANeuf()
await RdDStatBlockParser.adjustAttacks(newActor)
await RdDStatBlockParser.setValeursActuelles(newActor, statString)
await newActor?.sheet.render(true)
}
@ -260,7 +267,7 @@ export class RdDStatBlockParser {
}
let weapMatch = XRegExp.exec(statString, XRegExp(weapon.name
+ "(\\s*" + XREGEXP_WEAPON_MANIEMENT + ")?"
+ "\\s+(?<value>[\\+\\-]?\\d+)", 'giu'));
+ "\\s+(?<value>\\+\\d+)", 'giu'));
if (weapMatch) {
weapon = weapon.toObject();
weapon.system.equipe = 'true';
@ -289,21 +296,6 @@ export class RdDStatBlockParser {
}
}
static async adjustAttacks(newActor) {
if (["creature", "entite"].includes(newActor.type)) {
const bonusDommages = newActor.getBonusDegat()
const ajustementAttaques = newActor.itemTypes[ITEM_TYPES.competencecreature].filter(it => it.system.iscombat)
.map(it => {
return {
_id: it.id,
'system.categorie': 'melee',
'system.dommages': it.system.dommages - bonusDommages
}
})
await newActor.updateEmbeddedDocuments('Item', ajustementAttaques)
}
}
static async setValeursActuelles(newActor, statString) {
const updates = {
}
@ -420,9 +412,9 @@ export class RdDStatBlockParser {
actorData.taille = taille.value;
}
// Get weight
const poids = XRegExp.exec(statString, XRegExp(",\\s+(?<value>\\d+)\\s+kg", 'giu'));
const poids = XRegExp.exec(statString, XRegExp("(?<value>\\d+ kg)", 'giu'));
if (poids?.value) {
actorData.poids = poids.value + ' kg';
actorData.poids = poids.value;
}
// Get cheveux
const cheveux = XRegExp.exec(statString, XRegExp("kg,\\s+(?<value>[A-Za-zÀ-ÖØ-öø-ÿ\\s\\-]+),\\s+yeux", 'giu'));
@ -443,7 +435,7 @@ export class RdDStatBlockParser {
}
static parseCreature(statString, actorData) {
let protection = XRegExp.exec(statString, XRegExp("protection(\\s+naturelle)?\\s+(?<value>[\\-]?\\d+)", 'giu'));
let protection = XRegExp.exec(statString, XRegExp("protection\\s+(?<value>[\\-]?\\d+)", 'giu'));
if (protection?.value) {
actorData.attributs.protection.value = Number(protection.value);
}
@ -469,40 +461,33 @@ export class RdDStatBlockParser {
}
static parseActorType(statString) {
let force = XRegExp.exec(statString, XRegExp("Force\\s+(?<value>[\\+\\-]?\\d+)", 'giu'))
let vue = XRegExp.exec(statString, XRegExp("Vue\\s+(?<value>[\\+\\-]?\\d+)", 'giu'))
let niveau = XRegExp.exec(statString, XRegExp("Niveau\\s+(?<value>[\\+\\-]?\\d+)", 'giu'))
let perception = XRegExp.exec(statString, XRegExp("perception\\s+(?<value>\\d+)", 'giu'))
if (!force) {
return "entite"
}
if (!vue || perception) {
if (perception?.value) {
return "creature"
}
if (niveau?.value) {
return "entite"
}
return "personnage"
}
static extractName(actorType, statString) {
if (actorType == "personnage") {
// Check if ',né le' is present
let namePersonnage = "Importé"
if (statString.includes(", né")) {
// Name is all string before first comma ','
namePersonnage = XRegExp.exec(statString, XRegExp("(?<value>[\\p{Letter}\'\\-\\s\\d]+),", 'giu'));
} else {
namePersonnage = XRegExp.exec(statString, XRegExp("(?<value>[\\p{Letter}\'\\-\\s\\d]+)\\s+TAILLE", 'giu'));
}
if (namePersonnage?.value) {
return Misc.upperFirst(namePersonnage?.value.toLowerCase());
}
switch (actorType) {
case "personnage":
// Check if ',né le' is present
let namePersonnage = "Importé"
if (statString.includes(", né")) {
// Name is all string before first comma ','
namePersonnage = XRegExp.exec(statString, XRegExp("(?<value>[\\p{Letter}\\s\\d]+),", 'giu'));
} else {
namePersonnage = XRegExp.exec(statString, XRegExp("(?<value>[\\p{Letter}\\s\\d]+)\\s+TAILLE", 'giu'));
}
if (namePersonnage?.value) {
return Misc.upperFirst(namePersonnage?.value);
}
}
const name = XRegExp.exec(statString, XRegExp("(?<value>.+)\\s+taille", 'giu'));
if (actorType == "entite") {
if (!(name?.value)) {
const nameEntiteReve = XRegExp.exec(statString, XRegExp("(?<value>.+)\\s+rêve", 'giu'));
return Misc.upperFirst(nameEntiteReve?.value || "Importé");
}
}
return Misc.upperFirst(name?.value || "Importé");
}

View File

@ -1,78 +0,0 @@
import "./xregexp-all.js";
import { SystemCompendiums } from "../settings/system-compendiums.js";
import { ACTOR_TYPES } from "../constants.js";
import { TextRollAlchimie } from "./textroll/text-roll-alchimie.js";
import { TextRollCaracCompetence } from "./textroll/text-roll-carac-competence.js";
import { TextRollFormula } from "./textroll/text-roll-formula.js";
import { TextRollManager } from "./textroll/text-roll-formatter.js";
const TEXT_ROLL_MANAGERS = [
new TextRollAlchimie(),
new TextRollCaracCompetence(),
new TextRollFormula()]
export class RdDTextEditor {
static registerChatCallbacks(html) {
html.on("click", '.roll-text', async event => await RdDTextEditor.rollText(event))
}
static async enrichHTML(text, object, options = {showlink:true}) {
const context = {
text,
object,
options,
competences: await SystemCompendiums.getCompetences(ACTOR_TYPES.personnage),
}
for (let manager of TEXT_ROLL_MANAGERS) {
context.code = manager.code
context.template = manager.template
context.text = await manager.onReplaceRoll(context);
}
return await TextEditor.enrichHTML(context.text, {
relativeTo: object,
secrets: object?.isOwner,
async: true
})
}
static async _applyReplaceAll(manager, context) {
context.code = manager.code
context.template = manager.template
context.text = await manager.onReplaceRoll(context);
return context.text
}
static getEventElement(event) {
return $(event.currentTarget)?.parents(".roll-text-link");
}
static async rollText(event, actor) {
const code = TextRollManager.getNode(event)?.data('code')
const manager = TEXT_ROLL_MANAGERS.find(it => it.code == code)
if (manager) {
await manager.onRollText(event, actor)
}
}
static async chatRollText(event) {
const node = TextRollManager.getNode(event);
if (node) {
const code = node.data('code')
const param = node.data('json')
const manager = TEXT_ROLL_MANAGERS.find(it => it.code == code)
const text = await TextRollManager.createRollText(
{
code,
template: manager.template,
options: { showLink: false }
},
param)
ChatMessage.create({
content: text
})
}
}
}

View File

@ -1,79 +0,0 @@
import "../xregexp-all.js";
import { ACTOR_TYPES, ITEM_TYPES } from "../../constants.js";
import { RdDCarac } from "../../rdd-carac.js";
import { RdDUtility } from "../../rdd-utility.js";
import { RdDAlchimie } from "../../rdd-alchimie.js";
import { TextRollManager } from "./text-roll-formatter.js";
const REGEX_ALCHIMIE_TERMES = "(?<termes>(\\w|-)+)"
const REGEX_ALCHIMIE_MANIP = "(?<manip>(couleur|consistance))"
const XREGEXP_ROLL_ALCHIMIE = XRegExp("@roll\\[" + REGEX_ALCHIMIE_MANIP + "\\s+" + REGEX_ALCHIMIE_TERMES + "\\]", 'giu')
const XREGEXP_ROLL_ALCHIMIE_MANIP = XRegExp("@" + REGEX_ALCHIMIE_MANIP + "\\{" + REGEX_ALCHIMIE_TERMES + "\\}", 'giu')
/**
* classe pour gérer les jets d'alchimie
*/
export class TextRollAlchimie {
get code() { return 'alchimie' }
get template() { return `systems/foundryvtt-reve-de-dragon/templates/apps/textroll/link-text-roll-alchimie.hbs` }
async onReplaceRoll(context) {
const handler = new AlchimieTextBuilder(context)
return await handler.replaceAll()
}
async onRollText(event, actor) {
actor = this.getSelectedActor(actor)
if (actor) {
const node = TextRollManager.getNode(event)
const recetteId = node.data('recetteid')
const manip = node.data('manip')
const termes = node.data('termes')
if (recetteId) {
await actor.effectuerTacheAlchimie(recetteId, manip, termes)
}
else {
const carac = RdDCarac.caracDetails(RdDAlchimie.getCaracTache(manip))
const diff = RdDAlchimie.getDifficulte(termes)
await actor.rollCaracCompetence(carac.code, 'Alchimie', diff)
}
}
}
getSelectedActor(actor) {
actor = actor ?? RdDUtility.getSelectedActor()
if (actor && actor.type == ACTOR_TYPES.personnage) {
return actor
}
return undefined
}
}
class AlchimieTextBuilder {
constructor(context) {
this.context = context
}
async replaceAll() {
await XRegExp.forEach(this.context.text, XREGEXP_ROLL_ALCHIMIE, async (rollMatch, i) => await this.replaceMatch(rollMatch, i))
await XRegExp.forEach(this.context.text, XREGEXP_ROLL_ALCHIMIE_MANIP, async (rollMatch, i) => await this.replaceMatch(rollMatch, i))
return this.context.text
}
async replaceMatch(rollMatch, i) {
if (rollMatch.termes && rollMatch.manip) {
const manip = rollMatch.manip
const termes = rollMatch.termes
const carac = RdDCarac.caracDetails(RdDAlchimie.getCaracTache(manip))
const diff = RdDAlchimie.getDifficulte(termes)
const recette = (this.context.object instanceof Item && this.context.object.type == ITEM_TYPES.recettealchimique) ? this.context.object : undefined
const replacement = await TextRollManager.createRollText(this.context,
{
code: this.context.code,
manip, termes, carac, diff, recetteid: recette?.id,
})
this.context.text = this.context.text.replace(rollMatch[0], replacement);
}
}
}

View File

@ -1,98 +0,0 @@
import "../xregexp-all.js";
import { RdDCarac } from "../../rdd-carac.js";
import { RdDItemCompetence } from "../../item-competence.js";
import { RdDUtility } from "../../rdd-utility.js";
import { TextRollManager } from "./text-roll-formatter.js";
const REGECP_CARAC = "(?<carac>[A-Za-zÀ-ÖØ-öø-ÿ\\s\\-]+)"
const REGEXP_COMP = "(\\/(?<competence>[A-Za-zÀ-ÖØ-öø-ÿ\\s\\-]+))?"
const REGEXP_DIFF = "(/(?<diff>[\\+\\-]?\\d+(d\\d+)?))?"
const REGEXP_ROLL_CARAC_COMP = REGECP_CARAC + REGEXP_COMP + REGEXP_DIFF
const XREGEXP_ROLL_CARAC_COMP = XRegExp("@roll\\[" + REGEXP_ROLL_CARAC_COMP + "\\]", 'giu')
/**
* classe pour gérer les jets de caractéristique/compétence depuis
* les journaux/descriptions
*/
export class TextRollCaracCompetence {
get code() { return 'carac' }
get template() { return `systems/foundryvtt-reve-de-dragon/templates/apps/textroll/link-text-roll-carac-competence.hbs` }
async onReplaceRoll(context) {
const handler = new CaracCompetenceTextBuilder(context)
return await handler.replaceAll()
}
async onRollText(event, actor) {
const node = TextRollManager.getNode(event)
const caracCode = node.data('carac-code')
if (caracCode) {
const competence = node.data('competence')
const diff = await this.calculDiff(node)
const actors = this.getSelectedActors(actor)
actors.forEach(async it => await this.doRoll(it, caracCode, competence, diff))
}
}
async calculDiff(node) {
const diff = node.data('diff') ?? 0
if (!Number.isInteger(diff)) {
const roll = new Roll(diff)
await roll.evaluate()
await roll.toMessage({ flavor: `La difficulté de ${diff} a donné ${roll.total}` })
return roll.total
}
return diff
}
async doRoll(actor, caracCode, competence, diff) {
caracCode = actor.mapCarac(caracCode)
if (caracCode) {
if (competence) {
await actor.rollCaracCompetence(caracCode, competence, diff)
}
else {
await actor.rollCarac(caracCode, { diff })
}
}
}
getSelectedActors(actor) {
const selected = canvas.tokens.controlled.map(it => it.actor).filter(it => it)
if (selected.length > 0) {
return selected
}
actor = actor ?? RdDUtility.getSelectedActor()
if (actor) {
return [actor]
}
return []
}
}
class CaracCompetenceTextBuilder {
constructor(context) {
this.context = context
}
async replaceAll() {
await XRegExp.forEach(this.context.text, XREGEXP_ROLL_CARAC_COMP, async (rollMatch, i) => await this.replaceMatch(rollMatch, i))
return this.context.text
}
async replaceMatch(rollMatch, i) {
const carac = RdDCarac.caracDetails(rollMatch.carac)
if (carac) {
const competence = rollMatch.competence ? RdDItemCompetence.findCompetence(this.context.competences, rollMatch.competence) : undefined
const replacement = await TextRollManager.createRollText(this.context,
{
code: this.context.code,
carac: carac,
competence: competence?.name,
diff: rollMatch.diff,
})
this.context.text = this.context.text.replace(rollMatch[0], replacement)
}
}
}

View File

@ -1,13 +0,0 @@
export class TextRollManager {
static async createRollText(context, param) {
return await renderTemplate(context.template, {
param, options: context.options
})
}
static getNode(event) {
return $(event.currentTarget)?.parents(".roll-text-link");
}
}

View File

@ -1,51 +0,0 @@
import "../xregexp-all.js";
import { TextRollManager } from "./text-roll-formatter.js";
const REGEXP_ROLL_FORMULA = "(?<formula>[^\\[\\]]+)"
const XREGEXP_ROLL_FORMULA = XRegExp("@roll\\[" + REGEXP_ROLL_FORMULA + "\\]", 'giu')
/**
* classe pour gérer les jets de dés (formules Foundry)
*/
export class TextRollFormula {
get code() { return 'formula' }
get template() { return `systems/foundryvtt-reve-de-dragon/templates/apps/textroll/link-text-roll-formula.hbs` }
async onReplaceRoll(context) {
const handler = new FormulaTextBuilder(context)
return await handler.replaceAll()
}
async onRollText(event, actor) {
const node = TextRollManager.getNode(event)
const rollFormula = node.data('formula')
if (rollFormula) {
const roll = new Roll(rollFormula)
await roll.evaluate()
await roll.toMessage()
}
}
}
class FormulaTextBuilder {
constructor(context) {
this.context = context
}
async replaceAll() {
await XRegExp.forEach(this.context.text, XREGEXP_ROLL_FORMULA,
async (rollMatch, i) => await this.replaceMatch(rollMatch, i))
return this.context.text
}
async replaceMatch(rollMatch, i) {
if (rollMatch.formula) {
const replacement = await TextRollManager.createRollText(this.context,
{
code: this.context.code,
formula: rollMatch.formula,
})
this.context.text = this.context.text.replace(rollMatch[0], replacement)
}
}
}

View File

@ -2002,7 +2002,7 @@ XRegExp.exec = function (str, regex, pos, sticky) {
*/
XRegExp.forEach = async function (str, regex, callback) {
XRegExp.forEach = function (str, regex, callback) {
var pos = 0;
var i = -1;
var match;
@ -2014,7 +2014,7 @@ XRegExp.forEach = async function (str, regex, callback) {
// at least. Actually, because of the way `XRegExp.exec` caches globalized versions of
// regexes, mutating the regex will not have any effect on the iteration or matched strings,
// which is a nice side effect that brings extra safety.
await callback(match, ++i, str, regex);
callback(match, ++i, str, regex);
pos = match.index + (match[0].length || 1);
}
};

View File

@ -1,7 +1,6 @@
import { Misc } from "./misc.js";
import { SYSTEM_RDD, SYSTEM_SOCKET_ID } from "./constants.js";
import { RdDTimestamp } from "./time/rdd-timestamp.js";
import { RdDTextEditor } from "./apps/rdd-text-roll-editor.js";
/**
@ -199,7 +198,6 @@ export class ChatUtility {
static async onCreateChatMessage(chatMessage, options, id) {
if (chatMessage.isAuthor) {
await chatMessage.setFlag(SYSTEM_RDD, 'rdd-timestamp', game.system.rdd.calendrier.getTimestamp());
await chatMessage.update({ content: await RdDTextEditor.enrichHTML(chatMessage.content, undefined, {showLink:false}) })
}
}
}

View File

@ -1,5 +1,6 @@
import { RdDBaseActor } from "../actor/base-actor.js";
import { ChatUtility } from "../chat-utility.js";
import { ReglesOptionnelles } from "../settings/regles-optionnelles.js";
const INFO_COEUR = 'info-coeur';

View File

@ -1,13 +1,13 @@
export const SYSTEM_RDD = 'foundryvtt-reve-de-dragon'
export const SYSTEM_SOCKET_ID = 'system.foundryvtt-reve-de-dragon'
export const LOG_HEAD = 'RdD | '
export const SYSTEM_RDD = 'foundryvtt-reve-de-dragon';
export const SYSTEM_SOCKET_ID = 'system.foundryvtt-reve-de-dragon';
export const LOG_HEAD = 'RdD | ';
export const HIDE_DICE = 'hide'
export const SHOW_DICE = 'show'
export const HIDE_DICE = 'hide';
export const SHOW_DICE = 'show';
export const ENTITE_INCARNE = 'incarne'
export const ENTITE_NONINCARNE = 'nonincarne'
export const ENTITE_BLURETTE = 'blurette'
export const ENTITE_INCARNE = 'incarne';
export const ENTITE_NONINCARNE = 'nonincarne';
export const ENTITE_BLURETTE = 'blurette';
export const RDD_CONFIG = {
niveauEthylisme : [
@ -51,58 +51,3 @@ export const RDD_CONFIG = {
{value: "Rarissime", label: "Rarissime"}
]
}
export const ACTOR_TYPES = {
personnage: 'personnage',
creature: 'creature',
entite: 'entite',
commerce: 'commerce',
vehicule: 'vehicule'
}
export const ITEM_TYPES = {
competence: 'competence',
competencecreature: 'competencecreature',
empoignade: 'empoignade',
possession: 'possession',
blessure: 'blessure',
maladie: 'maladie',
poison: 'poison',
arme: 'arme',
armure: 'armure',
conteneur: 'conteneur',
objet: 'objet',
monnaie: 'monnaie',
gemme: 'gemme',
munition: 'munition',
nourritureboisson: 'nourritureboisson',
herbe: 'herbe',
plante: 'plante',
ingredient: 'ingredient',
faune: 'faune',
livre: 'livre',
potion: 'potion',
service: 'service',
musique: 'musique',
danse: 'danse',
chant: 'chant',
jeu: 'jeu',
race: 'race',
recettecuisine: 'recettecuisine',
oeuvre: 'oeuvre',
recettealchimique: 'recettealchimique',
tache: 'tache',
sort: 'sort',
sortreserve: 'sortreserve',
rencontre: 'rencontre',
queue: 'queue',
ombre: 'ombre',
souffle: 'souffle',
tete: 'tete',
casetmr: 'casetmr',
meditation: 'meditation',
signedraconique: 'signedraconique',
tarot: 'tarot',
nombreastral: 'nombreastral',
extraitpoetique: 'extraitpoetique',
}

View File

@ -1,7 +1,6 @@
import { Grammar } from "./grammar.js";
import { RdDItemCompetenceCreature } from "./item-competencecreature.js"
import { ITEM_TYPES } from "./constants.js";
import { BASE_CORPS_A_CORPS } from "./item/base-items.js";
import { ITEM_TYPES } from "./item.js";
import { RdDCombatManager } from "./rdd-combat.js";
const nomCategorieParade = {
@ -237,13 +236,13 @@ export class RdDItemArme extends Item {
}
static corpsACorps(actor) {
let competence = actor?.getCompetenceCorpsACorps() ?? BASE_CORPS_A_CORPS
let competence = actor?.getCompetenceCorpsACorps() ?? { system: { niveau: -6 } };
let melee = actor ? actor.system.carac['melee'].value : 0
return {
_id: competence.id,
_id: competence?.id,
name: 'Corps à corps',
type: ITEM_TYPES.arme,
img: competence.img,
img: 'systems/foundryvtt-reve-de-dragon/icons/competence_corps_a_corps.webp',
system: {
initiative: RdDCombatManager.calculInitiative(competence.system.niveau, melee),
equipe: true,

View File

@ -1,6 +1,5 @@
import { Grammar } from "./grammar.js";
import { RdDItem } from "./item.js";
import { SANS_COMPETENCE } from "./item/base-items.js";
import { Misc } from "./misc.js";
const competenceTroncs = [["Esquive", "Dague", "Corps à corps"],
@ -138,7 +137,7 @@ export class RdDItemCompetence extends Item {
/* -------------------------------------------- */
static computeEconomieXPTronc(competences) {
return competenceTroncs.map(
list => list.map(name => RdDItemCompetence.findCompetence(competences, name, { onMessage: message => { } }))
list => list.map(name => RdDItemCompetence.findCompetence(competences, name))
// calcul du coût xp jusqu'au niveau 0 maximum
.map(it => RdDItemCompetence.computeDeltaXP(it?.system.base ?? -11, Math.min(it?.system.niveau ?? -11, 0)))
.sort(Misc.ascending())
@ -204,12 +203,26 @@ export class RdDItemCompetence extends Item {
}
/* -------------------------------------------- */
static findCompetences(list, name, options = {}) {
options = foundry.utils.mergeObject(options, { preFilter: it => it.isCompetence(), description: 'compétence' }, { overwrite: false, inplace: false });
return Misc.findAllLike(name, list, options);
static findCompetences(list, name) {
return Misc.findAllLike(name, list, { filter: it => it.isCompetence(), description: 'compétence' });
}
static sansCompetence() { return SANS_COMPETENCE }
static sansCompetence() {
return {
name: "Sans compétence",
type: "competence",
img: "systems/foundryvtt-reve-de-dragon/icons/templates/icone_parchement_vierge.webp",
system: {
niveau: 0,
default_diffLibre: 0,
base: 0,
categorie: "Aucune",
description: "",
descriptionmj: "",
defaut_carac: "",
}
};
}
static findFirstItem(list, idOrName, options) {
return list.find(it => it.id == idOrName && options.preFilter(it))
@ -259,9 +272,8 @@ export class RdDItemCompetence extends Item {
/* -------------------------------------------- */
static triVisible(competences) {
return competences
? competences.filter(it => !it.system.isHidden).sort((a, b) => RdDItemCompetence.compare(a, b))
: []
return competences.filter(it => !it.system.isHidden)
.sort((a, b) => RdDItemCompetence.compare(a, b))
}
static $positionTri(comp) {

View File

@ -1,5 +1,5 @@
import { ITEM_TYPES } from "./constants.js";
import { ITEM_TYPES } from "./item.js";
import { RdDCombatManager } from "./rdd-combat.js";
export const CATEGORIES_COMPETENCES_CREATURES = {

View File

@ -1,5 +1,5 @@
import { Misc } from "./misc.js";
import { ITEM_TYPES, LOG_HEAD } from "./constants.js";
import { LOG_HEAD } from "./constants.js";
const MONNAIE_ETAIN = {
name: "Denier (étain)", type: 'monnaie',
@ -70,17 +70,18 @@ export class Monnaie {
}
static getFortune(monnaies) {
return (monnaies ?? [])
return (monnaies??[])
.map(m => Number(m.system.cout) * Number(m.system.quantite))
.reduce(Misc.sum(), 0);
}
static async optimiserFortune(actor, fortune) {
Monnaie.validerMonnaies(actor)
let resteEnDeniers = Math.round(fortune * 100);
const updates = []
let monnaies = actor.itemTypes['monnaie'];
let updates = [];
Monnaie.validerMonnaies(monnaies, actor);
const parValeur = Misc.classifyFirst(actor.itemTypes[ITEM_TYPES.monnaie], it => VALEUR_DENIERS(it.system.cout));
let parValeur = Misc.classifyFirst(monnaies, it => VALEUR_DENIERS(it.system.cout));
for (let valeurDeniers of [1000, 100, 10, 1]) {
const itemPiece = parValeur[valeurDeniers];
if (itemPiece) {
@ -101,11 +102,8 @@ export class Monnaie {
}
}
static validerMonnaies(actor) {
if (!actor) {
return
}
actor.itemTypes[ITEM_TYPES.monnaie]?.filter(it => VALEUR_DENIERS(it.system.cout) == 0)
static validerMonnaies(monnaies, actor = undefined) {
monnaies.filter(it => VALEUR_DENIERS(it.system.cout) == 0)
.map(it => `La monnaie ${it.name} de l'acteur ${actor?.name ?? 'sélectionné'} a une valeur de 0!`)
.forEach(message => {
ui.notifications.warn(message);

View File

@ -1,7 +1,8 @@
import { ACTOR_TYPES, ITEM_TYPES } from "./constants.js";
import { RdDItemSort } from "./item-sort.js";
import { RdDUtility } from "./rdd-utility.js";
import { RdDAlchimie } from "./rdd-alchimie.js";
import { RdDItemCompetence } from "./item-competence.js";
import { RdDHerbes } from "./rdd-herbes.js";
import { RdDGemme } from "./rdd-gemme.js";
import { HtmlUtility } from "./html-utility.js";
import { ReglesOptionnelles } from "./settings/regles-optionnelles.js";
@ -11,10 +12,8 @@ import { SystemCompendiums } from "./settings/system-compendiums.js";
import { Misc } from "./misc.js";
import { RdDTimestamp } from "./time/rdd-timestamp.js";
import { RdDItemCompetenceCreature } from "./item-competencecreature.js";
import { RdDItem } from "./item.js";
import { ITEM_TYPES, RdDItem } from "./item.js";
import { FLEUVE_COORD, TMRUtility } from "./tmr-utility.js";
import { RdDTextEditor } from "./apps/rdd-text-roll-editor.js";
import { ItemAction } from "./item/item-actions.js";
/**
* Extend the basic ItemSheet for RdD specific items
@ -27,8 +26,8 @@ export class RdDItemSheet extends ItemSheet {
static defaultTemplate(type) {
return type ?
`systems/foundryvtt-reve-de-dragon/templates/item/${type}-sheet.hbs` :
"systems/foundryvtt-reve-de-dragon/templates/item/item-sheet.hbs";
`systems/foundryvtt-reve-de-dragon/templates/item-${type}-sheet.html` :
"systems/foundryvtt-reve-de-dragon/templates/item-sheet.html";
}
static register(sheetClass) {
@ -98,11 +97,11 @@ export class RdDItemSheet extends ItemSheet {
name: this.item.name,
system: this.item.system,
actorId: this.actor?.id,
description: await RdDTextEditor.enrichHTML(this.item.system.description, this.item),
descriptionmj: await RdDTextEditor.enrichHTML(this.item.system.descriptionmj, this.item),
description: await TextEditor.enrichHTML(this.item.system.description, { async: true }),
descriptionmj: await TextEditor.enrichHTML(this.item.system.descriptionmj, { async: true }),
isComestible: this.item.getUtilisationCuisine(),
options: RdDSheetUtility.mergeDocumentRights(this.options, this.item, this.isEditable),
competences: await SystemCompendiums.getCompetences(ACTOR_TYPES.personnage),
competences: await SystemCompendiums.getCompetences('personnage'),
categories: RdDItem.getCategories(this.item.type),
}
@ -121,23 +120,26 @@ export class RdDItemSheet extends ItemSheet {
formData.competences = formData.competences.filter(it => it.isCompetenceArme())
}
if (this.item.type == ITEM_TYPES.recettecuisine) {
formData.ingredients = await RdDTextEditor.enrichHTML(this.item.system.ingredients, this.item)
formData.ingredients = await TextEditor.enrichHTML(this.object.system.ingredients, { async: true })
}
if (this.item.type == ITEM_TYPES.extraitpoetique) {
formData.extrait = await RdDTextEditor.enrichHTML(this.item.system.extrait, this.item)
formData.texte = await RdDTextEditor.enrichHTML(this.item.system.texte, this.item)
formData.extrait = await TextEditor.enrichHTML(this.object.system.extrait, { async: true })
formData.texte = await TextEditor.enrichHTML(this.object.system.texte, { async: true })
}
if (this.item.type == ITEM_TYPES.recettealchimique) {
formData.manipulation = await RdDTextEditor.enrichHTML(this.item.system.manipulation, this.item)
formData.utilisation = await RdDTextEditor.enrichHTML(this.item.system.utilisation, this.item)
formData.enchantement = await RdDTextEditor.enrichHTML(this.item.system.enchantement, this.item)
formData.sureffet = await RdDTextEditor.enrichHTML(this.item.system.sureffet, this.item)
RdDAlchimie.processManipulation(this.item, this.actor?.id);
formData.manipulation_update = await TextEditor.enrichHTML(this.object.system.manipulation_update, { async: true })
formData.utilisation = await TextEditor.enrichHTML(this.object.system.utilisation, { async: true })
formData.enchantement = await TextEditor.enrichHTML(this.object.system.enchantement, { async: true })
formData.sureffet = await TextEditor.enrichHTML(this.object.system.sureffet, { async: true })
}
if (this.item.type == ITEM_TYPES.gemme) {
formData.gemmeTypeList = RdDGemme.getGemmeTypeOptionList();
RdDGemme.calculDataDerivees(this.item)
}
if (this.item.type == ITEM_TYPES.potion) {
RdDHerbes.calculFormData(formData, this.item)
}
if (this.item.type == ITEM_TYPES.herbe) {
if (formData.options.isOwned && ['Soin', 'Repos'].includes(formData.system.categorie)) {
formData.isIngredientPotionBase = true;
@ -192,22 +194,38 @@ export class RdDItemSheet extends ItemSheet {
this.supprimerBonusCase(event.currentTarget.attributes['data-deleteCoord'].value)
})
this.html.find('.date-enchantement').change((event) => {
const jour = Number(this.html.find('input.date-enchantement[name="enchantement.jour"]').val());
const mois = RdDTimestamp.definition(this.html.find('select.date-enchantement[name="enchantement.mois"]').val());
const indexDate = game.system.rdd.calendrier.getIndexFromDate(jour, mois.heure);
this.item.update({ 'system.prdate': indexDate });
console.warn(`Date d'enchantement modifiée ${jour}/${mois.heure}: ${indexDate}`)
});
this.html.find('.creer-tache-livre').click((event) => this._getEventActor(event).creerTacheDepuisLivre(this.item));
this.html.find('.consommer-potion').click((event) => this._getEventActor(event).consommerPotion(this.item, this.getActionRenderItem()));
this.html.find('.creer-potion-base').click((event) => this._getEventActor(event).actionHerbe(this.item));
this.html.find('input[name="system.cacher_points_de_tache"]').change(async event => await this.item.update({ 'system.cacher_points_de_tache': event.currentTarget.checked }));
this.html.find('.roll-text').click(async event => await RdDTextEditor.rollText(event, this.actor))
this.html.find('.chat-roll-text').click(async event => await RdDTextEditor.chatRollText(event))
this.html.find('.alchimie-tache a').click((event) => {
let actor = this._getEventActor(event);
if (actor) {
let recetteId = event.currentTarget.attributes['data-recette-id'].value;
let tacheName = event.currentTarget.attributes['data-alchimie-tache'].value;
let tacheData = event.currentTarget.attributes['data-alchimie-data'].value;
actor.effectuerTacheAlchimie(recetteId, tacheName, tacheData);
} else {
ui.notifications.info("Impossible trouver un acteur pour réaliser cette tache Alchimique.");
}
});
if (this.actor) {
// TODO
this.html.find('.actionItem').click(event => ItemAction.onActionItem(event, this.actor, this.options))
this.html.find('.item-potion-consommer').click(event => this.itemActionConsommer(event))
this.html.find('.item-split').click( event => this.itemActionSplit(event))
this.html.find('.item-split').click(async event => RdDSheetUtility.splitItem(RdDSheetUtility.getItem(event, this.actor), this.actor, this.getActionRenderItem()));
this.html.find('.item-edit').click(async event => RdDSheetUtility.getItem(event, this.actor)?.sheet.render(true));
this.html.find('.item-delete').click(async event => this.itemActionDelete(event));
this.html.find('.item-delete').click(async event => RdDUtility.confirmActorItemDelete(this, RdDSheetUtility.getItem(event, this.actor)));
this.html.find('.item-vendre').click(async event => RdDSheetUtility.getItem(event, this.actor)?.proposerVente());
this.html.find('.item-montrer').click(async event => RdDSheetUtility.getItem(event, this.actor)?.postItemToChat());
this.html.find('.item-action').click(async event => RdDSheetUtility.getItem(event, this.actor)?.actionPrincipale(this.actor, this.getActionRenderItem()));
this.html.find('.item-quantite-plus').click(async event => {
await this.actor.itemQuantiteIncDec(RdDSheetUtility.getItemId(event), 1)
@ -225,24 +243,13 @@ export class RdDItemSheet extends ItemSheet {
RdDTimestamp.handleTimestampEditor(this.html, 'system.temporel.fin', updateItemTimestamp);
}
itemActionDelete(event) {
const item = RdDSheetUtility.getItem(event, this.actor)
return RdDUtility.confirmActorItemDelete(item, this.actor)
}
async itemActionConsommer(event) {
const item = RdDSheetUtility.getItem(event, this.actor)
if (item) {
await actor.consommerPotion(item)
await RdDSheetUtility.renderItemBranch(this.actor, item)
}
}
async itemActionSplit(event) {
const item = RdDSheetUtility.getItem(event, this.actor)
if (item) {
await RdDSheetUtility.splitItem(item, this.actor)
await RdDSheetUtility.renderItemBranch(this.actor, item)
getActionRenderItem() {
return async () => {
let item = this.item;
while (item) {
await item.sheet?.render()
item = this.actor.getContenant(item)
}
}
}
@ -265,7 +272,7 @@ export class RdDItemSheet extends ItemSheet {
}
}
async supprimerBonusCase(deleteCoord) {
async supprimerBonusCase(deleteCoord){
if (this.item.type == ITEM_TYPES.sort) {
const oldList = RdDItemSort.getBonusCaseList(this.item)
const newList = oldList.filter(it => it.case != deleteCoord);

View File

@ -1,6 +1,6 @@
import { Grammar } from "./grammar.js";
import { RdDItemCompetence } from "./item-competence.js";
import { ITEM_TYPES } from "./constants.js";
import { ITEM_TYPES } from "./item.js";
import { Misc } from "./misc.js";
import { FLEUVE_COORD, TMRUtility } from "./tmr-utility.js";

View File

@ -1,15 +1,67 @@
import { ITEM_TYPES } from "./constants.js";
import { DialogItemVente } from "./achat-vente/dialog-item-vente.js";
import { Grammar } from "./grammar.js";
import { Misc } from "./misc.js";
import { RdDHerbes } from "./rdd-herbes.js";
import { RdDTimestamp } from "./time/rdd-timestamp.js";
import { RdDUtility } from "./rdd-utility.js";
import { SystemCompendiums } from "./settings/system-compendiums.js";
import { RdDRaretes } from "./item/raretes.js";
import { CATEGORIES_COMPETENCES } from "./item-competence.js";
import { CATEGORIES_COMPETENCES_CREATURES } from "./item-competencecreature.js";
import { BASE_CORPS_A_CORPS, BASE_ESQUIVE } from "./item/base-items.js";
import { ITEM_ACTIONS, DEFAULT_ACTIONS, COMMON_ACTIONS } from "./item/item-actions.js";
export const ACTOR_TYPES = {
personnage: 'personnage',
creature: 'creature',
entite: 'entite',
commerce: 'commerce',
vehicule: 'vehicule'
}
export const ITEM_TYPES = {
competence: 'competence',
competencecreature: 'competencecreature',
empoignade: 'empoignade',
possession: 'possession',
blessure: 'blessure',
maladie: 'maladie',
poison: 'poison',
arme: 'arme',
armure: 'armure',
conteneur: 'conteneur',
objet: 'objet',
monnaie: 'monnaie',
gemme: 'gemme',
munition: 'munition',
nourritureboisson: 'nourritureboisson',
herbe: 'herbe',
plante: 'plante',
ingredient: 'ingredient',
faune: 'faune',
livre: 'livre',
potion: 'potion',
service: 'service',
musique: 'musique',
danse: 'danse',
chant: 'chant',
jeu: 'jeu',
recettecuisine: 'recettecuisine',
oeuvre: 'oeuvre',
recettealchimique: 'recettealchimique',
tache: 'tache',
sort: 'sort',
sortreserve: 'sortreserve',
rencontre: 'rencontre',
queue: 'queue',
ombre: 'ombre',
souffle: 'souffle',
tete: 'tete',
casetmr: 'casetmr',
meditation: 'meditation',
signedraconique: 'signedraconique',
tarot: 'tarot',
nombreastral: 'nombreastral',
extraitpoetique: 'extraitpoetique',
}
const typesInventaireMateriel = [
ITEM_TYPES.arme,
@ -46,41 +98,41 @@ densité 3.5 (~2.3 à 4, parfois plus) -- https://www.juwelo.fr/guide-des-pierre
*/
export const defaultItemImg = {
arme: "systems/foundryvtt-reve-de-dragon/icons/armes_armures/epee_gnome.webp",
armure: "systems/foundryvtt-reve-de-dragon/icons/armes_armures/armure_plaques.webp",
chant: "systems/foundryvtt-reve-de-dragon/icons/arts/chant_0.webp",
competence: "systems/foundryvtt-reve-de-dragon/icons/competence_defaut.webp",
competencecreature: "systems/foundryvtt-reve-de-dragon/icons/competence_defaut.webp",
arme: "systems/foundryvtt-reve-de-dragon/icons/armes_armures/epee_gnome.webp",
armure: "systems/foundryvtt-reve-de-dragon/icons/armes_armures/armure_plaques.webp",
conteneur: "systems/foundryvtt-reve-de-dragon/icons/objets/sac_a_dos.webp",
danse: "systems/foundryvtt-reve-de-dragon/icons/arts/danse_0.webp",
empoignade: "systems/foundryvtt-reve-de-dragon/icons/empoignade.webp",
extraitpoetique: "systems/foundryvtt-reve-de-dragon/icons/competence_ecriture.webp",
faune: "systems/foundryvtt-reve-de-dragon/icons/faune/rongeur.webp",
gemme: "systems/foundryvtt-reve-de-dragon/icons/gemmes/almaze.webp",
sort: "systems/foundryvtt-reve-de-dragon/icons/competence_oniros.webp",
herbe: "systems/foundryvtt-reve-de-dragon/icons/botanique/Endorlotte.webp",
faune: "systems/foundryvtt-reve-de-dragon/icons/faune/rongeur.webp",
ingredient: "systems/foundryvtt-reve-de-dragon/icons/objets/sable_poudre.webp",
jeu: "systems/foundryvtt-reve-de-dragon/icons/arts/jeux_petasse.webp",
livre: "systems/foundryvtt-reve-de-dragon/icons/objets/livre.webp",
maladie: "systems/foundryvtt-reve-de-dragon/icons/maladies_venins/maladie.webp",
meditation: "systems/foundryvtt-reve-de-dragon/icons/meditations_ecrits/meditation_alchimie.webp",
musique: "systems/foundryvtt-reve-de-dragon/icons/arts/chant_0.webp",
nourritureboisson: "systems/foundryvtt-reve-de-dragon/icons/objets/provision_crue.webp",
oeuvre: "systems/foundryvtt-reve-de-dragon/icons/competence_comedie.webp",
ombre: "systems/foundryvtt-reve-de-dragon/icons/queue_dragon.webp",
poison: "systems/foundryvtt-reve-de-dragon/icons/maladies_venins/venin.webp",
possession: "systems/foundryvtt-reve-de-dragon/icons/entites/possession2.webp",
potion: "systems/foundryvtt-reve-de-dragon/icons/objets/liqueur_de_bagdol.webp",
queue: "systems/foundryvtt-reve-de-dragon/icons/queue_dragon.webp",
recettealchimique: "systems/foundryvtt-reve-de-dragon/icons/competence_alchimie.webp",
recettecuisine: "systems/foundryvtt-reve-de-dragon/icons/arts/recette_cuisine_1.webp",
rencontre: "systems/foundryvtt-reve-de-dragon/icons/tete_dragon.webp",
queue: "systems/foundryvtt-reve-de-dragon/icons/queue_dragon.webp",
ombre: "systems/foundryvtt-reve-de-dragon/icons/queue_dragon.webp",
souffle: "systems/foundryvtt-reve-de-dragon/icons/souffle_dragon.webp",
tete: "systems/foundryvtt-reve-de-dragon/icons/tete_dragon.webp",
meditation: "systems/foundryvtt-reve-de-dragon/icons/meditations_ecrits/meditation_alchimie.webp",
recettealchimique: "systems/foundryvtt-reve-de-dragon/icons/competence_alchimie.webp",
chant: "systems/foundryvtt-reve-de-dragon/icons/arts/chant_0.webp",
danse: "systems/foundryvtt-reve-de-dragon/icons/arts/danse_0.webp",
jeu: "systems/foundryvtt-reve-de-dragon/icons/arts/jeux_petasse.webp",
recettecuisine: "systems/foundryvtt-reve-de-dragon/icons/arts/recette_cuisine_1.webp",
musique: "systems/foundryvtt-reve-de-dragon/icons/arts/chant_0.webp",
maladie: "systems/foundryvtt-reve-de-dragon/icons/maladies_venins/maladie.webp",
poison: "systems/foundryvtt-reve-de-dragon/icons/maladies_venins/venin.webp",
oeuvre: "systems/foundryvtt-reve-de-dragon/icons/competence_comedie.webp",
nourritureboisson: "systems/foundryvtt-reve-de-dragon/icons/objets/provision_crue.webp",
service: "systems/foundryvtt-reve-de-dragon/icons/services/lit.webp",
signedraconique: "systems/foundryvtt-reve-de-dragon/icons/tmr/signe_draconique.webp",
sort: "systems/foundryvtt-reve-de-dragon/icons/competence_oniros.webp",
gemme: "systems/foundryvtt-reve-de-dragon/icons/gemmes/almaze.webp",
possession: "systems/foundryvtt-reve-de-dragon/icons/entites/possession2.webp",
sortreserve: "systems/foundryvtt-reve-de-dragon/icons/competence_oniros.webp",
souffle: "systems/foundryvtt-reve-de-dragon/icons/souffle_dragon.webp",
extraitpoetique: "systems/foundryvtt-reve-de-dragon/icons/competence_ecriture.webp",
tarot: "systems/foundryvtt-reve-de-dragon/icons/tarots/dos-tarot.webp",
tete: "systems/foundryvtt-reve-de-dragon/icons/tete_dragon.webp",
empoignade: "systems/foundryvtt-reve-de-dragon/icons/competence_corps_a_corps.webp"
}
/* -------------------------------------------- */
@ -192,13 +244,13 @@ export class RdDItem extends Item {
isEsquive() {
return (this.isCompetence()
&& this.system.categorie == 'melee'
&& Grammar.includesLowerCaseNoAccent(this.name, BASE_ESQUIVE.name));
&& Grammar.includesLowerCaseNoAccent(this.name, 'Esquive'));
}
isCorpsACorps() {
return this.isCompetence()
&& this.system.categorie == 'melee'
&& Grammar.includesLowerCaseNoAccent(this.name, BASE_CORPS_A_CORPS.name)
&& Grammar.includesLowerCaseNoAccent(this.name, 'Corps à Corps')
}
isCompetenceArme() {
@ -302,6 +354,13 @@ export class RdDItem extends Item {
getUtilisation() {
switch (this.type) {
case ITEM_TYPES.potion:
switch (this.system.categorie) {
case 'Alchimie': case 'AlchimieEnchante': case 'AlchimieAutre': return 'alchimie'
case 'Cuisine': return 'cuisine'
case 'Remede': case 'Repos': case 'ReposEnchante': case 'Soin': case 'SoinEnchante': return 'soins'
}
return '';
case ITEM_TYPES.nourritureboisson: return 'cuisine';
case ITEM_TYPES.herbe: case ITEM_TYPES.faune: case ITEM_TYPES.ingredient: case ITEM_TYPES.plante:
switch (this.system.categorie) {
@ -410,51 +469,68 @@ export class RdDItem extends Item {
// appliquer le pourcentage
return this.parent.calculerPrix(this);
}
return this.system.cout
return this.system.cout;
}
prepareDerivedData() {
super.prepareDerivedData();
if (this.isInventaire()) {
this.system.encTotal = this.getEncTotal()
this.system.encTotal = this.getEncTotal();
if (this.isPotion()) {
this.prepareDataPotion()
}
this.system.actionPrincipale = this.getActionPrincipale({ warnIfNot: false });
}
this.equipable = this.isEquipable()
this.equipable = this.isEquipable();
}
itemActions() {
return COMMON_ACTIONS.concat(this.itemSpecificActions()).concat(DEFAULT_ACTIONS)
prepareDataPotion() {
const categorie = Grammar.toLowerCaseNoAccent(this.system.categorie);
this.system.magique = categorie.includes('enchante');
if (this.system.magique) {
if (categorie.includes('soin') || categorie.includes('repos')) {
// TODO: utiliser calculPointsRepos / calculPointsGuerison
this.system.puissance = RdDHerbes.calculPuissancePotion(this);
}
}
}
itemSpecificActions() {
const actions = ITEM_ACTIONS[this.type] ?? []
// const actorTypes = actions.actorTypes ?? [ACTOR_TYPES.personnage]
// if (!actorTypes.includes(this.actor?.type)) {
// return []
// }
return actions
}
isActionAllowed(code) {
getActionPrincipale(options = { warnIfNot: true }) {
switch (this.type) {
case ITEM_TYPES.possession:
case ITEM_TYPES.empoignade:
case ITEM_TYPES.rencontre:
case ITEM_TYPES.signedraconique:
switch (code) {
case 'item-edit':
case 'item-delete':
return game.user.isGM
}
case ITEM_TYPES.maladie:
case ITEM_TYPES.poison:
return game.user.isGM
case ITEM_TYPES.casetmr:
switch (code) {
case 'item-delete':
return game.user.isGM
}
case ITEM_TYPES.conteneur: return 'Ouvrir';
}
if (this.actor?.isPersonnage()) {
const warn = options.warnIfNot;
if (this.getUtilisationCuisine() == 'brut') {
return 'Cuisiner';
}
switch (this.type) {
case ITEM_TYPES.nourritureboisson: return this._actionOrWarnQuantiteZero(this.system.boisson ? 'Boire' : 'Manger', warn);
case ITEM_TYPES.potion: return this._actionOrWarnQuantiteZero('Consommer', warn);
case ITEM_TYPES.livre: return this._actionOrWarnQuantiteZero('Lire', warn);
case ITEM_TYPES.herbe: return this.isHerbeAPotion() ? this._actionOrWarnQuantiteZero('Décoction', warn) : undefined;
case ITEM_TYPES.queue: case ITEM_TYPES.ombre: return this.system.refoulement > 0 ? 'Refouler' : undefined;
}
}
return undefined;
}
/* -------------------------------------------- */
async actionPrincipale(actor, onActionItem = async () => { }) {
if (!this.getActionPrincipale()) { return }
await actor?.actionPrincipale(this, onActionItem);
}
_actionOrWarnQuantiteZero(actionName, warn) {
if ((this.system.quantite ?? 0) <= 0) {
if (warn) {
ui.notifications.warn(`Vous n'avez plus de ${this.name}.`);
}
return undefined;
}
else {
return actionName;
}
return true
}
async diminuerQuantite(nombre, options = { diminuerQuantite: true, supprimerSiZero: false }) {
@ -526,7 +602,7 @@ export class RdDItem extends Item {
if (!other || !this.isInventaire()) {
return [false, undefined];
}
if (this.isConteneur()) {
if (this.isConteneur()){
return [false, `Impossible de regrouper des conteneurs, ils ne sont pas empilables`];
}
if (this.system.quantite == undefined) {
@ -727,6 +803,14 @@ export class RdDItem extends Item {
]
}
/* -------------------------------------------- */
_potionChatData() {
return [
`<b>Rareté</b>: ${this.system.rarete}`,
`<b>Catégorie</b>: ${this.system.categorie}`,
...this._inventaireTemplateChatData()
]
}
/* -------------------------------------------- */
_queueChatData() {
function label(categorie) {
switch (categorie) {

View File

@ -1,17 +1,14 @@
import { ITEM_TYPES } from "../constants.js";
import { RdDItem } from "../item.js";
import { Misc } from "../misc.js";
import { ReglesOptionnelles } from "../settings/regles-optionnelles.js";
export class RdDItemArmure extends RdDItem {
static get ITEM_TYPE() { return ITEM_TYPES.armure }
static get defaultIcon() {
return "systems/foundryvtt-reve-de-dragon/icons/armes_armures/armure_plaques.webp";
}
async deteriorerArmure(dmg) {
deteriorerArmure(dmg) {
if (!ReglesOptionnelles.isUsing('deteriorationArmure') || this.system.protection == '0') {
return;
}
@ -23,10 +20,12 @@ export class RdDItemArmure extends RdDItem {
protection = this.calculProtectionDeterioree();
ChatMessage.create({ content: `Votre armure ${this.name} s'est détériorée, elle protège maintenant de ${protection}` });
}
await this.update({
'system.deterioration': deterioration,
'system.protection': protection
})
this.update({
system: {
deterioration: deterioration,
protection: protection
}
});
}
calculProtectionDeterioree() {

View File

@ -1,20 +0,0 @@
export const POSSESSION_SANS_DRACONIC = { name: 'Sans draconic', type: 'competence', system: { niveau: 0, defaut_carac: "reve-actuel", }, img: 'systems/foundryvtt-reve-de-dragon/icons/entites/possession.webp' }
export const PAS_DE_DRACONIC = { name: 'Pas de draconic', type: 'competence', system: { niveau: -11, defaut_carac: "reve" }, img: 'systems/foundryvtt-reve-de-dragon/icons/entites/possession.webp' }
export const BASE_CORPS_A_CORPS = { name: 'Corps à Corps', type: 'competence', system: { niveau: -6, defaut_carac: "melee" }, img: 'systems/foundryvtt-reve-de-dragon/icons/competence_corps_a_corps.webp' }
export const BASE_ESQUIVE = { name: 'Esquive', type: 'competence', system: { niveau: -6, defaut_carac: "derobee" }, img: 'systems/foundryvtt-reve-de-dragon/icons/competence_esquive.webp' }
export const SANS_COMPETENCE = {
name: "Sans compétence",
type: 'competence',
system: {
niveau: 0,
default_diffLibre: 0,
base: 0,
categorie: "Aucune",
description: "",
descriptionmj: "",
defaut_carac: "",
},
img: "systems/foundryvtt-reve-de-dragon/icons/templates/icone_parchement_vierge.webp"
}

View File

@ -30,7 +30,7 @@ export class RdDItemBlessure extends RdDItem {
prepareDerivedData() {
super.prepareDerivedData();
this.system.label = RdDItemBlessure.getLabelGravite(this.system.gravite)
this.system.label = this.getLabelGravite()
}
static prepareTacheSoin(gravite) {
@ -43,32 +43,29 @@ export class RdDItemBlessure extends RdDItem {
}
static async applyFullBlessure(actor, gravite) {
const definition = foundry.utils.duplicate(RdDItemBlessure.getDefinition(gravite))
const definition = RdDItemBlessure.getDefinition(gravite)
let lostEndurance = 0
let lostVie = 0
if (definition.endurance) {
lostEndurance = new Roll(definition.endurance)
await lostEndurance.roll();
actor.santeIncDec("endurance", -Number(lostEndurance.total));
}
if (definition.vie) {
await actor.santeIncDec("vie", definition.vie)
}
const lostEndurance = await RdDItemBlessure.rollLostEndurance(definition.endurance)
if (lostEndurance) {
await actor.santeIncDec("endurance", -Number(lostEndurance));
lostVie = definition.vie
actor.santeIncDec("vie", definition.vie)
}
await this.createBlessure(actor, gravite)
ChatMessage.create({
//TODO: hbs
content: `Blessure ${definition.label} appliquée à ${actor.name}<br>Perte d'endurance : ${lostEndurance} (${definition.endurance})<br>Perte de Vie : ${definition.vie}`,
content: `Blessure ${definition.label} appliquée à ${actor.name}`+
`<br>Perte d'endurance : ${lostEndurance}`+
`<br>Perte de Vie : ${lostVie}`,
whisper: ChatUtility.getOwners(actor)
});
actor.sheet?.render()
}
static async rollLostEndurance(formula) {
if (formula) {
const roll = new Roll(formula)
await roll.evaluate()
return roll.total
}
return 0
}
static async createBlessure(actor, gravite, localisation = '', attackerToken) {
@ -128,10 +125,10 @@ export class RdDItemBlessure extends RdDItem {
}
if (this.system.gravite > 0) {
const update = { system: { premierssoins: { bonus: 0 }, soinscomplets: { bonus: 0 } } }
const gravite = this.system.gravite
const graviteMoindre = gravite - 2
const gravite = this.system.gravite;
const graviteMoindre = gravite - 2;
const moindres = blessures.filter(it => it.system.gravite == graviteMoindre, 'blessures').length
const label = RdDItemBlessure.getLabelGravite(this.system.gravite)
const label = this.getLabelGravite();
let rolled = await actor.jetRecuperationConstitution(this.system.soinscomplets.bonus, message);
@ -161,11 +158,11 @@ export class RdDItemBlessure extends RdDItem {
}
peutRetrograder(graviteMoindre, moindres) {
return moindres < RdDItemBlessure.maxBlessures(graviteMoindre)
return moindres < RdDItemBlessure.getDefinition(graviteMoindre).max
}
async calculerFinPeriodeTemporel(debut) {
return debut.nouveauJour().addJours(this.system.gravite);
return await debut.nouveauJour().addJours(this.system.gravite);
}
async onFinPeriode(oldTimestamp, newTimestamp) {
@ -185,16 +182,16 @@ export class RdDItemBlessure extends RdDItem {
return `systems/foundryvtt-reve-de-dragon/icons/sante/${soins ? 'blessure-soins' : img}.webp`
}
static getLabelGravite(gravite) {
return definitionsBlessures.find(it => it.gravite >= gravite).label
getLabelGravite() {
return RdDItemBlessure.getDefinition(this.system.gravite).label
}
static getDefinition(gravite) {
return definitionsBlessures.find(it => it.gravite >= gravite)
return definitionsBlessures.sort(Misc.ascending(it => it.gravite))
.find(it => it.gravite >= gravite);
}
static maxBlessures(gravite) {
return definitionsBlessures.find(it => it.gravite >= gravite).max
return RdDItemBlessure.getDefinition(gravite).max
}
isContusion() {
@ -219,7 +216,7 @@ export class RdDItemBlessure extends RdDItem {
`<b>Heure et Date</b>: ${new RdDTimestamp(this.system.temporel.debut).formatDateHeure()}`,
RdDItem.propertyIfDefined('Blessé', this.parent?.name, this.parent),
`<b>Localisation</b>: ${this.system.localisation}`,
`<b>Gravité</b>: ${this.system.label}`,
`<b>Gravité</b>: ${RdDItemBlessure.getDefinition(this.system.gravite).label}`,
`<b>Difficulté des soins</b>: ${this.system.difficulte}`,
(this.system.soinscomplets.done ?
`<b>Bonus soins complets</b>: ${this.system.soinscomplets.bonus}` :

View File

@ -1,154 +0,0 @@
import { Misc } from "../misc.js"
import { RdDSheetUtility } from "../rdd-sheet-utility.js"
import { RdDUtility } from "../rdd-utility.js"
/**
* TODO:
* options.editable ?
*
*/
const _SPACEHOLDER = { placeholder: true }
const _VENDRE = {
code: 'item-vendre', label: 'Vendre ou donner', icon: it => 'fa-solid fa-comments-dollar',
filter: it => Misc.toInt(it.system.quantite) > 0,
optionsFilter: options => options.editable,
action: (item, actor) => item.proposerVente()
}
const _ACHAT_SERVICE = {
code: 'item-service-acheter', label: 'Acheter', icon: it => 'fa-regular fa-coins',
//filter: it => Misc.toInt(it.system.quantite) > 0,
//optionsFilter: options => options.editable,
//action: (item, actor) => item.proposerVente()
}
const _MONTRER = {
code: 'item-montrer', label: 'Montrer', icon: it => 'fa-solid fa-comment',
action: (item, actor) => item.postItemToChat()
}
const _EDIT = {
code: 'item-edit', label: 'Editer', icon: it => 'fa-solid fa-edit',
action: (item, actor) => item.sheet.render(true)
}
const _DELETE = {
code: 'item-delete', label: 'Supprimer', icon: it => 'fa-solid fa-trash',
optionsFilter: options => options.editable && options.isOwner,
action: (item, actor) => RdDUtility.confirmActorItemDelete(item, actor)
}
const _EQUIPER = {
code: 'item-equip', label: 'Equiper', icon: it => it.system.equipe ? 'fa-solid fa-hand-rock' : 'fa-regular fa-hand-paper',
filter: it => !it.estContenu && it.isEquipable(),
action: (item, actor) => actor.equiperObjet(item)
}
const _CUISINER = {
code: 'item-cuisiner', label: 'Cuisiner', icon: it => 'fa-solid fa-utensils',
filter: it => it.getUtilisation() == 'cuisine' && it.system.sust > 0,
optionsFilter: options => options.editable,
action: (item, actor) => actor.preparerNourriture(item)
}
const _MANGER_CRU = {
code: 'item-manger-cru', label: 'Manger cru', icon: it => 'fa-solid fa-drumstick-bite',
filter: it => it.getUtilisation() == 'cuisine' && it.system.sust > 0,
optionsFilter: options => options.editable,
action: (item, actor) => actor.mangerNourriture(item)
}
const _MANGER = {
code: 'item-manger', label: 'Manger', icon: it => 'fa-solid fa-utensils',
filter: it => !(it.system.boisson),
optionsFilter: options => options.editable,
action: (item, actor) => actor.mangerNourriture(item)
}
const _BOIRE = {
code: 'item-boire', label: 'Boire', icon: it => 'fa-solid fa-glass-water',
filter: it => it.system.boisson,
optionsFilter: options => options.editable,
action: (item, actor) => actor.mangerNourriture(item)
}
const _DECOCTION = {
code: 'item-decoction', label: 'Décoction', icon: it => 'fa-solid fa-flask-vial',
optionsFilter: options => options.editable,
action: (item, actor) => actor.actionHerbe(item)
}
const _OUVRIR = {
code: 'item-edit', label: 'Ouvrir', icon: it => 'fa-solid fa-eye',
action: (item, actor) => item.sheet.render(true)
}
const _LIRE = {
code: 'item-lire', label: 'Lire', icon: it => 'fa-solid fa-book-open',
optionsFilter: options => options.editable,
action: (item, actor) => actor.actionLire(item)
}
const _REFOULER = {
code: 'item-refouler', label: 'Refouler', icon: it => 'fa-solid fa-burst',
filter: it => it.system.refoulement > 0,
optionsFilter: options => options.editable,
action: (item, actor) => actor.actionRefoulement(item)
}
const _CONSOMMER_POTION = {
code: 'item-potion-consommer', label: 'Consommer', icon: it => 'fa-solid fa-vial',
optionsFilter: options => options.editable,
action: (item, actor) => actor.consommerPotion(item)
}
const _ENCHANTER = {
code: 'item-enchanter', label: 'Enchanter', icon: it => 'fa-solid fa-sparkles',
filter: it => it.isEnchantable(),
optionsFilter: options => options.editable,
action: (item, actor) => item.enchanterPotion()
}
const _SORT_RESERVE = {
code: 'item-sortreserve-add', label: 'Ajouter en réserve', icon: it => 'fa-solid fa-sparkles',
filter: it => game.user.isGM && !it.system.isrituel,
action: (item, actor) => actor.addSortReserve(item)
}
export const COMMON_ACTIONS = [_EQUIPER]
export const DEFAULT_ACTIONS = [_SPACEHOLDER, _VENDRE, _MONTRER, _EDIT, _DELETE]
export const ITEM_ACTIONS = {
faune: [_CUISINER, _MANGER_CRU],
ingredient: [_CUISINER, _MANGER_CRU],
conteneur: [_OUVRIR],
herbe: [_DECOCTION, _CUISINER, _MANGER_CRU],
livre: [_LIRE],
nourritureboisson: [_MANGER, _BOIRE],
ombre: [_REFOULER],
plante: [_CUISINER, _MANGER_CRU],
potion: [_CONSOMMER_POTION, _ENCHANTER],
queue: [_REFOULER],
sort: [_SORT_RESERVE],
service: [_ACHAT_SERVICE]
}
export class ItemAction {
static applies(action, item, options) {
return action
&& item.isActionAllowed(action.code)
&& (!action.filter || action.filter(item))
&& (!action.optionsFilter || action.optionsFilter(options))
}
static icon(action, item) {
if (action && action.icon) {
return action.icon(item)
}
return undefined
}
static onActionItem(event, actor, options) {
const item = RdDSheetUtility.getItem(event, actor)
const code = $(event.currentTarget).data('code')
const action = item.itemActions().find(it => it.code == code)
if (action && (!action.optionsFilter || action.optionsFilter(options))) {
action.action(item, actor)
}
}
}

View File

@ -10,7 +10,7 @@ export class RdDItemMaladie extends RdDItem {
}
async calculerFinPeriodeTemporel(debut) {
return debut.addPeriode(this.system.periode.nombre, this.system.periode.unite);
return await debut.addPeriode(this.system.periode.nombre, this.system.periode.unite);
}
async onFinPeriode(oldTimestamp, newTimestamp) {

View File

@ -1,8 +1,11 @@
import { RdDItemQueue } from "./queue.js";
export class RdDItemOmbre extends RdDItemQueue {
import { RdDItem } from "../item.js";
export class RdDItemOmbre extends RdDItem {
static get defaultIcon() {
return "systems/foundryvtt-reve-de-dragon/icons/queue_dragon.webp";
}
async calculerFinPeriodeTemporel(debut) {
return await debut.appliquerDuree(this.system.duree, this.parent);
}
}

View File

@ -8,7 +8,7 @@ export class RdDItemPoison extends RdDItem {
}
async calculerFinPeriodeTemporel(debut) {
return debut.addPeriode(this.system.periode.nombre, this.system.periode.unite) ;
return await debut.addPeriode(this.system.periode.nombre, this.system.periode.unite) ;
}
async onFinPeriode(oldTimestamp, newTimestamp) {

View File

@ -1,154 +0,0 @@
import { ITEM_TYPES } from "../constants.js";
import { Grammar } from "../grammar.js";
import { RdDItem } from "../item.js";
import { SystemCompendiums } from "../settings/system-compendiums.js";
import { ITEM_ACTIONS } from "./item-actions.js";
import { DialogEnchanter } from "./potion/dialog-enchanter.js";
const POTION_MAGIQUE = ['AlchimieEnchante', 'ReposEnchante', 'SoinEnchante', 'AutreEnchante']
const POTION_ENCHANTABLE = ['Alchimie', 'Repos', 'Soin', 'Autre']
.concat(POTION_MAGIQUE)
const MAP_CATEGORIE_ENCHANTEMENT = [
{ basique: 'Alchimie', enchante: 'AlchimieEnchante' },
{ basique: 'Repos', enchante: 'ReposEnchante' },
{ basique: 'Soin', enchante: 'SoinEnchante' },
{ basique: 'Autre', enchante: 'AutreEnchante' }]
export class RdDItemPotion extends RdDItem {
static async herbesSoins() {
return await RdDItemPotion.$listHerbes(it => Grammar.equalsInsensitive(it.system.categorie, 'Soin') && it.system.niveau > 0)
}
static async herbesRepos() {
return await RdDItemPotion.$listHerbes(it => Grammar.equalsInsensitive(it.system.categorie, 'Repos') && it.system.niveau > 0)
}
static async $listHerbes(filter) {
const herbes = await SystemCompendiums.getWorldOrCompendiumItems('herbe', 'faune-flore-mineraux');
return herbes.filter(filter)
}
static get defaultIcon() {
return "systems/foundryvtt-reve-de-dragon/icons/objets/liqueur_de_bagdol.webp"
}
prepareDerivedData() {
super.prepareDerivedData()
this.system.puissance = this.system.magique ? this.calculPuissance() : 0
}
isPotion() { return true }
isEnchantable() { return POTION_ENCHANTABLE.includes(this.system.categorie) }
isMagique() { return POTION_MAGIQUE.includes(this.system.categorie) }
itemSpecificActions() {
return ITEM_ACTIONS[ITEM_TYPES.potion]
}
getActions(options = { warnIfNot: true }) {
const actionConsommer = this.prepareAction('Consommer', options.warnIfNot);
if (this.isEnchantable()) {
return [
actionConsommer,
this.prepareAction('Enchanter', options.warnIfNot)
]
}
return [
actionConsommer
]
}
// TDOD: purifier?
getUtilisation() {
switch (this.system.categorie) {
case 'Alchimie': case 'AlchimieEnchante':
case 'AlchimieAutre':
return 'alchimie'
case 'Cuisine': return 'cuisine'
case 'Remede': case 'Repos': case 'ReposEnchante': case 'Soin': case 'SoinEnchante':
return 'soins'
}
return ''
}
_potionChatData() {
return [
`<b>Rareté</b>: ${this.system.rarete}`,
`<b>Catégorie</b>: ${this.system.categorie}`,
...this._inventaireTemplateChatData()
]
}
async enchanterPotion() {
const actor = this.parent;
if (actor && (!actor.isPersonnage() || !actor.isHautRevant())) {
ui.notifications.info('Seul un haut rêvant peut enchanter une potion')
return
}
const dailog = await DialogEnchanter.create(this, actor, (updates) => this.$onEnchanterPotion(updates));
dailog.render(true)
}
perteRevePotion() {
if (this.system.magique && !this.system.prpermanent && this.system.pr > 0) {
const nouveauReve = Math.max(this.system.pr - 1, 0)
return {
_id: this.id,
name: this.name,
img: this.img,
'system.pr': nouveauReve,
'system.quantite': nouveauReve > 0 ? this.system.quantite : 0,
'system.magique': nouveauReve > 0
}
}
return undefined
}
async $onEnchanterPotion(enchanter) {
if (enchanter.nouveaupr == 0) {
await this.update({
'system.pr': 0,
'system.purifie': false,
'system.magique': false,
'system.categorie': this.categorieEnchantement().basique,
'system.prpermanent': false,
'system.prdate': 0,
'system.quantite': this.parent ? 0 : this.system.quantite
})
}
else {
await this.update({
'system.pr': enchanter.nouveaupr,
'system.purifie': enchanter.purifier,
'system.magique': true,
'system.categorie': this.categorieEnchantement().enchante,
'system.prpermanent': enchanter.prpermanent,
'system.prdate': RdDItemPotion.dateEnchantement()
})
}
this.sheet?.render(true)
}
calculPuissance() { return this.system.herbebonus * this.system.pr }
categorieEnchantement() {
const categorie = this.system.categorie
const categorieEnchantement = MAP_CATEGORIE_ENCHANTEMENT.find(it => [it.basique, it.enchante].includes(categorie))
return categorieEnchantement ?? { basique: categorie, enchante: categorie }
}
static dateEnchantement() {
return game.system.rdd.calendrier.getTimestamp().debutJournee().indexDate
}
static buildHerbesList(listeHerbes, max) {
let list = {}
for (let herbe of listeHerbes) {
let brins = max - herbe.system.niveau;
list[herbe.name] = `${herbe.name} (Bonus: ${herbe.system.niveau}, Brins: ${brins})`;
}
list['Autre'] = 'Autre (Bonus: variable, Brins: variable)'
return list;
}
}

View File

@ -1,46 +0,0 @@
export class DialogEnchanter extends Dialog {
static async create(item, actor, callback) {
const enchanter = {
actor: actor,
item: item,
nouveaupr: item.system.pr,
prpermanent: item.system.prpermanent,
purifier: false
}
const html = await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/item/potion/dialog-enchanter.hbs`, enchanter)
return new DialogEnchanter(enchanter, html, callback)
}
constructor(enchanter, html, callback) {
let options = { classes: ["dialog-enchanter"], width: 400, height: 'fit-content', 'z-index': 99999 }
let conf = {
title: "Enchanter une potion",
content: html,
default: "enchanter",
buttons: {
"enchanter": { label: "Enchanter", callback: it => this.onEnchanter() }
}
};
super(conf, options)
this.callback = callback
this.enchanter = enchanter
}
activateListeners(html) {
super.activateListeners(html)
this.html = html
this.html.find("input.nouveaupr").change(event => this.enchanter.nouveaupr = Number(event.currentTarget.value))
this.html.find("input.purifier").change(event => this.enchanter.purifier = event.currentTarget.checked)
this.html.find("input.prpermanent").change(event => this.enchanter.prpermanent = event.currentTarget.checked)
}
async onEnchanter() {
await this.html.find(".nouveaupr").change()
this.callback(this.enchanter);
}
}

View File

@ -6,9 +6,8 @@ export class RdDItemQueue extends RdDItem {
return "systems/foundryvtt-reve-de-dragon/icons/queue_dragon.webp";
}
async calculerFinPeriodeTemporel(timestamp) {
// décaller le début pour calcul correct si la queue dure 12h
const debut = timestamp.addMinutes(timestamp.indexMinute == 0 ? -1 : 0);
async calculerFinPeriodeTemporel(debut) {
return await debut.appliquerDuree(this.system.duree, this.parent);
}
}

View File

@ -1,101 +0,0 @@
import { ITEM_TYPES } from "../constants.js";
import { RdDItem } from "../item.js";
import { Misc } from "../misc.js";
import { LIST_CARAC_PERSONNAGE, RdDCarac } from "../rdd-carac.js";
export class RdDItemRace extends RdDItem {
static get ITEM_TYPE() { return ITEM_TYPES.race }
static get defaultIcon() {
return "systems/foundryvtt-reve-de-dragon/icons/humanoides/humain.webp";
}
static checkRacialMax(actor, code, value) {
const race = RdDItemRace.getRace(actor)
if (code == LIST_CARAC_PERSONNAGE.force.code) {
if (!race.isForceValid(actor, value)) {
ui.notifications.warn(race.system.carac.force.limitmessage)
return false
}
}
const carac = RdDCarac.carac(code)
if (race.isMax(actor, code, value - 1)) {
ui.notifications.warn(`${value} est supérieure au maximum de ${carac.label}`)
return false
}
return true
}
static applyRacialLimits(actor) {
const race = RdDItemRace.getRace(actor)
actor.system.carac.taille.value = race.getValidTaille(actor.getTaille())
actor.system.carac.force.value = Math.min(
actor.getForce(),
race.getForceMax(actor))
}
static isRacialMax(actor, code, value = undefined) {
return RdDItemRace.getRace(actor).isMax(actor, code, value)
}
static getRace(actor) {
return actor.itemTypes[ITEM_TYPES.race].find(it => true) ?? RdDItemRace.getFallbackRace()
}
static getFallbackRace() {
if (RdDItemRace.fallback == undefined) {
RdDItemRace.fallback = new RdDItemRace({ name: 'Humain', type: RdDItemRace.ITEM_TYPE })
}
return RdDItemRace.fallback
}
isMax(actor, code, value = undefined) {
const path = RdDCarac.carac(code)?.path
if (value == undefined) {
value = path ? foundry.utils.getProperty(actor, path) : 0
}
if (code == LIST_CARAC_PERSONNAGE.force.code) {
return value >= this.getForceMax(actor)
}
const max = foundry.utils.getProperty(this, path) ?? -1
return (max > 0 && value >= max)
}
getValidTaille(taille) {
const min = Math.max(this.system.carac.taille.min, 0)
if (min > taille) {
ui.notifications.warn("La Taille est inférieur au minimum racial")
return min
}
const raceMax = this.system.carac.taille.max;
const max = raceMax < 0 ? taille + 1 : raceMax
if (max < taille) {
ui.notifications.warn("La Taille est supérieure au maximum racial")
return max
}
return taille
}
isForceValid(actor, value) {
return value <= this.getForceMax(actor)
}
getForceMax(actor) {
const terms = this.system.carac.force.limit.replaceAll(' ', '').split('+')
return terms.map(
it => {
const term = Number.parseInt(it)
if (Number.isInteger(term)) {
return term
}
const path = RdDCarac.carac(it)?.path
if (path) {
return foundry.utils.getProperty(actor, path)
}
return 0
}
).reduce(Misc.sum());
}
}

View File

@ -74,7 +74,7 @@ export class RdDRencontre extends RdDItem {
}
async calculerFinPeriodeTemporel(debut) {
return debut.nouvelleHeure().addHeures(12);
return await debut.nouvelleHeure().addHeures(12);
}
}

View File

@ -1,12 +1,11 @@
import { RdDBaseActorSheet } from "../actor/base-actor-sheet.js";
import { ITEM_TYPES } from "../constants.js";
import { RdDSheetUtility } from "../rdd-sheet-utility.js";
import { RdDUtility } from "../rdd-utility.js";
import { RdDItemInventaireSheet } from "./sheet-base-inventaire.js";
export class RdDConteneurItemSheet extends RdDItemInventaireSheet {
static get ITEM_TYPE() { return ITEM_TYPES.conteneur };
static get ITEM_TYPE() { return "conteneur" };
async getData() {
const formData = await super.getData();
@ -29,10 +28,9 @@ export class RdDConteneurItemSheet extends RdDItemInventaireSheet {
/* -------------------------------------------- */
prepareConteneurData(formData) {
RdDUtility.filterItemsPerTypeForSheet(formData, this.actor.itemTypes);
RdDBaseActorSheet.filterItemsPerTypeForSheet(formData, this.actor.itemTypes);
this.objetVersConteneur = RdDUtility.buildArbreDeConteneurs(formData.conteneurs, formData.inventaires);
const subItems = formData.conteneurs.find(it => it._id == this.item.id)?.subItems;
formData.subItems = subItems
formData.subItems = formData.conteneurs.find(it => it._id == this.item.id)?.subItems;
}
async _onDragStart(event) {

View File

@ -1,58 +0,0 @@
import { ITEM_TYPES } from "../constants.js";
import { RdDTimestamp } from "../time/rdd-timestamp.js";
import { RdDItemPotion } from "./potion.js";
import { RdDItemInventaireSheet } from "./sheet-base-inventaire.js";
export class RdDPotionItemSheet extends RdDItemInventaireSheet {
static get ITEM_TYPE() { return ITEM_TYPES.potion };
static $calculBonusHerbe(formData, herbesList, max) {
if (Number(formData.system.herbebrins)) {
let herbe = herbesList.find(h => h.name.toLowerCase() == formData.system.herbe.toLowerCase());
if (herbe) {
const brinsRequis = max - herbe.system.niveau;
const brinsManquants = Math.max(brinsRequis - formData.system.herbebrins, 0);
formData.system.herbebonus = Math.max(herbe.system.niveau - brinsManquants, 0);
}
}
}
get potion(){ return this.item }
async getData() {
const formData = await super.getData()
formData.enchantable = this.potion.isEnchantable()
const enchantement = this.potion.categorieEnchantement()
formData.isSoins = enchantement.basique == 'Soin'
formData.isRepos = enchantement.basique == 'Repos'
if (formData.isSoins) {
const herbesSoins = await RdDItemPotion.herbesSoins()
RdDPotionItemSheet.$calculBonusHerbe(formData, herbesSoins, 12);
formData.herbesSoins = RdDItemPotion.buildHerbesList(herbesSoins, 12)
}
if (formData.isRepos) {
const herbesRepos = await RdDItemPotion.herbesRepos()
RdDPotionItemSheet.$calculBonusHerbe(formData, herbesRepos, 7);
formData.herbesRepos = RdDItemPotion.buildHerbesList(herbesRepos, 7)
}
formData.dateActuelle = game.system.rdd.calendrier.dateCourante()
formData.enchantement = RdDTimestamp.splitIndexDate(this.potion.system.prdate)
return formData
}
activateListeners(html) {
super.activateListeners(html);
this.html.find('.item-enchanter').click((event) => this.potion.enchanterPotion())
this.html.find('.date-enchantement').change((event) => {
const jour = Number(this.html.find('input.date-enchantement[name="enchantement.jour"]').val())
const mois = RdDTimestamp.definition(this.html.find('select.date-enchantement[name="enchantement.mois"]').val())
const indexDate = game.system.rdd.calendrier.getIndexFromDate(jour, mois.heure)
this.potion.update({ 'system.prdate': indexDate })
console.warn(`Date d'enchantement modifiée ${jour}/${mois.heure}: ${indexDate}`)
});
}
}

View File

@ -106,7 +106,7 @@ export class RdDItemSigneDraconique extends RdDItem {
}
static async randomSigneDescription() {
return await RdDRollTables.drawTextFromRollTable("Signes draconiques", {toChat:false});
return await RdDRollTables.drawTextFromRollTable("Signes draconiques", false);
}
}

View File

@ -1,6 +1,5 @@
import { ITEM_TYPES } from "../constants.js";
import { RdDItem } from "../item.js";
import { Grammar } from "../grammar.js"
import { ITEM_TYPES, RdDItem } from "../item.js"
import { SystemCompendiums } from "../settings/system-compendiums.js"
const DON_HAUT_REVE = "Don de Haut-Rêve"

View File

@ -1,29 +0,0 @@
import { RdDTextEditor } from "../apps/rdd-text-roll-editor.js";
import { SYSTEM_RDD } from "../constants.js";
import { Misc } from "../misc.js";
export class RdDJournalSheet extends JournalTextPageSheet {
static register() {
DocumentSheetConfig.unregisterSheet(JournalEntryPage, "core", JournalTextPageSheet)
DocumentSheetConfig.registerSheet(JournalEntryPage,
SYSTEM_RDD,
RdDJournalSheet, {
types: ["text"],
makeDefault: true,
});
}
async getData(options) {
const journalData = await super.getData(options);
journalData.editor.content = await RdDTextEditor.enrichHTML(journalData.document.text.content, this.object)
return journalData
}
activateListeners(html) {
super.activateListeners(html);
html.find('.roll-text').click(async event => await RdDTextEditor.rollText(event, this.actor))
html.find('.chat-roll-text').click(async event => await RdDTextEditor.chatRollText(event))
}
}

View File

@ -2,12 +2,10 @@ import { RdDBaseActor } from "./actor/base-actor.js";
import { LOG_HEAD, SYSTEM_RDD } from "./constants.js";
import { Grammar } from "./grammar.js";
import { Monnaie } from "./item-monnaie.js";
import { ITEM_TYPES, ACTOR_TYPES } from "./constants.js";
import { RdDItem } from "./item.js";
import { RdDItem, ITEM_TYPES } from "./item.js";
import { RdDTimestamp } from "./time/rdd-timestamp.js";
import { RdDRaretes } from "./item/raretes.js";
import { VOIES_DRACONIC } from "./item-sort.js";
import { SystemCompendiums } from "./settings/system-compendiums.js";
class Migration {
get code() { return "sample"; }
@ -568,27 +566,6 @@ class _12_0_26_MigrationVoieSorts extends Migration {
}
}
class _12_0_32_MigrationRaces extends Migration {
get code() { return "migration-races" }
get version() { return "12.0.32" }
async migrate() {
const races = await SystemCompendiums.getItems("races", ITEM_TYPES.race)
await game.actors.filter(it => it.type == ACTOR_TYPES.personnage).forEach(async actor => {
if (actor.itemTypes[ITEM_TYPES.race].length == 0) {
const raceName = actor.system.race ?? 'Humain'
const race = races.find(it => Grammar.equalsInsensitive(raceName, it.name))
if (race) {
console.log(this.code, `Adding race ${race.name} to actor ${actor.name}`)
actor.createEmbeddedDocuments('Item', [race])
console.log(this.code, `Neutralizing race ${race.name} adjustments for actor ${actor.name}`)
actor._applyRaceCaracUpdates(race, -1)
}
}
})
}
}
export class Migrations {
static getMigrations() {
return [
@ -608,8 +585,7 @@ export class Migrations {
new _10_7_19_CategorieCompetenceCreature(),
new _10_7_19_PossessionsEntiteVictime(),
new _11_2_20_MigrationAstrologie(),
new _12_0_26_MigrationVoieSorts(),
new _12_0_32_MigrationRaces(),
new _12_0_26_MigrationVoieSorts()
];
}

View File

@ -1,12 +1,5 @@
import { Grammar } from "./grammar.js";
const DEFAULT_FIND_OPTIONS = {
mapper: it => it.name,
preFilter: it => true,
description: 'valeur',
onMessage: m => ui.notifications.info(m)
}
/**
* This class is intended as a placeholder for utility methods unrelated
* to actual classes of the game system or of FoundryVTT
@ -204,7 +197,7 @@ export class Misc {
}
static isFirstOwnerPlayer(document) {
if (!document.testUserPermission) {
if (!document.testUserPermission){
return false
}
return game.users.find(u => document.testUserPermission(u, CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER)) == game.user
@ -217,10 +210,6 @@ export class Misc {
return game.user == Misc.firstConnectedGM();
}
static hasConnectedGM() {
return Misc.firstConnectedGM();
}
static firstConnectedGMId() {
return Misc.firstConnectedGM()?.id;
}
@ -237,7 +226,13 @@ export class Misc {
/* -------------------------------------------- */
static findFirstLike(value, elements, options = {}) {
options = foundry.utils.mergeObject(DEFAULT_FIND_OPTIONS, options, { overwrite: true, inplace: false });
options = foundry.utils.mergeObject({
mapper: it => it.name,
preFilter: it => true,
description: 'valeur',
onMessage: m => ui.notifications.info(m)
}, options);
const subset = this.findAllLike(value, elements, options);
if (subset.length == 0) {
console.log(`Aucune ${options.description} pour ${value}`);
@ -256,7 +251,13 @@ export class Misc {
}
static findAllLike(value, elements, options = {}) {
options = foundry.utils.mergeObject(DEFAULT_FIND_OPTIONS, options, { overwrite: true, inplace: false });
options = foundry.utils.mergeObject({
mapper: it => it.name,
preFilter: it => true,
description: 'valeur',
onMessage: m => ui.notifications.info(m)
}, options);
if (!value) {
options.onMessage(`Pas de ${options.description} correspondant à une valeur vide`);
return [];

View File

@ -1,8 +1,48 @@
/* -------------------------------------------- */
import { Misc } from "./misc.js";
const matchOperations = new RegExp(/@(\w*){([\w\-]+)}/ig);
const matchOperationTerms = new RegExp(/@(\w*){([\w\-]+)}/i);
/* -------------------------------------------- */
export class RdDAlchimie {
static getDifficulte(termes) {
let elements = termes.split('-');
/* -------------------------------------------- */
static processManipulation(recette, actorId = undefined) {
let manip = recette.system.manipulation;
let matchArray = manip.match(matchOperations);
if (matchArray) {
for (let matchStr of matchArray) {
let result = matchStr.match(matchOperationTerms);
if (result[1] && result[2]) {
let commande = Misc.upperFirst(result[1]);
let replacement = this[`_alchimie${commande}`](recette, result[2], actorId);
manip = manip.replace(result[0], replacement);
}
}
}
recette.system.manipulation_update = manip;
}
/* -------------------------------------------- */
static _alchimieCouleur(recette, couleurs, actorId) {
return RdDAlchimie._alchimieLink(recette, couleurs, actorId, 'couleur', 'Température');
}
/* -------------------------------------------- */
static _alchimieConsistance(recette, consistances, actorId) {
return RdDAlchimie._alchimieLink(recette, consistances, actorId, 'consistance', 'Consistance');
}
static _alchimieLink(recette, termes, actorId, tacheAlchimie, labelTache) {
const difficulte = RdDAlchimie.getDifficulte(termes);
const link = actorId ? ` <a data-recette-id="${recette._id}" data-actor-id="${actorId}" data-alchimie-tache="${tacheAlchimie}" data-alchimie-data="${termes}">` : '';
const endLink = actorId ? '</a>' : '';
return `<span class="alchimie-tache">${link}${labelTache} ${termes} (${difficulte})${endLink}</span>`;
}
/* -------------------------------------------- */
static getDifficulte(aspects) {
let elements = aspects.split('-');
let composantes = elements.length;
let distincts = Object.keys(Misc.classifyFirst(elements, it => it)).length;
if (distincts == 1) {
@ -18,4 +58,5 @@ export class RdDAlchimie {
}
return 'intellect';
}
}

View File

@ -3,98 +3,42 @@ 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, poids: "moins de 1kg", poidsMin: 0, poidsMax: 1, plusdom: -5, sconst: 0.5, sust: 0.1 },
2: { xp: 3, poids: "1-5", poidsMin: 1, poidsMax: 5, plusdom: -4, sconst: 0.5, sust: 0.3 },
3: { xp: 4, poids: "6-10", poidsMin: 6, poidsMax: 10, plusdom: -3, sconst: 1, sust: 0.5, beaute: 'hideux' },
4: { xp: 4, poids: "11-20", poidsMin: 11, poidsMax: 20, plusdom: -3, sconst: 1, sust: 1, beaute: 'repoussant' },
5: { xp: 5, poids: "21-30", poidsMin: 21, poidsMax: 30, plusdom: -2, sconst: 1, sust: 1, beaute: 'franchement très laid' },
6: { xp: 5, poids: "31-40", poidsMin: 31, poidsMax: 40, plusdom: -1, sconst: 2, sust: 2, beaute: 'laid' },
7: { xp: 6, poids: "41-50", poidsMin: 41, poidsMax: 50, plusdom: -1, sconst: 2, sust: 2, beaute: 'très désavantagé' },
8: { xp: 6, poids: "51-60", poidsMin: 51, poidsMax: 60, plusdom: 0, sconst: 2, sust: 2, beaute: 'désavantagé' },
9: { xp: 7, poids: "61-65", poidsMin: 61, poidsMax: 65, plusdom: 0, sconst: 3, sust: 2, beaute: 'pas terrible' },
10: { xp: 7, poids: "66-70", poidsMin: 66, poidsMax: 70, plusdom: 0, sconst: 3, sust: 3, beaute: 'commun' },
11: { xp: 8, poids: "71-75", poidsMin: 71, poidsMax: 75, plusdom: 0, sconst: 3, sust: 3, beaute: 'pas mal' },
12: { xp: 8, poids: "76-80", poidsMin: 76, poidsMax: 80, plusdom: +1, sconst: 4, sust: 3, beaute: 'avantagé' },
13: { xp: 9, poids: "81-90", poidsMin: 81, poidsMax: 90, plusdom: +1, sconst: 4, sust: 3, beaute: 'mignon' },
14: { xp: 9, poids: "91-100", poidsMin: 91, poidsMax: 100, plusdom: +2, sconst: 4, sust: 4, beaute: 'beau' },
15: { xp: 10, poids: "101-110", poidsMin: 101, poidsMax: 110, plusdom: +2, sconst: 5, sust: 4, beaute: 'très beau' },
16: { xp: 20, poids: "111-120", poidsMin: 111, poidsMax: 120, plusdom: +3, sconst: 5, sust: 4, beaute: 'éblouissant' },
17: { xp: 30, poids: "121-131", poidsMin: 121, poidsMax: 131, plusdom: +3, sconst: 5, sust: 5 },
18: { xp: 40, poids: "131-141", poidsMin: 131, poidsMax: 141, plusdom: +4, sconst: 6, sust: 5 },
19: { xp: 50, poids: "141-150", poidsMin: 141, poidsMax: 150, plusdom: +4, sconst: 6, sust: 5 },
20: { xp: 60, poids: "151-160", poidsMin: 151, poidsMax: 160, plusdom: +4, sconst: 6, sust: 6 },
21: { xp: 70, poids: "161-180", poidsMin: 161, poidsMax: 180, plusdom: +5, sconst: 7, sust: 6 },
22: { xp: 80, poids: "181-200", poidsMin: 181, poidsMax: 200, plusdom: +5, sconst: 7, sust: 7 },
23: { xp: 90, poids: "201-300", poidsMin: 201, poidsMax: 300, plusdom: +6, sconst: 7, sust: 8 },
24: { xp: 100, poids: "301-400", poidsMin: 301, poidsMax: 400, plusdom: +6, sconst: 8, sust: 9 },
25: { xp: 110, poids: "401-500", poidsMin: 401, poidsMax: 500, plusdom: +7, sconst: 8, sust: 10 },
26: { xp: 120, poids: "501-600", poidsMin: 501, poidsMax: 600, plusdom: +7, sconst: 8, sust: 11 },
27: { xp: 130, poids: "601-700", poidsMin: 601, poidsMax: 700, plusdom: +8, sconst: 9, sust: 12 },
28: { xp: 140, poids: "701-800", poidsMin: 701, poidsMax: 800, plusdom: +8, sconst: 9, sust: 13 },
29: { xp: 150, poids: "801-900", poidsMin: 801, poidsMax: 900, plusdom: +9, sconst: 9, sust: 14 },
30: { xp: 160, poids: "901-1000", poidsMin: 901, poidsMax: 1000, plusdom: +9, sconst: 10, sust: 15 },
31: { xp: 170, poids: "1001-1500", poidsMin: 1001, poidsMax: 1500, plusdom: +10, sconst: 10, sust: 16 },
32: { xp: 180, poids: "1501-2000", poidsMin: 1501, poidsMax: 2000, plusdom: +11, sconst: 10, sust: 17 }
};
export const LIST_CARAC_PERSONNAGE = {
'taille': { code: 'taille', label: 'Taille', isCarac: true, path: 'system.carac.taille.value' },
'apparence': { code: 'apparence', label: 'Apparence', isCarac: true, path: 'system.carac.apparence.value' },
'constitution': { code: 'constitution', label: 'Constitution', isCarac: true, path: 'system.carac.constitution.value' },
'force': { code: 'force', label: 'Force', isCarac: true, path: 'system.carac.force.value' },
'agilite': { code: 'agilite', label: 'Agilité', isCarac: true, path: 'system.carac.agilite.value' },
'dexterite': { code: 'dexterite', label: 'Dextérité', isCarac: true, path: 'system.carac.dexterite.value' },
'vue': { code: 'vue', label: 'Vue', isCarac: true, path: 'system.carac.vue.value' },
'ouie': { code: 'ouie', label: 'Ouïe', isCarac: true, path: 'system.carac.ouie.value' },
'odoratgout': { code: 'odoratgout', label: 'Odorat-Goût', isCarac: true, path: 'system.carac.odoratgout.value' },
'volonte': { code: 'volonte', label: 'Volonté', isCarac: true, path: 'system.carac.volonte.value' },
'intellect': { code: 'intellect', label: 'Intellect', isCarac: true, path: 'system.carac.intellect.value' },
'empathie': { code: 'empathie', label: 'Empathie', isCarac: true, path: 'system.carac.empathie.value' },
'reve': { code: 'reve', label: 'Rêve', isCarac: true, path: 'system.carac.reve.value' },
'chance': { code: 'chance', label: 'Chance', isCarac: true, path: 'system.carac.chance.value' },
'protection': { code: 'protection', label: 'Protection naturelle', isCarac: false, path: 'system.attributs.protection.value' },
'beaute': { code: 'beaute', label: 'Beauté', isCarac: false, path: 'system.background.beaute.value' }
}
export const LIST_CARAC_AUTRES = {
'perception': { code: 'perception', label: 'Perception', path: 'system.carac.perception.value' },
}
const LIST_CARAC_DERIVEE = {
'melee': { code: "melee", label: 'Mêlée', path: 'system.carac.melee.value' },
'tir': { code: "tir", label: 'Tir', path: 'system.carac.tir.value' },
'lancer': { code: "lancer", label: 'Lancer', path: 'system.carac.lancer.value' },
'derobee': { code: "derobee", label: 'Dérobée', path: 'system.carac.derobee.value' },
'chance-actuelle': { code: "chance-actuelle", label: 'Chance actuelle', path: 'system.carac.lancer.value' },
'reve-actuel': { code: "reve-actuel", label: 'Rêve actuel', path: 'system.reve.reve.value' },
}
const LIST_CARAC_ROLL = Object.values(LIST_CARAC_PERSONNAGE).filter(it => it.isCarac && it.code != 'taille')
.concat(Object.values(LIST_CARAC_AUTRES))
.concat(Object.values(LIST_CARAC_DERIVEE))
export class RdDCarac {
static caracDetails(name) {
let entry = Misc.findFirstLike(name, LIST_CARAC_ROLL, { mapper: it => it.code, description: 'caractéristique', onMessage: m => { } })
if (entry) {
return entry
}
return Misc.findFirstLike(name, LIST_CARAC_ROLL, { mapper: it => it.label, description: 'caractéristique' })
}
static carac(code) {
return LIST_CARAC_PERSONNAGE[code]
}
static label(code) {
return RdDCarac.carac(code)?.label ?? '---'
}
static caracs(filter = it => it.isCarac) {
return Object.values(LIST_CARAC_PERSONNAGE).filter(filter)
}
static isAgiliteOuDerobee(selectedCarac) {
return selectedCarac?.label.match(/(Agilité|Dérobée)/);
}

View File

@ -228,19 +228,16 @@ export class RdDCombatManager extends Combat {
static $prepareAttaqueArme(infoAttaque) {
const comp = infoAttaque.competences.find(it => Grammar.equalsInsensitive(it.name, infoAttaque.competence))
const arme = infoAttaque.arme;
const attaque = foundry.utils.duplicate(arme)
const carac = comp?.system.defaut_carac ?? (infoAttaque.infoMain == '(lancer)' ? 'lancer' : infoAttaque.infoMain == '(lancer)' ? 'tir' : 'melee')
const niveau = comp?.system.niveau ?? (infoAttaque.infoMain == '(lancer)' ? -8 : -6)
const attaque = foundry.utils.duplicate(arme);
attaque.action = 'attaque';
attaque.system.competence = infoAttaque.competence;
attaque.system.dommagesReels = infoAttaque.dommagesReel;
attaque.system.infoMain = infoAttaque.infoMain;
attaque.system.niveau = niveau
attaque.system.niveau = comp.system.niveau;
const ajustement = (arme.parent?.getEtatGeneral() ?? 0) + (arme.system.magique) ? arme.system.ecaille_efficacite : 0
attaque.system.initiative = RdDCombatManager.calculInitiative(niveau, infoAttaque.carac[carac].value, ajustement)
return attaque
const ajustement = (arme?.parent?.getEtatGeneral() ?? 0) + (arme?.system.magique) ? arme.system.ecaille_efficacite : 0;
attaque.system.initiative = RdDCombatManager.calculInitiative(comp.system.niveau, infoAttaque.carac[comp.system.defaut_carac].value, ajustement);
return attaque;
}
/* -------------------------------------------- */
@ -472,15 +469,15 @@ export class RdDCombat {
/* -------------------------------------------- */
static registerChatCallbacks(html) {
for (let button of [
'.parer-button',
'.esquiver-button',
'.particuliere-attaque',
'.encaisser-button',
'.appel-chance-defense',
'.appel-destinee-defense',
'.appel-chance-attaque',
'.appel-destinee-attaque',
'.echec-total-attaque',
'#parer-button',
'#esquiver-button',
'#particuliere-attaque',
'#encaisser-button',
'#appel-chance-defense',
'#appel-destinee-defense',
'#appel-chance-attaque',
'#appel-destinee-attaque',
'#echec-total-attaque',
]) {
html.on("click", button, event => {
const rddCombat = RdDCombat.rddCombatForAttackerAndDefender(
@ -539,22 +536,22 @@ export class RdDCombat {
const compId = event.currentTarget.attributes['data-compid']?.value;
switch (button) {
case '.particuliere-attaque': return await this.choixParticuliere(attackerRoll, event.currentTarget.attributes['data-mode'].value);
case '.parer-button': return this.parade(attackerRoll, armeParadeId);
case '.esquiver-button': return this.esquive(attackerRoll, compId, competence);
case '.encaisser-button': return this.encaisser(attackerRoll, defenderRoll);
case '.echec-total-attaque': return this._onEchecTotal(attackerRoll);
case '#particuliere-attaque': return await this.choixParticuliere(attackerRoll, event.currentTarget.attributes['data-mode'].value);
case '#parer-button': return this.parade(attackerRoll, armeParadeId);
case '#esquiver-button': return this.esquive(attackerRoll, compId, competence);
case '#encaisser-button': return this.encaisser(attackerRoll, defenderRoll);
case '#echec-total-attaque': return this._onEchecTotal(attackerRoll);
case '.appel-chance-attaque': return this.attacker.rollAppelChance(
case '#appel-chance-attaque': return this.attacker.rollAppelChance(
() => this.attaqueChanceuse(attackerRoll),
() => this._onEchecTotal(attackerRoll));
case '.appel-chance-defense': return this.defender.rollAppelChance(
case '#appel-chance-defense': return this.defender.rollAppelChance(
() => this.defenseChanceuse(attackerRoll, defenderRoll),
() => this.afficherOptionsDefense(attackerRoll, defenderRoll, { defenseChance: true }));
case '.appel-destinee-attaque': return this.attacker.appelDestinee(
case '#appel-destinee-attaque': return this.attacker.appelDestinee(
() => this.attaqueSignificative(attackerRoll),
() => { });
case '.appel-destinee-defense': return this.defender.appelDestinee(
case '#appel-destinee-defense': return this.defender.appelDestinee(
() => this.defenseDestinee(defenderRoll),
() => { });
}
@ -752,6 +749,7 @@ export class RdDCombat {
dialog.render(true);
}
/* -------------------------------------------- */
_prepareAttaque(competence, arme) {
let rollData = {
@ -967,6 +965,7 @@ export class RdDCombat {
async _onAttaqueEchec(rollData) {
console.log("RdDCombat.onAttaqueEchec >>>", rollData);
await RdDResolutionTable.displayRollData(rollData, this.attacker, 'chat-resultat-attaque.html');
}
/* -------------------------------------------- */

View File

@ -361,14 +361,13 @@ export class RdDCommands {
async getTMRAleatoire(msg, params) {
if (params.length < 2) {
let type = params[0]
const solvedTerrain = type ? TMRUtility.findTMRLike(type)?.type : undefined
const filter = solvedTerrain ? (it => it.type == solvedTerrain) : (it => true)
if (type == undefined || solvedTerrain != undefined) {
const tmr = await TMRUtility.getTMRAleatoire(filter)
const solvedTerrain = TMRUtility.findTMRLike(type)?.type
if (solvedTerrain){
const tmr = await TMRUtility.getTMRAleatoire(type ? (it => it.type == solvedTerrain) : (it => true))
return RdDCommands._chatAnswer(msg, `Case aléatoire: ${tmr.coord} - ${tmr.label}`)
}
}
return false
return false;
}
async findTMR(msg, params) {

View File

@ -4,7 +4,8 @@ import { RdDRoll } from "./rdd-roll.js";
import { RdDItemCompetenceCreature } from "./item-competencecreature.js";
import { ChatUtility } from "./chat-utility.js";
import { STATUSES } from "./settings/status-effects.js";
import { ITEM_TYPES } from "./constants.js";
import { ReglesOptionnelles } from "./settings/regles-optionnelles.js";
import { ITEM_TYPES } from "./item.js";
/* -------------------------------------------- */
@ -428,6 +429,7 @@ export class RdDEmpoignade {
return await Item.create({
name: "Empoignade en cours de " + attacker.name + ' sur ' + defender.name,
type: 'empoignade',
img: "systems/foundryvtt-reve-de-dragon/icons/entites/possession2.webp",
system: { description: "", empoignadeid: foundry.utils.randomID(16), compteempoigne: 0, empoigneurid: attacker.id, empoigneid: defender.id, ptsemp: 0, empoigneurname: attacker.name, empoignename: defender.name }
},
{

73
module/rdd-herbes.js Normal file
View File

@ -0,0 +1,73 @@
import { Grammar } from "./grammar.js";
import { SystemCompendiums } from "./settings/system-compendiums.js";
import { RdDTimestamp } from "./time/rdd-timestamp.js";
/* -------------------------------------------- */
export class RdDHerbes extends Item {
/* -------------------------------------------- */
static async onReady() {
this.herbesSoins = await RdDHerbes.listCategorieHerbes('Soin');
this.herbesRepos = await RdDHerbes.listCategorieHerbes('Repos');
}
static async listCategorieHerbes(categorie) {
const herbes = await SystemCompendiums.getWorldOrCompendiumItems('herbe', 'faune-flore-mineraux');
return herbes.filter(it => Grammar.equalsInsensitive(it.system.categorie, categorie));
}
/* -------------------------------------------- */
static buildHerbesList(listeHerbes, max) {
let list = {}
for (let herbe of listeHerbes) {
let brins = max - herbe.system.niveau;
list[herbe.name] = `${herbe.name} (Bonus: ${herbe.system.niveau}, Brins: ${brins})`;
}
list['Autre'] = 'Autre (Bonus: variable, Brins: variable)'
return list;
}
/* -------------------------------------------- */
static calculFormData(formData, item) {
formData.isSoins = item.system.categorie.includes('Soin');
formData.isRepos = item.system.categorie.includes('Repos');
if (formData.isSoins) {
RdDHerbes.calculBonusHerbe(formData, this.herbesSoins, 12);
}
if (formData.isRepos) {
RdDHerbes.calculBonusHerbe(formData, this.herbesRepos, 7);
}
formData.herbesSoins = RdDHerbes.buildHerbesList(this.herbesSoins, 12);
formData.herbesRepos = RdDHerbes.buildHerbesList(this.herbesRepos, 7);
formData.dateActuelle = game.system.rdd.calendrier.dateCourante();
formData.enchantement = RdDTimestamp.splitIndexDate(item.system.prdate);
}
/* -------------------------------------------- */
static calculPuissancePotion(potion) {
return potion.system.herbebonus * potion.system.pr;
}
/* -------------------------------------------- */
static calculPointsRepos(potion) {
return potion.system.herbebonus * potion.system.pr;
}
/* -------------------------------------------- */
static calculPointsGuerison(potion) {
return potion.system.herbebonus * potion.system.pr;
}
/* -------------------------------------------- */
static calculBonusHerbe(formData, herbesList, max) {
if (Number(formData.system.herbebrins)) {
let herbe = herbesList.find(item => item.name.toLowerCase() == formData.system.herbe.toLowerCase());
if (herbe) {
const brinsRequis = max - herbe.system.niveau;
const brinsManquants = Math.max(brinsRequis - formData.system.herbebrins, 0);
formData.system.herbebonus = Math.max(herbe.system.niveau - brinsManquants, 0);
}
}
}
}

View File

@ -1,6 +1,6 @@
import { RdDItemArme } from "./item-arme.js";
import { RdDItemCompetenceCreature } from "./item-competencecreature.js";
import { ITEM_TYPES } from "./constants.js";
import { ITEM_TYPES } from "./item.js";
export class RdDHotbar {

View File

@ -18,6 +18,7 @@ import { RdDCompendiumOrganiser } from "./rdd-compendium-organiser.js"
import { ReglesOptionnelles } from "./settings/regles-optionnelles.js"
import { RdDHotbar } from "./rdd-hotbar-drop.js"
import { EffetsDraconiques } from "./tmr/effets-draconiques.js"
import { RdDHerbes } from "./rdd-herbes.js"
import { RdDDice } from "./rdd-dice.js"
import { RdDPossession } from "./rdd-possession.js"
import { Misc } from "./misc.js"
@ -27,11 +28,9 @@ import { Environnement } from "./environnement.js"
import { RdDActor } from "./actor.js"
import { RdDBaseActor } from "./actor/base-actor.js"
import { RdDCreature } from "./actor/creature.js"
import { RdDCommerce } from "./actor/commerce.js"
import { RdDEntite } from "./actor/entite.js"
import { RdDVehicule } from "./actor/vehicule.js"
import { RdDActorSheet } from "./actor-sheet.js"
import { RdDCommerceSheet } from "./actor/commerce-sheet.js"
import { RdDCreatureSheet } from "./actor/creature-sheet.js"
@ -39,7 +38,6 @@ import { RdDActorEntiteSheet } from "./actor/entite-sheet.js"
import { RdDActorVehiculeSheet } from "./actor/vehicule-sheet.js"
import { RdDItem } from "./item.js"
import { RdDItemArmure } from "./item/armure.js"
import { RdDItemBlessure } from "./item/blessure.js"
import { RdDItemService } from "./item/service.js"
import { RdDItemMaladie } from "./item/maladie.js"
@ -47,11 +45,7 @@ import { RdDItemPoison } from "./item/poison.js"
import { RdDItemSigneDraconique } from "./item/signedraconique.js"
import { RdDItemQueue } from "./item/queue.js"
import { RdDItemOmbre } from "./item/ombre.js"
import { RdDItemSort } from "./item-sort.js"
import { RdDItemTete } from "./item/tete.js"
import { RdDItemRace } from "./item/race.js"
import { RdDItemSouffle } from "./item/souffle.js"
import { RdDRencontre } from "./item/rencontre.js"
import { RdDItemSheet } from "./item-sheet.js"
@ -63,20 +57,20 @@ import { RdDPlanteItemSheet } from "./item/sheet-plante.js"
import { RdDIngredientItemSheet } from "./item/sheet-ingredient.js"
import { RdDFauneItemSheet } from "./item/sheet-faune.js"
import { RdDConteneurItemSheet } from "./item/sheet-conteneur.js"
import { RdDItemInventaireSheet } from "./item/sheet-base-inventaire.js"
import { RdDSigneDraconiqueItemSheet } from "./item/sheet-signedraconique.js"
import { RdDItemInventaireSheet } from "./item/sheet-base-inventaire.js"
import { AppAstrologie } from "./sommeil/app-astrologie.js"
import { RdDItemArmure } from "./item/armure.js"
import { AutoAdjustDarkness } from "./time/auto-adjust-darkness.js"
import { RdDCreature } from "./actor/creature.js"
import { RdDTMRDialog } from "./rdd-tmr-dialog.js"
import { OptionsAvancees } from "./settings/options-avancees.js"
import { ExportScriptarium } from "./actor/export-scriptarium/export-scriptarium.js"
import { AppPersonnageAleatoire } from "./actor/random/app-personnage-aleatoire.js"
import { RdDActorExportSheet } from "./actor/export-scriptarium/actor-encart-sheet.js"
import { RdDStatBlockParser } from "./apps/rdd-import-stats.js"
import { RdDJournalSheet } from "./journal/journal-sheet.js"
import { RdDPotionItemSheet } from "./item/sheet-potion.js"
import { RdDItemPotion } from "./item/potion.js"
import { RdDItemSort } from "./item-sort.js"
import { RdDItemTete } from "./item/tete.js"
/**
* RdD system
@ -87,9 +81,9 @@ export class SystemReveDeDragon {
static start() {
const system = new SystemReveDeDragon()
Hooks.once('init', () => system.onInit())
Hooks.once('init', async () => await system.onInit())
Hooks.once('diceSoNiceReady', (dice3d) => RdDDice.diceSoNiceReady(dice3d))
Hooks.once('ready', () => system.onReady())
Hooks.once('ready', async () => await system.onReady())
}
constructor() {
@ -105,8 +99,6 @@ export class SystemReveDeDragon {
poison: RdDItemPoison,
queue: RdDItemQueue,
tete: RdDItemTete,
potion: RdDItemPotion,
race: RdDItemRace,
rencontre: RdDRencontre,
service: RdDItemService,
signedraconique: RdDItemSigneDraconique,
@ -124,7 +116,7 @@ export class SystemReveDeDragon {
/* -------------------------------------------- */
/* Foundry VTT Initialization */
/* -------------------------------------------- */
onInit() {
async onInit() {
game.system.rdd = this
this.AppAstrologie = AppAstrologie
@ -188,7 +180,7 @@ export class SystemReveDeDragon {
Actors.registerSheet(SYSTEM_RDD, RdDActorVehiculeSheet, { types: ["vehicule"], makeDefault: true })
Actors.registerSheet(SYSTEM_RDD, RdDActorEntiteSheet, { types: ["entite"], makeDefault: true })
Items.unregisterSheet("core", ItemSheet)
RdDActorExportSheet.init()
await RdDActorExportSheet.init()
RdDItemSheet.register(RdDSigneDraconiqueItemSheet)
RdDItemSheet.register(RdDRencontreItemSheet)
@ -196,29 +188,24 @@ export class SystemReveDeDragon {
RdDItemSheet.register(RdDHerbeItemSheet)
RdDItemSheet.register(RdDFauneItemSheet)
RdDItemSheet.register(RdDPlanteItemSheet)
RdDItemSheet.register(RdDPotionItemSheet)
RdDItemSheet.register(RdDIngredientItemSheet)
RdDItemSheet.register(RdDServiceItemSheet)
RdDItemSheet.register(RdDBlessureItemSheet)
RdDJournalSheet.register()
Items.registerSheet(SYSTEM_RDD, RdDItemInventaireSheet, {
types: [
"objet", "arme", "armure", "livre", "munition",
"objet", "arme", "armure", "livre", "potion", "munition",
"monnaie", "nourritureboisson", "gemme",
],
makeDefault: true
], makeDefault: true
})
Items.registerSheet(SYSTEM_RDD, RdDItemSheet, {
types: [
"competence", "competencecreature",
"recettealchimique", "musique", "chant", "danse", "jeu", "race",
"recettecuisine", "oeuvre", "meditation",
"queue", "ombre", "souffle", "tete", "casetmr", "sort", "sortreserve",
"recettealchimique", "musique", "chant", "danse", "jeu", "recettecuisine", "oeuvre",
"meditation", "queue", "ombre", "souffle", "tete", "casetmr", "sort", "sortreserve",
"nombreastral", "tache", "maladie", "poison", "possession",
"tarot", "extraitpoetique", "empoignade"
],
makeDefault: true
], makeDefault: true
})
// préparation des différents modules
@ -320,6 +307,7 @@ export class SystemReveDeDragon {
}
StatusEffects.onReady()
RdDHerbes.onReady()
RdDDice.onReady()
RdDStatBlockParser.parseStatBlock()

View File

@ -3,7 +3,7 @@ import { RdDResolutionTable } from "./rdd-resolution-table.js";
import { RdDRoll } from "./rdd-roll.js";
import { RdDItemCompetenceCreature } from "./item-competencecreature.js";
import { Targets } from "./targets.js";
import { ITEM_TYPES } from "./constants.js";
import { ITEM_TYPES } from "./item.js";
/* -------------------------------------------- */
/* On part du principe qu'une entité démarre tjs
@ -174,7 +174,7 @@ export class RdDPossession {
await RdDResolutionTable.displayRollData(rollData, rollData.attacker, 'chat-resultat-possession.html')
if (rollData.possession.isPosseder || rollData.possession.isConjurer) {
// conjuration
await victime.deleteEmbeddedDocuments("Item", [rollData.possession._id])
victime.deleteEmbeddedDocuments("Item", [rollData.possession._id])
}
}

View File

@ -8,7 +8,6 @@ import { RdDCarac } from "./rdd-carac.js";
import { RdDResolutionTable } from "./rdd-resolution-table.js";
import { ReglesOptionnelles } from "./settings/regles-optionnelles.js";
import { Grammar } from "./grammar.js";
import { ACTOR_TYPES } from "./constants.js";
/**
* Extend the base Dialog entity to select roll parameters
@ -63,7 +62,7 @@ export class RdDRoll extends Dialog {
forceDiceResult: -1
}
// Mini patch :Ajout du rêve actuel
if (actor.type == ACTOR_TYPES.personnage) {
if (actor.system.type == "personnage") {
defaultRollData.carac["reve-actuel"] = actor.system.reve.reve
}
@ -132,16 +131,11 @@ export class RdDRoll extends Dialog {
console.log('RdDRoll.activateListeners', this.rollData);
// Update html, according to rollData
if (!this.rollData.selectedCarac && this.rollData.competence) {
if (this.rollData.competence) {
const defaut_carac = this.rollData.competence.system.defaut_carac
// Set the default carac from the competence item
this.rollData.selectedCarac = this.rollData.carac[this.actor.mapCarac(this.rollData.competence.system.defaut_carac)]
}
if (this.rollData.selectedCarac) {
this.html.find("[name='carac']").val(
this.actor?.type == ACTOR_TYPES.personnage
? RdDCarac.caracDetails(this.rollData.selectedCarac.label).code
: this.rollData.selectedCarac.label
)
this.rollData.selectedCarac = this.rollData.carac[defaut_carac];
this.html.find("[name='carac']").val(defaut_carac);
}
if (this.rollData.selectedSort) {
this.setSelectedSort(this.rollData.selectedSort);
@ -179,7 +173,7 @@ export class RdDRoll extends Dialog {
this.updateRollResult(html);
this.html.find("[name='diffLibre']").val(this.rollData.diffLibre);
});
this.html.find('.roll-text').change((event) => {
this.html.find('.roll-carac-competence').change((event) => {
const competence = event.currentTarget.value
this.rollData.competence = this.rollData.competences.find(it => Grammar.equalsInsensitive(it.name, competence))
this.updateRollResult(html);

View File

@ -28,8 +28,8 @@ export class RdDRollTables {
}
/* -------------------------------------------- */
static async drawTextFromRollTable(tableName, options = {}) {
const drawResult = await RdDRollTables.genericGetTableResult(tableName, options.toChat);
static async drawTextFromRollTable(tableName, toChat) {
const drawResult = await RdDRollTables.genericGetTableResult(tableName, toChat);
return drawResult.text;
}
@ -103,7 +103,7 @@ export class RdDRollTables {
static async getMaladresse(options = { toChat: false, arme: false }) {
return await RdDRollTables.drawTextFromRollTable(
options.arme ? "Maladresse armé" : "Maladresses non armé",
options)
options.toChat);
}
}

View File

@ -70,7 +70,7 @@ export class RdDSheetUtility {
await RdDSheetUtility._onSplitItem(item, split, actor);
onSplit();
});
dialog.render(true)
dialog.render(true);
}
static async _onSplitItem(item, split, actor) {
@ -82,11 +82,4 @@ export class RdDSheetUtility {
await actor.createEmbeddedDocuments('Item', [splitItem])
}
}
static async renderItemBranch(actor, item) {
while (item) {
await item.sheet?.render()
item = actor.getContenant(item)
}
}
}

View File

@ -16,7 +16,7 @@ import { RdDDice } from "./rdd-dice.js";
import { STATUSES } from "./settings/status-effects.js";
import { RdDRencontre } from "./item/rencontre.js";
import { RdDTimestamp } from "./time/rdd-timestamp.js";
import { ITEM_TYPES } from "./constants.js";
import { ITEM_TYPES } from "./item.js";
import { Misc } from "./misc.js";
const TMR_DISPLAY_SIZE = {
@ -176,7 +176,7 @@ export class RdDTMRDialog extends Dialog {
}
bringSubDialogToTop() {
if (this.subdialog?.bringToTop && this.subdialog?.element && this.subdialog?.element[0]) {
if (this.subdialog?.bringToTop && this.subdialog?.element[0]) {
this.subdialog.bringToTop();
}
}
@ -212,7 +212,7 @@ export class RdDTMRDialog extends Dialog {
}
getSortsReserve(coord) {
return this.sortsReserve.filter(// Reserve sur une case fleuve ou normale
return this.actor.itemTypes[ITEM_TYPES.sortreserve].filter(// Reserve sur une case fleuve ou normale
TMRUtility.getTMR(coord).type == 'fleuve'
? it => TMRUtility.getTMR(it.system.coord).type == 'fleuve'
: it => it.system.coord == coord
@ -245,7 +245,6 @@ export class RdDTMRDialog extends Dialog {
/* -------------------------------------------- */
updateTokens() {
this._removeTokens(t => true);
this.allTokens = []
this.loadRencontres();
this.loadCasesSpeciales();
this._createTokens();
@ -271,7 +270,8 @@ export class RdDTMRDialog extends Dialog {
}
_getTokensSortsReserve() {
return Misc.concat(this.sortsReserve.map(sortReserve =>
const sortsReserve = this.actor.itemTypes[ITEM_TYPES.sortreserve];
return Misc.concat(sortsReserve.map(sortReserve =>
EffetsDraconiques.sortReserve.tokens(this.pixiTMR, sortReserve, () => sortReserve.system.coord)))
}
@ -907,8 +907,8 @@ export class RdDTMRDialog extends Dialog {
/* -------------------------------------------- */
lancerSortEnReserve(coord, sortId) {
const sort = this.getSortsReserve(coord)
.find(it => it.id == sortId);
let sorts = this.getSortsReserve(coord);
let sort = sorts.find(it => it.id == sortId);
if (sort) {
this.processSortReserve(sort);
} else {
@ -1133,14 +1133,6 @@ export class RdDTMRDialog extends Dialog {
return tmr;
}
getTokensDetails(coordTMR) {
const tmrTooltip = `${coordTMR}: ${TMRUtility.getTMRLabel(coordTMR)}`
const tokenTooltips = this.allTokens
.filter(token => token.coordTMR() == coordTMR)
.map(token => token.tooltip);
return [tmrTooltip, ...tokenTooltips].reduce(Misc.joining('\n'))
}
/* -------------------------------------------- */
_removeTokens(filter = it => true) {
this.allTokens.filter(filter).forEach(token => this.pixiTMR.removeToken(token))
@ -1152,7 +1144,7 @@ export class RdDTMRDialog extends Dialog {
return
}
if (this.demiReve === token && this.isDemiReveCache()) {
return
return;
}
this.pixiTMR.positionToken(token);
if (!this.allTokens.includes(token)) {

View File

@ -19,12 +19,8 @@ import { RdDEmpoignade } from "./rdd-empoignade.js";
import { ExperienceLog } from "./actor/experience-log.js";
import { RdDCoeur } from "./coeur/rdd-coeur.js";
import { APP_ASTROLOGIE_REFRESH } from "./sommeil/app-astrologie.js";
import { ITEM_TYPES, RDD_CONFIG } from "./constants.js";
import { RDD_CONFIG } from "./constants.js";
import { RdDBaseActor } from "./actor/base-actor.js";
import { RdDCarac } from "./rdd-carac.js";
import { RdDTextEditor } from "./apps/rdd-text-roll-editor.js";
import { Monnaie } from "./item-monnaie.js";
import { ItemAction } from "./item/item-actions.js";
/* -------------------------------------------- */
// This table starts at 0 -> niveau -10
@ -109,7 +105,7 @@ export class RdDUtility {
}
/* -------------------------------------------- */
static preloadHandlebarsTemplates() {
static async preloadHandlebarsTemplates() {
const templatePaths = [
//Character Sheets
'systems/foundryvtt-reve-de-dragon/templates/actor-sheet.html',
@ -117,7 +113,6 @@ export class RdDUtility {
'systems/foundryvtt-reve-de-dragon/templates/actor-entite-sheet.html',
'systems/foundryvtt-reve-de-dragon/templates/actor-vehicule-sheet.html',
// sous-parties de feuilles de personnages
'systems/foundryvtt-reve-de-dragon/templates/actor/item-action-controls.hbs',
'systems/foundryvtt-reve-de-dragon/templates/actor/header-buttons.html',
'systems/foundryvtt-reve-de-dragon/templates/actor/header-etat.html',
'systems/foundryvtt-reve-de-dragon/templates/actor/header-compteurs.html',
@ -132,47 +127,48 @@ export class RdDUtility {
'systems/foundryvtt-reve-de-dragon/templates/actor/carac-derivee.html',
'systems/foundryvtt-reve-de-dragon/templates/actor/carac-creature.html',
'systems/foundryvtt-reve-de-dragon/templates/actor/carac-entitee.html',
'systems/foundryvtt-reve-de-dragon/templates/actor/comp-creature.hbs',
'systems/foundryvtt-reve-de-dragon/templates/actor/comp-possession.hbs',
'systems/foundryvtt-reve-de-dragon/templates/actor/comp-creature.html',
'systems/foundryvtt-reve-de-dragon/templates/actor/comp-possession.html',
'systems/foundryvtt-reve-de-dragon/templates/actor/carac-total.html',
'systems/foundryvtt-reve-de-dragon/templates/actor/competence.hbs',
'systems/foundryvtt-reve-de-dragon/templates/actor/competence.html',
'systems/foundryvtt-reve-de-dragon/templates/actor/competence-categorie.html',
'systems/foundryvtt-reve-de-dragon/templates/actor/xp-competences.html',
'systems/foundryvtt-reve-de-dragon/templates/actor/combat.html',
'systems/foundryvtt-reve-de-dragon/templates/actor/blessures.html',
'systems/foundryvtt-reve-de-dragon/templates/actor/blessure.hbs',
'systems/foundryvtt-reve-de-dragon/templates/actor/maladies-poisons.hbs',
'systems/foundryvtt-reve-de-dragon/templates/actor/possessions.hbs',
'systems/foundryvtt-reve-de-dragon/templates/actor/maladies-poisons.html',
'systems/foundryvtt-reve-de-dragon/templates/actor/possessions.html',
'systems/foundryvtt-reve-de-dragon/templates/actor/resonances.hbs',
'systems/foundryvtt-reve-de-dragon/templates/actor/taches.hbs',
'systems/foundryvtt-reve-de-dragon/templates/actor/oeuvres.hbs',
'systems/foundryvtt-reve-de-dragon/templates/actor/oeuvre.hbs',
'systems/foundryvtt-reve-de-dragon/templates/actor/jeus.hbs',
'systems/foundryvtt-reve-de-dragon/templates/actor/alchimie.hbs',
'systems/foundryvtt-reve-de-dragon/templates/actor/taches.html',
'systems/foundryvtt-reve-de-dragon/templates/actor/taches.html',
'systems/foundryvtt-reve-de-dragon/templates/actor/oeuvres.html',
'systems/foundryvtt-reve-de-dragon/templates/actor/oeuvre.html',
'systems/foundryvtt-reve-de-dragon/templates/actor/jeux.html',
'systems/foundryvtt-reve-de-dragon/templates/actor/alchimie.html',
'systems/foundryvtt-reve-de-dragon/templates/actor/astrologie.html',
'systems/foundryvtt-reve-de-dragon/templates/actor/chirurgie.hbs',
'systems/foundryvtt-reve-de-dragon/templates/actor/chirurgie.html',
'systems/foundryvtt-reve-de-dragon/templates/actor/non-haut-revant.hbs',
'systems/foundryvtt-reve-de-dragon/templates/actor/haut-revant.hbs',
'systems/foundryvtt-reve-de-dragon/templates/actor/dragon-queues.html',
'systems/foundryvtt-reve-de-dragon/templates/actor/dragon-queue.hbs',
'systems/foundryvtt-reve-de-dragon/templates/actor/dragon-souffles.hbs',
'systems/foundryvtt-reve-de-dragon/templates/actor/dragon-tetes.hbs',
'systems/foundryvtt-reve-de-dragon/templates/actor/hr-signes-draconiques.hbs',
'systems/foundryvtt-reve-de-dragon/templates/actor/hr-rencontres.hbs',
'systems/foundryvtt-reve-de-dragon/templates/actor/hr-sorts.hbs',
'systems/foundryvtt-reve-de-dragon/templates/actor/hr-sorts-reserve.hbs',
'systems/foundryvtt-reve-de-dragon/templates/actor/hr-meditations.hbs',
'systems/foundryvtt-reve-de-dragon/templates/actor/hr-casetmrs.hbs',
'systems/foundryvtt-reve-de-dragon/templates/actor/dragon-queue.html',
'systems/foundryvtt-reve-de-dragon/templates/actor/dragon-souffles.html',
'systems/foundryvtt-reve-de-dragon/templates/actor/dragon-tetes.html',
'systems/foundryvtt-reve-de-dragon/templates/actor/hr-signes-draconiques.html',
'systems/foundryvtt-reve-de-dragon/templates/actor/hr-rencontres.html',
'systems/foundryvtt-reve-de-dragon/templates/actor/hr-sorts.html',
'systems/foundryvtt-reve-de-dragon/templates/actor/hr-sorts-reserve.html',
'systems/foundryvtt-reve-de-dragon/templates/actor/hr-meditations.html',
'systems/foundryvtt-reve-de-dragon/templates/actor/hr-casestmr.html',
'systems/foundryvtt-reve-de-dragon/templates/actor/xp-journal.html',
'systems/foundryvtt-reve-de-dragon/templates/actor/editor-notes-mj.html',
'systems/foundryvtt-reve-de-dragon/templates/actor/inventaire.html',
'systems/foundryvtt-reve-de-dragon/templates/actor/inventaire-item.hbs',
"systems/foundryvtt-reve-de-dragon/templates/actor/inventaire-monnaie.hbs",
'systems/foundryvtt-reve-de-dragon/templates/actor/inventaire-item.html',
"systems/foundryvtt-reve-de-dragon/templates/actor/inventaire-monnaie.html",
'systems/foundryvtt-reve-de-dragon/templates/actor/liens-animaux.hbs',
'systems/foundryvtt-reve-de-dragon/templates/actor/liens-suivants.hbs',
'systems/foundryvtt-reve-de-dragon/templates/actor/liens-vehicules.hbs',
'systems/foundryvtt-reve-de-dragon/templates/actor/commerce-inventaire.hbs',
'systems/foundryvtt-reve-de-dragon/templates/actor/commerce-inventaire-item.hbs',
'systems/foundryvtt-reve-de-dragon/templates/actor/commerce-inventaire.html',
'systems/foundryvtt-reve-de-dragon/templates/actor/commerce-inventaire-item.html',
//Items
'systems/foundryvtt-reve-de-dragon/templates/scripts/autocomplete-script.hbs',
'systems/foundryvtt-reve-de-dragon/templates/scripts/autocomplete.hbs',
@ -182,9 +178,8 @@ export class RdDUtility {
'systems/foundryvtt-reve-de-dragon/templates/item/partial-inventaire.html',
'systems/foundryvtt-reve-de-dragon/templates/item/partial-environnement.html',
'systems/foundryvtt-reve-de-dragon/templates/item/partial-tab-environnement.html',
'systems/foundryvtt-reve-de-dragon/templates/item-queue-sheet.html',
'systems/foundryvtt-reve-de-dragon/templates/header-item.html',
'systems/foundryvtt-reve-de-dragon/templates/item/queue-sheet.hbs',
// partial enums
'systems/foundryvtt-reve-de-dragon/templates/enum-aspect-tarot.html',
'systems/foundryvtt-reve-de-dragon/templates/enum-base-competence.html',
@ -192,7 +187,7 @@ export class RdDUtility {
'systems/foundryvtt-reve-de-dragon/templates/enum-categories.html',
'systems/foundryvtt-reve-de-dragon/templates/enum-categorie-ingredient.html',
'systems/foundryvtt-reve-de-dragon/templates/enum-categorie-parade.html',
'systems/foundryvtt-reve-de-dragon/templates/item/potion-enum-categorie.hbs',
'systems/foundryvtt-reve-de-dragon/templates/enum-categorie-potion.html',
'systems/foundryvtt-reve-de-dragon/templates/enum-categorie-queue.html',
'systems/foundryvtt-reve-de-dragon/templates/enum-categorie-vehicule.html',
'systems/foundryvtt-reve-de-dragon/templates/enum-competence.html',
@ -267,24 +262,7 @@ export class RdDUtility {
'systems/foundryvtt-reve-de-dragon/templates/chat-signe-draconique-actor.html'
];
// foundry et options
Handlebars.registerHelper('RDD_CONFIG', path => RDD_CONFIG[path])
Handlebars.registerHelper('linkCompendium', (pack, id, name) => RdDUtility.linkCompendium(pack, id, name));
Handlebars.registerHelper('regle-optionnelle', (option) => ReglesOptionnelles.isUsing(option));
Handlebars.registerHelper('plusMoins', diff => (diff > 0 ? '+' : '') + Math.round(diff))
// Handle v12 removal of this helper
Handlebars.registerHelper('select', function (selected, options) {
const escapedValue = RegExp.escape(Handlebars.escapeExpression(selected));
const rgx = new RegExp(' value=[\"\']' + escapedValue + '[\"\']');
const html = options.fn(this);
return html.replace(rgx, "$& selected");
})
// logic
Handlebars.registerHelper('either', (a, b) => a ?? b);
// string manipulation
Handlebars.registerHelper('upperFirst', str => Misc.upperFirst(str ?? 'Null'));
Handlebars.registerHelper('lowerFirst', str => Misc.lowerFirst(str ?? 'Null'));
Handlebars.registerHelper('uppercase', str => str?.toUpperCase() ?? '');
@ -293,60 +271,50 @@ export class RdDUtility {
Handlebars.registerHelper('grammar-apostrophe', (article, str) => Grammar.apostrophe(article, str));
Handlebars.registerHelper('grammar-un', str => Grammar.articleIndetermine(str));
Handlebars.registerHelper('grammar-accord', (genre, ...args) => Grammar.accord(genre, args));
Handlebars.registerHelper('json-stringify', object => JSON.stringify(object))
// math
Handlebars.registerHelper('min', (...args) => Math.min(...args.slice(0, -1)));
Handlebars.registerHelper('repeat', function (n, block) {
let accum = '';
for (let i = 0; i < n; ++i) {
accum += block.fn(i)
}
return accum
})
// tableaux, listes
Handlebars.registerHelper('array-includes', (array, value) => array.includes(value));
Handlebars.registerHelper('isLastIndex', (index, list) => index + 1 >= list.length);
Handlebars.registerHelper('trier', list => list.sort((a, b) => a.name.localeCompare(b.name)));
// table de résolution
Handlebars.registerHelper('RDD_CONFIG', path => RDD_CONFIG[path])
Handlebars.registerHelper('computeResolutionScore', (row, col) => RdDResolutionTable.computePercentage(row, col));
Handlebars.registerHelper('computeResolutionChances', (row, col) => RdDResolutionTable.computeChances(row, col));
Handlebars.registerHelper('buildLigneInventaire', (item, options) => { return new Handlebars.SafeString(RdDUtility.buildLigneInventaire(item, options)); });
Handlebars.registerHelper('buildInventaireConteneur', (actorId, itemId, options) => { return new Handlebars.SafeString(RdDUtility.buildInventaireConteneur(actorId, itemId, options)); });
Handlebars.registerHelper('buildContenuConteneur', (item, options) => { return new Handlebars.SafeString(RdDUtility.buildContenuConteneur(item, options)); });
Handlebars.registerHelper('calculerPrixCommercant', item => item.calculerPrixCommercant());
Handlebars.registerHelper('caseTmr-label', coord => TMRUtility.getTMRLabel(coord));
Handlebars.registerHelper('caseTmr-type', coord => TMRUtility.getTMRType(coord));
Handlebars.registerHelper('typeTmr-name', type => TMRUtility.typeTmrName(type));
Handlebars.registerHelper('effetRencontre-name', coord => TMRUtility.typeTmrName(coord));
// gestion des dates et heures
Handlebars.registerHelper('timestamp-imgSigneHeure', (heure) => { return new Handlebars.SafeString(RdDTimestamp.imgSigneHeure(heure)) });
Handlebars.registerHelper('timestamp-imgSigne', (heure) => { return new Handlebars.SafeString(RdDTimestamp.imgSigne(heure)) });
Handlebars.registerHelper('timestamp-extract', timestamp => new RdDTimestamp(timestamp).toCalendrier());
Handlebars.registerHelper('timestamp-formulesDuree', () => RdDTimestamp.formulesDuree());
Handlebars.registerHelper('timestamp-formulesPeriode', () => RdDTimestamp.formulesPeriode());
// informations sur les acteurs
Handlebars.registerHelper('actor-default', (actorType, ...path) => RdDBaseActor.getDefaultValue(actorType, path.slice(0, -1)));
Handlebars.registerHelper('array-includes', (array, value) => array.includes(value));
Handlebars.registerHelper('min', (...args) => Math.min(...args.slice(0, -1)));
Handlebars.registerHelper('isLastIndex', (index, list) => index + 1 >= list.length);
Handlebars.registerHelper('regle-optionnelle', (option) => ReglesOptionnelles.isUsing(option));
Handlebars.registerHelper('trier', list => list.sort((a, b) => a.name.localeCompare(b.name)));
Handlebars.registerHelper('filtreTriCompetences', competences => RdDItemCompetence.triVisible(competences));
Handlebars.registerHelper('experienceLog-topic', topic => ExperienceLog.labelTopic(topic));
Handlebars.registerHelper('carac-label', (code) => RdDCarac.label(code))
// inventaire et marchands
Handlebars.registerHelper('buildLigneInventaire', (item, options) => { return new Handlebars.SafeString(RdDUtility.buildLigneInventaire(item, options)); });
Handlebars.registerHelper('buildInventaireConteneur', (actorId, itemId, options) => { return new Handlebars.SafeString(RdDUtility.buildInventaireConteneur(actorId, itemId, options)); });
Handlebars.registerHelper('buildContenuConteneur', (item, options) => { return new Handlebars.SafeString(RdDUtility.buildContenuConteneur(item, options)); });
Handlebars.registerHelper('calculerPrixCommercant', item => item.calculerPrixCommercant());
Handlebars.registerHelper('linkCompendium', (pack, id, name) => RdDUtility.linkCompendium(pack, id, name));
Handlebars.registerHelper('uniteQuantite', (itemId, actorId) => RdDUtility.getItem(itemId, actorId)?.getUniteQuantite());
Handlebars.registerHelper('isFieldInventaireModifiable', (type, field) => RdDItem.isFieldInventaireModifiable(type, field));
// Items
Handlebars.registerHelper('rarete-getChamp', (rarete, field) => RdDRaretes.getChamp(rarete, field));
Handlebars.registerHelper('item-action-applies', (action, item, options) => ItemAction.applies(action, item, options))
Handlebars.registerHelper('item-action-icon', (action, item) => ItemAction.icon(action, item))
// TMRs
Handlebars.registerHelper('caseTmr-label', coord => TMRUtility.getTMRLabel(coord));
Handlebars.registerHelper('caseTmr-type', coord => TMRUtility.getTMRType(coord));
Handlebars.registerHelper('typeTmr-name', type => TMRUtility.typeTmrName(type));
Handlebars.registerHelper('effetRencontre-name', coord => TMRUtility.typeTmrName(coord));
Handlebars.registerHelper('plusMoins', diff => (diff > 0 ? '+' : '') + Math.round(diff))
Handlebars.registerHelper('experienceLog-topic', topic => ExperienceLog.labelTopic(topic));
loadTemplates(templatePaths);
// Handle v12 removal of this helper
Handlebars.registerHelper('select', function (selected, options) {
const escapedValue = RegExp.escape(Handlebars.escapeExpression(selected));
const rgx = new RegExp(' value=[\"\']' + escapedValue + '[\"\']');
const html = options.fn(this);
return html.replace(rgx, "$& selected");
});
return loadTemplates(templatePaths);
}
static getItem(itemId, actorId = undefined) {
@ -440,8 +408,8 @@ export class RdDUtility {
};
if (!optionsArbre.templateItem) {
optionsArbre.templateItem = item.parent?.type == 'commerce'
? "systems/foundryvtt-reve-de-dragon/templates/actor/commerce-inventaire-item.hbs"
: "systems/foundryvtt-reve-de-dragon/templates/actor/inventaire-item.hbs";
? "systems/foundryvtt-reve-de-dragon/templates/actor/commerce-inventaire-item.html"
: "systems/foundryvtt-reve-de-dragon/templates/actor/inventaire-item.html";
}
item.niveau = optionsArbre.profondeur;
}
@ -469,38 +437,13 @@ export class RdDUtility {
return ligneObjet;
}
static filterItemsPerTypeForSheet(formData, itemTypes) {
Object.values(ITEM_TYPES).forEach(t => {
formData[t + 's'] = Misc.arrayOrEmpty(itemTypes[t])
itemTypes[t].forEach(item => item.actions = item.itemActions())
})
formData.maladiesPoisons = formData.maladies.concat(formData.poisons)
formData.competences = formData.competences.concat(formData.competencecreatures)
formData.monnaies = formData.monnaies.sort(Monnaie.triValeurEntiere())
formData.inventaires = RdDUtility.prepareInventaire(itemTypes)
}
static buildInventaireConteneur(actorId, itemId, options) {
const actor = game.actors.get(actorId)
const item = actor?.items.get(itemId)
if (item?.type == ITEM_TYPES.conteneur) {
const formData = {}
RdDUtility.filterItemsPerTypeForSheet(formData, actor.itemTypes);
RdDUtility.buildArbreDeConteneurs(formData.conteneurs, formData.inventaires);
item.subItems = formData.conteneurs.find(it => it._id == itemId)?.subItems;
return RdDUtility.buildContenuConteneur(item, options, { ouvert: true, profondeur: 1 })
if (item) {
return RdDUtility.buildContenuConteneur(item, options, { ouvert: true, profondeur: 1 });
}
return ''
}
static prepareInventaire(itemTypes) {
return RdDItem.getItemTypesInventaire('all')
.map(t => Misc.arrayOrEmpty(itemTypes[t]))
.reduce((a, b) => a.concat(b), [])
.sort(Misc.ascending(it => it.name))
return '';
}
/* -------------------------------------------- */
@ -727,7 +670,6 @@ export class RdDUtility {
RdDCombat.registerChatCallbacks(html)
RdDEmpoignade.registerChatCallbacks(html)
RdDCoeur.registerChatCallbacks(html)
RdDTextEditor.registerChatCallbacks(html)
// Gestion spécifique message passeurs
html.on("click", '.tmr-passeur-coord a', event => {
@ -902,7 +844,7 @@ export class RdDUtility {
}
/* -------------------------------------------- */
static async confirmActorItemDelete(item, actor) {
static async confirmActorItemDelete(sheet, item, htmlToDelete) {
const itemId = item.id;
const confirmationSuppression = {
settingConfirmer: "confirmation-supprimer-" + item.getItemGroup(),
@ -911,7 +853,8 @@ export class RdDUtility {
buttonLabel: "Supprimer",
onAction: () => {
console.log('Delete : ', itemId);
actor.deleteEmbeddedDocuments('Item', [itemId], { renderSheet: false });
sheet.actor.deleteEmbeddedDocuments('Item', [itemId], { renderSheet: false });
RdDUtility.slideOnDelete(sheet, htmlToDelete);
}
};
if (item.isConteneurNonVide()) {
@ -924,7 +867,8 @@ export class RdDUtility {
label: "Supprimer conteneur et contenu",
callback: () => {
console.log("Delete : ", itemId);
actor.deleteAllConteneur(itemId, { renderSheet: false });
sheet.actor.deleteAllConteneur(itemId, { renderSheet: false });
RdDUtility.slideOnDelete(sheet, htmlToDelete);
}
}
});
@ -964,7 +908,7 @@ export class RdDUtility {
/*-------------------------------------------- */
static checkThanatosXP(compName) {
if (compName.includes('Thanatos')) {
let message = "Vous avez mis des points d'Expérience en Thanatos !<br>Vous devez réduire manuellement d'un même montant d'XP une autre compétence Draconique.";
let message = "Vous avez mis des points d'Expérience dans la Voie de Thanatos !<br>Vous devez réduire manuellement d'un même montant d'XP une autre compétence Draconique.";
ChatMessage.create({
whisper: ChatUtility.getUserAndGMs(),
content: message

View File

@ -168,7 +168,7 @@ export class RollDataAjustements {
// s'assurer de la correction des infos rollData
foundry.utils.mergeObject(rollData, { ajustements: {}, use: {} }, { overwrite: false })
for (let key in referenceAjustements) {
for (var key in referenceAjustements) {
const reference = referenceAjustements[key];
rollData.ajustements[key] = {
visible: reference.isVisible && reference.isVisible(rollData, actor),

View File

@ -15,7 +15,6 @@ const CONFIGURABLE_COMPENDIUMS = {
'ombres-de-thanatos': { label: "Ombres de Thanatos", type: "Item" },
'souffles-de-dragon': { label: "Souffles de Dragon", type: "Item" },
'tarot-draconique': { label: "Tarots draconiques", type: "Item" },
'races': { label: "Races", type: "Item" },
'rencontres': { label: "Rencontres dans les TMR", type: "Item" },
'tetes-de-dragon-pour-haut-revants': { label: "Têtes de dragons (haut-rêvant)", type: "Item" },
'tetes-de-dragon-pour-tous-personnages': { label: "Têtes de dragons (tous)", type: "Item" },

View File

@ -14,14 +14,13 @@ export class Targets {
return {
id: target?.id,
name: target?.document.name,
img: target?.document.texture.src ?? target?.actor.img ?? 'icons/svg/mystery-man.svg'
}
img: target?.document.texture.src ?? target?.actor.img ?? 'icons/svg/mystery-man.svg',
target
};
}
static buildActorTokenData(tokenId, actor) {
return { id: tokenId, name: actor.name, img: actor.img ?? 'icons/svg/mystery-man.svg' };
}
static isTargetEntite(target) {
return target?.actor.type == 'entite' && target?.actor.system.definition.typeentite == ENTITE_NONINCARNE;
}

View File

@ -334,10 +334,6 @@ export class RdDTimestamp {
return this.nouvelleHeure().addHeures((12 + heure - this.heure) % 12);
}
debutJournee() {
return RdDTimestamp.timestamp(this.annee, this.mois, this.jour)
}
async appliquerDuree(duree, actor) {
const formule = FORMULES_DUREE.find(it => it.code == duree) ?? FORMULES_DUREE.find(it => it.code == "");
return await formule.calcul(this, actor);

View File

@ -26,7 +26,7 @@ export class TMRRencontres {
* @param {*} forcedRoll
*/
async rollRencontre(terrain, forcedRoll) {
const tmrType = TMRUtility.findTMRLike(terrain, { inclusMauvaise: true })?.type
const tmrType = TMRUtility.findTMRLike(terrain)?.type
if (tmrType == undefined) {
return undefined;
}
@ -38,7 +38,7 @@ export class TMRRencontres {
const frequence = it => it.system.frequence[tmrType];
const row = await this.table.getRandom(frequence, filtreMauvaise, forcedRoll);
if (row) {
await CompendiumTableHelpers.tableRowToChatMessage(row, 'Item', { showSource: false });
await CompendiumTableHelpers.tableRowToChatMessage(row, 'Item', {showSource: false});
}
return row?.document;

View File

@ -22,7 +22,7 @@ export const TMRType = {
export const FLEUVE_COORD = 'Fleuve'
const TMRMapping = {
Fleuve: { type: TMRType.fleuve.type, label: "Fleuve de l'Oubli", generique: 'fleuve' },
Fleuve: { type: TMRType.fleuve.type, label: "Fleuve de l'Oubli" },
A1: { type: TMRType.cite.type, label: "Cité Vide" },
B1: { type: TMRType.plaines.type, label: "Plaines dAssorh" },
C1: { type: TMRType.necropole.type, label: "Nécropole de Kroak" },
@ -281,18 +281,18 @@ export class TMRUtility {
return Grammar.articleDetermine(tmr.type) + ' ' + tmr.label;
}
static findTMRLike(type, options = { inclusMauvaise: false }) {
static findTMRLike(type, options = { inclusMauvaise: true }) {
const choix = [...Object.values(TMRType)]
if (options.inclusMauvaise) {
choix.push({ name: 'Mauvaise', type: 'mauvaise'});
}
const selection = Misc.findAllLike(type, choix)
if (selection.length == 0) {
ui.notifications.warn(`Un type de TMR doit être indiqué, '${type}' n'est pas trouvé dans ${choix.map(it => it.name).reduce(Misc.joining(', '))}`);
ui.notifications.warn(`Un type de TMR doit être indiqué, '${type}' n'est pas trouvé dans ${choix}`);
return undefined
}
if (selection.length > 1) {
ui.notifications.warn(`Plusieurs types de TMR pourraient correspondre à '${type}': ${selection.map(it => it.name).reduce(Misc.joining(', '))}`);
ui.notifications.warn(`Plusieurs types de TMR pourraient correspondre à '${type}': ${selection.map(it => it.name)}`);
return undefined;
}
return selection[0]
@ -357,7 +357,7 @@ export class TMRUtility {
}
static filterTMR(filter) {
return Object.values(TMRMapping).filter(it => !it.generique && filter(it))
return Object.values(TMRMapping).filter(filter);
}
static getCasesType(type) {

View File

@ -14,8 +14,7 @@ export class CarteTmr extends Draconique {
{
name: 'Carte des TMR',
hint: "Choix de l'image de la carte des TMR",
scope: "client",
requiresReload: true,
scope: "world",
config: true,
choices: {
[TMR_V3_COULEUR]: "TMR Scriptarium v3 couleur",

View File

@ -1,4 +1,4 @@
import { ITEM_TYPES } from "../constants.js";
import { ITEM_TYPES } from "../item.js";
import { TMRUtility } from "../tmr-utility.js";
import { PixiTMR } from "./pixi-tmr.js";

View File

@ -18,7 +18,7 @@ import { Periple } from "./periple.js";
import { UrgenceDraconique } from "./urgence-draconique.js";
import { Grammar } from "../grammar.js";
import { AugmentationSeuil } from "./augmentation-seuil.js";
import { ITEM_TYPES } from "../constants.js";
import { ITEM_TYPES } from "../item.js";
export class EffetsDraconiques {
static carteTmr = new CarteTmr();

View File

@ -184,9 +184,12 @@ export class PixiTMR {
const coordTMR = TMRUtility.oddqToCoordTMR(oddq);
const tmr = TMRUtility.getTMR(coordTMR)
if (tmr) {
return this.tmrDialog.getTokensDetails(coordTMR)
const tmrTooltip = `${coordTMR}: ${TMRUtility.getTMRLabel(coordTMR)}`;
const tokenTooltips = this.tmrDialog.allTokens
.filter(token => token.coordTMR() == coordTMR)
.map(token => token.tooltip);
return [tmrTooltip, ...tokenTooltips].reduce(Misc.joining('\n'))
}
return undefined
}
computeEventOddq(event) {

View File

@ -5,7 +5,7 @@ import { RdDRollTables } from "../rdd-rolltables.js";
import { TMRUtility } from "../tmr-utility.js";
import { tmrTokenZIndex } from "../tmr-constants.js";
import { Draconique } from "./draconique.js";
import { ITEM_TYPES } from "../constants.js";
import { ITEM_TYPES } from "../item.js";
import { TMRAnimations } from "./animation.js";
export class UrgenceDraconique extends Draconique {

View File

@ -1,4 +1,4 @@
import { ITEM_TYPES } from "../constants.js"
import { ITEM_TYPES } from "../item.js"
import { RdDItemCompetence } from "../item-competence.js"
import { ChatUtility } from "../chat-utility.js"
import { Misc } from "../misc.js"

View File

@ -125,39 +125,39 @@ system:
carac:
taille:
type: number
value: 23
value: '23'
label: Taille
xp: 0
derivee: false
constitution:
type: number
value: 18
value: '18'
label: Constitution
xp: 0
xp: '0'
derivee: false
force:
type: number
value: 18
value: '18'
label: Force
xp: 0
xp: '0'
derivee: false
perception:
type: number
value: 11
value: '11'
label: Perception
xp: 0
xp: '0'
derivee: false
volonte:
type: number
value: 7
value: '7'
label: Volonté
xp: 0
xp: '0'
derivee: false
reve:
type: number
value: 8
value: '8'
label: Rêve
xp: 0
xp: '0'
derivee: false
sante:
vie:
@ -190,12 +190,12 @@ system:
derivee: true
encombrement:
type: number
value: 20
value: '20'
label: Encombrement
derivee: false
protection:
type: number
value: 4
value: '4'
label: Protection
derivee: false
compteurs:

View File

@ -155,37 +155,37 @@ system:
carac:
taille:
type: number
value: 3
value: '3'
label: Taille
xp: 0
derivee: false
constitution:
type: number
value: 12
value: '12'
label: Constitution
xp: 0
derivee: false
force:
type: number
value: 7
value: '7'
label: Force
xp: 0
derivee: false
perception:
type: number
value: 15
value: '15'
label: Perception
xp: 0
derivee: false
volonte:
type: number
value: 10
value: '10'
label: Volonté
xp: 0
derivee: false
reve:
type: number
value: 7
value: '7'
label: Rêve
xp: 0
derivee: false
@ -210,7 +210,7 @@ system:
attributs:
plusdom:
type: number
value: -2
value: '-2'
label: +dom
derivee: true
vitesse:
@ -220,12 +220,12 @@ system:
derivee: true
encombrement:
type: number
value: 0
value: '0'
label: Encombrement
derivee: false
protection:
type: number
value: -3
value: '-3'
label: Protection
derivee: false
compteurs:
@ -257,8 +257,47 @@ system:
d&eacute;vore.</p>
<h1>Venin</h1>
<p>@UUID[Compendium.foundryvtt-reve-de-dragon.maladies-et-poisons.Item.v7yZidE9mObKO566]{Venin
d'Araflate}</p> <p></p>
<table style="width: 65.039%; height: 65px;" border="1">
<tbody>
<tr style="height: 16px;">
<td style="width: 30.8567%; height: 16px;">Malignit&eacute;</td>
<td style="width: 68.3263%; height: 16px;">6</td>
</tr>
<tr style="height: 16px;">
<td style="width: 30.8567%; height: 16px;">P&eacute;riodicit&eacute;</td>
<td style="width: 68.3263%; height: 16px;">1 round</td>
</tr>
<tr style="height: 16px;">
<td style="width: 30.8567%; height: 16px;">Dommages</td>
<td style="width: 68.3263%; height: 16px;">-1d6 points d'endurance</td>
</tr>
<tr style="height: 17px;">
<td style="width: 30.8567%; height: 17px;">Antidotes</td>
<td style="width: 68.3263%; height: 17px;">-3 \ Liqueur de Bagdol +12, Lait
de lune +6</td>
</tr>
</tbody>
</table>
race: ''
notesmj: ''
ownership:

View File

@ -155,37 +155,37 @@ system:
carac:
taille:
type: number
value: 19
value: '19'
label: Taille
xp: 0
derivee: false
constitution:
type: number
value: 18
value: '18'
label: Constitution
xp: 0
derivee: false
force:
type: number
value: 18
value: '18'
label: Force
xp: 0
derivee: false
perception:
type: number
value: 12
value: '12'
label: Perception
xp: 0
derivee: false
volonte:
type: number
value: 4
value: '4'
label: Volonté
xp: 0
derivee: false
reve:
type: number
value: 6
value: '6'
label: Rêve
xp: 0
derivee: false
@ -220,12 +220,12 @@ system:
derivee: true
encombrement:
type: number
value: 0
value: '0'
label: Encombrement
derivee: false
protection:
type: number
value: 2
value: '2'
label: Protection
derivee: false
compteurs:

View File

@ -126,37 +126,37 @@ system:
carac:
taille:
type: number
value: 33
value: '33'
label: Taille
xp: 0
derivee: false
constitution:
type: number
value: 26
value: '26'
label: Constitution
xp: 0
derivee: false
force:
type: number
value: 26
value: '26'
label: Force
xp: 0
derivee: false
perception:
type: number
value: 13
value: '13'
label: Perception
xp: 0
derivee: false
volonte:
type: number
value: 3
value: '3'
label: Volonté
xp: 0
derivee: false
reve:
type: number
value: 10
value: '10'
label: Rêve
xp: 0
derivee: false
@ -191,12 +191,12 @@ system:
derivee: true
encombrement:
type: number
value: 0
value: '0'
label: Encombrement
derivee: false
protection:
type: number
value: 2
value: '2'
label: Protection
derivee: false
compteurs:

View File

@ -154,37 +154,37 @@ system:
carac:
taille:
type: number
value: 20
value: '20'
label: Taille
xp: 0
derivee: false
constitution:
type: number
value: 15
value: '15'
label: Constitution
xp: 0
derivee: false
force:
type: number
value: 16
value: '16'
label: Force
xp: 0
derivee: false
perception:
type: number
value: 13
value: '13'
label: Perception
xp: 0
derivee: false
volonte:
type: number
value: 9
value: '9'
label: Volonté
xp: 0
derivee: false
reve:
type: number
value: 10
value: '10'
label: Rêve
xp: 0
derivee: false
@ -219,12 +219,12 @@ system:
derivee: true
encombrement:
type: number
value: 0
value: '0'
label: Encombrement
derivee: false
protection:
type: number
value: 1
value: '1'
label: Protection
derivee: false
compteurs:

View File

@ -183,37 +183,37 @@ system:
carac:
taille:
type: number
value: 7
value: '7'
label: Taille
xp: 0
derivee: false
constitution:
type: number
value: 12
value: '12'
label: Constitution
xp: 0
derivee: false
force:
type: number
value: 11
value: '11'
label: Force
xp: 0
derivee: false
perception:
type: number
value: 14
value: '14'
label: Perception
xp: 0
derivee: false
volonte:
type: number
value: 8
value: '8'
label: Volonté
xp: 0
derivee: false
reve:
type: number
value: 15
value: '15'
label: Rêve
xp: 0
derivee: false
@ -248,12 +248,12 @@ system:
derivee: true
encombrement:
type: number
value: 0
value: '0'
label: Encombrement
derivee: false
protection:
type: number
value: 0
value: '0'
label: Protection
derivee: false
compteurs:
@ -300,7 +300,7 @@ system:
d&eacute;chirure. Celle-l&agrave; se contente de chercher &agrave; fuir en
cas d&rsquo;agression, ou attaque toutes griffes dehors si elle se sent
accul&eacute;e. Pour la distinguer (visuellement) de la rieuse,
r&eacute;ussir @roll[VUE/Zoologie/-5]. Les caract&eacute;ristiques de
r&eacute;ussir VUE/Zoologie &agrave; -5. Les caract&eacute;ristiques de
combat indiqu&eacute;es ne s&rsquo;appliquent qu&rsquo;&agrave; la
pointue.</p>
race: ''

View File

@ -153,37 +153,37 @@ system:
carac:
taille:
type: number
value: 21
value: '21'
label: Taille
xp: 0
derivee: false
constitution:
type: number
value: 17
value: '17'
label: Constitution
xp: 0
derivee: false
force:
type: number
value: 16
value: '16'
label: Force
xp: 0
derivee: false
perception:
type: number
value: 12
value: '12'
label: Perception
xp: 0
derivee: false
volonte:
type: number
value: 12
value: '12'
label: Volonté
xp: 0
derivee: false
reve:
type: number
value: 12
value: '12'
label: Rêve
xp: 0
derivee: false
@ -218,12 +218,12 @@ system:
derivee: true
encombrement:
type: number
value: 18
value: '18'
label: Encombrement
derivee: false
protection:
type: number
value: 1
value: '1'
label: Protection
derivee: false
compteurs:

View File

@ -126,37 +126,37 @@ system:
carac:
taille:
type: number
value: 25
value: '25'
label: Taille
xp: 0
derivee: false
constitution:
type: number
value: 18
value: '18'
label: Constitution
xp: 0
derivee: false
force:
type: number
value: 20
value: '20'
label: Force
xp: 0
derivee: false
perception:
type: number
value: 12
value: '12'
label: Perception
xp: 0
derivee: false
volonte:
type: number
value: 8
value: '8'
label: Volonté
xp: 0
derivee: false
reve:
type: number
value: 10
value: '10'
label: Rêve
xp: 0
derivee: false
@ -191,12 +191,12 @@ system:
derivee: true
encombrement:
type: number
value: 22
value: '22'
label: Encombrement
derivee: false
protection:
type: number
value: 2
value: '2'
label: Protection
derivee: false
compteurs:
@ -215,7 +215,7 @@ system:
souffrir ses premiers malus &agrave; la course et au saut. La vitesse
indiqu&eacute;e correspond &agrave; une allure plut&ocirc;t lente.
Contrairement aux autres animaux pour qui la vitesse de base est fixe, le
gardien des r&ecirc;ves peut rajouter jusqu&rsquo;&agrave; @roll[3d6] points
gardien des r&ecirc;ves peut rajouter jusqu&rsquo;&agrave; 3d6 points
&agrave; la vitesse de course de chaque individu. Cette nouvelle vitesse de
course est rajout&eacute;e une fois pour toutes, mais peut &ecirc;tre
modul&eacute;e par un jet de course sur la table de Course animale.</p>

View File

@ -153,37 +153,37 @@ system:
carac:
taille:
type: number
value: 6
value: '6'
label: Taille
xp: 0
derivee: false
constitution:
type: number
value: 10
value: '10'
label: Constitution
xp: 0
derivee: false
force:
type: number
value: 10
value: '10'
label: Force
xp: 0
derivee: false
perception:
type: number
value: 11
value: '11'
label: Perception
xp: 0
derivee: false
volonte:
type: number
value: 8
value: '8'
label: Volonté
xp: 0
derivee: false
reve:
type: number
value: 8
value: '8'
label: Rêve
xp: 0
derivee: false
@ -218,12 +218,12 @@ system:
derivee: true
encombrement:
type: number
value: 0
value: '0'
label: Encombrement
derivee: false
protection:
type: number
value: -1
value: '-1'
label: Protection
derivee: false
compteurs:

View File

@ -126,37 +126,37 @@ system:
carac:
taille:
type: number
value: 7
value: '7'
label: Taille
xp: 0
derivee: false
constitution:
type: number
value: 9
value: '9'
label: Constitution
xp: 0
derivee: false
force:
type: number
value: 11
value: '11'
label: Force
xp: 0
derivee: false
perception:
type: number
value: 10
value: '10'
label: Perception
xp: 0
derivee: false
volonte:
type: number
value: 3
value: '3'
label: Volonté
xp: 0
derivee: false
reve:
type: number
value: 2
value: '2'
label: Rêve
xp: 0
derivee: false
@ -184,19 +184,19 @@ system:
value: '+0'
label: +dom
derivee: true
encombrement:
type: number
value: 0
label: Encombrement
derivee: false
vitesse:
type: string
value: 12/28
label: Vitesse
derivee: true
encombrement:
type: number
value: '0'
label: Encombrement
derivee: false
protection:
type: number
value: 4
value: '4'
label: Protection
derivee: false
compteurs:
@ -207,19 +207,67 @@ system:
value: 0
label: Sur-encombrement
description: >-
<h1>Description</h1><p>Description Le chrasme (prononcer krasme) est une
sorte de cafard géant à carapace de crabe aux jointures poilues. Il mesure
en moyenne 1 m de haut sur 1m50 de long, et peut peser jusquà 50 kg. Doté
de mandibules acérées et puissantes, il est redouté pour son venin
mortel.</p><h1>Mœurs</h1><p>Le chrasme vit dans les lieux sombres, cavernes
et souterrains, où il se nourrit de tout. Paranos le Moindre affirme quà
défaut dune meilleure chère, il peut même se sustenter de cailloux. Il
déteste la lumière comme son cousin de petite taille, mais a toutefois un
comportement différent: au lieu de fuir, il entre dans une rage féroce et se
rue sur le porteur de lumière pour le réduire en charpie. Savez-vous, cher
Paranos, que vous nous faites un peu peur
?</p><h1>Venin</h1><p>@UUID[Compendium.foundryvtt-reve-de-dragon.maladies-et-poisons.Item.cFMUtU6LZG0mKeDl]{Venin
de chrasme}</p><p></p>
<h1>Description</h1>
<p>Description Le chrasme (prononcer krasme) est une sorte de cafard
g&eacute;ant &agrave; carapace de crabe aux jointures poilues. Il mesure en
moyenne 1 m de haut sur 1m50 de long, et peut peser jusqu&rsquo;&agrave; 50
kg. Dot&eacute; de mandibules ac&eacute;r&eacute;es et puissantes, il est
redout&eacute; pour son venin mortel.</p>
<h1>M&oelig;urs</h1>
<p>Le chrasme vit dans les lieux sombres, cavernes et souterrains, o&ugrave;
il se nourrit de tout. Paranos le Moindre affirme qu&rsquo;&agrave;
d&eacute;faut d&rsquo;une meilleure ch&egrave;re, il peut m&ecirc;me se
sustenter de cailloux. Il d&eacute;teste la lumi&egrave;re comme son cousin
de petite taille, mais a toutefois un comportement diff&eacute;rent: au lieu
de fuir, il entre dans une rage f&eacute;roce et se rue sur le porteur de
lumi&egrave;re pour le r&eacute;duire en charpie. Savez-vous, cher Paranos,
que vous nous faites un peu peur ?</p>
<h1>Venin</h1>
<table style="width: 399px; height: 65px;" border="1">
<tbody>
<tr style="height: 16px;">
<td style="width: 121px; height: 16px;">Malignit&eacute;</td>
<td style="width: 274px; height: 16px;">3</td>
</tr>
<tr style="height: 16px;">
<td style="width: 121px; height: 16px;">P&eacute;riodicit&eacute;</td>
<td style="width: 274px; height: 16px;">1 miute</td>
</tr>
<tr style="height: 16px;">
<td style="width: 121px; height: 16px;">Dommages</td>
<td style="width: 274px; height: 16px;">-1 point de vie</td>
</tr>
<tr style="height: 17px;">
<td style="width: 121px; height: 17px;">Antidotes</td>
<td style="width: 274px; height: 17px;">-2 \ Liqueur de Bagdol +16, Teinture
d'Erozonne +10</td>
</tr>
</tbody>
</table>
race: ''
notesmj: ''
ownership:
@ -302,13 +350,7 @@ prototypeToken:
texture: null
_stats:
systemId: foundryvtt-reve-de-dragon
systemVersion: 12.0.32
systemVersion: 12.0.22
coreVersion: '12.331'
createdTime: null
modifiedTime: 1736537299708
lastModifiedBy: Hp9ImM4o9YRTSdfu
compendiumSource: null
duplicateSource: null
flags: {}
_key: '!actors!yL1XStIKWxGnhKvR'

View File

@ -155,37 +155,37 @@ system:
carac:
taille:
type: number
value: 20
value: '20'
label: Taille
xp: 0
derivee: false
constitution:
type: number
value: 18
value: '18'
label: Constitution
xp: 0
derivee: false
force:
type: number
value: 16
value: '16'
label: Force
xp: 0
derivee: false
perception:
type: number
value: 13
value: '13'
label: Perception
xp: 0
derivee: false
volonte:
type: number
value: 7
value: '7'
label: Volonté
xp: 0
derivee: false
reve:
type: number
value: 9
value: '9'
label: Rêve
xp: 0
derivee: false
@ -220,12 +220,12 @@ system:
derivee: true
encombrement:
type: number
value: 0
value: '0'
label: Encombrement
derivee: false
protection:
type: number
value: 3
value: '3'
label: Protection
derivee: false
compteurs:

View File

@ -154,37 +154,37 @@ system:
carac:
taille:
type: number
value: 12
value: '12'
label: Taille
xp: 0
derivee: false
constitution:
type: number
value: 12
value: '12'
label: Constitution
xp: 0
derivee: false
force:
type: number
value: 15
value: '15'
label: Force
xp: 0
derivee: false
perception:
type: number
value: 10
value: '10'
label: Perception
xp: 0
derivee: false
volonte:
type: number
value: 6
value: '6'
label: Volonté
xp: 0
derivee: false
reve:
type: number
value: 4
value: '4'
label: Rêve
xp: 0
derivee: false
@ -219,12 +219,12 @@ system:
derivee: true
encombrement:
type: number
value: 0
value: '0'
label: Encombrement
derivee: false
protection:
type: number
value: 3
value: '3'
label: Protection
derivee: false
compteurs:

View File

@ -97,37 +97,37 @@ system:
carac:
taille:
type: number
value: 4
value: '4'
label: Taille
xp: 0
derivee: false
constitution:
type: number
value: 10
value: '10'
label: Constitution
xp: 0
derivee: false
force:
type: number
value: 8
value: '8'
label: Force
xp: 0
derivee: false
perception:
type: number
value: 12
value: '12'
label: Perception
xp: 0
derivee: false
volonte:
type: number
value: 7
value: '7'
label: Volonté
xp: 0
derivee: false
reve:
type: number
value: 7
value: '7'
label: Rêve
xp: 0
derivee: false
@ -152,7 +152,7 @@ system:
attributs:
plusdom:
type: number
value: -1
value: '-1'
label: +dom
derivee: true
vitesse:
@ -162,12 +162,12 @@ system:
derivee: true
encombrement:
type: number
value: 0
value: '0'
label: Encombrement
derivee: false
protection:
type: number
value: -3
value: '-3'
label: Protection
derivee: false
compteurs:
@ -203,10 +203,10 @@ system:
<p>En combat, quand un drakkule r&eacute;ussit une particuli&egrave;re et
cause au moins une blessure l&eacute;g&egrave;re, il reste accroch&eacute;
&agrave; sa victime qui perd alors automatiquement @roll[1d6] points
&agrave; sa victime qui perd alors automatiquement 1d6 points
d&rsquo;endurance par round sous l&rsquo;effet de la saign&eacute;e. Quand
l&rsquo;endurance tombe &agrave; z&eacute;ro, le drakkule continue &agrave;
la vider de son sang &agrave; raison de @roll[1d6] points de vie par round. Le
la vider de son sang &agrave; raison de 1d6 points de vie par round. Le
drakkule ne se d&eacute;tache que <em>bless&eacute; gravement </em>ou
<em>sonn&eacute;</em>. Pour se d&eacute;gager, la victime ne peut utiliser
que Corps &agrave; corps (totaliser 2 points d&rsquo;empoignade) ou une

View File

@ -97,37 +97,37 @@ system:
carac:
taille:
type: number
value: 2
value: '2'
label: Taille
xp: 0
derivee: false
constitution:
type: number
value: 8
value: '8'
label: Constitution
xp: 0
derivee: false
force:
type: number
value: 3
value: '3'
label: Force
xp: 0
derivee: false
perception:
type: number
value: 13
value: '13'
label: Perception
xp: 0
derivee: false
volonte:
type: number
value: 10
value: '10'
label: Volonté
xp: 0
derivee: false
reve:
type: number
value: 11
value: '11'
label: Rêve
xp: 0
derivee: false
@ -152,7 +152,7 @@ system:
attributs:
plusdom:
type: number
value: -4
value: '-4'
label: +dom
derivee: true
vitesse:
@ -162,12 +162,12 @@ system:
derivee: true
encombrement:
type: number
value: 0
value: '0'
label: Encombrement
derivee: false
protection:
type: number
value: -6
value: '-6'
label: Protection
derivee: false
compteurs:

View File

@ -184,37 +184,37 @@ system:
carac:
taille:
type: number
value: 7
value: '7'
label: Taille
xp: 0
derivee: false
constitution:
type: number
value: 12
value: '12'
label: Constitution
xp: 0
derivee: false
force:
type: number
value: 11
value: '11'
label: Force
xp: 0
derivee: false
perception:
type: number
value: 13
value: '13'
label: Perception
xp: 0
derivee: false
volonte:
type: number
value: 10
value: '10'
label: Volonté
xp: 0
derivee: false
reve:
type: number
value: 10
value: '10'
label: Rêve
xp: 0
derivee: false
@ -249,12 +249,12 @@ system:
derivee: true
encombrement:
type: number
value: 0
value: '0'
label: Encombrement
derivee: false
protection:
type: number
value: 0
value: '0'
label: Protection
derivee: false
compteurs:

View File

@ -206,37 +206,37 @@ system:
carac:
taille:
type: number
value: 6
value: '6'
label: Taille
xp: 0
derivee: false
constitution:
type: number
value: 10
value: '10'
label: Constitution
xp: 0
derivee: false
force:
type: number
value: 9
value: '9'
label: Force
xp: 0
derivee: false
perception:
type: number
value: 14
value: '14'
label: Perception
xp: 0
derivee: false
volonte:
type: number
value: 11
value: '11'
label: Volonté
xp: 0
derivee: false
reve:
type: number
value: 12
value: '12'
label: Rêve
xp: 0
derivee: false
@ -261,7 +261,7 @@ system:
attributs:
plusdom:
type: number
value: -1
value: '-1'
label: +dom
derivee: true
vitesse:
@ -271,12 +271,12 @@ system:
derivee: true
encombrement:
type: number
value: 0
value: '0'
label: Encombrement
derivee: false
protection:
type: number
value: 0
value: '0'
label: Protection
derivee: false
compteurs:

View File

@ -241,39 +241,39 @@ system:
carac:
taille:
type: number
value: 16
value: '16'
label: Taille
xp: 0
derivee: false
constitution:
type: number
value: 15
value: '15'
label: Constitution
xp: 0
xp: '0'
derivee: false
force:
type: number
value: 13
value: '13'
label: Force
xp: 0
xp: '0'
derivee: false
perception:
type: number
value: 10
value: '10'
label: Perception
xp: 0
xp: '0'
derivee: false
volonte:
type: number
value: 8
value: '8'
label: Volonté
xp: 0
xp: '0'
derivee: false
reve:
type: number
value: 10
value: '10'
label: Rêve
xp: 0
xp: '0'
derivee: false
sante:
vie:
@ -306,12 +306,12 @@ system:
derivee: true
encombrement:
type: number
value: 0
value: '0'
label: Encombrement
derivee: false
protection:
type: number
value: 4
value: '4'
label: Protection
derivee: false
compteurs:

View File

@ -155,37 +155,37 @@ system:
carac:
taille:
type: number
value: 11
value: '11'
label: Taille
xp: 0
derivee: false
constitution:
type: number
value: 14
value: '14'
label: Constitution
xp: 0
derivee: false
force:
type: number
value: 13
value: '13'
label: Force
xp: 0
derivee: false
perception:
type: number
value: 10
value: '10'
label: Perception
xp: 0
derivee: false
volonte:
type: number
value: 7
value: '7'
label: Volonté
xp: 0
derivee: false
reve:
type: number
value: 10
value: '10'
label: Rêve
xp: 0
derivee: false
@ -220,12 +220,12 @@ system:
derivee: true
encombrement:
type: number
value: 0
value: '0'
label: Encombrement
derivee: false
protection:
type: number
value: 0
value: '0'
label: Protection
derivee: false
compteurs:
@ -257,8 +257,56 @@ system:
<h1 style="box-sizing: border-box; user-select: text; color: #191813;
font-family: GoudyAcc, sans-serif;">Venin</h1>
<p>@UUID[Compendium.foundryvtt-reve-de-dragon.maladies-et-poisons.Item.IF19EUvrY1HL87lr]{Venin
paralysant de goule}</p>
<table style="box-sizing: border-box; user-select: text; width: 395px;
color: #191813; font-family: GoudyAcc, sans-serif; height: 65px;"
border="1">
<tbody style="box-sizing: border-box; user-select: text;">
<tr style="box-sizing: border-box; user-select: text; height: 16px;">
<td style="box-sizing: border-box; user-select: text; width: 122px; height:
16px;">Malignit&eacute;</td>
<td style="box-sizing: border-box; user-select: text; width: 272px; height:
16px;">6</td>
</tr>
<tr style="box-sizing: border-box; user-select: text; height: 16px;">
<td style="box-sizing: border-box; user-select: text; width: 122px; height:
16px;">P&eacute;riodicit&eacute;</td>
<td style="box-sizing: border-box; user-select: text; width: 272px; height:
16px;">1 round</td>
</tr>
<tr style="box-sizing: border-box; user-select: text; height: 16px;">
<td style="box-sizing: border-box; user-select: text; width: 122px; height:
16px;">Dommages</td>
<td style="box-sizing: border-box; user-select: text; width: 272px; height:
16px;">1 ligne de fatigue</td>
</tr>
<tr style="box-sizing: border-box; user-select: text; height: 17px;">
<td style="box-sizing: border-box; user-select: text; width: 122px; height:
17px;">Antidotes</td>
<td style="box-sizing: border-box; user-select: text; width: 272px; height:
17px;">-4 \ Floume-dhu +16</td>
</tr>
</tbody>
</table>
<p>La paralysie intervient quand toutes les lignes de fatigue sont pleines
et dure 6 heures.</p>

View File

@ -137,7 +137,7 @@ system:
elles-m&ecirc;mes, leur grincement involontaire est une torture. Toute
personne se trouvant dans un rayon de 10m doit manquer un jet
d&rsquo;OU&Iuml;E &agrave; +5. Si le jet r&eacute;ussit, perte de 1 point
d&rsquo;endurance, puis jet de @roll[volonté/-5]. Si le jet de
d&rsquo;endurance, puis jet de VOLONT&Eacute; &agrave; -5. Si le jet de
VOLONT&Eacute; &eacute;choue, le personnage est sonn&eacute;
jusqu&rsquo;&agrave; la fin du round suivant.</p>

View File

@ -183,37 +183,37 @@ system:
carac:
taille:
type: number
value: 23
value: '23'
label: Taille
xp: 0
derivee: false
constitution:
type: number
value: 20
value: '20'
label: Constitution
xp: 0
derivee: false
force:
type: number
value: 20
value: '20'
label: Force
xp: 0
derivee: false
perception:
type: number
value: 11
value: '11'
label: Perception
xp: 0
derivee: false
volonte:
type: number
value: 8
value: '8'
label: Volonté
xp: 0
derivee: false
reve:
type: number
value: 10
value: '10'
label: Rêve
xp: 0
derivee: false
@ -248,12 +248,12 @@ system:
derivee: true
encombrement:
type: number
value: 0
value: '0'
label: Encombrement
derivee: false
protection:
type: number
value: 3
value: '3'
label: Protection
derivee: false
compteurs:

View File

@ -68,37 +68,37 @@ system:
carac:
taille:
type: number
value: 9
value: '9'
label: Taille
xp: 0
derivee: false
constitution:
type: number
value: 11
value: '11'
label: Constitution
xp: 0
derivee: false
force:
type: number
value: 12
value: '12'
label: Force
xp: 0
derivee: false
perception:
type: number
value: 11
value: '11'
label: Perception
xp: 0
derivee: false
volonte:
type: number
value: 12
value: '12'
label: Volonté
xp: 0
derivee: false
reve:
type: number
value: 11
value: '11'
label: Rêve
xp: 0
derivee: false
@ -133,12 +133,12 @@ system:
derivee: true
encombrement:
type: number
value: 0
value: '0'
label: Encombrement
derivee: false
protection:
type: number
value: 4
value: '4'
label: Protection
derivee: false
compteurs:
@ -174,8 +174,8 @@ system:
agressivit&eacute; s&rsquo;appliquant aux humano&iuml;des. S&rsquo;agissant
d&rsquo;un pouvoir inn&eacute;, elles n&rsquo;ont ni &agrave; monter dans
les TMR, ni &agrave; d&eacute;penser de points de r&ecirc;ve. La victime
doit jouer un jet de r&eacute;sistance standard, @roll[reve-actuel/-8], et en cas
d&rsquo;&eacute;chec, r&eacute;ussir un jet de @roll[Volonté/-3]
doit jouer un jet de r&eacute;sistance standard, r-8, et en cas
d&rsquo;&eacute;chec, r&eacute;ussir un jet de VOLONT&Eacute; &agrave; -3
pour pouvoir attaquer la harpie. Le JR n&rsquo;est &agrave; jouer
qu&rsquo;une seule fois, tandis qu&rsquo;en cas d&rsquo;&eacute;chec, le jet
de VOLONT&Eacute; est &agrave; jouer tous les rounds. La non

Some files were not shown because too many files have changed in this diff Show More