diff --git a/module/actor-sheet.js b/module/actor-sheet.js index addb05e3..3306bb30 100644 --- a/module/actor-sheet.js +++ b/module/actor-sheet.js @@ -30,8 +30,7 @@ export class RdDActorSheet extends ActorSheet { dragDrop: [{ dragSelector: ".item-list .item", dropSelector: null }], editCaracComp: false, showCompNiveauBase: false, - montrerArchetype: false, - hideControls: true + vueDetaillee: false }); } @@ -80,7 +79,7 @@ export class RdDActorSheet extends ActorSheet { formData.competences.forEach(item => { item.visible = !this.options.showCompNiveauBase || !RdDItemCompetence.isNiveauBase(item); - RdDItemCompetence.levelUp(item); + RdDItemCompetence.levelUp(item, formData.data.compteurs.experience.value); }); Object.values(formData.data.carac).forEach(c => { @@ -414,7 +413,7 @@ export class RdDActorSheet extends ActorSheet { }); } - html.find('#show-hide-competences').click(async event => { + html.find('.show-hide-competences').click(async event => { this.options.showCompNiveauBase = !this.options.showCompNiveauBase; this.render(true); }); @@ -422,13 +421,9 @@ export class RdDActorSheet extends ActorSheet { this.options.editCaracComp = !this.options.editCaracComp; this.render(true); }); - html.find('#show-hide-archetype').click(async event => { - this.options.montrerArchetype = !this.options.montrerArchetype; - this.render(true); - }); - html.find('.lock-unlock-controls').click(async event => { - console.log("CONTROLS", this.options.hideControls) - this.options.hideControls = !this.options.hideControls; + html.find('.vue-detaillee').click(async event => { + console.log("CONTROLS", this.options.vueDetaillee) + this.options.vueDetaillee = !this.options.vueDetaillee; this.render(true); }); diff --git a/module/actor.js b/module/actor.js index e9042d51..66675976 100644 --- a/module/actor.js +++ b/module/actor.js @@ -922,6 +922,36 @@ export class RdDActor extends Actor { } } + async updateCompetenceStress(idOrName) { + const competence = this.getCompetence(idOrName); + if (!competence) { + return; + } + const compData = Misc.data(competence); + const niveau = Number(compData.data.niveau); + const stressTransforme = Misc.data(this).data.compteurs.experience.value; + const xpRequis = RdDItemCompetence.getCompetenceNextXp(niveau) - compData.data.xp; + if (stressTransforme <= 0 || niveau >= compData.data.niveau_archetype || xpRequis <=0) { + ui.notifications.info(`La compétence ne peut pas augmenter! + stress disponible: ${stressTransforme} + expérience requise: ${xpRequis} + niveau : ${niveau} + archétype : ${compData.data.niveau_archetype}`); + return; + } + const xpUtilise = Math.min(stressTransforme, xpRequis); + const stressTransformeRestant = Math.max(0, stressTransforme - xpUtilise); + const gainNiveau = xpUtilise>=xpRequis ? 1 : 0; + + await this.update({ "data.compteurs.experience.value": stressTransformeRestant }); + const nouveauNiveau = niveau + gainNiveau; + await competence.update({ + "data.xp": Math.max(compData.data.xp - xpRequis, 0), + "data.niveau": nouveauNiveau, + }); + this.updateExperienceLog('Dépense stress', xpUtilise, `Stress en ${competence.name} ${gainNiveau? "pour passer à "+nouveauNiveau : ""}`); + } + /* -------------------------------------------- */ async updateCreatureCompetence(idOrName, fieldName, compValue) { let competence = this.getCompetence(idOrName); diff --git a/module/item-competence.js b/module/item-competence.js index 4a7c246c..8abae8cf 100644 --- a/module/item-competence.js +++ b/module/item-competence.js @@ -84,7 +84,7 @@ export class RdDItemCompetence extends Item { /* -------------------------------------------- */ static getVoieDraconic(competences, voie) { - return RdDItemCompetence.findCompetence(competences.filter(it => RdDItemCompetence.isDraconic(it) ), voie); + return RdDItemCompetence.findCompetence(competences.filter(it => RdDItemCompetence.isDraconic(it)), voie); } /* -------------------------------------------- */ @@ -145,11 +145,11 @@ export class RdDItemCompetence extends Item { static computeEconomieXPTronc(competences) { return competenceTroncs.map( list => list.map(name => RdDItemCompetence.findCompetence(competences, name)) - // calcul du coût xp jusqu'au niveau 0 maximum - .map(it => RdDItemCompetence.computeDeltaXP(it?.data.base ?? -11, Math.min(it?.data.niveau ?? -11, 0))) - .sort(Misc.ascending()) - .splice(0, list.length-1) // prendre toutes les valeurs sauf l'une des plus élevées - .reduce(Misc.sum(), 0) + // calcul du coût xp jusqu'au niveau 0 maximum + .map(it => RdDItemCompetence.computeDeltaXP(it?.data.base ?? -11, Math.min(it?.data.niveau ?? -11, 0))) + .sort(Misc.ascending()) + .splice(0, list.length - 1) // prendre toutes les valeurs sauf l'une des plus élevées + .reduce(Misc.sum(), 0) ).reduce(Misc.sum(), 0); } @@ -160,7 +160,6 @@ export class RdDItemCompetence extends Item { return competence_xp_cumul[to] - competence_xp_cumul[from]; } - /* -------------------------------------------- */ static computeCompetenceXPCost(competence) { const compData = Misc.data(competence); @@ -186,9 +185,15 @@ export class RdDItemCompetence extends Item { } /* -------------------------------------------- */ - static levelUp(itemData) { + static levelUp(itemData, stressTransforme) { itemData.data.xpNext = RdDItemCompetence.getCompetenceNextXp(itemData.data.niveau); - itemData.data.isLevelUp = itemData.data.xp >= itemData.data.xpNext; + const xpManquant = itemData.data.xpNext - itemData.data.xp; + itemData.data.isLevelUp = xpManquant <= 0; + itemData.data.isStressLevelUp = (xpManquant > 0 && stressTransforme >= xpManquant && itemData.data.niveau < itemData.data.niveau_archetype); + itemData.data.stressXpMax = 0; + if (xpManquant > 0 && stressTransforme > 0 && itemData.data.niveau < itemData.data.niveau_archetype) { + itemData.data.stressXpMax = Math.min(xpManquant , stressTransforme); + } } /* -------------------------------------------- */ diff --git a/packs/rappel-des-regles.db b/packs/rappel-des-regles.db index 94a5445b..9da93dee 100644 --- a/packs/rappel-des-regles.db +++ b/packs/rappel-des-regles.db @@ -1,5 +1,5 @@ {"_id":"3wVxF2IRf3c1lOxC","name":"Communication avec les créatures invoquées","content":"

Seul le haut-rêvant invocateur peut communiquer avec sa créature invoquée (Guerrier Sorde, Kanaillou, etc.) et ne peut le faire qu’oralement. Cela sous-entend que le haut-rêvant doit être en mesure de parler.

","img":"systems/foundryvtt-reve-de-dragon/icons/competence_hypnos.webp","folder":null,"sort":0,"permission":{"default":0,"jOzRscDxoXZWpGS6":3},"flags":{"core":{"sourceId":"Compendium.foundryvtt-reve-de-dragon.rappel-des-regles.3wVxF2IRf3c1lOxC"}}} -{"_id":"7uGrUHGdPu0EmIu2","name":"Documentation MJ/Joueurs","content":"

Préambule

\n

Ce système pour Foundry est une implémentation de Rêve de Dragon, un jeu de Denis Gerfaud, publié dans sa troisième édition par \"Le Scriptarium\". Rêve de Dragon est une marque déposée par \"Scriptarium\". Tous les droits leur en reviennent naturellement. 

\n

Merci à Scriptarium (Jidus et Roland Barthelémy) pour l'autorisation d'utilisation des silhouettes de créatures et les Terres Médianes du Rêve.

\n

Crédits : 

\n\n

Pour nous contacter : https://discord.gg/pPSDNJk  , channel #reve-de-dragon

\n

Créer un Personnage

\n

Tout se fait manuellement à l'heure actuelle, il convient donc procéder comme suit :

\n

Caractéristiques, compétences, équipement

\n\n

Haut-Rêvant

\n

Si votre personnage est haut-rêvant, allez dans le menu Compendium.

\n\n

C'est aussi dans l'onglet Haut-Rêve du personnage que vous pouvez ajouter des têtes, queues, souffles de dragons, (ouvrez le compendium correspondant et faites glisser/déplacer), ainsi que modifier le seuil de rêve.

\n

Partie haute

\n

Les principaux compteurs (vie, endurance, fatigue et rêve, sonné) sont visibles dans la partie haute. Un clic sur le rêve à cet endroit permet de faire un jet de points actuels de rêve (par exemple, un jet de résistance).

\n

Plusieurs boutons sont disponibles:

\n\n

Combat

\n

Pour l'initiative et les attaques, des options sont disponibles sur le token (menu contextuel). A droite, l'initiative (préfixe I:), à gauche les attaques (préfixe A:).

\n

Une fois l'initiative réglée, l'attaquant sélectionne sa cible, puis utilise l'option d'attaque avec cette arme souhaitée (il peut aussi utiliser l'arme dans la feuille de persionnage). La fenêtre de jet de résolution est alors ouverte pour choisir sa difficulté libre, et différents ajustements liés aux conditions et tactiques. 

\n

Si l'attaque réussit, le défenseur recevra un message dans le tchat avec ses actions de défense -ou d'encaissement- disponibles, selon ses compétences : Encaisser, Esquiver, Parer, ...

\n

Un click sur ces actions génère le jet de riposte et produit les résultats. En cas d'échec, le défenseur aura de nouveau un message lui demandant d'encaisser, pour lui donner l'opportunité de faire appel à la chance ou à la destinée.

\n

Si décidément ce n'est pas son jour, il peut cliquer sur le lien pour encaisser, les blessures et l'état général sont automatiquement mis à jour.

\n

Faire un test de Compétence / Caractéristique

\n

Pour réaliser un jet, il suffit de cliquer sur le nom d'une caractéristique, sur une compétence ou sur un objet. Ce clic ouvre la boite de dialogue des jets, qui permet de paramétrer les différentes options (difficulté, compétence/carac, etc). Le lancer affiche les résultats dans le tchat, avec le résultat, la qualité de la réussite, les points d'expérience éventuels à répartir (pour les caractéristiques dérivées) et les points de taches.

\n

L'état général du personnage est automatiquement pris en compte.

\n

De nombreux cas particuliers (interprêter une oeuvre, cuisiner, recette alchimiques, tâches de lecture, de soins, ...) sont aussi disponibles (savoirs et tâches).

\n

Haut Rêve

\n

Pour monter dans les Terres Médianes, il suffit de cliquer sur l'un des boutons \"Monter dans les Terres Médianes!\" sur la feuille de personnage.

\n

La fiche des TMR apparait alors, vous permettant de vous déplacer. Le point de rêve de montée, la fatigue, les rencontres, les cases humides sont automatiquement gérés.

\n

Lorsque vous êtes sur la bonne case, il vous suffit de cliquer sur 'Lancer le sort', qui ouvre la boite de dialogue du lancement.

\n

Si un signe draconique peut être lu dans cette case, il suffit de cliquer sur 'Lire un signe draconique', qui ouvre la boite de dialogue de lecture.

\n

Divers

\n

Certains raccourcis de commandes sont disponibles directement dans le tchat, quelques exemples:

\n\n

Ce qui n'est pas implémenté

\n\n

","img":"systems/foundryvtt-reve-de-dragon/styles/img/logo.webp","folder":null,"sort":0,"permission":{"default":0,"Q4cUvqxCxMoTJXDL":3},"flags":{"exportSource":{"world":"world-rdd-fontaine-ortigrise","system":"foundryvtt-reve-de-dragon","coreVersion":"0.7.9","systemVersion":"1.3.51"},"core":{"sourceId":"Compendium.foundryvtt-reve-de-dragon.rappel-des-regles.7uGrUHGdPu0EmIu2"}}} +{"_id":"7uGrUHGdPu0EmIu2","name":"Documentation MJ/Joueurs","content":"

Préambule

\n

Ce système pour Foundry est une implémentation de Rêve de Dragon, un jeu de Denis Gerfaud, publié dans sa troisième édition par \"Le Scriptarium\". Rêve de Dragon est une marque déposée par \"Scriptarium\". Tous les droits leur en reviennent naturellement. 

\n

Merci à Scriptarium (Jidus et Roland Barthelémy) pour l'autorisation d'utilisation des silhouettes de créatures et les Terres Médianes du Rêve.

\n

Crédits : 

\n\n

Pour nous contacter : https://discord.gg/pPSDNJk  , channel #reve-de-dragon

\n

Créer un Personnage

\n

Tout se fait manuellement à l'heure actuelle, il convient donc procéder comme suit :

\n

Caractéristiques, compétences, équipement

\n\n

Pour aller plus loin sur les compétences:

\n\n

Haut-Rêvant

\n

Si votre personnage est haut-rêvant, allez dans le menu Compendium.

\n\n

C'est aussi dans l'onglet Haut-Rêve du personnage que vous pouvez ajouter des têtes, queues, souffles de dragons, (ouvrez le compendium correspondant et faites glisser/déplacer), ainsi que modifier le seuil de rêve.

\n

Partie haute

\n

Les principaux compteurs (vie, endurance, fatigue et rêve, sonné) sont visibles dans la partie haute. Un clic sur le rêve à cet endroit permet de faire un jet de points actuels de rêve (par exemple, un jet de résistance).

\n

Plusieurs boutons sont disponibles:

\n\n

Combat

\n

Pour l'initiative et les attaques, des options sont disponibles sur le token (menu contextuel). A droite, l'initiative (préfixe I:), à gauche les attaques (préfixe A:).

\n

Une fois l'initiative réglée, l'attaquant sélectionne sa cible, puis utilise l'option d'attaque avec cette arme souhaitée (il peut aussi utiliser l'arme dans la feuille de persionnage). La fenêtre de jet de résolution est alors ouverte pour choisir sa difficulté libre, et différents ajustements liés aux conditions et tactiques. 

\n

Si l'attaque réussit, le défenseur recevra un message dans le tchat avec ses actions de défense -ou d'encaissement- disponibles, selon ses compétences : Encaisser, Esquiver, Parer, ...

\n

Un click sur ces actions génère le jet de riposte et produit les résultats. En cas d'échec, le défenseur aura de nouveau un message lui demandant d'encaisser, pour lui donner l'opportunité de faire appel à la chance ou à la destinée.

\n

Si décidément ce n'est pas son jour, il peut cliquer sur le lien pour encaisser, les blessures et l'état général sont automatiquement mis à jour.

\n

Faire un test de Compétence / Caractéristique

\n

Pour réaliser un jet, il suffit de cliquer sur le nom d'une caractéristique, sur une compétence ou sur un objet. Ce clic ouvre la boite de dialogue des jets, qui permet de paramétrer les différentes options (difficulté, compétence/carac, etc). Le lancer affiche les résultats dans le tchat, avec le résultat, la qualité de la réussite, les points d'expérience éventuels à répartir (pour les caractéristiques dérivées) et les points de taches.

\n

L'état général du personnage est automatiquement pris en compte.

\n

De nombreux cas particuliers (interprêter une oeuvre, cuisiner, recette alchimiques, tâches de lecture, de soins, ...) sont aussi disponibles (savoirs et tâches).

\n

Haut Rêve

\n

Pour monter dans les Terres Médianes, il suffit de cliquer sur l'un des boutons \"Monter dans les Terres Médianes!\" sur la feuille de personnage.

\n

La fiche des TMR apparait alors, vous permettant de vous déplacer. Le point de rêve de montée, la fatigue, les rencontres, les cases humides sont automatiquement gérés.

\n

Lorsque vous êtes sur la bonne case, il vous suffit de cliquer sur 'Lancer le sort', qui ouvre la boite de dialogue du lancement.

\n

Si un signe draconique peut être lu dans cette case, il suffit de cliquer sur 'Lire un signe draconique', qui ouvre la boite de dialogue de lecture.

\n

Divers

\n

Certains raccourcis de commandes sont disponibles directement dans le tchat, quelques exemples:

\n\n

Il y en a bien d'autres!

\n

 

\n

Ce qui n'est pas implémenté

\n\n

","img":"systems/foundryvtt-reve-de-dragon/styles/img/logo.webp","folder":null,"sort":0,"permission":{"default":0,"Q4cUvqxCxMoTJXDL":3},"flags":{"exportSource":{"world":"world-rdd-fontaine-ortigrise","system":"foundryvtt-reve-de-dragon","coreVersion":"0.7.9","systemVersion":"1.3.51"},"core":{"sourceId":"Compendium.foundryvtt-reve-de-dragon.rappel-des-regles.7uGrUHGdPu0EmIu2"}}} {"_id":"G2WDlZwZaEyH94Au","name":"Passeur fou","content":"

Non maîtrisé, le Passeur fou emporte immédiatement le demi- rêve du haut-rêvant jusqu’à la plus proche case où il a un sort en réserve, l’obligeant à le déclencher. Peu importe la distance, même si elle excède les 2d8. À distances égales, choisir le haut de la carte en priorité et tourner dans le sens des aiguilles d’une montre. Si aucun sort n’est en réserve, le Passeur fou emporte le demi-rêve du haut-rêvant dans une direction aléatoire et à un nombre de cases équivalent à sa force.

","img":"systems/foundryvtt-reve-de-dragon/styles/img/ui/tmp_main_r1.webp","folder":null,"sort":0,"permission":{"default":0,"jOzRscDxoXZWpGS6":3},"flags":{"core":{"sourceId":"Compendium.foundryvtt-reve-de-dragon.rappel-des-regles.G2WDlZwZaEyH94Au"}}} {"_id":"GRKYbbNDIHdzVNaj","name":"Note sur les invocations de créatures","content":"

Les créatures invoquées ne sont pas des hologrammes sans substance mais des présences physiques véritables. La plupart d’entre elles, comme les guerriers, peuvent être blessées, sonnées, tuées. À l’exception du Kanaillou, chaque type de créature invoquée ne peut accomplir qu’un genre de tâche spécifique. Le ciblage doit être fait, dans les limites de la portée, sur un point du sol libre de tout obstacle, où la créature puisse se matérialiser. La durée de l’invocation dépend de la tâche, mais ne peut excéder la fin de l’heure de naissance du haut-rêvant. À ce moment, la créature se dématérialise intégralement, ainsi que tout son équipement. Même chose si elle est tuée. Il est vain de songer à récupérer l’armure et les armes d’un Guerrier Sorde. Chaque type de créature est toujours invoqué dans une case spécifique et non pas dans n’importe quelle case du même genre. Par ailleurs, ces rituels obéissent à toutes les règles standard d’application des rituels.

","img":"systems/foundryvtt-reve-de-dragon/icons/competence_hypnos.webp","folder":null,"sort":0,"permission":{"default":0,"jOzRscDxoXZWpGS6":3},"flags":{"core":{"sourceId":"Compendium.foundryvtt-reve-de-dragon.rappel-des-regles.GRKYbbNDIHdzVNaj"}}} {"_id":"K42KNuBHizMppV5F","name":"Tourbillon rouge","content":"

Le Tourbillon rouge est un tourbillon vampire. Il fonctionne comme les Tourbillons blancs et noirs, sauf que chaque round tant qu’il n’est pas maîtrisé fait dériver le demi-rêve de 4 cases, draine 2 points de rêve et 1 point de vie.

\n

On peut se dérober normalement devant ces rencontres ou les refouler. Toutefois, leur refoulement coûte 2 points au lieu d’un, sauf le Tourbillon rouge qui en coûte 3.

","img":"systems/foundryvtt-reve-de-dragon/styles/img/ui/tmp_main_r1.webp","folder":null,"sort":0,"permission":{"default":0,"jOzRscDxoXZWpGS6":3},"flags":{"core":{"sourceId":"Compendium.foundryvtt-reve-de-dragon.rappel-des-regles.K42KNuBHizMppV5F"}}} diff --git a/styles/simple.css b/styles/simple.css index 0f2bb880..c9e26778 100644 --- a/styles/simple.css +++ b/styles/simple.css @@ -738,6 +738,15 @@ ul, li { flex: 1 1 5rem; background: var(--gradient-gold) !important; } +.niveau-archetype { + background: var(--gradient-silver-light) !important; +} +.fa-arrow-alt-circle-up.allouer-stress { + color: rgba(83, 60, 14, 0.8); +} +.fa-arrow-alt-circle-up.allouer-stress-level-up { + color: rgba(191, 149, 63, 0.8); +} .blessures-list ul { display: flex; diff --git a/templates/actor-sheet-competence-partial.html b/templates/actor-sheet-competence-partial.html index 65dcc4ee..0b422cb1 100644 --- a/templates/actor-sheet-competence-partial.html +++ b/templates/actor-sheet-competence-partial.html @@ -21,16 +21,22 @@ value="{{numberFormat data.xp_sort decimals=0 sign=false}}" data-dtype="number" {{#unless @root.options.editCaracComp}}disabled{{/unless}}/> {{/if}} - {{#if @root.options.montrerArchetype}} - - {{/if}} - {{#unless @root.options.hideControls}} + {{#if @root.options.vueDetaillee}}
+ {{#if data.stressXpMax}} + + + + {{/if}} + + {{#if @root.options.isGM}} + {{/if}}
- {{/unless}} + {{/if}} {{/if}} \ No newline at end of file diff --git a/templates/actor-sheet.html b/templates/actor-sheet.html index ada11fbb..09eb6f74 100644 --- a/templates/actor-sheet.html +++ b/templates/actor-sheet.html @@ -212,15 +212,14 @@ blocker/débloquer{{#if options.editCaracComp}}Verrouiller{{else}}Déverrouiller{{/if}} - filter/montrer tout{{#if options.showCompNiveauBase}}Montrer tout{{else}}Filtrer{{/if}} - filter/montrer l'archétype{{#if options.montrerArchetype}}Masquer l'archétype{{else}}Voir l'archétype{{/if}} - - {{#if options.hideControls}}Contrôles On{{else}}Contrôles Off{{/if}} - + filter/montrer tout + {{#if options.showCompNiveauBase}}Montrer tout{{else}}Filtrer{{/if}} + + + + {{#if options.vueDetaillee}}Vue simplifiée{{else}}Vue détaillée{{/if}} +
@@ -234,7 +233,7 @@ {{> "systems/foundryvtt-reve-de-dragon/templates/actor-sheet-categorie-competences-partial.html" competences=(sortCompetence competenceByCategory.tir) categorie="Compétences de Tir"}} {{> "systems/foundryvtt-reve-de-dragon/templates/actor-sheet-categorie-competences-partial.html" competences=(sortCompetence competenceByCategory.lancer) categorie="Compétences de Lancer"}} {{> "systems/foundryvtt-reve-de-dragon/templates/actor-sheet-categorie-competences-partial.html" competences=(sortCompetence competenceByCategory.connaissance) categorie="Connaissances"}} - {{#if (or data.attributs.hautrevant.value options.montrerArchetype)}} + {{#if (or data.attributs.hautrevant.value options.vueDetaillee)}} {{> "systems/foundryvtt-reve-de-dragon/templates/actor-sheet-categorie-competences-partial.html" competences=(sortCompetence competenceByCategory.draconic) categorie="Draconic"}} {{/if}} @@ -249,11 +248,14 @@ Total XP compétences {{calc.competenceXPTotal}} - {{#if options.montrerArchetype}} + {{#if options.vueDetaillee}} +
  • Niveaux d'archétype à répartir
  • {{#each calc.comptageArchetype as |archetype key|}} + {{#if (lt archetype.nombre archetype.nombreMax)}}
  • + {{/if}} {{/each}} {{/if}}