Compare commits
50 Commits
foundryvtt
...
v10
Author | SHA1 | Date | |
---|---|---|---|
54df875451 | |||
253a1bd433 | |||
e58d88fab6 | |||
41d2404de2 | |||
631ee0b801 | |||
ed9c574cd2 | |||
bb624e8e96 | |||
40f2ac8714 | |||
804fa3b784 | |||
d35e47824d | |||
37d3fa5bc5 | |||
8a12eb865c | |||
5baa94b3f0 | |||
37c2b6432d | |||
fc63835a71 | |||
d82a543860 | |||
2e76961ba7 | |||
a9f50bbc5e | |||
8ba3476d7b | |||
4e8f6e8872 | |||
727701bdcd | |||
dcc0f0acfd | |||
61eee66ebe | |||
c75d10f69b | |||
333bb051c1 | |||
1bf247db33 | |||
49fc2c9b0a | |||
9013376096 | |||
972459a08d | |||
1607629365 | |||
8f7efdad87 | |||
2dbe0dea4a | |||
5fc455fbad | |||
8a7e4d3a9e | |||
c10195f753 | |||
4d7317b964 | |||
7b1fa009bb | |||
71bb8a14e1 | |||
5444bc7fd8 | |||
debaf1da34 | |||
69e2ab9000 | |||
24218ed062 | |||
da4e18dc3c | |||
154a9b7a37 | |||
fb8189606b | |||
cfbfad27bd | |||
f541849306 | |||
d2d1891838 | |||
5580b6d59c | |||
40c45c30de |
302
changelog.md
302
changelog.md
|
@ -1,10 +1,298 @@
|
|||
==================================================================
|
||||
v0.9.2 - 05/09/2020
|
||||
# v10.7 - L'os de Sémolosse
|
||||
|
||||
Erreur de calcul sur points de vie
|
||||
Gestion différente des compétences "troncs"
|
||||
## v10.7.20 - la poigne de Sémolosse
|
||||
- correction de méthodes qui filtrent les items
|
||||
- recherche de cases TMR
|
||||
- recherche de tâches de lecture
|
||||
- recherche d'armure (pour le malus armure)
|
||||
- recherche de potions
|
||||
|
||||
==================================================================
|
||||
v0.9.1 - 03/09/2020
|
||||
## v10.7.20 - la poigne de Sémolosse
|
||||
- correction de l'empoignade
|
||||
- les items d'empoignade sont ajoutés par le MJ quand nécessaire
|
||||
- seul le joueur propriétaire du personnage peut effectuer ses choix et actions d'empoignade
|
||||
- les caractéristiques du défenseur sont utilisées pour la défense
|
||||
- la difficulté d'attaque est imposée au défenseur
|
||||
- les attaques particulières sont en finesse (p133)
|
||||
- on peut entraîner au sol dès 2 points d'empoignade
|
||||
- les actions liée à l'immobilisation sont proposées en fin de round
|
||||
|
||||
Initial official release
|
||||
## v10.7.19 - les fantômes de Sémolosse
|
||||
- les créatures ont maintenant le droit d'avoir des compétences de tir, lancer, mêlée, armes naturelles, parade.
|
||||
- les créatures armées utilisent la bonne phase d'initiative
|
||||
- correction des possessions
|
||||
- la difficulté de la défense est imposée par l'attaque
|
||||
- une attaque particulière de possession est en finesse
|
||||
- le rêve actuel des personnages est bien utilisé
|
||||
- correction des achats par le MJ sans acteur sélectionné
|
||||
|
||||
## v10.7.18 - le repos de Sémolosse
|
||||
- correction des dates de blessures qui ne marchaient plus
|
||||
|
||||
## v10.7.17 - le doigt du destin de Sémolosse
|
||||
- correction de la validation d'encaissement par le MJ
|
||||
|
||||
## v10.7.16 - la morsure de Sémolosse
|
||||
- correction de l'affichage des objets suite à confusion
|
||||
- correction de liens dans la liste des équipements
|
||||
|
||||
## v10.7.14 - l'expérience de Sémolosse
|
||||
- Affichage des personnages accordés sur les fiches des entités
|
||||
- Refonte du journal d'expérience
|
||||
- disponible pour les personnages des joueurs
|
||||
- explication "comptable" des changements (dépense ou ajout, changements de niveaux, ...)
|
||||
- tri alphabétique des différentes listes (sorts, recettes, oeuvres, ...)
|
||||
|
||||
## v10.7.13 - l'armure de Sémolosse
|
||||
- Fix: en cas d'armure variable, la détérioration diminue le dé d'armure
|
||||
|
||||
## v10.7.12
|
||||
- Fix: si le MJ gère les changements de jours, l'option "sieste" de la fenêtre de repos est prise par défaut si chateau dormant n'est pas passé
|
||||
|
||||
## v10.7.11 - Le Pugilat de Sémolosse
|
||||
- Fix sur la projection au sol.
|
||||
|
||||
## v10.7.10 - Le Pugilat de Sémolosse
|
||||
- Gestion de l'empoignade
|
||||
- Corrections sur l'initiative
|
||||
- Correction sur l'equipement des vêtements et bijoux
|
||||
|
||||
## v10.7.9 - Le Pugilat de Sémolosse
|
||||
|
||||
- Gestion assistée de l'empoignade
|
||||
1. On selectionne sa cible (ie le token qui va être empoigné)
|
||||
2. On lance une attaque avec l'"arme" _Empoignade_
|
||||
3. A ce stade, si la victime a une arme, on rappelle le point de règle d'engagement
|
||||
(page 134), et un bouton permet de confirmer l'empoignade
|
||||
4. L'empoigneur fait son jet
|
||||
5. Si réussite, l'empoigné peut se défendre, avec gestion du premier round d'engagement
|
||||
(ie Esquive autorisée ou pas)
|
||||
- 4 bis. et 5 bis. L'empoigné, à son tour, peut tenter de se libérer, toujours en cliquant sur l'action "Empoignade"
|
||||
6. Selon le résultat, incrément/décrément des points d'emp
|
||||
7. Retour en 4., ou si 2 points d'Emp, alors 8.
|
||||
8. Affichage des options disponibles pour l'empoigneur : perte d'endurance, projection au
|
||||
sol ou entrainer au sol. Ces 3 options sont gérées automatiquement ensuite, selon le
|
||||
bouton cliqué par l'empoigneur.
|
||||
|
||||
Les empoignades sont des "items" supprimées à la fin d'un combat, qui peuvent aussi être
|
||||
gérés par le MJ au cas ou. Hors combat, penser à les supprimer (ou commencer et
|
||||
arrêter un combat).
|
||||
|
||||
## v10.7.7 - Les bobos de Sémolosse
|
||||
- Mise à jour du texte de l'heure pour les joueurs
|
||||
- L'horloge n'empêche plus de sélectionner les tokens dessous
|
||||
- _Lecture & Détection d'Aura_ sous Hypnos sont des rituels
|
||||
- _Lire les étoiles_ pour les joueurs de nouveau fonctionnel
|
||||
- Ajout de logs pour comprendre un cas d'échec des achatVente
|
||||
|
||||
## v10.7.6 - L'origine des maux de Sémolosse
|
||||
- Calendrier
|
||||
- fix du ré-affichage de l'horloge qui ne marchait pas pour les joueurs
|
||||
- l'horloge ne se ferme plus sur Escape
|
||||
- amélioration d'affichage
|
||||
- couleurs jour/nuit plus marquées
|
||||
- Divers
|
||||
- correction de l'affichage de quantités diminuées d'herbes dans les contenants ouvert
|
||||
- ajout d'un bouton pour diminuer les quantités dans l'équipement (si quantité > 1)
|
||||
- ajout de la signature de l'acteur sur les blessures qu'il a causées
|
||||
|
||||
- Magie
|
||||
- correction des bonus de cases pour les sorts en Fleuve
|
||||
|
||||
## v10.7.5 - La montre-gousset de Sémolosse
|
||||
- Amélioration de la fenêtre calendrier
|
||||
* plus compacte
|
||||
* horloge analogique (optionnelle)
|
||||
* minimizable (juste la barre de titre)
|
||||
* normalement compatible pop-out
|
||||
|
||||
## v10.7.4 - Les ligatures de Sémolosse
|
||||
- Corrections diverses
|
||||
- Correction des boutons pour déclencher un sort en réserve avec réserve en sécurité ou réserve extensible
|
||||
- le lien pour les jets de vie suite à une blessure critique est remplacé par un bouton
|
||||
- déplacement des tâches et boutons de chirurgie dans l'onglet savoirs et tâches
|
||||
- correction de l'affichage des bonus de cases des sorts
|
||||
- corrections des queues non-refoulables dans le compendium
|
||||
|
||||
## v10.7.3 - Les tisanes de Sémolosse
|
||||
- Soins
|
||||
- on peut de nouveau boire une potion de soins enchantée
|
||||
- les potions non enchantées donnent de nouveau un bonus au prochain jet de récupération
|
||||
- Une fois les soins complets faits, le bonus aux soins complets fournis par les premiers soins est masqué
|
||||
|
||||
- Horloge
|
||||
- A l'heure de Couronne pile, les aiguilles des heures et des minutes pointent sur couronne (comme une montre) au lieu d'avoir l'aiguille des heures 15° à gauche
|
||||
|
||||
## v10.7.2 - les maux de dents de Sémolosse
|
||||
- correction des récupérations de blessures
|
||||
- la fin de château dormant se passe normalement
|
||||
|
||||
## v10.7.1 - L'os de Sémolosse
|
||||
- Fix rapide sur les jets de carac qui n'étaient plus possibles
|
||||
|
||||
## v10.7.0 - L'os de Sémolosse
|
||||
- gestion des blessures en items
|
||||
- soins du token ciblé par menu contextuel (comme le combat)
|
||||
- automatisation des soins et de l'affichage de l'avancement des soins
|
||||
- support des changements d'opérants
|
||||
|
||||
---
|
||||
# v10.6 - Les recherches de Pralinor le Goûteux
|
||||
|
||||
## v10.6.25 - Fix sur l'astrologie
|
||||
|
||||
## v10.6.22 - le nuage de lait dans le thé de Pralinor
|
||||
- Amélioration de l'affichage de l'horloge
|
||||
- Fix: affichage des points de guérison dans les potions
|
||||
|
||||
## v10.6.21 - La théière de Pralinor
|
||||
- Astrologie
|
||||
- le thème astral est directement dans la fenêtre d'astrologie
|
||||
- la roue des heures sert d'horloge
|
||||
- sélectionner un personnage ajuste le thème astral pour son heure de naissance
|
||||
- sélectionner le nombre astral d'un jour ajuste le thème astral
|
||||
|
||||
- Fix: les PNJs peuvent de nouveau dormir
|
||||
|
||||
## v10.6.20 - Les Oracles de Pralinor: vous mangerez à Couronne
|
||||
- Ajout de la fenêtre pour effectuer un thème astral
|
||||
|
||||
## v10.6.19 - La cerise de Pralinor
|
||||
- les joueurs peuvent chercher dans les commerces avec un droit limité/observateur
|
||||
- simplifications des fins de tours et nombre d'utilisations
|
||||
- ajout du _Haubert d'Oniros_ dans le compendium de sorts
|
||||
|
||||
## v10.6.17 - Les désordres de Pralinor
|
||||
- le contenu des casseroles et autres contenants est maintenant trié dans l'ordre alphabétique
|
||||
- les objets dupliqués du compendium d'équipement sont de nouveaux uniques
|
||||
|
||||
## v0.6.16 - Le pardon de Pralinor
|
||||
- Ajout d'un commerce _Liste d'équipement_ dans les archétypes de PNJs
|
||||
- Séparations d'équipements groupés et corrections de quelques objets & herbes
|
||||
- On peut éditer les armes stockées dans un commerce
|
||||
|
||||
## v10.6.15 - les digestifs de Pralinor
|
||||
- amélioration des messages de sommeil (nombre d'heure dormies, uniquement les
|
||||
récupérations de rêve en dessous du seuil, affichage de la récupération d'endurance
|
||||
qui avait disparu, meilleur message sur le jet de moral)
|
||||
- les insomnies ne durent bien que 12h draconique à partir du prochain
|
||||
Chateau Dormant (elles pouvaient durer 3 nuits suite à une erreur).
|
||||
- la recherche dans l'équipement affiche correctement les conteneurs dans lesquels les
|
||||
objets trouvés sont rangés
|
||||
|
||||
## v10.6.14 - la digestion de Pralinor
|
||||
- Chateau dormant
|
||||
- la situation du jet de moral peut être choisie lorsque l'on dort
|
||||
- les queues de dragon "insomnie" empêchent de dormir, et de rêver
|
||||
- ajout d'une option pour meilleure gestion de Chateau Dormant par le MJ
|
||||
- avec cette option, à la fin Chateau Dormant, une fenêtre permet au gardien de
|
||||
positionner pour chaque joueur:
|
||||
- le stress de la journée
|
||||
- les heures de sommeil
|
||||
- la situation du jet de moral (neutre/heureux/malheureux)
|
||||
|
||||
- l'affichage des heures Chateau Dormant et Poisson Acrobate est correct
|
||||
- le jet de moral en situation neutre fait maintenant retourner le moral vers 0, et
|
||||
n'affecte plus un moral à 0.
|
||||
## v10.6.13 - la cave de Pralinor
|
||||
- on peut maintenant chercher dans l'inventaire des commerces
|
||||
- l'inventaire est correctement affiché en entier après suppression de la recherche
|
||||
- le message de chateau dormant reflète correctement un jet de moral neutre qui passe le moral de 0 à +1
|
||||
|
||||
## v10.6.12 - l'index de Pralinor
|
||||
- On peut désormais chercher dans l'inventaire comme dans les compétences
|
||||
|
||||
## v10.6.11 - l'empoisonnement de Pralinor
|
||||
- La récupération est bloquée par les maladies. Pas de récupération de vie ou de blessures possibles sous l'effet d'un poison ou d'une maladie
|
||||
- ajout d'un "poison" pour bloquer la récupération sous Griffe Morbide de Thanatos.
|
||||
Ajout du lien vers l'objet du compendium dans la description MJ,, qui pourra donc
|
||||
ajouter ce "poison" à la victime pour empêcher ses guérisons de vie ou blessure.
|
||||
|
||||
## v10.6.10
|
||||
- Correction de l'édition des description
|
||||
- Amélioration des descriptions d'alchimie:
|
||||
- difficulté calculée automatiquement
|
||||
- Température pour les couleurs
|
||||
- La sustentation n'est plus concaténée dans certains cas (ce qui donnait 2+2=22)
|
||||
|
||||
## v10.6.8 : les bon mots de Pralinor
|
||||
- Dans la fenêtre de _recherche et tirages_, possibilité de chercher sur le nom des objets en plus des autres critères
|
||||
|
||||
## v10.6.7 : les grumelés de Pralinor
|
||||
- les objets peuvent être utilisés depuis la fenêtre d'un conteneur
|
||||
- dans les fenêtres de contenants, le contenu est correctement indenté
|
||||
- la présentation du contenu d'un sac est améliorée
|
||||
- le bouton Nouvel Objet n'est affiché que si on est propriétaire de l'acteur
|
||||
- la fenêtre de vente permet de nouveau de choisir les quantités à vendre
|
||||
|
||||
## v10.6.6
|
||||
- Corrections d'armes rudimentaires
|
||||
- Inversion: Taille puis poids
|
||||
- Suppression d'une ligne de caractéristique vide (causée par la beauté)
|
||||
- Les messages liés aux compétences troncs deviennent des notifications
|
||||
## v10.6.5
|
||||
- Le +dom est de nouveau affiché
|
||||
- L'édition de caractéristiques des créatures fonctionne de nouveau
|
||||
|
||||
## v10.6.4 - La sénilité de Pralinor
|
||||
- Fenêtre _Recherches et tirages_
|
||||
- les résultats de recherches sur plusieurs compendiums sont triés
|
||||
- lors de recherches avec un ou des milieux sélectionnés:
|
||||
- le filtre sur la rareté utilise la rareté dans ces milieux
|
||||
- les tirages se basent sur la fréquence la plus élevées dans ces milieux
|
||||
- les filtres par utilisation prennent les potions en compte
|
||||
- les remèdes ont une catégorie de potion 'Remède' (et correspondent à une utilisation médicale)
|
||||
- ajout d'un filtre d'utilisation 'cuisine'
|
||||
|
||||
|
||||
# Divers
|
||||
- fix du cas où la transformation de 0 points de stress était concaténé, (passage de 29 à 290 avec 0 points transformés)
|
||||
- suppression du compendium de taches courantes, désormais inutile
|
||||
|
||||
## v10.6.3 - le baba-brandevin de Pralinor
|
||||
- les tâches de Soins sont maintenant déplacées à côté des blessures
|
||||
- on peut créer les tâches de soins directement avec un bouton par gravité.
|
||||
|
||||
- le round n'est plus bloqué si un acteur est sonné
|
||||
- un rare cas d'initiative négative pouvait empêcher de faire une initiative (à cause de l'état général)
|
||||
- dans une circonstance inconnue, une rencontre pouvait disparaître lors de la maîtrise. Ajout d'un message pour essayer d'obtenir des détails sur ce cas, et ajout d'une sécurité pour retrouver la rencontre (qui est conservée par la fenêtre de choix d'action).
|
||||
- les objets temporels (queues, souffles, poisons, maladies...) créés avant la gestion temporelle ne pouvaient pas être édités.
|
||||
- les particulières sur les jets de résistance de rêve actuel ne rapportent qu'un point d'expérience (p191)
|
||||
- pour lutter contre l'alcoolisme, les jets d'éthylisme sont considérés comme des jets de résistance, et n'apportent qu'un point d'expérience.
|
||||
## v10.6.2 - Le méli-mélo de Pralinor
|
||||
- Fenêtre _Recherches et tirages_
|
||||
- support de la recherche dans les compendiums choisis
|
||||
- suppression des commandes `/table milieu` et `/tirer milieu` (remplacées par la fenêtre de recherche)
|
||||
- ajout de fréquences à tous les équipements
|
||||
## v10.6.1 - Les recherches de Pralinor
|
||||
- Fenêtre _Recherches et tirages_
|
||||
- Amélioration des filtres de cuisine/utilisation
|
||||
- Ajout de catégories pour les poisons, urtiquants, ...
|
||||
- Bouton "Effacer les filtres" plus clair
|
||||
- Drag&drop depuis la recherche
|
||||
- Reprise du compendium
|
||||
- pour les plantes vénéneuses
|
||||
- pour les plantes venimeuses
|
||||
- ajout de sust pour les champignons et autres plantes comestibles
|
||||
|
||||
- Affichage de l'image du token pour les commerces non liés
|
||||
- Les pièces d'or sont appelées 'Dragon'
|
||||
|
||||
## v10.6.0 - Les recherches de Pralinor le Goûteux
|
||||
- Fenêtre _Recherches et tirages_
|
||||
- ajout de la fenêtre _Recherches et tirages_ avec filtres paramétrables
|
||||
- ouverture de la fenêtre: commande `/tirage` ou macro disponible dans les macros du système
|
||||
- support des équipements, faune & flore (depuis les compendiums configurés par défaut)
|
||||
- nombreux choix à activer
|
||||
- possibilité de montrer les objets correspondant à la sélection
|
||||
- possibilité de faire un tirage parmi ces objets (en prenant en compte la fréquence)
|
||||
|
||||
- Plantes & pèche
|
||||
- séparation des ingrédients et plantes comestibles
|
||||
- retour des poissons dans les compendiums
|
||||
- ajout d'un lien depuis les plantes toxiques/dangereuses vers la maladie/poison correspondante
|
||||
|
||||
- On peut de nouveau ouvrir les conteneurs dans une fenêtre séparée
|
||||
- Les jets de volontés d'éthylisme calculent correctement la difficulté liée au moral (ie: 0 au lieu de -22)
|
||||
- si le journal de chronologie est supprimée, on peut en choisir un autre
|
||||
- la taille du calendrier est ajustée pour éviter une présentation bancale quand le nom du mois est court
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
import { RdDActorSheet } from "./actor-sheet.js";
|
||||
import { RdDSheetUtility } from "./rdd-sheet-utility.js";
|
||||
import { RdDUtility } from "./rdd-utility.js";
|
||||
|
||||
export class RdDActorEntiteSheet extends RdDActorSheet {
|
||||
|
||||
|
@ -13,6 +15,12 @@ export class RdDActorEntiteSheet extends RdDActorSheet {
|
|||
dragDrop: [{ dragSelector: ".item-list .item", dropSelector: undefined }]
|
||||
});
|
||||
}
|
||||
async getData() {
|
||||
let formData = await super.getData();
|
||||
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
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/** @override */
|
||||
|
@ -35,6 +43,23 @@ export class RdDActorEntiteSheet extends RdDActorSheet {
|
|||
let compName = event.currentTarget.attributes.compname.value;
|
||||
this.actor.updateCreatureCompetence(compName, "dommages", parseInt(event.target.value));
|
||||
});
|
||||
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.confirmerSuppressionSubacteur(this, actorResonance, li, () => {
|
||||
console.log('Delete : ', actorId);
|
||||
this.removeSubacteur(actorId);
|
||||
RdDUtility.slideOnDelete(this, li);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async removeSubacteur(actorId) {
|
||||
let newResonances = this.actor.system.sante.resonnance.actors.filter(id => id != actorId);
|
||||
await this.actor.update({ 'system.sante.resonnance.actors': newResonances }, { renderSheet: false });
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -84,7 +84,7 @@ export class RdDActorSheet extends RdDBaseActorSheet {
|
|||
RdDItemArme.ajoutCorpsACorps(formData.combat, formData.competences, formData.system.carac);
|
||||
formData.esquives = this.actor.getCompetences("Esquive");
|
||||
formData.combat = RdDCombatManager.listActionsArmes(formData.combat, formData.competences, formData.system.carac);
|
||||
formData.empoignades = this.actor.getEmpoignades("Esquive");
|
||||
formData.empoignades = this.actor.getEmpoignades();
|
||||
|
||||
this.armesList = formData.combat;
|
||||
|
||||
|
@ -129,7 +129,11 @@ export class RdDActorSheet extends RdDBaseActorSheet {
|
|||
const actorId = li.data("actor-id");
|
||||
if (actorId) {
|
||||
const subActor = game.actors.get(actorId);
|
||||
RdDUtility.confirmerSuppressionSubacteur(this, subActor, li);
|
||||
RdDUtility.confirmerSuppressionSubacteur(this, subActor, li, () => {
|
||||
console.log('Delete : ', subActor.id);
|
||||
this.actor.removeSubacteur(subActor.id);
|
||||
RdDUtility.slideOnDelete(this, li);
|
||||
});
|
||||
}
|
||||
});
|
||||
this.html.find('.experiencelog-delete').click(async event => {
|
||||
|
@ -142,6 +146,13 @@ export class RdDActorSheet extends RdDBaseActorSheet {
|
|||
const key = Number(li.data("key") ?? -1);
|
||||
await this.actor.deleteExperienceLog(0, key + 1);
|
||||
});
|
||||
this.html.find("input.derivee-value[name='system.compteurs.stress.value']").change(async event => {
|
||||
this.actor.updateCompteurValue("stress", parseInt(event.target.value));
|
||||
});
|
||||
this.html.find("input.derivee-value[name='system.compteurs.experience.value']").change(async event => {
|
||||
this.actor.updateCompteurValue("experience", parseInt(event.target.value));
|
||||
});
|
||||
|
||||
this.html.find('.encaisser-direct').click(async event => {
|
||||
this.actor.encaisser();
|
||||
})
|
||||
|
@ -445,9 +456,9 @@ export class RdDActorSheet extends RdDBaseActorSheet {
|
|||
|
||||
/* -------------------------------------------- */
|
||||
async selectTypeOeuvreToCreate() {
|
||||
let typeObjets = RdDItem.getTypesOeuvres();
|
||||
let types = RdDItem.getTypesOeuvres();
|
||||
let content = `<span class="competence-label">Selectionnez le type d'oeuvre</span><select class="item-type">`;
|
||||
for (let typeName of typeObjets) {
|
||||
for (let typeName of types) {
|
||||
content += `<option value="${typeName}">${Misc.typeName('Item', typeName)}</option>`
|
||||
}
|
||||
content += '</select>';
|
||||
|
|
462
module/actor.js
462
module/actor.js
|
@ -37,13 +37,15 @@ import { RdDTimestamp } from "./time/rdd-timestamp.js";
|
|||
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 { TYPES } from "./item.js";
|
||||
|
||||
const POSSESSION_SANS_DRACONIC = {
|
||||
img: 'systems/foundryvtt-reve-de-dragon/icons/entites/possession.webp',
|
||||
name: 'Sans draconic',
|
||||
system: {
|
||||
niveau: 0,
|
||||
defaut_carac: "reve",
|
||||
defaut_carac: "reve-actuel",
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -98,7 +100,7 @@ export class RdDActor extends RdDBaseActor {
|
|||
|
||||
/* -------------------------------------------- */
|
||||
async cleanupConteneurs() {
|
||||
let updates = this.listItems('conteneur')
|
||||
let updates = this.itemTypes['conteneur']
|
||||
.filter(c => c.system.contenu.filter(id => this.getItem(id) == undefined).length > 0)
|
||||
.map(c => { return { _id: c._id, 'system.contenu': c.system.contenu.filter(id => this.getItem(id) != undefined) } });
|
||||
if (updates.length > 0) {
|
||||
|
@ -108,7 +110,7 @@ export class RdDActor extends RdDBaseActor {
|
|||
|
||||
canReceive(item) {
|
||||
if (this.isCreature()) {
|
||||
return item.type == 'competencecreature' || item.isInventaire();
|
||||
return item.type == TYPES.competencecreature || item.isInventaire();
|
||||
}
|
||||
if (this.isEntite()) {
|
||||
return item.type == 'competencecreature';
|
||||
|
@ -269,25 +271,26 @@ export class RdDActor extends RdDBaseActor {
|
|||
}
|
||||
|
||||
getDraconicOuPossession() {
|
||||
const possessions = this.items.filter(it => it.type == 'competencecreature' && it.system.ispossession)
|
||||
.sort(Misc.descending(it => it.system.niveau));
|
||||
if (possessions.length > 0) {
|
||||
return duplicate(possessions[0]);
|
||||
const possession = this.items.filter(it => it.type == TYPES.competencecreature && it.system.categorie == 'possession')
|
||||
.sort(Misc.descending(it => it.system.niveau))
|
||||
.find(it => true);
|
||||
if (possession) {
|
||||
return possession.clone();
|
||||
}
|
||||
const draconics = [...this.getDraconicList().filter(it => it.system.niveau >= 0),
|
||||
const draconics = [...this.getDraconicList().filter(it => it.system.niveau >= 0).map(it => it.clone()),
|
||||
POSSESSION_SANS_DRACONIC]
|
||||
.sort(Misc.descending(it => it.system.niveau));
|
||||
return duplicate(draconics[0]);
|
||||
return draconics[0];
|
||||
}
|
||||
|
||||
getPossession(possessionId) {
|
||||
return this.items.find(it => it.type == 'possession' && it.system.possessionid == possessionId);
|
||||
return this.items.find(it => it.type == TYPES.possession && it.system.possessionid == possessionId);
|
||||
}
|
||||
getPossessions() {
|
||||
return this.items.filter(it => it.type == 'possession');
|
||||
return this.items.filter(it => it.type == TYPES.possession);
|
||||
}
|
||||
getEmpoignades() {
|
||||
return this.items.filter(it => it.type == 'empoignade');
|
||||
return this.items.filter(it => it.type == TYPES.empoignade);
|
||||
}
|
||||
getDemiReve() {
|
||||
return this.system.reve.tmrpos.coord;
|
||||
|
@ -295,7 +298,7 @@ export class RdDActor extends RdDBaseActor {
|
|||
|
||||
/* -------------------------------------------- */
|
||||
async verifierPotionsEnchantees() {
|
||||
let potionsEnchantees = this.filterItems(it => it.type == 'potion' && it.system.categorie.toLowerCase().includes('enchant'));
|
||||
let potionsEnchantees = this.filterItems(it => it.system.categorie.toLowerCase().includes('enchant'), 'potion');
|
||||
for (let potion of potionsEnchantees) {
|
||||
if (!potion.system.prpermanent) {
|
||||
console.log(potion);
|
||||
|
@ -333,18 +336,12 @@ export class RdDActor extends RdDBaseActor {
|
|||
|
||||
/* -------------------------------------------- */
|
||||
hasArmeeMeleeEquipee() { // Return true si l'acteur possède au moins 1 arme de mêlée équipée
|
||||
let melee = this.items.filter(it => it.type == "arme" && it.system.equipe && it.system.competence != "")
|
||||
return (melee.length > 0)
|
||||
}
|
||||
isEmpoignadeEnCours() {
|
||||
return this.items.find(it => it.type == "empoignade" && it.system.pointsemp > 0)
|
||||
return this.itemTypes['arme'].find(it => it.system.equipe && it.system.competence != "")
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async roll() {
|
||||
if (this.isEmpoignadeEnCours()) {
|
||||
ui.notifications.warn("Une empoignade est en cours ! Normalement, vous ne pouvez rien faire d'autre que continuer l'empoignade ou la rompre.")
|
||||
}
|
||||
RdDEmpoignade.checkEmpoignadeEnCours(this)
|
||||
|
||||
const carac = mergeObject(duplicate(this.system.carac),
|
||||
{
|
||||
|
@ -783,7 +780,7 @@ export class RdDActor extends RdDBaseActor {
|
|||
async combattreReveDeDragon(force) {
|
||||
let rollData = {
|
||||
actor: this,
|
||||
competence: duplicate(this.getDraconicOuPossession()),
|
||||
competence: this.getDraconicOuPossession(),
|
||||
canClose: false,
|
||||
rencontre: await game.system.rdd.rencontresTMR.getReveDeDragon(force),
|
||||
tmr: true,
|
||||
|
@ -827,31 +824,40 @@ export class RdDActor extends RdDBaseActor {
|
|||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async updateCarac(caracName, caracValue) {
|
||||
async updateCarac(caracName, to) {
|
||||
if (caracName == "force") {
|
||||
if (Number(caracValue) > this.getTaille() + 4) {
|
||||
if (Number(to) > this.getTaille() + 4) {
|
||||
ui.notifications.warn("Votre FORCE doit être au maximum de TAILLE+4");
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (caracName == "reve") {
|
||||
if (caracValue > Misc.toInt(this.system.reve.seuil.value)) {
|
||||
this.setPointsDeSeuil(caracValue);
|
||||
if (to > Misc.toInt(this.system.reve.seuil.value)) {
|
||||
this.setPointsDeSeuil(to);
|
||||
}
|
||||
}
|
||||
if (caracName == "chance") {
|
||||
if (caracValue > Misc.toInt(this.system.compteurs.chance.value)) {
|
||||
this.setPointsDeChance(caracValue);
|
||||
if (to > Misc.toInt(this.system.compteurs.chance.value)) {
|
||||
this.setPointsDeChance(to);
|
||||
}
|
||||
}
|
||||
await this.update({ [`system.carac.${caracName}.value`]: caracValue });
|
||||
let selectedCarac = RdDActor._findCaracByName(this.system.carac, caracName);
|
||||
const from = selectedCarac.value
|
||||
await this.update({ [`system.carac.${caracName}.value`]: to });
|
||||
await ExperienceLog.add(this, XP_TOPIC.CARAC, from, to, caracName);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async updateCaracXP(caracName, caracXP) {
|
||||
async updateCaracXP(caracName, to) {
|
||||
if (caracName == 'Taille') {
|
||||
return;
|
||||
}
|
||||
let selectedCarac = RdDActor._findCaracByName(this.system.carac, caracName);
|
||||
if (!selectedCarac.derivee) {
|
||||
const from = Number(selectedCarac.xp);
|
||||
await this.update({ [`system.carac.${caracName}.xp`]: to });
|
||||
await ExperienceLog.add(this, XP_TOPIC.XPCARAC, from, to, caracName);
|
||||
}
|
||||
this.checkCaracXP(caracName);
|
||||
}
|
||||
|
||||
|
@ -863,16 +869,19 @@ export class RdDActor extends RdDBaseActor {
|
|||
let carac = RdDActor._findCaracByName(this.system.carac, caracName);
|
||||
if (carac) {
|
||||
carac = duplicate(carac);
|
||||
let xp = Number(carac.xp);
|
||||
let value = Number(carac.value);
|
||||
while (xp >= RdDCarac.getCaracNextXp(value) && xp > 0) {
|
||||
xp -= RdDCarac.getCaracNextXp(value);
|
||||
value++;
|
||||
const fromXp = Number(carac.xp);
|
||||
const fromValue = Number(carac.value);
|
||||
let toXp = fromXp;
|
||||
let toValue = fromValue;
|
||||
while (toXp >= RdDCarac.getCaracNextXp(toValue) && toXp > 0) {
|
||||
toXp -= RdDCarac.getCaracNextXp(toValue);
|
||||
toValue++;
|
||||
}
|
||||
carac.xp = xp;
|
||||
carac.value = value;
|
||||
carac.xp = toXp;
|
||||
carac.value = toValue;
|
||||
await this.update({ [`system.carac.${caracName}`]: carac });
|
||||
this.updateExperienceLog("Carac +", xp, caracName + " passée à " + value);
|
||||
await ExperienceLog.add(this, XP_TOPIC.XPCARAC, fromXp, toXp, caracName);
|
||||
await ExperienceLog.add(this, XP_TOPIC.CARAC, fromValue, toValue, caracName);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -880,17 +889,20 @@ export class RdDActor extends RdDBaseActor {
|
|||
async updateCompetenceXPAuto(idOrName) {
|
||||
let competence = this.getCompetence(idOrName);
|
||||
if (competence) {
|
||||
let xp = Number(competence.system.xp);
|
||||
let niveau = Number(competence.system.niveau);
|
||||
while (xp >= RdDItemCompetence.getCompetenceNextXp(niveau) && xp > 0) {
|
||||
xp -= RdDItemCompetence.getCompetenceNextXp(niveau);
|
||||
niveau++;
|
||||
const fromXp = Number(competence.system.xp);
|
||||
const fromNiveau = Number(competence.system.niveau);
|
||||
let toXp = fromXp;
|
||||
let toNiveau = fromNiveau;
|
||||
while (toXp >= RdDItemCompetence.getCompetenceNextXp(toNiveau) && toXp > 0) {
|
||||
toXp -= RdDItemCompetence.getCompetenceNextXp(toNiveau);
|
||||
toNiveau++;
|
||||
}
|
||||
await competence.update({
|
||||
"system.xp": xp,
|
||||
"system.niveau": niveau,
|
||||
"system.xp": toXp,
|
||||
"system.niveau": toNiveau,
|
||||
});
|
||||
this.updateExperienceLog("Compétence +", xp, competence.name + " passée à " + niveau);
|
||||
await ExperienceLog.add(this, XP_TOPIC.XP, fromXp, toXp, competence.name);
|
||||
await ExperienceLog.add(this, XP_TOPIC.NIVEAU, fromNiveau, toNiveau, competence.name);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -899,29 +911,33 @@ export class RdDActor extends RdDBaseActor {
|
|||
if (!competence) {
|
||||
return;
|
||||
}
|
||||
const stress = this.system.compteurs.experience.value;
|
||||
const niveau = Number(competence.system.niveau);
|
||||
const xpSuivant = RdDItemCompetence.getCompetenceNextXp(niveau);
|
||||
const xpRequis = xpSuivant - competence.system.xp;
|
||||
if (stress <= 0 || niveau >= competence.system.niveau_archetype) {
|
||||
const fromXp = competence.system.xp;
|
||||
const fromXpStress = this.system.compteurs.experience.value;
|
||||
const fromNiveau = Number(competence.system.niveau);
|
||||
const xpSuivant = RdDItemCompetence.getCompetenceNextXp(fromNiveau);
|
||||
const xpRequis = xpSuivant - fromXp;
|
||||
if (fromXpStress <= 0 || fromNiveau >= competence.system.niveau_archetype) {
|
||||
ui.notifications.info(`La compétence ne peut pas augmenter!
|
||||
stress disponible: ${stress}
|
||||
stress disponible: ${fromXpStress}
|
||||
expérience requise: ${xpRequis}
|
||||
niveau : ${niveau}
|
||||
niveau : ${fromNiveau}
|
||||
archétype : ${competence.system.niveau_archetype}`);
|
||||
return;
|
||||
}
|
||||
const xpUtilise = Math.max(0, Math.min(stress, xpRequis));
|
||||
const xpUtilise = Math.max(0, Math.min(fromXpStress, xpRequis));
|
||||
const gainNiveau = (xpUtilise >= xpRequis || xpRequis <= 0) ? 1 : 0;
|
||||
const nouveauNiveau = niveau + gainNiveau;
|
||||
const nouveauXp = gainNiveau > 0 ? Math.max(competence.system.xp - xpSuivant, 0) : (competence.system.xp + xpUtilise);
|
||||
const toNiveau = fromNiveau + gainNiveau;
|
||||
const newXp = gainNiveau > 0 ? Math.max(fromXp - xpSuivant, 0) : (fromXp + xpUtilise);
|
||||
await competence.update({
|
||||
"system.xp": nouveauXp,
|
||||
"system.niveau": nouveauNiveau,
|
||||
"system.xp": newXp,
|
||||
"system.niveau": toNiveau,
|
||||
});
|
||||
const stressTransformeRestant = Math.max(0, stress - xpUtilise);
|
||||
await this.update({ "system.compteurs.experience.value": stressTransformeRestant });
|
||||
this.updateExperienceLog('Dépense stress', xpUtilise, `Stress en ${competence.name} ${gainNiveau ? "pour passer à " + nouveauNiveau : ""}`);
|
||||
const toXpStress = Math.max(0, fromXpStress - xpUtilise);
|
||||
await this.update({ "system.compteurs.experience.value": toXpStress });
|
||||
|
||||
await ExperienceLog.add(this, XP_TOPIC.TRANSFORM, fromXpStress, toXpStress, `Dépense stress`);
|
||||
await ExperienceLog.add(this, XP_TOPIC.XP, fromXp, newXp, competence.name);
|
||||
await ExperienceLog.add(this, XP_TOPIC.NIVEAU, fromNiveau, toNiveau, competence.name);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
@ -945,51 +961,59 @@ export class RdDActor extends RdDBaseActor {
|
|||
|
||||
/* -------------------------------------------- */
|
||||
async updateCompetence(idOrName, compValue) {
|
||||
const competence = this.getCompetence(idOrName);
|
||||
if (competence) {
|
||||
const toNiveau = compValue ?? RdDItemCompetence.getNiveauBase(competence.system.categorie, competence.getCategories());
|
||||
this.notifyCompetencesTronc(competence, toNiveau);
|
||||
const fromNiveau = competence.system.niveau;
|
||||
await this.updateEmbeddedDocuments('Item', [{ _id: competence.id, 'system.niveau': toNiveau }]);
|
||||
await ExperienceLog.add(this, XP_TOPIC.NIVEAU, fromNiveau, toNiveau, competence.name, true);
|
||||
} else {
|
||||
console.log("Competence not found", idOrName);
|
||||
}
|
||||
}
|
||||
|
||||
notifyCompetencesTronc(competence, toNiveau) {
|
||||
const listTronc = RdDItemCompetence.getListTronc(competence.name).filter(it => {
|
||||
const autreComp = this.getCompetence(it);
|
||||
const niveauTr = autreComp?.system.niveau ?? 0;
|
||||
return niveauTr < 0 && niveauTr < toNiveau;
|
||||
});
|
||||
if (listTronc.length > 0) {
|
||||
ui.notifications.info(
|
||||
"Vous avez modifié une compétence 'tronc'. Vérifiez que les compétences suivantes évoluent ensemble jusqu'au niveau 0 : <br>"
|
||||
+ Misc.join(listTronc, '<br>'));
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async updateCompetenceXP(idOrName, toXp) {
|
||||
let competence = this.getCompetence(idOrName);
|
||||
if (competence) {
|
||||
let nouveauNiveau = compValue ?? RdDItemCompetence.getNiveauBase(competence.system.categorie);
|
||||
const tronc = RdDItemCompetence.getListTronc(competence.name).filter(it => {
|
||||
const comp = this.getCompetence(it);
|
||||
const niveauTr = competence ? competence.system.niveau : 0;
|
||||
return niveauTr < 0 && niveauTr < nouveauNiveau;
|
||||
});
|
||||
if (tronc.length > 0) {
|
||||
let message = "Vous avez modifié une compétence 'tronc'. Vérifiez que les compétences suivantes évoluent ensemble jusqu'au niveau 0 : ";
|
||||
for (let troncName of tronc) {
|
||||
message += "<br>" + troncName;
|
||||
}
|
||||
ui.notifications.info(message);
|
||||
if (isNaN(toXp) || typeof (toXp) != 'number') toXp = 0;
|
||||
const fromXp = competence.system.xp;
|
||||
this.checkCompetenceXP(idOrName, toXp);
|
||||
await this.updateEmbeddedDocuments('Item', [{ _id: competence.id, 'system.xp': toXp }]);
|
||||
await ExperienceLog.add(this, XP_TOPIC.XP, fromXp, toXp, competence.name, true);
|
||||
if (toXp > fromXp) {
|
||||
RdDUtility.checkThanatosXP(idOrName);
|
||||
}
|
||||
const update = { _id: competence.id, 'system.niveau': nouveauNiveau };
|
||||
await this.updateEmbeddedDocuments('Item', [update]); // Updates one EmbeddedEntity
|
||||
} else {
|
||||
console.log("Competence not found", idOrName);
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async updateCompetenceXP(idOrName, newXp) {
|
||||
async updateCompetenceXPSort(idOrName, toXpSort) {
|
||||
let competence = this.getCompetence(idOrName);
|
||||
if (competence) {
|
||||
if (isNaN(newXp) || typeof (newXp) != 'number') newXp = 0;
|
||||
this.checkCompetenceXP(idOrName, newXp);
|
||||
const update = { _id: competence.id, 'system.xp': newXp };
|
||||
await this.updateEmbeddedDocuments('Item', [update]); // Updates one EmbeddedEntity
|
||||
this.updateExperienceLog("XP", newXp, "XP modifié en " + competence.name);
|
||||
} else {
|
||||
console.log("Competence not found", idOrName);
|
||||
}
|
||||
RdDUtility.checkThanatosXP(idOrName);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async updateCompetenceXPSort(idOrName, compValue) {
|
||||
let competence = this.getCompetence(idOrName);
|
||||
if (competence) {
|
||||
if (isNaN(compValue) || typeof (compValue) != 'number') compValue = 0;
|
||||
const update = { _id: competence.id, 'system.xp_sort': compValue };
|
||||
await this.updateEmbeddedDocuments('Item', [update]); // Updates one EmbeddedEntity
|
||||
this.updateExperienceLog("XP Sort", compValue, "XP modifié en sort de " + competence.name);
|
||||
if (isNaN(toXpSort) || typeof (toXpSort) != 'number') toXpSort = 0;
|
||||
const fromXpSort = competence.system.xp_sort;
|
||||
await this.updateEmbeddedDocuments('Item', [{ _id: competence.id, 'system.xp_sort': toXpSort }]);
|
||||
await ExperienceLog.add(this, XP_TOPIC.XPSORT, fromXpSort, toXpSort, competence.name, true);
|
||||
if (toXpSort > fromXpSort) {
|
||||
RdDUtility.checkThanatosXP(idOrName);
|
||||
}
|
||||
} else {
|
||||
console.log("Competence not found", idOrName);
|
||||
}
|
||||
|
@ -999,26 +1023,12 @@ export class RdDActor extends RdDBaseActor {
|
|||
async updateCompetenceArchetype(idOrName, compValue) {
|
||||
let competence = this.getCompetence(idOrName);
|
||||
if (competence) {
|
||||
compValue = compValue ?? 0;
|
||||
const update = { _id: competence.id, 'system.niveau_archetype': compValue };
|
||||
await this.updateEmbeddedDocuments('Item', [update]); // Updates one EmbeddedEntity
|
||||
await this.updateEmbeddedDocuments('Item', [{ _id: competence.id, 'system.niveau_archetype': Math.max(compValue ?? 0, 0) }]);
|
||||
} else {
|
||||
console.log("Competence not found", idOrName);
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async updateExperienceLog(modeXP, valeurXP, raisonXP = 'Inconnue') {
|
||||
let d = new Date();
|
||||
let expLog = duplicate(this.system.experiencelog);
|
||||
expLog.push({
|
||||
mode: Misc.upperFirst(modeXP), valeur: valeurXP, raison: Misc.upperFirst(raisonXP),
|
||||
daterdd: game.system.rdd.calendrier.dateCourante(),
|
||||
datereel: `${d.getDate()}/${d.getMonth() + 1}/${d.getFullYear()}`
|
||||
});
|
||||
await this.update({ [`system.experiencelog`]: expLog });
|
||||
}
|
||||
|
||||
async deleteExperienceLog(from, count) {
|
||||
if (from >= 0 && count > 0) {
|
||||
let expLog = duplicate(this.system.experiencelog);
|
||||
|
@ -1027,24 +1037,27 @@ export class RdDActor extends RdDBaseActor {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async updateCompteurValue(fieldName, fieldValue, raison = 'Inconnue') {
|
||||
await this.update({ [`system.compteurs.${fieldName}.value`]: fieldValue });
|
||||
await this.addStressExperienceLog(fieldName, fieldValue, 'forcé: ' + raison);
|
||||
async updateCompteurValue(fieldName, to) {
|
||||
const from = this.system.compteurs[fieldName].value
|
||||
await this.update({ [`system.compteurs.${fieldName}.value`]: to });
|
||||
await this.addStressExperienceLog(fieldName, from, to, fieldName, true);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async addCompteurValue(fieldName, fieldValue, raison = 'Inconnue') {
|
||||
let oldValue = this.system.compteurs[fieldName].value;
|
||||
await this.update({ [`system.compteurs.${fieldName}.value`]: Number(oldValue) + Number(fieldValue) });
|
||||
await this.addStressExperienceLog(fieldName, fieldValue, raison);
|
||||
async addCompteurValue(fieldName, add, raison) {
|
||||
let from = this.system.compteurs[fieldName].value;
|
||||
const to = Number(from) + Number(add);
|
||||
await this.update({ [`system.compteurs.${fieldName}.value`]: to });
|
||||
await this.addStressExperienceLog(fieldName, from, to, raison);
|
||||
}
|
||||
|
||||
async addStressExperienceLog(fieldName, fieldValue, raison) {
|
||||
switch (fieldName) {
|
||||
case 'stress': case 'experience':
|
||||
await this.updateExperienceLog(fieldName, fieldValue, raison);
|
||||
async addStressExperienceLog(topic, from, to, raison, manuel) {
|
||||
switch (topic) {
|
||||
case 'stress':
|
||||
return await ExperienceLog.add(this, XP_TOPIC.STRESS, from, to, raison, manuel)
|
||||
case 'experience':
|
||||
return await ExperienceLog.add(this, XP_TOPIC.TRANSFORM, from, to, raison, manuel)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1101,21 +1114,17 @@ export class RdDActor extends RdDBaseActor {
|
|||
/* -------------------------------------------- */
|
||||
computeIsHautRevant() {
|
||||
if (this.isPersonnage()) {
|
||||
this.system.attributs.hautrevant.value = this.hasItemNamed('tete', 'don de haut-reve')
|
||||
this.system.attributs.hautrevant.value = this.itemTypes['tete'].find(it => Grammar.equalsInsensitive(it.name, 'don de haut-reve'))
|
||||
? "Haut rêvant"
|
||||
: "";
|
||||
}
|
||||
}
|
||||
|
||||
hasItemNamed(type, name) {
|
||||
name = Grammar.toLowerCaseNoAccent(name);
|
||||
return this.listItems(type).find(it => Grammar.toLowerCaseNoAccent(it.name) == name);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async computeMalusArmure() {
|
||||
if (this.isPersonnage()) {
|
||||
const malusArmure = this.filterItems(it => it.type == 'armure' && it.system.equipe)
|
||||
const malusArmure = this.filterItems(it => it.system.equipe, 'armure')
|
||||
.map(it => it.system.malus ?? 0)
|
||||
.reduce(Misc.sum(), 0);
|
||||
// Mise à jour éventuelle du malus armure
|
||||
|
@ -1288,8 +1297,7 @@ export class RdDActor extends RdDBaseActor {
|
|||
|
||||
/* -------------------------------------------- */
|
||||
buildTMRInnaccessible() {
|
||||
const tmrInnaccessibles = this.filterItems(it => Draconique.isCaseTMR(it) &&
|
||||
EffetsDraconiques.isInnaccessible(it));
|
||||
const tmrInnaccessibles = this.filterItems(it => Draconique.isCaseTMR(it) && EffetsDraconiques.isInnaccessible(it));
|
||||
return tmrInnaccessibles.map(it => it.system.coord);
|
||||
}
|
||||
|
||||
|
@ -1353,21 +1361,46 @@ export class RdDActor extends RdDBaseActor {
|
|||
|
||||
/* -------------------------------------------- */
|
||||
async finDeRound(options = { terminer: false }) {
|
||||
await this.$finDeRoundSuppressionEffetsTermines(options);
|
||||
await this.$finDeRoundBlessuresGraves();
|
||||
await this.$finDeRoundSupprimerObsoletes();
|
||||
await this.$finDeRoundEmpoignade();
|
||||
}
|
||||
|
||||
async $finDeRoundSuppressionEffetsTermines(options) {
|
||||
for (let effect of this.getEffects()) {
|
||||
if (effect.duration.type !== 'none' && (effect.duration.remaining <= 0 || options.terminer)) {
|
||||
await effect.delete();
|
||||
ChatMessage.create({ content: `${this.name} n'est plus ${Misc.lowerFirst(game.i18n.localize(effect.system.label))} !` });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async $finDeRoundBlessuresGraves() {
|
||||
if (this.isPersonnage() || this.isCreature()) {
|
||||
const nbGraves = this.filterItems(it => it.isGrave(), 'blessure').length
|
||||
const nbGraves = this.filterItems(it => it.isGrave(), 'blessure').length;
|
||||
if (nbGraves > 0) {
|
||||
// Gestion blessure graves : -1 pt endurance par blessure grave
|
||||
await this.santeIncDec("endurance", - nbGraves);
|
||||
await this.santeIncDec("endurance", -nbGraves);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async $finDeRoundSupprimerObsoletes() {
|
||||
const obsoletes = []
|
||||
.concat(this.itemTypes[TYPES.empoignade].filter(it => it.system.pointsemp <= 0))
|
||||
.concat(this.itemTypes[TYPES.possession].filter(it => it.system.compteur < -2 || it.system.compteur > 2))
|
||||
.map(it => it.id);
|
||||
await this.deleteEmbeddedDocuments('Item', obsoletes);
|
||||
}
|
||||
|
||||
async $finDeRoundEmpoignade(){
|
||||
const immobilisations = this.itemTypes[TYPES.empoignade].filter(it => it.system.pointsemp >= 2 && it.system.empoigneurid == this.id);
|
||||
immobilisations.forEach(emp => RdDEmpoignade.onImmobilisation(this,
|
||||
game.actors.get(emp.system.empoigneid),
|
||||
emp
|
||||
))
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
async setSonne(sonne = true) {
|
||||
if (this.isEntite()) {
|
||||
|
@ -1672,9 +1705,9 @@ export class RdDActor extends RdDBaseActor {
|
|||
await this.rollTache(tache.id);
|
||||
}
|
||||
}
|
||||
async actionHerbe(item, onActionItem = async () => {}) {
|
||||
async actionHerbe(item, onActionItem = async () => { }) {
|
||||
if (item.isHerbeAPotion()) {
|
||||
return DialogFabriquerPotion.create(this, item, onActionItem);
|
||||
return DialogFabriquerPotion.create(this, item, onActionItem);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -1853,14 +1886,14 @@ export class RdDActor extends RdDBaseActor {
|
|||
|
||||
/* -------------------------------------------- */
|
||||
async transformerStress() {
|
||||
const stress = Number(this.system.compteurs.stress.value);
|
||||
if (this.system.sommeil?.insomnie || stress <= 0) {
|
||||
const fromStress = Number(this.system.compteurs.stress.value);
|
||||
if (this.system.sommeil?.insomnie || fromStress <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const stressRoll = await this._stressRoll(this.getReveActuel());
|
||||
|
||||
const conversion = Math.floor(stress * stressRoll.factor / 100);
|
||||
const conversion = Math.floor(fromStress * stressRoll.factor / 100);
|
||||
let dissolution = Math.max(0, Number(this.system.compteurs.dissolution.value));
|
||||
let exaltation = Math.max(0, Number(this.system.compteurs.exaltation.value));
|
||||
const annule = Math.min(dissolution, exaltation);
|
||||
|
@ -1872,8 +1905,8 @@ export class RdDActor extends RdDBaseActor {
|
|||
alias: this.name,
|
||||
selectedCarac: this.system.carac.reve,
|
||||
rolled: stressRoll,
|
||||
stress: stress,
|
||||
perte: Math.min(conversion, stress),
|
||||
stress: fromStress,
|
||||
perte: Math.min(conversion, fromStress),
|
||||
convertis: conversion - perteDissolution,
|
||||
xp: conversion - perteDissolution + exaltation,
|
||||
dissolution: dissolution,
|
||||
|
@ -1885,15 +1918,18 @@ export class RdDActor extends RdDBaseActor {
|
|||
content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-resultat-transformer-stress.html`, stressRollData)
|
||||
});
|
||||
|
||||
const toStress = Math.max(fromStress - stressRollData.perte - 1, 0);
|
||||
const fromXpSress = Number(this.system.compteurs.experience.value);
|
||||
const toXpStress = fromXpSress + Number(stressRollData.xp);
|
||||
const updates = {
|
||||
"system.compteurs.stress.value": Math.max(stress - stressRollData.perte - 1, 0),
|
||||
"system.compteurs.experience.value": Number(this.system.compteurs.experience.value) + Number(stressRollData.xp),
|
||||
"system.compteurs.stress.value": toStress,
|
||||
"system.compteurs.experience.value": toXpStress,
|
||||
"system.compteurs.dissolution.value": dissolution - perteDissolution,
|
||||
"system.compteurs.exaltation.value": 0
|
||||
}
|
||||
await this.update(updates);
|
||||
|
||||
this.updateExperienceLog('XP', stressRollData.xp, "Transformation du stress");
|
||||
await ExperienceLog.add(this, XP_TOPIC.STRESS, fromStress, toStress, 'Transformation')
|
||||
await ExperienceLog.add(this, XP_TOPIC.TRANSFORM, fromXpSress, toXpStress, 'Transformation')
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
@ -2076,16 +2112,13 @@ export class RdDActor extends RdDBaseActor {
|
|||
|
||||
/* -------------------------------------------- */
|
||||
async rollUnSort(coord) {
|
||||
if (this.isEmpoignadeEnCours()) {
|
||||
ui.notifications.warn("Une empoignade est en cours ! Normalement, vous ne pouvez rien faire d'autre que continuer l'empoignade ou la rompre.")
|
||||
}
|
||||
|
||||
RdDEmpoignade.checkEmpoignadeEnCours(this)
|
||||
if (EffetsDraconiques.isSortImpossible(this)) {
|
||||
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 = duplicate(this.$filterSortList(this.getSortList(), coord));
|
||||
let sorts = duplicate(this.$filterSortList(this.itemTypes['sort'], coord));
|
||||
if (sorts.length == 0) {
|
||||
ui.notifications.info(`Aucun sort disponible en ${TMRUtility.getTMR(coord).label} !`);
|
||||
return;
|
||||
|
@ -2219,10 +2252,7 @@ export class RdDActor extends RdDBaseActor {
|
|||
|
||||
/* -------------------------------------------- */
|
||||
async rollCarac(caracName, jetResistance = undefined) {
|
||||
if (this.isEmpoignadeEnCours()) {
|
||||
ui.notifications.warn("Une empoignade est en cours ! Normalement, vous ne pouvez rien faire d'autre que continuer l'empoignade ou la rompre.")
|
||||
}
|
||||
|
||||
RdDEmpoignade.checkEmpoignadeEnCours(this)
|
||||
let selectedCarac = this.getCaracByName(caracName)
|
||||
await this._openRollDialog({
|
||||
name: 'jet-' + caracName,
|
||||
|
@ -2290,22 +2320,19 @@ export class RdDActor extends RdDBaseActor {
|
|||
|
||||
/* -------------------------------------------- */
|
||||
async rollCompetence(idOrName, options = { tryTarget: true }) {
|
||||
if (this.isEmpoignadeEnCours()) {
|
||||
ui.notifications.warn("Une empoignade est en cours ! Normalement, vous ne pouvez rien faire d'autre que continuer l'empoignade ou la rompre.")
|
||||
}
|
||||
|
||||
RdDEmpoignade.checkEmpoignadeEnCours(this)
|
||||
let rollData = {
|
||||
carac: this.system.carac,
|
||||
competence: this.getCompetence(idOrName)
|
||||
}
|
||||
if (rollData.competence.type == 'competencecreature') {
|
||||
if (rollData.competence.system.iscombat && options.tryTarget && Targets.hasTargets()) {
|
||||
if (rollData.competence.type == TYPES.competencecreature) {
|
||||
const arme = RdDItemCompetenceCreature.armeCreature(rollData.competence)
|
||||
if (arme && options.tryTarget && Targets.hasTargets()) {
|
||||
Targets.selectOneToken(target => {
|
||||
if (rollData.competence.system.ispossession) {
|
||||
if (arme.action == "possession") {
|
||||
RdDPossession.onAttaquePossession(target, this, rollData.competence)
|
||||
}
|
||||
else {
|
||||
const arme = RdDItemCompetenceCreature.armeNaturelle(rollData.competence)
|
||||
RdDCombat.rddCombatTarget(target, this).attaque(competence, arme)
|
||||
}
|
||||
});
|
||||
|
@ -2335,8 +2362,7 @@ export class RdDActor extends RdDBaseActor {
|
|||
/* -------------------------------------------- */
|
||||
async creerTacheDepuisLivre(item, options = { renderSheet: true }) {
|
||||
const nomTache = "Lire " + item.name;
|
||||
const filterTacheLecture = it => it.type == 'tache' && it.name == nomTache;
|
||||
let tachesExistantes = this.filterItems(filterTacheLecture);
|
||||
let tachesExistantes = findTache(nomTache);
|
||||
if (tachesExistantes.length == 0) {
|
||||
const tache = {
|
||||
name: nomTache, type: 'tache',
|
||||
|
@ -2352,20 +2378,24 @@ export class RdDActor extends RdDBaseActor {
|
|||
}
|
||||
}
|
||||
await this.createEmbeddedDocuments('Item', [tache], options);
|
||||
tachesExistantes = this.filterItems(filterTacheLecture);
|
||||
tachesExistantes = findTache(nomTache)
|
||||
}
|
||||
return tachesExistantes.length > 0 ? tachesExistantes[0] : undefined;
|
||||
|
||||
function findTache(name) {
|
||||
return this.filterItems(it => it.name == name, 'tache');
|
||||
}
|
||||
}
|
||||
|
||||
blessuresASoigner() {
|
||||
// TODO or not TODO: filtrer les blessures poour lesquels on ne peut plus faire de premiers soins?
|
||||
// TODO or not TODO: filtrer les blessures pour lesquelles on ne peut plus faire de premiers soins?
|
||||
return this.filterItems(it => it.system.gravite > 0 && it.system.gravite <= 6 && !(it.system.premierssoins.done && it.system.soinscomplets.done), 'blessure')
|
||||
}
|
||||
|
||||
async getTacheBlessure(blesse, blessure) {
|
||||
const gravite = blessure?.system.gravite ?? 0;
|
||||
if (gravite > 0) {
|
||||
const tache = this.listItems('tache').find(it => it.system.itemId == blessure.id)
|
||||
const tache = this.itemTypes['tache'].find(it => it.system.itemId == blessure.id)
|
||||
?? await RdDItemBlessure.createTacheSoinBlessure(this, gravite);
|
||||
await blessure?.updateTacheSoinBlessure(tache);
|
||||
return tache
|
||||
|
@ -2374,10 +2404,7 @@ export class RdDActor extends RdDBaseActor {
|
|||
}
|
||||
|
||||
async rollCaracCompetence(caracName, compName, diff, options = { title: "" }) {
|
||||
if (this.isEmpoignadeEnCours()) {
|
||||
ui.notifications.warn("Une empoignade est en cours ! Normalement, vous ne pouvez rien faire d'autre que continuer l'empoignade ou la rompre.")
|
||||
}
|
||||
|
||||
RdDEmpoignade.checkEmpoignadeEnCours(this)
|
||||
const competence = this.getCompetence(compName);
|
||||
await this._openRollDialog({
|
||||
name: 'jet-competence',
|
||||
|
@ -2398,10 +2425,7 @@ export class RdDActor extends RdDBaseActor {
|
|||
|
||||
/* -------------------------------------------- */
|
||||
async rollTache(id, options = {}) {
|
||||
if (this.isEmpoignadeEnCours()) {
|
||||
ui.notifications.warn("Une empoignade est en cours ! Normalement, vous ne pouvez rien faire d'autre que continuer l'empoignade ou la rompre.")
|
||||
}
|
||||
|
||||
RdDEmpoignade.checkEmpoignadeEnCours(this)
|
||||
const tacheData = this.getTache(id)
|
||||
const compData = this.getCompetence(tacheData.system.competence)
|
||||
compData.system.defaut_carac = tacheData.system.carac; // Patch !
|
||||
|
@ -2668,7 +2692,7 @@ export class RdDActor extends RdDBaseActor {
|
|||
/* -------------------------------------------- */
|
||||
_getSignesDraconiques(coord) {
|
||||
const type = TMRUtility.getTMRType(coord);
|
||||
return this.listItems("signedraconique").filter(it => it.system.typesTMR.includes(type));
|
||||
return this.itemTypes["signedraconique"].filter(it => it.system.typesTMR.includes(type));
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
@ -2734,8 +2758,10 @@ export class RdDActor extends RdDBaseActor {
|
|||
}
|
||||
rollData.xpSort = RdDItemSigneDraconique.getXpSortSigneDraconique(rollData.rolled.code, rollData.signe);
|
||||
if (rollData.xpSort > 0) {
|
||||
await this.updateEmbeddedDocuments("Item", [{ _id: compData._id, 'system.xp_sort': Misc.toInt(compData.system.xp_sort) + rollData.xpSort }]);
|
||||
await this.updateExperienceLog("XP Sort", rollData.xpSort, "Signe draconique en " + rollData.competence.name);
|
||||
const fromXp = Number(compData.system.xp_sort);
|
||||
const toXp = fromXp + rollData.xpSort;
|
||||
await this.updateEmbeddedDocuments("Item", [{ _id: compData._id, 'system.xp_sort': toXp }]);
|
||||
await ExperienceLog.add(this, XP_TOPIC.XPSORT, fromXp, toXp, `${rollData.competence.name} : signe draconique`);
|
||||
}
|
||||
await this.deleteEmbeddedDocuments("Item", [rollData.signe._id]);
|
||||
await RdDResolutionTable.displayRollData(rollData, this.name, 'chat-resultat-lecture-signedraconique.html');
|
||||
|
@ -2849,11 +2875,12 @@ export class RdDActor extends RdDBaseActor {
|
|||
/* -------------------------------------------- */
|
||||
async _xpCompetence(xpData) {
|
||||
if (xpData.competence) {
|
||||
const newXp = Misc.toInt(xpData.competence.system.xp) + xpData.xpCompetence;
|
||||
let update = { _id: xpData.competence._id, 'system.xp': newXp };
|
||||
const from = Number(xpData.competence.system.xp);
|
||||
const to = from + xpData.xpCompetence;
|
||||
let update = { _id: xpData.competence._id, 'system.xp': to };
|
||||
await this.updateEmbeddedDocuments('Item', [update]);
|
||||
xpData.checkComp = await this.checkCompetenceXP(xpData.competence.name, undefined, false);
|
||||
this.updateExperienceLog("XP", xpData.xpCompetence, "XP gagné en " + xpData.competence.name);
|
||||
await ExperienceLog.add(this, XP_TOPIC.XP, from, to, xpData.competence.name);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2863,10 +2890,12 @@ export class RdDActor extends RdDBaseActor {
|
|||
let carac = duplicate(this.system.carac);
|
||||
let selectedCarac = RdDActor._findCaracByName(carac, xpData.caracName);
|
||||
if (!selectedCarac.derivee) {
|
||||
selectedCarac.xp = Misc.toInt(selectedCarac.xp) + xpData.xpCarac;
|
||||
const from = Number(selectedCarac.xp);
|
||||
const to = from + xpData.xpCarac;
|
||||
selectedCarac.xp = to;
|
||||
await this.update({ "system.carac": carac });
|
||||
xpData.checkCarac = await this.checkCaracXP(selectedCarac.label, false);
|
||||
this.updateExperienceLog("XP", xpData.xpCarac, "XP gagné en " + xpData.caracName);
|
||||
await ExperienceLog.add(this, XP_TOPIC.XPCARAC, from, to, xpData.caracName);
|
||||
} else {
|
||||
xpData.caracRepartitionManuelle = true;
|
||||
}
|
||||
|
@ -2875,8 +2904,7 @@ export class RdDActor extends RdDBaseActor {
|
|||
|
||||
/* -------------------------------------------- */
|
||||
async resetNombresAstraux() {
|
||||
let toDelete = this.listItems('nombreastral');
|
||||
const deletions = toDelete.map(it => it._id);
|
||||
const deletions = this.itemTypes['nombreastral'].map(it => it._id);
|
||||
await this.deleteEmbeddedDocuments("Item", deletions);
|
||||
}
|
||||
|
||||
|
@ -2900,7 +2928,7 @@ export class RdDActor extends RdDBaseActor {
|
|||
async supprimerAnciensNombresAstraux() {
|
||||
const calendrier = game.system.rdd.calendrier;
|
||||
if (calendrier) {
|
||||
const toDelete = this.listItems('nombreastral')
|
||||
const toDelete = this.itemTypes['nombreastral']
|
||||
.filter(it => calendrier.isAfterIndexDate(it.system.jourindex))
|
||||
.map(it => it._id);
|
||||
await this.deleteEmbeddedDocuments("Item", toDelete);
|
||||
|
@ -2958,11 +2986,6 @@ export class RdDActor extends RdDBaseActor {
|
|||
return entry && entry.length > 0 ? carac[entry[0]] : undefined;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
getSortList() {
|
||||
return this.listItems("sort");
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
countMonteeLaborieuse() { // Return +1 par queue/ombre/souffle Montée Laborieuse présente
|
||||
let countMonteeLaborieuse = EffetsDraconiques.countMonteeLaborieuse(this);
|
||||
|
@ -3022,8 +3045,8 @@ export class RdDActor extends RdDBaseActor {
|
|||
mode: mode,
|
||||
fatigue: RdDUtility.calculFatigueHtml(fatigue, endurance),
|
||||
draconic: this.getDraconicList(),
|
||||
sort: this.getSortList(),
|
||||
signes: this.listItems("signedraconique"),
|
||||
sort: this.itemTypes['sort'],
|
||||
signes: this.itemTypes['signedraconique'],
|
||||
caracReve: this.system.carac.reve.value,
|
||||
pointsReve: this.getReveActuel(),
|
||||
isRapide: isRapide,
|
||||
|
@ -3059,7 +3082,7 @@ export class RdDActor extends RdDBaseActor {
|
|||
|
||||
|
||||
const competence = this.getCompetence(arme.system.competence)
|
||||
if (competence.system.ispossession) {
|
||||
if (competence.isCompetencePossession()) {
|
||||
return RdDPossession.onAttaquePossession(target, this, competence);
|
||||
}
|
||||
RdDCombat.rddCombatTarget(target, this).attaque(competence, arme);
|
||||
|
@ -3139,9 +3162,7 @@ export class RdDActor extends RdDBaseActor {
|
|||
|
||||
/* -------------------------------------------- */
|
||||
conjurerPossession(possession) {
|
||||
// TODO: choix de la compétence de draconic ou de possession
|
||||
let draconic = this.getDraconicOuPossession();
|
||||
RdDPossession.onConjurerPossession(this, draconic, possession)
|
||||
RdDPossession.onConjurerPossession(this, possession)
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
@ -3163,7 +3184,7 @@ export class RdDActor extends RdDBaseActor {
|
|||
/* -------------------------------------------- */
|
||||
async equiperObjet(itemID) {
|
||||
let item = this.getEmbeddedDocument('Item', itemID);
|
||||
if (item && ['arme', 'armure'].includes(item.type)) {
|
||||
if (item?.isEquipable()) {
|
||||
const isEquipe = !item.system.equipe;
|
||||
await this.updateEmbeddedDocuments('Item', [{ _id: item.id, "system.equipe": isEquipe }]);
|
||||
this.computeEncTotal(); // Mise à jour encombrement
|
||||
|
@ -3180,8 +3201,8 @@ export class RdDActor extends RdDBaseActor {
|
|||
const armures = this.items.filter(it => it.type == "armure" && it.system.equipe);
|
||||
for (const armure of armures) {
|
||||
protection += await RdDDice.rollTotal(armure.system.protection.toString());
|
||||
if (dmg > 0) {
|
||||
this._deteriorerArmure(armure, dmg);
|
||||
if (dmg > 0 && attackerRoll.dmg.encaisserSpecial != "noarmure") {
|
||||
armure.deteriorerArmure(dmg);
|
||||
dmg = 0;
|
||||
}
|
||||
}
|
||||
|
@ -3199,35 +3220,6 @@ export class RdDActor extends RdDBaseActor {
|
|||
return protection;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
_deteriorerArmure(armure, dmg) {
|
||||
armure = duplicate(armure);
|
||||
if (!ReglesOptionelles.isUsing('deteriorationArmure') || armure.system.protection == '0') {
|
||||
return;
|
||||
}
|
||||
armure.system.deterioration = (armure.system.deterioration ?? 0) + dmg;
|
||||
if (armure.system.deterioration >= 10) {
|
||||
armure.system.deterioration -= 10;
|
||||
let res = /(\d+)?d(\d+)(\-\d+)?/.exec(armure.system.protection);
|
||||
if (res) {
|
||||
let malus = Misc.toInt(res[3]) - 1;
|
||||
let armure = Misc.toInt(res[2]);
|
||||
if (armure + malus <= 0) {
|
||||
armure.system.protection = 0;
|
||||
} else {
|
||||
armure.system.protection = '' + (res[1] ?? '1') + 'd' + armure + malus;
|
||||
}
|
||||
}
|
||||
else if (/\d+/.exec(armure.system.protection)) {
|
||||
armure.system.protection = "1d" + armure.system.protection;
|
||||
}
|
||||
else {
|
||||
ui.notifications.warn(`La valeur d'armure de votre ${armure.name} est incorrecte`);
|
||||
}
|
||||
ChatMessage.create({ content: "Votre armure s'est détériorée, elle protège maintenant de " + armure.system.protection });
|
||||
}
|
||||
this.updateEmbeddedDocuments('Item', [armure]);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async encaisser() {
|
||||
|
@ -3239,25 +3231,31 @@ export class RdDActor extends RdDBaseActor {
|
|||
if (attacker && !await attacker.accorder(this, 'avant-encaissement')) {
|
||||
return;
|
||||
}
|
||||
const attackerId = attacker?.id;
|
||||
if (ReglesOptionelles.isUsing('validation-encaissement-gr') && !game.user.isGM) {
|
||||
RdDBaseActor.remoteActorCall({
|
||||
actorId: this.id,
|
||||
method: 'validerEncaissement',
|
||||
args: [rollData, show]
|
||||
method: 'appliquerEncaissement',
|
||||
args: [rollData, show, attackerId]
|
||||
});
|
||||
return;
|
||||
}
|
||||
await this.appliquerEncaissement(rollData, show, attackerId);
|
||||
}
|
||||
|
||||
async appliquerEncaissement(rollData, show, attackerId) {
|
||||
const armure = await this.computeArmure(rollData);
|
||||
if (ReglesOptionelles.isUsing('validation-encaissement-gr')) {
|
||||
DialogValidationEncaissement.validerEncaissement(this, rollData, armure, show, (encaissement, show) => this._appliquerEncaissement(encaissement, show, attacker));
|
||||
DialogValidationEncaissement.validerEncaissement(this, rollData, armure, show, attackerId, (encaissement, show, attackerId) => this._appliquerEncaissement(encaissement, show, attackerId));
|
||||
}
|
||||
else {
|
||||
let encaissement = await RdDUtility.jetEncaissement(rollData, armure, { showDice: SHOW_DICE });
|
||||
await this._appliquerEncaissement(encaissement, show, attacker)
|
||||
await this._appliquerEncaissement(encaissement, show, attackerId);
|
||||
}
|
||||
}
|
||||
|
||||
async _appliquerEncaissement(encaissement, show, attacker) {
|
||||
async _appliquerEncaissement(encaissement, show, attackedId) {
|
||||
const attacker = attackedId ? game.actors.get(attackedId) : undefined
|
||||
let santeOrig = duplicate(this.system.sante);
|
||||
|
||||
const blessure = await this.ajouterBlessure(encaissement, attacker); // Will update the result table
|
||||
|
|
|
@ -3,7 +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 { RdDItem } from "../item.js";
|
||||
import { RdDItem, TYPES } from "../item.js";
|
||||
import { RdDItemCompetenceCreature } from "../item-competencecreature.js";
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/**
|
||||
|
@ -50,16 +51,18 @@ export class RdDBaseActorSheet extends ActorSheet {
|
|||
encTotal: await this.actor.computeEncTotal(),
|
||||
}
|
||||
|
||||
this.objetVersConteneur = RdDUtility.buildArbreDeConteneurs(formData.conteneurs, formData.objets);
|
||||
this._appliquerRechercheObjets(formData.objets, formData.conteneurs);
|
||||
this.objetVersConteneur = RdDUtility.buildArbreDeConteneurs(formData.conteneurs, formData.inventaires);
|
||||
this._appliquerRechercheObjets(formData.conteneurs, formData.inventaires);
|
||||
formData.conteneurs = RdDUtility.conteneursRacine(formData.conteneurs);
|
||||
formData.competences.filter(it => it.type == TYPES.competencecreature)
|
||||
.forEach(it => it.isdommages = RdDItemCompetenceCreature.isDommages(it))
|
||||
return formData;
|
||||
}
|
||||
|
||||
_appliquerRechercheObjets(objets, conteneurs) {
|
||||
_appliquerRechercheObjets(conteneurs, inventaires) {
|
||||
if (this.options.recherche?.text) {
|
||||
const recherche = this.options.recherche;
|
||||
const allVisible = objets.filter(it => it.isNomTypeLike(recherche.text)).map(it => it.id);
|
||||
const allVisible = inventaires.filter(it => it.isNomTypeLike(recherche.text)).map(it => it.id);
|
||||
let addVisible = conteneurs.filter(it => it.isNomTypeLike(recherche.text)).map(it => it.id)
|
||||
do {
|
||||
allVisible.push(...addVisible)
|
||||
|
@ -67,11 +70,11 @@ export class RdDBaseActorSheet extends ActorSheet {
|
|||
addVisible = parentsIds.filter(id => !allVisible.includes(id))
|
||||
}
|
||||
while (addVisible.length > 0)
|
||||
objets.forEach(it => it.system.isHidden = !allVisible.includes(it.id))
|
||||
inventaires.forEach(it => it.system.isHidden = !allVisible.includes(it.id))
|
||||
conteneurs.forEach(it => it.system.isHidden = !allVisible.includes(it.id))
|
||||
}
|
||||
else {
|
||||
objets.forEach(it => it.system.isHidden = false)
|
||||
inventaires.forEach(it => it.system.isHidden = false)
|
||||
conteneurs.forEach(it => it.system.isHidden = false)
|
||||
}
|
||||
}
|
||||
|
@ -118,33 +121,34 @@ export class RdDBaseActorSheet extends ActorSheet {
|
|||
formData.herbes = Misc.arrayOrEmpty(itemTypes['herbe']);
|
||||
formData.nourritureboissons = Misc.arrayOrEmpty(itemTypes['nourritureboisson']);
|
||||
formData.gemmes = Misc.arrayOrEmpty(itemTypes['gemme']);
|
||||
formData.monnaie = Misc.arrayOrEmpty(itemTypes['monnaie']).sort(Monnaie.triValeurEntiere());
|
||||
formData.monnaies = Misc.arrayOrEmpty(itemTypes['monnaie']).sort(Monnaie.triValeurEntiere());
|
||||
formData.objets = Misc.arrayOrEmpty(itemTypes['objet'])
|
||||
|
||||
formData.objets = RdDItem.getItemTypesInventaire('all')
|
||||
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('.conteneur-name a').click(async event => {
|
||||
RdDUtility.toggleAfficheContenu(this.getItemId(event));
|
||||
this.render(true);
|
||||
});
|
||||
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('.actor-montrer').click(async event => this.actor.postActorToChat());
|
||||
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 );
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */ /** @override */
|
||||
activateListeners(html) {
|
||||
super.activateListeners(html);
|
||||
this.html = html;
|
||||
|
||||
this.html.find('.conteneur-name a').click(async event => {
|
||||
RdDUtility.toggleAfficheContenu(this.getItemId(event));
|
||||
this.render(true);
|
||||
});
|
||||
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('.actor-montrer').click(async event => this.actor.postActorToChat());
|
||||
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);
|
||||
// Everything below here is only needed if the sheet is editable
|
||||
if (!this.options.editable) return;
|
||||
|
||||
|
@ -230,9 +234,9 @@ export class RdDBaseActorSheet extends ActorSheet {
|
|||
|
||||
/* -------------------------------------------- */
|
||||
async selectObjetTypeToCreate() {
|
||||
let typeObjets = this.getTypesInventaire().sort(Misc.ascending(type => Misc.typeName('Item', type)));
|
||||
let types = this.getTypesInventaire().sort(Misc.ascending(type => Misc.typeName('Item', type)));
|
||||
let content = `<span class="competence-label">Selectionnez le type d'équipement</span><select class="item-type">`;
|
||||
for (let typeName of typeObjets) {
|
||||
for (let typeName of types) {
|
||||
content += `<option value="${typeName}">${Misc.typeName('Item', typeName)}</option>`
|
||||
}
|
||||
content += '</select>';
|
||||
|
|
|
@ -3,6 +3,7 @@ import { SYSTEM_SOCKET_ID } from "../constants.js";
|
|||
import { Monnaie } from "../item-monnaie.js";
|
||||
import { Misc } from "../misc.js";
|
||||
import { RdDAudio } from "../rdd-audio.js";
|
||||
import { RdDConfirm } from "../rdd-confirm.js";
|
||||
import { RdDUtility } from "../rdd-utility.js";
|
||||
import { SystemCompendiums } from "../settings/system-compendiums.js";
|
||||
import { APP_ASTROLOGIE_REFRESH } from "../sommeil/app-astrologie.js";
|
||||
|
@ -32,7 +33,7 @@ export class RdDBaseActor extends Actor {
|
|||
case "msg_refresh_nombre_astral":
|
||||
Hooks.callAll(APP_ASTROLOGIE_REFRESH);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static remoteActorCall(callData, userId = undefined) {
|
||||
|
@ -109,7 +110,6 @@ export class RdDBaseActor extends Actor {
|
|||
isEntite() { return this.type == 'entite'; }
|
||||
isPersonnage() { return this.type == 'personnage'; }
|
||||
isVehicule() { return this.type == 'vehicule'; }
|
||||
|
||||
getItem(id, type = undefined) {
|
||||
const item = this.items.get(id);
|
||||
if (type == undefined || (item?.type == type)) {
|
||||
|
@ -119,7 +119,7 @@ export class RdDBaseActor extends Actor {
|
|||
}
|
||||
|
||||
listItems(type = undefined) { return (type ? this.itemTypes[type] : this.items); }
|
||||
filterItems(filter, type = undefined) { return this.listItems(type)?.filter(filter) ?? []; }
|
||||
filterItems(filter, type = undefined) { return (type ? this.itemTypes[type] : this.items)?.filter(filter); }
|
||||
findItemLike(idOrName, type) {
|
||||
return this.getItem(idOrName, type)
|
||||
?? Misc.findFirstLike(idOrName, this.listItems(type), { description: Misc.typeName('Item', type) });
|
||||
|
@ -144,6 +144,18 @@ export class RdDBaseActor extends Actor {
|
|||
.forEach(async it => await it.onFinPeriodeTemporel(oldTimestamp, newTimestamp))
|
||||
}
|
||||
|
||||
async creerObjetParMJ(object){
|
||||
if (!Misc.isUniqueConnectedGM()) {
|
||||
RdDBaseActor.remoteActorCall({
|
||||
actorId: this.id,
|
||||
method: 'creerObjetParMJ',
|
||||
args: [object]
|
||||
});
|
||||
return;
|
||||
}
|
||||
await this.createEmbeddedDocuments('Item', [object])
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
getFortune() {
|
||||
return Monnaie.getFortune(this.itemTypes['monnaie']);
|
||||
|
@ -244,13 +256,16 @@ export class RdDBaseActor extends Actor {
|
|||
});
|
||||
return;
|
||||
}
|
||||
console.log('achatVente', achat);
|
||||
const cout = Number(achat.prixTotal ?? 0);
|
||||
const vendeur = achat.vendeurId ? game.actors.get(achat.vendeurId) : undefined;
|
||||
const acheteur = achat.acheteurId ? game.actors.get(achat.acheteurId) : undefined;
|
||||
const quantite = (achat.choix.nombreLots ?? 1) * (achat.vente.tailleLot);
|
||||
const itemVendu = vendeur?.getItem(achat.vente.item._id);
|
||||
if (!this.verifierQuantite(vendeur, itemVendu, quantite)) {
|
||||
const itemVendu = vendeur?.getItem(achat.vente.item._id) ?? game.items.get(achat.vente.item._id);
|
||||
if (!itemVendu) {
|
||||
ChatUtility.notifyUser(achat.userId, 'warn', vendeur ? `Le vendeur n'a pas plus de ${achat.vente.item.name} !`: `Impossible de retrouver: ${achat.vente.item.name} !`);
|
||||
return;
|
||||
}
|
||||
if (vendeur && !this.verifierQuantite(itemVendu, quantite)) {
|
||||
ChatUtility.notifyUser(achat.userId, 'warn', `Le vendeur n'a pas assez de ${itemVendu.name} !`);
|
||||
return
|
||||
}
|
||||
|
@ -261,7 +276,7 @@ export class RdDBaseActor extends Actor {
|
|||
await this.decrementerVente(vendeur, itemVendu, quantite, cout);
|
||||
if (acheteur) {
|
||||
await acheteur.depenserSols(cout);
|
||||
const createdItemId = await acheteur.creerQuantiteItem(achat.vente.item, quantite);
|
||||
const createdItemId = await acheteur.creerQuantiteItem(itemVendu, quantite);
|
||||
await acheteur.consommerNourritureAchetee(achat, achat.vente, createdItemId);
|
||||
}
|
||||
if (cout > 0) {
|
||||
|
@ -302,9 +317,9 @@ export class RdDBaseActor extends Actor {
|
|||
return this.getFortune() >= cout;
|
||||
}
|
||||
|
||||
verifierQuantite(vendeur, item, quantiteTotal) {
|
||||
const disponible = vendeur?.getQuantiteDisponible(item);
|
||||
return disponible == undefined || disponible >= quantiteTotal;
|
||||
verifierQuantite(item, quantiteDemande) {
|
||||
const disponible = item?.getQuantite();
|
||||
return disponible == undefined || disponible >= quantiteDemande;
|
||||
}
|
||||
|
||||
async consommerNourritureAchetee(achat, vente, createdItemId) {
|
||||
|
|
|
@ -22,7 +22,7 @@ export class RdDCommerce extends RdDBaseActor {
|
|||
}
|
||||
|
||||
getQuantiteDisponible(item) {
|
||||
return this.system.illimite || item.isService() ? undefined : item.getQuantite();
|
||||
return (this.system.illimite || item?.isService()) ? undefined : item.getQuantite();
|
||||
}
|
||||
|
||||
verifierFortune(cout) {
|
||||
|
|
39
module/actor/experience-log.js
Normal file
39
module/actor/experience-log.js
Normal file
|
@ -0,0 +1,39 @@
|
|||
|
||||
export const XP_TOPIC = {
|
||||
XP: { code: 'xp', label: 'xp' },
|
||||
XPSORT: { code: 'xpsort', label: 'xp sort' },
|
||||
NIVEAU: { code: 'niveau', label: 'Niveau' },
|
||||
XPCARAC: { code: 'xpcarac', label: 'xp carac' },
|
||||
CARAC: { code: 'carac', label: 'Carac' },
|
||||
STRESS: { code: 'stress', label: 'Stress' },
|
||||
TRANSFORM: { code: 'xps', label: 'Transformé' },
|
||||
}
|
||||
|
||||
export class ExperienceLog {
|
||||
|
||||
static async add(actor, topic, from, to, raison, manuel = false) {
|
||||
if (!actor.hasPlayerOwner || !actor.isPersonnage()) {
|
||||
return
|
||||
}
|
||||
if (from == to) {
|
||||
return
|
||||
}
|
||||
const newXpLog = {
|
||||
mode: topic?.code ?? topic,
|
||||
raison: (manuel ? '(manuel) ' : '') + raison,
|
||||
from: from,
|
||||
to: to,
|
||||
valeur: to - from,
|
||||
daterdd: game.system.rdd.calendrier.dateCourante(),
|
||||
datereel: game.system.rdd.calendrier.dateReel().replace('T', ' ')
|
||||
};
|
||||
console.log('ExperienceLog.add', newXpLog)
|
||||
const newExperienceLog = (actor.system.experiencelog ?? []).concat([newXpLog]);
|
||||
await actor.update({ [`system.experiencelog`]: newExperienceLog });
|
||||
}
|
||||
|
||||
static labelTopic(topic) {
|
||||
const xpt = Object.values(XP_TOPIC).find(it => it.code == topic);
|
||||
return xpt?.label ?? xpt?.code ?? topic;
|
||||
}
|
||||
}
|
|
@ -78,11 +78,7 @@ export class ChatUtility {
|
|||
|
||||
/* -------------------------------------------- */
|
||||
static async createChatWithRollMode(name, chatOptions) {
|
||||
return await ChatUtility.createChatMessage(name, game.settings.get("core", "rollMode"), chatOptions);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async createChatMessage(name, rollMode, chatOptions) {
|
||||
let rollMode = game.settings.get("core", "rollMode")
|
||||
switch (rollMode) {
|
||||
case "blindroll": // GM only
|
||||
if (!game.user.isGM) {
|
||||
|
|
|
@ -25,23 +25,13 @@ export class DialogChronologie extends Dialog {
|
|||
journalId: game.settings.get(SYSTEM_RDD, LATEST_USED_JOURNAL_ID),
|
||||
journaux: game.journal.filter(it => it.testUserPermission(game.user, CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER)),
|
||||
timestamp: game.system.rdd.calendrier.timestamp,
|
||||
dateReel: DialogChronologie.getCurrentDateTime()
|
||||
dateReel: game.system.rdd.calendrier.dateReel()
|
||||
};
|
||||
const html = await renderTemplate("systems/foundryvtt-reve-de-dragon/templates/dialog-chronologie.html", dialogData);
|
||||
const dialog = new DialogChronologie(html, dialogData);
|
||||
dialog.render(true);
|
||||
}
|
||||
|
||||
static getCurrentDateTime() {
|
||||
return new Date().toLocaleString("sv-SE", {
|
||||
year: "numeric",
|
||||
month: "2-digit",
|
||||
day: "2-digit",
|
||||
hour: "2-digit",
|
||||
minute: "2-digit"
|
||||
}).replace(" ", "T");
|
||||
}
|
||||
|
||||
constructor(html, dialogData) {
|
||||
const options = {
|
||||
classes: ["DialogChronologie"],
|
||||
|
@ -124,7 +114,7 @@ export class DialogChronologie extends Dialog {
|
|||
heure: RdDTimestamp.definition(this.html.find("form.rdddialogchrono :input[name='chronologie.heure']").val()),
|
||||
minute: this.html.find("form.rdddialogchrono :input[name='chronologie.minute']").val(),
|
||||
},
|
||||
dateReel: this.html.find("form.rdddialogchrono :input[name='dateReel']").val().replace('T', ' ')
|
||||
dateReel: this.html.find("form.rdddialogchrono :input[name='dateReel']").val()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ export class DialogItemAchat extends Dialog {
|
|||
}
|
||||
|
||||
return {
|
||||
item: (json ? JSON.parse(json) : undefined),
|
||||
item: JSON.parse(json),
|
||||
vendeur,
|
||||
acheteur,
|
||||
nbLots: parseInt(chatButton.attributes['data-quantiteNbLots']?.value),
|
||||
|
@ -34,7 +34,6 @@ export class DialogItemAchat extends Dialog {
|
|||
const venteData = {
|
||||
item,
|
||||
actingUserId: game.user.id,
|
||||
vendeurId: vendeur?.id,
|
||||
vendeur,
|
||||
acheteur,
|
||||
tailleLot,
|
||||
|
|
|
@ -7,7 +7,7 @@ import { RdDUtility } from "./rdd-utility.js";
|
|||
*/
|
||||
export class DialogValidationEncaissement extends Dialog {
|
||||
|
||||
static async validerEncaissement(actor, rollData, armure, show, onEncaisser) {
|
||||
static async validerEncaissement(actor, rollData, armure, show, attackerId, onEncaisser) {
|
||||
let encaissement = await RdDUtility.jetEncaissement(rollData, armure, { showDice: HIDE_DICE });
|
||||
const html = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/dialog-validation-encaissement.html', {
|
||||
actor: actor,
|
||||
|
@ -15,12 +15,12 @@ export class DialogValidationEncaissement extends Dialog {
|
|||
encaissement: encaissement,
|
||||
show: show
|
||||
});
|
||||
const dialog = new DialogValidationEncaissement(html, actor, rollData, armure, encaissement, show, onEncaisser);
|
||||
const dialog = new DialogValidationEncaissement(html, actor, rollData, armure, encaissement, show, attackerId, onEncaisser);
|
||||
dialog.render(true);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
constructor(html, actor, rollData, armure, encaissement, show, onEncaisser) {
|
||||
constructor(html, actor, rollData, armure, encaissement, show, attackerId, onEncaisser) {
|
||||
// Common conf
|
||||
let buttons = {
|
||||
"valider": { label: "Valider", callback: html => this.onValider() },
|
||||
|
@ -48,6 +48,7 @@ export class DialogValidationEncaissement extends Dialog {
|
|||
this.armure = armure;
|
||||
this.encaissement = encaissement;
|
||||
this.show = show;
|
||||
this.attackerId = attackerId;
|
||||
this.onEncaisser = onEncaisser;
|
||||
this.forceDiceResult = {total: encaissement.roll.result };
|
||||
}
|
||||
|
@ -66,6 +67,6 @@ export class DialogValidationEncaissement extends Dialog {
|
|||
|
||||
async onValider() {
|
||||
this.encaissement = await RdDUtility.jetEncaissement(this.rollData, this.armure, { showDice: SHOW_DICE, forceDiceResult: this.forceDiceResult});
|
||||
this.onEncaisser(this.encaissement, this.show)
|
||||
this.onEncaisser(this.encaissement, this.show, this.attackerId)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { RdDItemCompetenceCreature } from "./item-competencecreature.js"
|
||||
import { TYPES } from "./item.js";
|
||||
import { RdDCombatManager } from "./rdd-combat.js";
|
||||
|
||||
const nomCategorieParade = {
|
||||
|
@ -19,7 +20,7 @@ const nomCategorieParade = {
|
|||
export class RdDItemArme extends Item {
|
||||
|
||||
static isArme(item) {
|
||||
return (item.type == 'competencecreature' && item.system.iscombat) || item.type == 'arme';
|
||||
return RdDItemCompetenceCreature.getCategorieAttaque(item) || item.type == 'arme';
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
@ -27,7 +28,7 @@ export class RdDItemArme extends Item {
|
|||
switch (arme ? arme.type : '') {
|
||||
case 'arme': return arme;
|
||||
case 'competencecreature':
|
||||
return RdDItemCompetenceCreature.armeNaturelle(arme);
|
||||
return RdDItemCompetenceCreature.armeCreature(arme);
|
||||
}
|
||||
return RdDItemArme.mainsNues();
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ const limitesArchetypes = [
|
|||
];
|
||||
|
||||
/* -------------------------------------------- */
|
||||
const categorieCompetences = {
|
||||
const categoriesCompetences = {
|
||||
"generale": { base: -4, label: "Générales" },
|
||||
"particuliere": { base: -8, label: "Particulières" },
|
||||
"specialisee": { base: -11, label: "Spécialisées" },
|
||||
|
@ -49,16 +49,16 @@ const competence_xp_cumul = _buildCumulXP();
|
|||
|
||||
export class RdDItemCompetence extends Item {
|
||||
/* -------------------------------------------- */
|
||||
static getCategorieCompetences() {
|
||||
return categorieCompetences;
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
static getNiveauBase(category) {
|
||||
return categorieCompetences[category].base;
|
||||
static getCategories() {
|
||||
return categoriesCompetences;
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
static getLabelCategorie(category) {
|
||||
return categorieCompetences[category].label;
|
||||
return categoriesCompetences[category].label;
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
static getNiveauBase(category, categories = categoriesCompetences) {
|
||||
return categories[category]?.base ?? 0;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
@ -192,7 +192,7 @@ export class RdDItemCompetence extends Item {
|
|||
|
||||
/* -------------------------------------------- */
|
||||
static isNiveauBase(item) {
|
||||
return Number(item.system.niveau) == RdDItemCompetence.getNiveauBase(item.system.categorie);
|
||||
return Number(item.system.niveau) == RdDItemCompetence.getNiveauBase(item.system.categorie, item.getCategories());
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
|
|
@ -1,51 +1,97 @@
|
|||
|
||||
import { RdDItem, TYPES } from "./item.js";
|
||||
import { RdDCombatManager } from "./rdd-combat.js";
|
||||
|
||||
const categories = {
|
||||
"generale": { base: 0, label: "Générale" },
|
||||
"naturelle": { base: 0, label: "Arme naturelle" },
|
||||
"melee": { base: 0, label: "Mêlée" },
|
||||
"parade": { base: 0, label: "Parade" },
|
||||
"tir": { base: 0, label: "Tir" },
|
||||
"lancer": { base: 0, label: "Lancer" },
|
||||
"possession": { base: 0, label: "Possession" },
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
export class RdDItemCompetenceCreature extends Item {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static setRollDataCreature(rollData) {
|
||||
rollData.competence = rollData.competence
|
||||
rollData.carac = { "carac_creature": { label: rollData.competence.name, value: rollData.competence.system.carac_value } }
|
||||
rollData.competence.system.defaut_carac = "carac_creature"
|
||||
rollData.competence.system.categorie = "creature"
|
||||
rollData.selectedCarac = rollData.carac.carac_creature
|
||||
if (rollData.competence.system.iscombat) {
|
||||
rollData.arme = RdDItemCompetenceCreature.armeNaturelle(rollData.competence);
|
||||
}
|
||||
static getCategories() {
|
||||
return categories;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static armeNaturelle(competencecreature) {
|
||||
if (RdDItemCompetenceCreature.isCompetenceAttaque(competencecreature)) {
|
||||
// si c'est un Item compétence: cloner pour ne pas modifier lma compétence
|
||||
let arme = (competencecreature instanceof Item) ? competencecreature.clone(): competencecreature;
|
||||
mergeObject(arme.system,
|
||||
static setRollDataCreature(rollData) {
|
||||
rollData.carac = { "carac_creature": { label: rollData.competence.name, value: rollData.competence.system.carac_value } }
|
||||
rollData.competence.system.defaut_carac = "carac_creature"
|
||||
rollData.selectedCarac = rollData.carac.carac_creature
|
||||
rollData.arme = RdDItemCompetenceCreature.armeCreature(rollData.competence);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static armeCreature(item) {
|
||||
const categorieAttaque = RdDItemCompetenceCreature.getCategorieAttaque(item)
|
||||
if (categorieAttaque != undefined) {
|
||||
// si c'est un Item compétence: cloner pour ne pas modifier la compétence
|
||||
let arme = item.clone();
|
||||
mergeObject(arme,
|
||||
{
|
||||
competence: arme.name,
|
||||
initiative: RdDCombatManager.calculInitiative(competencecreature.system.niveau, competencecreature.system.carac_value),
|
||||
niveau: competencecreature.system.niveau,
|
||||
equipe: true,
|
||||
resistance: 100,
|
||||
dommagesReels: arme.system.dommages,
|
||||
penetration: 0,
|
||||
force: 0,
|
||||
rapide: true,
|
||||
cac: competencecreature.system.isnaturelle ? "naturelle" : "",
|
||||
action: 'attaque'
|
||||
action: item.isCompetencePossession() ? 'possession' : 'attaque',
|
||||
system: {
|
||||
competence: arme.name,
|
||||
cac: categorieAttaque == "naturelle" ? "naturelle" : "",
|
||||
niveau: item.system.niveau,
|
||||
initiative: RdDCombatManager.calculInitiative(item.system.niveau, item.system.carac_value),
|
||||
equipe: true,
|
||||
resistance: 100,
|
||||
dommagesReels: arme.system.dommages,
|
||||
penetration: 0,
|
||||
force: 0,
|
||||
rapide: true,
|
||||
}
|
||||
});
|
||||
return arme;
|
||||
}
|
||||
console.error("RdDItemCompetenceCreature.toActionArme(", competencecreature, ") : impossible de transformer l'Item en arme");
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static isCompetenceAttaque(item) {
|
||||
return item.type == 'competencecreature' && item.system.iscombat;
|
||||
static getCategorieAttaque(item) {
|
||||
if (item.type == TYPES.competencecreature) {
|
||||
switch (item.system.categorie) {
|
||||
case "melee":
|
||||
case "tir":
|
||||
case "lancer":
|
||||
case "naturelle":
|
||||
case "possession":
|
||||
return item.system.categorie
|
||||
}
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
|
||||
static isDommages(item) {
|
||||
if (item.type == TYPES.competencecreature) {
|
||||
switch (item.system.categorie) {
|
||||
case "melee":
|
||||
case "tir":
|
||||
case "lancer":
|
||||
case "naturelle":
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
static isParade(item) {
|
||||
if (item.type == TYPES.competencecreature) {
|
||||
switch (item.system.categorie) {
|
||||
case "melee":
|
||||
case "naturelle":
|
||||
case "parade":
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static isCompetenceParade(item) {
|
||||
return item.type == 'competencecreature' && item.system.categorie_parade !== "";
|
||||
|
|
|
@ -11,6 +11,8 @@ import { RdDSheetUtility } from "./rdd-sheet-utility.js";
|
|||
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 { TYPES } from "./item.js";
|
||||
|
||||
/**
|
||||
* Extend the basic ItemSheet for RdD specific items
|
||||
|
@ -98,9 +100,13 @@ export class RdDItemSheet extends ItemSheet {
|
|||
isComestible: this.item.getUtilisationCuisine(),
|
||||
options: RdDSheetUtility.mergeDocumentRights(this.options, this.item, this.isEditable)
|
||||
}
|
||||
if (this.item.type == TYPES.competencecreature) {
|
||||
formData.isparade = RdDItemCompetenceCreature.isParade(this.item)
|
||||
formData.isdommages = RdDItemCompetenceCreature.isDommages(this.item)
|
||||
}
|
||||
|
||||
const competences = await SystemCompendiums.getCompetences('personnage');
|
||||
formData.categorieCompetences = RdDItemCompetence.getCategorieCompetences()
|
||||
formData.categories = this.item.getCategories()
|
||||
if (this.item.type == 'tache' || this.item.type == 'livre' || this.item.type == 'meditation' || this.item.type == 'oeuvre') {
|
||||
formData.caracList = duplicate(game.system.model.Actor.personnage.carac)
|
||||
formData.caracList["reve-actuel"] = duplicate(game.system.model.Actor.personnage.reve.reve)
|
||||
|
@ -249,7 +255,8 @@ export class RdDItemSheet extends ItemSheet {
|
|||
event.preventDefault();
|
||||
|
||||
if (this.item.isCompetence()) {
|
||||
let level = RdDItemCompetence.getNiveauBase(event.currentTarget.value);
|
||||
const categorie = event.currentTarget.value;
|
||||
const level = RdDItemCompetence.getNiveauBase(categorie, this.item.getCategories());
|
||||
this.item.system.base = level;
|
||||
this.html.find('[name="system.base"]').val(level);
|
||||
}
|
||||
|
|
181
module/item.js
181
module/item.js
|
@ -6,34 +6,83 @@ 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 { RdDItemCompetence } from "./item-competence.js";
|
||||
import { RdDItemCompetenceCreature } from "./item-competencecreature.js";
|
||||
|
||||
export const 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 = [
|
||||
"arme",
|
||||
"armure",
|
||||
"conteneur",
|
||||
"faune",
|
||||
"gemme",
|
||||
"herbe",
|
||||
"plante",
|
||||
"ingredient",
|
||||
"livre",
|
||||
"monnaie",
|
||||
"munition",
|
||||
"nourritureboisson",
|
||||
"objet",
|
||||
"potion",
|
||||
TYPES.arme,
|
||||
TYPES.armure,
|
||||
TYPES.conteneur,
|
||||
TYPES.faune,
|
||||
TYPES.gemme,
|
||||
TYPES.herbe,
|
||||
TYPES.plante,
|
||||
TYPES.ingredient,
|
||||
TYPES.livre,
|
||||
TYPES.monnaie,
|
||||
TYPES.munition,
|
||||
TYPES.nourritureboisson,
|
||||
TYPES.objet,
|
||||
TYPES.potion,
|
||||
]
|
||||
const typesInventaire = {
|
||||
materiel: typesInventaireMateriel,
|
||||
all: ['service'].concat(typesInventaireMateriel),
|
||||
}
|
||||
|
||||
const typesObjetsOeuvres = ["oeuvre", "recettecuisine", "musique", "chant", "danse", "jeu"]
|
||||
const typesObjetsDraconiques = ["queue", "ombre", "souffle", "tete", "signedraconique", "sortreserve", "rencontre"]
|
||||
const typesObjetsConnaissance = ["meditation", "recettealchimique", "sort"]
|
||||
const typesObjetsEffet = ["possession", "poison", "maladie", "blessure"]
|
||||
const typesObjetsCompetence = ["competence", "competencecreature"]
|
||||
const typesObjetsTemporels = ["blessure", "poison", "maladie", "queue", "ombre", "souffle", "signedraconique", "rencontre"]
|
||||
const typesObjetsOeuvres = [TYPES.oeuvre, TYPES.recettecuisine, TYPES.musique, TYPES.chant, TYPES.danse, TYPES.jeu]
|
||||
const typesObjetsDraconiques = [TYPES.queue, TYPES.ombre, TYPES.souffle, TYPES.tete, TYPES.signedraconique, TYPES.sortreserve, TYPES.rencontre]
|
||||
const typesObjetsConnaissance = [TYPES.meditation, TYPES.recettealchimique, TYPES.sort]
|
||||
const typesObjetsEffet = [TYPES.possession, TYPES.poison, TYPES.maladie, TYPES.blessure]
|
||||
const typesObjetsCompetence = [TYPES.competence, TYPES.competencecreature]
|
||||
const typesObjetsTemporels = [TYPES.blessure, TYPES.poison, TYPES.maladie, TYPES.queue, TYPES.ombre, TYPES.souffle, TYPES.signedraconique, TYPES.rencontre]
|
||||
const typesObjetsEquipable = [TYPES.arme, TYPES.armure, TYPES.objet];
|
||||
const typesEnvironnement = typesInventaireMateriel;
|
||||
const encBrin = 0.00005; // un brin = 1 décigramme = 1/10g = 1/10000kg = 1/20000 enc
|
||||
const encPepin = 0.0007; /* un pépin de gemme = 1/10 cm3 = 1/1000 l = 3.5/1000 kg = 7/2000 kg = 7/1000 enc
|
||||
|
@ -81,6 +130,10 @@ export const defaultItemImg = {
|
|||
/* -------------------------------------------- */
|
||||
export class RdDItem extends Item {
|
||||
|
||||
static get defaultIcon() {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
static getDefaultImg(itemType) {
|
||||
return game.system.rdd.itemClasses[itemType]?.defaultIcon ?? defaultItemImg[itemType];
|
||||
}
|
||||
|
@ -88,12 +141,12 @@ export class RdDItem extends Item {
|
|||
static isFieldInventaireModifiable(type, field) {
|
||||
switch (field) {
|
||||
case 'quantite':
|
||||
if (['conteneur'].includes(type)) {
|
||||
if ([TYPES.conteneur].includes(type)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case 'cout':
|
||||
if (['monnaie'].includes(type)) {
|
||||
if ([TYPES.monnaie].includes(type)) {
|
||||
return game.user.isGM;
|
||||
}
|
||||
break;
|
||||
|
@ -139,49 +192,58 @@ export class RdDItem extends Item {
|
|||
super(docData, context);
|
||||
}
|
||||
|
||||
static get defaultIcon() {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
getUniteQuantite() {
|
||||
switch (this.type) {
|
||||
case "monnaie": return "(Pièces)"
|
||||
case "herbe":
|
||||
case TYPES.monnaie: return "(Pièces)"
|
||||
case TYPES.herbe:
|
||||
switch (this.system.categorie) {
|
||||
case 'Alchimie': case 'Repos': case 'Soin':
|
||||
return "(Brins)"
|
||||
case 'Cuisine': return '';
|
||||
}
|
||||
return '';
|
||||
case "ingredient": return "(Pépins ou Brins)"
|
||||
case TYPES.ingredient: return "(Pépins ou Brins)"
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
isCompetencePersonnage() { return this.type == 'competence' }
|
||||
isCompetenceCreature() { return this.type == 'competencecreature' }
|
||||
isConteneur() { return this.type == 'conteneur'; }
|
||||
isMonnaie() { return this.type == 'monnaie'; }
|
||||
isPotion() { return this.type == 'potion'; }
|
||||
isNourritureBoisson() { return this.type == 'nourritureboisson'; }
|
||||
isService() { return this.type == 'service'; }
|
||||
isEquipable() {
|
||||
return typesObjetsEquipable.includes(this.type)
|
||||
}
|
||||
|
||||
isCompetencePersonnage() { return this.type == TYPES.competence }
|
||||
isCompetenceCreature() { return this.type == TYPES.competencecreature }
|
||||
isConteneur() { return this.type == TYPES.conteneur; }
|
||||
isMonnaie() { return this.type == TYPES.monnaie; }
|
||||
isPotion() { return this.type == TYPES.potion; }
|
||||
isNourritureBoisson() { return this.type == TYPES.nourritureboisson; }
|
||||
isService() { return this.type == TYPES.service; }
|
||||
|
||||
isCompetence() { return typesObjetsCompetence.includes(this.type) }
|
||||
isCompetencePossession() { return TYPES.competencecreature == this.type && this.system.categorie == "possession" }
|
||||
isTemporel() { return typesObjetsTemporels.includes(this.type) }
|
||||
isOeuvre() { return typesObjetsOeuvres.includes(this.type) }
|
||||
isDraconique() { return RdDItem.getItemTypesDraconiques().includes(this.type) }
|
||||
isQueueDragon() { return [TYPES.queue, TYPES.ombre].includes(this.type) }
|
||||
isEffet() { return typesObjetsEffet.includes(this.type) }
|
||||
isConnaissance() { return typesObjetsConnaissance.includes(this.type) }
|
||||
|
||||
isInventaire(mode = 'materiel') { return RdDItem.getItemTypesInventaire(mode).includes(this.type); }
|
||||
isBoisson() { return this.isNourritureBoisson() && this.system.boisson; }
|
||||
isAlcool() { return this.isNourritureBoisson() && this.system.boisson && this.system.alcoolise; }
|
||||
isHerbeAPotion() { return this.type == 'herbe' && (this.system.categorie == 'Soin' || this.system.categorie == 'Repos'); }
|
||||
isBlessure() { return this.type == 'blessure' }
|
||||
isHerbeAPotion() { return this.type == TYPES.herbe && (this.system.categorie == 'Soin' || this.system.categorie == 'Repos'); }
|
||||
isBlessure() { return this.type == TYPES.blessure }
|
||||
|
||||
isPresentDansMilieux(milieux) {
|
||||
return this.getEnvironnements(milieux).length > 0
|
||||
}
|
||||
getCategories() {
|
||||
switch (this.type) {
|
||||
case TYPES.competence: return RdDItemCompetence.getCategories()
|
||||
case TYPES.competencecreature: return RdDItemCompetenceCreature.getCategories()
|
||||
}
|
||||
return {}
|
||||
}
|
||||
|
||||
getEnvironnements(milieux = undefined) {
|
||||
const environnements = this.isInventaire() ? this.system.environnement : undefined;
|
||||
|
@ -262,15 +324,15 @@ export class RdDItem extends Item {
|
|||
|
||||
getUtilisation() {
|
||||
switch (this.type) {
|
||||
case 'potion':
|
||||
case 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 'nourritureboisson': return 'cuisine';
|
||||
case 'herbe': case 'faune': case 'ingredient': case 'plante':
|
||||
case TYPES.nourritureboisson: return 'cuisine';
|
||||
case TYPES.herbe: case TYPES.faune: case TYPES.ingredient: case TYPES.plante:
|
||||
switch (this.system.categorie) {
|
||||
case 'Cuisine': return 'cuisine';
|
||||
case 'Toxique': case 'Poison': return 'poison';
|
||||
|
@ -285,9 +347,9 @@ export class RdDItem extends Item {
|
|||
getUtilisationCuisine() {
|
||||
if (this.getUtilisation() == 'cuisine') {
|
||||
switch (this.type) {
|
||||
case 'nourritureboisson':
|
||||
case TYPES.nourritureboisson:
|
||||
return 'pret';
|
||||
case 'herbe': case 'faune': case 'ingredient': case 'plante':
|
||||
case TYPES.herbe: case TYPES.faune: case TYPES.ingredient: case TYPES.plante:
|
||||
return 'brut';
|
||||
}
|
||||
}
|
||||
|
@ -295,7 +357,7 @@ export class RdDItem extends Item {
|
|||
}
|
||||
|
||||
isCristalAlchimique() {
|
||||
return this.type == 'objet' && Grammar.toLowerCaseNoAccent(this.name) == 'cristal alchimique' && this.system.quantite > 0;
|
||||
return this.type == TYPES.objet && Grammar.includesLowerCaseNoAccent(this.name, 'cristal alchimique') && this.system.quantite > 0;
|
||||
}
|
||||
|
||||
isMagique() {
|
||||
|
@ -318,16 +380,16 @@ export class RdDItem extends Item {
|
|||
}
|
||||
|
||||
getEncTotal() {
|
||||
return (this.isService() ? 0 : this.getQuantite()) * this.getEnc();
|
||||
return (this.getQuantite() ?? 0) * this.getEnc();
|
||||
}
|
||||
|
||||
getEnc() {
|
||||
switch (this.type) {
|
||||
case 'service':
|
||||
case TYPES.service:
|
||||
return 0;
|
||||
case 'herbe':
|
||||
case TYPES.herbe:
|
||||
return this.getEncHerbe();
|
||||
case 'gemme':
|
||||
case TYPES.gemme:
|
||||
return encPepin * this.system.taille;
|
||||
}
|
||||
return Math.max(this.system.encombrement ?? 0, 0);
|
||||
|
@ -367,6 +429,7 @@ export class RdDItem extends Item {
|
|||
}
|
||||
this.system.actionPrincipale = this.getActionPrincipale({ warnIfNot: false });
|
||||
}
|
||||
this.equipable = this.isEquipable();
|
||||
}
|
||||
|
||||
prepareDataPotion() {
|
||||
|
@ -382,7 +445,7 @@ export class RdDItem extends Item {
|
|||
|
||||
getActionPrincipale(options = { warnIfNot: true }) {
|
||||
switch (this.type) {
|
||||
case 'conteneur': return 'Ouvrir';
|
||||
case TYPES.conteneur: return 'Ouvrir';
|
||||
}
|
||||
if (this.actor?.isPersonnage()) {
|
||||
const warn = options.warnIfNot;
|
||||
|
@ -390,11 +453,11 @@ export class RdDItem extends Item {
|
|||
return 'Utiliser';
|
||||
}
|
||||
switch (this.type) {
|
||||
case 'nourritureboisson': return this._actionOrWarnQuantiteZero(this.system.boisson ? 'Boire' : 'Manger', warn);
|
||||
case 'potion': return this._actionOrWarnQuantiteZero('Boire', warn);
|
||||
case 'livre': return this._actionOrWarnQuantiteZero('Lire', warn);
|
||||
case 'herbe': return this.isHerbeAPotion() ? this._actionOrWarnQuantiteZero('Décoction', warn) : undefined;
|
||||
case 'queue': case 'ombre': return this.system.refoulement > 0 ? 'Refouler' : undefined;
|
||||
case TYPES.nourritureboisson: return this._actionOrWarnQuantiteZero(this.system.boisson ? 'Boire' : 'Manger', warn);
|
||||
case TYPES.potion: return this._actionOrWarnQuantiteZero('Boire', warn);
|
||||
case TYPES.livre: return this._actionOrWarnQuantiteZero('Lire', warn);
|
||||
case TYPES.herbe: return this.isHerbeAPotion() ? this._actionOrWarnQuantiteZero('Décoction', warn) : undefined;
|
||||
case TYPES.queue: case TYPES.ombre: return this.system.refoulement > 0 ? 'Refouler' : undefined;
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
|
@ -409,11 +472,11 @@ export class RdDItem extends Item {
|
|||
return;
|
||||
}
|
||||
switch (this.type) {
|
||||
case 'potion': return await actor.consommerPotion(this, onActionItem);
|
||||
case 'livre': return await actor.actionLire(this);
|
||||
case 'conteneur': return await this.sheet.render(true);
|
||||
case 'herbe': return await actor.actionHerbe(this, onActionItem);
|
||||
case 'queue': case 'ombre': return await actor.actionRefoulement(this);
|
||||
case TYPES.potion: return await actor.consommerPotion(this, onActionItem);
|
||||
case TYPES.livre: return await actor.actionLire(this);
|
||||
case TYPES.conteneur: return await this.sheet.render(true);
|
||||
case TYPES.herbe: return await actor.actionHerbe(this, onActionItem);
|
||||
case TYPES.queue: case TYPES.ombre: return await actor.actionRefoulement(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
51
module/item/armure.js
Normal file
51
module/item/armure.js
Normal file
|
@ -0,0 +1,51 @@
|
|||
import { RdDItem } from "../item.js";
|
||||
import { Misc } from "../misc.js";
|
||||
import { ReglesOptionelles } from "../settings/regles-optionelles.js";
|
||||
|
||||
export class RdDItemArmure extends RdDItem {
|
||||
|
||||
static get defaultIcon() {
|
||||
return "systems/foundryvtt-reve-de-dragon/icons/armes_armures/armure_plaques.webp";
|
||||
}
|
||||
|
||||
deteriorerArmure(dmg) {
|
||||
if (!ReglesOptionelles.isUsing('deteriorationArmure') || this.system.protection == '0') {
|
||||
return;
|
||||
}
|
||||
let deterioration = (this.system.deterioration ?? 0) + dmg;
|
||||
let protection = this.system.protection;
|
||||
|
||||
if (deterioration >= 10) {
|
||||
deterioration -= 10;
|
||||
protection = this.calculProtectionDeterioree();
|
||||
ChatMessage.create({ content: `Votre armure ${this.name} s'est détériorée, elle protège maintenant de ${protection}` });
|
||||
}
|
||||
this.update({
|
||||
system: {
|
||||
deterioration: deterioration,
|
||||
protection: protection
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
calculProtectionDeterioree() {
|
||||
const protectionCourante = this.system.protection;
|
||||
let res = /(\d+)?d(\d+)(\-\d+)?/.exec(protectionCourante);
|
||||
if (res) {
|
||||
let protection = Misc.toInt(res[2]);
|
||||
let malus = Misc.toInt(res[3]) - 1;
|
||||
if (protection + malus <= 0) {
|
||||
return 0;
|
||||
} else {
|
||||
return `1d${protection}${malus}`;
|
||||
}
|
||||
}
|
||||
else if (/\d+/.exec(protectionCourante)) {
|
||||
return `1d${protectionCourante}`;
|
||||
}
|
||||
else {
|
||||
ui.notifications.warn(`La valeur d'armure de votre ${this.name} est incorrecte`);
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -29,7 +29,7 @@ export class RdDConteneurItemSheet extends RdDItemInventaireSheet {
|
|||
/* -------------------------------------------- */
|
||||
prepareConteneurData(formData) {
|
||||
RdDBaseActorSheet.filterItemsPerTypeForSheet(formData, this.actor.itemTypes);
|
||||
this.objetVersConteneur = RdDUtility.buildArbreDeConteneurs(formData.conteneurs, formData.objets);
|
||||
this.objetVersConteneur = RdDUtility.buildArbreDeConteneurs(formData.conteneurs, formData.inventaires);
|
||||
formData.subItems = formData.conteneurs.find(it => it._id == this.item.id)?.subItems;
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ 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 { RdDItem } from "./item.js";
|
||||
import { RdDItem, TYPES } from "./item.js";
|
||||
import { RdDTimestamp } from "./time/rdd-timestamp.js";
|
||||
import { RdDRaretes } from "./item/raretes.js";
|
||||
|
||||
|
@ -13,7 +13,7 @@ class Migration {
|
|||
|
||||
async applyItemsUpdates(computeUpdates) {
|
||||
await game.actors.forEach(async (actor) => {
|
||||
const actorItemUpdates = computeUpdates(actor.items);
|
||||
const actorItemUpdates = computeUpdates(actor.items).filter(it => it != undefined);
|
||||
if (actorItemUpdates.length > 0) {
|
||||
console.log(
|
||||
this.code,
|
||||
|
@ -24,7 +24,7 @@ class Migration {
|
|||
}
|
||||
});
|
||||
|
||||
const itemUpdates = computeUpdates(game.items);
|
||||
const itemUpdates = computeUpdates(game.items).filter(it => it != undefined);
|
||||
if (itemUpdates.length > 0) {
|
||||
console.log(this.code, "Applying updates on items", itemUpdates);
|
||||
await Item.updateDocuments(itemUpdates);
|
||||
|
@ -65,7 +65,6 @@ class _1_5_34_migrationPngWebp {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
class _10_0_16_MigrationSortsReserve extends Migration {
|
||||
get code() { return "creation-item-sort-reserve"; }
|
||||
get version() { return "10.0.16"; }
|
||||
|
@ -370,6 +369,7 @@ class _10_4_6_ServicesEnCommerces extends Migration {
|
|||
return itemToCreate;
|
||||
}
|
||||
}
|
||||
|
||||
class _10_5_0_UpdatePeriodicite extends Migration {
|
||||
get code() { return "migration-periodicite-poisons-maladies"; }
|
||||
get version() { return "10.5.0"; }
|
||||
|
@ -458,6 +458,62 @@ class _10_7_0_MigrationBlessures extends Migration {
|
|||
}
|
||||
}
|
||||
|
||||
class _10_7_19_CategorieCompetenceCreature extends Migration {
|
||||
get code() { return "categorie-competence-creature"; }
|
||||
get version() { return "10.7.19"; }
|
||||
|
||||
async migrate() {
|
||||
await this.applyItemsUpdates(items => items
|
||||
.filter(it => TYPES.competencecreature == it.type)
|
||||
.map(it => this.migrateCompetenceCreature(it))
|
||||
);
|
||||
}
|
||||
|
||||
migrateCompetenceCreature(it) {
|
||||
const categorie = this.getCategorie(it)
|
||||
if (categorie == it.system.categorie) {
|
||||
return undefined
|
||||
}
|
||||
return { _id: it.id, 'system.categorie': categorie }
|
||||
}
|
||||
|
||||
getCategorie(it) {
|
||||
if (it.system.ispossession) {
|
||||
return 'possession'
|
||||
}
|
||||
switch (it.system.categorie) {
|
||||
case "melee":
|
||||
if (it.system.isnaturelle) {
|
||||
return 'naturelle'
|
||||
}
|
||||
return 'melee'
|
||||
case "particuliere": case "specialisee": case "connaissance":
|
||||
return "generale"
|
||||
default:
|
||||
return it.system.categorie
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class _10_7_19_PossessionsEntiteVictime extends Migration {
|
||||
get code() { return "possessions-entite-victime"; }
|
||||
get version() { return "10.7.19"; }
|
||||
|
||||
async migrate() {
|
||||
await this.applyItemsUpdates(items => items
|
||||
.filter(it => TYPES.possession == it.type)
|
||||
.map(it => this.migratePossession(it))
|
||||
);
|
||||
}
|
||||
|
||||
migratePossession(it) {
|
||||
return { _id: it.id,
|
||||
'system.entite.actorid': it.system.possesseurid,
|
||||
'system.victime.actorid': it.system.possedeid
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class Migrations {
|
||||
static getMigrations() {
|
||||
return [
|
||||
|
@ -474,6 +530,8 @@ export class Migrations {
|
|||
new _10_4_6_ServicesEnCommerces(),
|
||||
new _10_5_0_UpdatePeriodicite(),
|
||||
new _10_7_0_MigrationBlessures(),
|
||||
new _10_7_19_CategorieCompetenceCreature(),
|
||||
new _10_7_19_PossessionsEntiteVictime(),
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -490,7 +548,7 @@ export class Migrations {
|
|||
migrate() {
|
||||
const currentVersion = game.settings.get(SYSTEM_RDD, "systemMigrationVersion");
|
||||
if (isNewerVersion(game.system.version, currentVersion)) {
|
||||
//if (true) { /* comment previous and uncomment here to test before upgrade */
|
||||
// if (true) { /* comment previous and uncomment here to test before upgrade */
|
||||
const migrations = Migrations.getMigrations().filter(m => isNewerVersion(m.version, currentVersion));
|
||||
if (migrations.length > 0) {
|
||||
migrations.sort((a, b) => this.compareVersions(a, b));
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { RdDCarac } from "./rdd-carac.js";
|
||||
import { RdDPossession } from "./rdd-possession.js";
|
||||
|
||||
const conditionsTactiques = [
|
||||
{ type: '', descr: '', dmg: 0, attaque: 0, parade: 0, esquive: true },
|
||||
|
@ -27,6 +28,9 @@ export class RdDBonus {
|
|||
if (rollData.isEmpoignade && rollData.rolled?.isPart) {
|
||||
return true
|
||||
}
|
||||
if (RdDPossession.isDefensePossession(rollData)) {
|
||||
return RdDPossession.isPossessionFinesse(rollData)
|
||||
}
|
||||
return rollData.attackerRoll?.particuliere == 'finesse';
|
||||
}
|
||||
|
||||
|
@ -74,7 +78,7 @@ export class RdDBonus {
|
|||
|
||||
/* -------------------------------------------- */
|
||||
static _dmgArme(rollData) {
|
||||
if ( rollData.arme) {
|
||||
if (rollData.arme) {
|
||||
let dmgBase = rollData.arme.system.dommagesReels ?? Number(rollData.arme.system.dommages ?? 0);
|
||||
//Le bonus dégats magiques ne peut pas faire dépasser le bonus de l'arme (cf p.278)
|
||||
return dmgBase + Math.min(dmgBase, rollData.arme.system.magique ? rollData.arme.system.ecaille_efficacite : 0);
|
||||
|
|
|
@ -58,15 +58,6 @@ export class RdDCarac {
|
|||
selectedCarac?.label.match(/(Apparence|Force|Agilité|Dextérité|Vue|Ouïe|Odorat-Goût|Empathie|Dérobée|Mêlée|Tir|Lancer)/);
|
||||
}
|
||||
|
||||
static isIgnoreEtatGeneral(rollData) {
|
||||
const selectedCarac = rollData.selectedCarac;
|
||||
return !selectedCarac ||
|
||||
rollData.ethylisme ||
|
||||
RdDCarac.isChance(selectedCarac) ||
|
||||
(RdDCarac.isReve(selectedCarac) && !rollData.competence);
|
||||
}
|
||||
|
||||
|
||||
static computeTotal(carac, beaute = undefined) {
|
||||
const total = Object.values(carac ?? {}).filter(c => !c.derivee)
|
||||
.map(it => parseInt(it.value))
|
||||
|
|
|
@ -87,7 +87,7 @@ export class RdDCombatManager extends Combat {
|
|||
let rollFormula = formula ?? RdDCombatManager.formuleInitiative(2, 10, 0, 0);
|
||||
if (!formula) {
|
||||
if (combatant.actor.type == 'creature' || combatant.actor.type == 'entite') {
|
||||
const competence = combatant.actor.items.find(it => it.system.iscombat)
|
||||
const competence = combatant.actor.items.find(it => RdDItemCompetenceCreature.getCategorieAttaque(it))
|
||||
if (competence) {
|
||||
rollFormula = RdDCombatManager.formuleInitiative(2, competence.system.carac_value, competence.system.niveau, 0);
|
||||
}
|
||||
|
@ -96,15 +96,15 @@ export class RdDCombatManager extends Combat {
|
|||
let compName = "Corps à corps"
|
||||
if (armeCombat) {
|
||||
if (armeCombat.system.competence != "") {
|
||||
compName = armeCombat.system.competence
|
||||
compName = armeCombat.system.competence
|
||||
}
|
||||
if (armeCombat.system.lancer != "") {
|
||||
compName = armeCombat.system.lancer
|
||||
compName = armeCombat.system.lancer
|
||||
}
|
||||
if (armeCombat.system.tir != "") {
|
||||
compName = armeCombat.system.tir
|
||||
compName = armeCombat.system.tir
|
||||
}
|
||||
}
|
||||
}
|
||||
const competence = RdDItemCompetence.findCompetence(combatant.actor.items, compName);
|
||||
if (competence && competence.system.defaut_carac) {
|
||||
const carac = combatant.actor.system.carac[competence.system.defaut_carac].value;
|
||||
|
@ -230,15 +230,15 @@ export class RdDCombatManager extends Combat {
|
|||
}
|
||||
|
||||
static listActionsCreature(competences) {
|
||||
return competences.filter(it => RdDItemCompetenceCreature.isCompetenceAttaque(it))
|
||||
.map(it => RdDItemCompetenceCreature.armeNaturelle(it));
|
||||
return competences.map(it => RdDItemCompetenceCreature.armeCreature(it))
|
||||
.filter(it => it != undefined);
|
||||
}
|
||||
|
||||
static listActionsPossessions(actor) {
|
||||
return RdDCombatManager._indexActions(actor.getPossessions().map(p => {
|
||||
return {
|
||||
name: p.name,
|
||||
action: 'conjurer',
|
||||
action: 'possession',
|
||||
system: {
|
||||
competence: p.name,
|
||||
possessionid: p.system.possessionid,
|
||||
|
@ -255,7 +255,7 @@ export class RdDCombatManager extends Combat {
|
|||
return actions;
|
||||
}
|
||||
if (actor.isCreatureEntite()) {
|
||||
actions = actions.concat(RdDCombatManager.listActionsCreature(actor.itemTypes['competencecreature']));
|
||||
actions = RdDCombatManager.listActionsCreature(actor.itemTypes['competencecreature']);
|
||||
} else if (actor.isPersonnage()) {
|
||||
// Recupération des items 'arme'
|
||||
const armes = actor.itemTypes['arme'].filter(it => RdDItemArme.isArmeUtilisable(it))
|
||||
|
@ -263,7 +263,7 @@ export class RdDCombatManager extends Combat {
|
|||
.concat(RdDItemArme.mainsNues());
|
||||
|
||||
const competences = actor.itemTypes['competence'];
|
||||
actions = actions.concat(RdDCombatManager.listActionsArmes(armes, competences, actor.system.carac));
|
||||
actions = RdDCombatManager.listActionsArmes(armes, competences, actor.system.carac);
|
||||
|
||||
if (actor.system.attributs.hautrevant.value) {
|
||||
actions.push({ name: "Draconic", action: 'haut-reve', system: { initOnly: true, competence: "Draconic" } });
|
||||
|
@ -351,7 +351,7 @@ export class RdDCombatManager extends Combat {
|
|||
} else if (combatant.actor.getSurprise() == "demi") {
|
||||
initOffset = 0;
|
||||
initInfo = "Demi Surprise"
|
||||
} else if (action.action == 'conjurer') {
|
||||
} else if (action.action == 'possession') {
|
||||
initOffset = 10;
|
||||
caracForInit = combatant.actor.getReveActuel();
|
||||
initInfo = "Possession"
|
||||
|
@ -756,9 +756,7 @@ export class RdDCombat {
|
|||
RdDEmpoignade.onAttaqueEmpoignade(this.attacker, this.defender)
|
||||
return;
|
||||
}
|
||||
if ( this.attacker.isEmpoignadeEnCours() ) {
|
||||
ui.notifications.warn("Une empoignade est en cours ! Normalement, vous ne pouvez rien faire d'autre que continuer l'empoignade ou la rompre.")
|
||||
}
|
||||
RdDEmpoignade.checkEmpoignadeEnCours(this.attacker)
|
||||
|
||||
let rollData = this._prepareAttaque(competence, arme);
|
||||
console.log("RdDCombat.attaque >>>", rollData);
|
||||
|
@ -792,7 +790,7 @@ export class RdDCombat {
|
|||
passeArme: randomID(16),
|
||||
mortalite: arme?.system.mortalite,
|
||||
coupsNonMortels: false,
|
||||
competence: competence,
|
||||
competence: competence.clone(),
|
||||
surprise: this.attacker.getSurprise(true),
|
||||
surpriseDefenseur: this.defender.getSurprise(true),
|
||||
targetToken: Targets.extractTokenData(this.target),
|
||||
|
@ -1047,7 +1045,7 @@ export class RdDCombat {
|
|||
passeArme: attackerRoll.passeArme,
|
||||
diffLibre: attackerRoll.diffLibre,
|
||||
attackerRoll: attackerRoll,
|
||||
competence: this.defender.getCompetence(competenceParade),
|
||||
competence: this.defender.getCompetence(competenceParade).clone(),
|
||||
arme: armeParade,
|
||||
surprise: this.defender.getSurprise(true),
|
||||
needParadeSignificative: ReglesOptionelles.isUsing('categorieParade') && RdDItemArme.needParadeSignificative(attackerRoll.arme, armeParade),
|
||||
|
@ -1128,7 +1126,7 @@ export class RdDCombat {
|
|||
passeArme: attackerRoll.passeArme,
|
||||
diffLibre: attackerRoll.diffLibre,
|
||||
attackerRoll: attackerRoll,
|
||||
competence: competence,
|
||||
competence: competence.clone(),
|
||||
surprise: this.defender.getSurprise(true),
|
||||
surpriseDefenseur: this.defender.getSurprise(true),
|
||||
carac: this.defender.system.carac,
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
/* -------------------------------------------- */
|
||||
import { RdDCombat } from "./rdd-combat.js";
|
||||
import { RdDResolutionTable } from "./rdd-resolution-table.js";
|
||||
import { RdDRoll } from "./rdd-roll.js";
|
||||
import { RdDItemCompetenceCreature } from "./item-competencecreature.js";
|
||||
import { ChatUtility } from "./chat-utility.js";
|
||||
import { STATUSES, StatusEffects } from "./settings/status-effects.js";
|
||||
import { STATUSES } from "./settings/status-effects.js";
|
||||
import { ReglesOptionelles } from "./settings/regles-optionelles.js";
|
||||
import { TYPES } from "./item.js";
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
|
@ -15,69 +16,143 @@ export class RdDEmpoignade {
|
|||
static init() {
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static registerChatCallbacks(html) {
|
||||
html.on("click", '.defense-empoignade-cac', event => {
|
||||
const chatMessage = ChatUtility.getChatMessage(event);
|
||||
const rollData = RdDEmpoignade.$readRollEmpoignade(chatMessage);
|
||||
let defenseMode = event.currentTarget.attributes['data-defense-mode'].value
|
||||
RdDEmpoignade.onDefenseEmpoignade(rollData, defenseMode, "Corps à corps", "melee")
|
||||
});
|
||||
html.on("click", '.defense-empoignade-esquive', event => {
|
||||
const chatMessage = ChatUtility.getChatMessage(event);
|
||||
const rollData = RdDEmpoignade.$readRollEmpoignade(chatMessage);
|
||||
let defenseMode = event.currentTarget.attributes['data-defense-mode'].value
|
||||
RdDEmpoignade.onDefenseEmpoignade(rollData, defenseMode, "Esquive", "derobee")
|
||||
});
|
||||
html.on("click", '.empoignade-poursuivre', event => {
|
||||
let attackerId = event.currentTarget.attributes['data-attackerId'].value
|
||||
let defenderId = event.currentTarget.attributes['data-defenderId'].value
|
||||
RdDEmpoignade.onAttaqueEmpoignadeValidee(game.actors.get(attackerId), game.actors.get(defenderId))
|
||||
});
|
||||
html.on("click", '.empoignade-entrainer-sol', event => {
|
||||
const chatMessage = ChatUtility.getChatMessage(event);
|
||||
const rollData = RdDEmpoignade.$readRollEmpoignade(chatMessage);
|
||||
RdDEmpoignade.entrainerAuSol(rollData)
|
||||
ChatUtility.removeChatMessageId(chatMessage.id)
|
||||
});
|
||||
html.on("click", '.empoignade-projeter-sol', event => {
|
||||
const chatMessage = ChatUtility.getChatMessage(event);
|
||||
const rollData = RdDEmpoignade.$readRollEmpoignade(chatMessage);
|
||||
RdDEmpoignade.projeterAuSol(rollData)
|
||||
ChatUtility.removeChatMessageId(chatMessage.id)
|
||||
});
|
||||
html.on("change", '.empoignade-perte-endurance', event => {
|
||||
const chatMessage = ChatUtility.getChatMessage(event);
|
||||
const rollData = RdDEmpoignade.$readRollEmpoignade(chatMessage);
|
||||
if (event.currentTarget.value && event.currentTarget.value != "none") {
|
||||
RdDEmpoignade.perteEndurance(rollData, event.currentTarget.value)
|
||||
ChatUtility.removeChatMessageId(chatMessage.id)
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static checkEmpoignadeEnCours(actor) {
|
||||
// TODO: autoriser la perception? la comédie/séduction?
|
||||
if (RdDEmpoignade.isEmpoignadeEnCours(actor)) {
|
||||
ui.notifications.warn("Une empoignade est en cours ! Normalement, vous ne pouvez rien faire d'autre que continuer l'empoignade ou la rompre.")
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static $storeRollEmpoignade(msg, rollData) {
|
||||
RdDEmpoignade.$reduceActorToIds(rollData);
|
||||
ChatUtility.setMessageData(msg, "empoignade-roll-data", rollData);
|
||||
}
|
||||
|
||||
static $reduceActorToIds(rollData) {
|
||||
rollData.attacker = { id: rollData.attacker.id };
|
||||
rollData.defender = { id: rollData.defender.id };
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static $readRollEmpoignade(msg) {
|
||||
const rollData = ChatUtility.getMessageData(msg, 'empoignade-roll-data');
|
||||
RdDEmpoignade.$replaceIdsWithActors(rollData);
|
||||
return rollData
|
||||
}
|
||||
|
||||
static $replaceIdsWithActors(rollData) {
|
||||
rollData.attacker = game.actors.get(rollData.attacker.id);
|
||||
rollData.defender = game.actors.get(rollData.defender.id);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static isEmpoignadeEnCours(actor) {
|
||||
return actor.itemTypes[TYPES.empoignade].find(it => it.system.pointsemp > 0)
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static getEmpoignadeById(actor, id) {
|
||||
let emp = actor.items.find(emp => emp.type == 'empoignade' && emp.system.empoignadeid == id)
|
||||
let emp = actor.itemTypes[TYPES.empoignade].find(it => it.system.empoignadeid == id)
|
||||
return emp && duplicate(emp) || undefined;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static getEmpoignade(attacker, defender) {
|
||||
let emp = attacker.items.find(emp => emp.type == 'empoignade' && emp.system.empoigneurid == attacker.id && emp.system.empoigneid == defender.id)
|
||||
if (!emp) {
|
||||
emp = attacker.items.find(emp => emp.type == 'empoignade' && emp.system.empoigneurid == defender.id && emp.system.empoigneid == attacker.id)
|
||||
}
|
||||
let emp = attacker.itemTypes[TYPES.empoignade].find(it =>
|
||||
(it.system.empoigneurid == attacker.id && it.system.empoigneid == defender.id) ||
|
||||
(it.system.empoigneurid == defender.id && it.system.empoigneid == attacker.id)
|
||||
)
|
||||
if (emp) {
|
||||
// TODO ? central storage ?
|
||||
return duplicate(emp);
|
||||
}
|
||||
return emp && duplicate(emp) || undefined;
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static getMalusTaille(emp, attacker, defender) {
|
||||
// Si pas empoigné, alors 0
|
||||
if (emp.system.pointsemp == 0) {
|
||||
return 0
|
||||
}
|
||||
// Malus de -1 si différence de taille de 2 ou plus (p 135)
|
||||
if (attacker.system.carac.taille.value < defender.system.carac.taille.value - 1) {
|
||||
return attacker.system.carac.taille.value - (defender.system.carac.taille.value - 1)
|
||||
// p135: Malus de -1 par point de taille de différence de taille au delà de 1 (donc -2 pour une différence de 3, ...)
|
||||
const diffTaille = attacker.system.carac.taille.value - defender.system.carac.taille.value;
|
||||
const diffTailleAbs = Math.abs(diffTaille)
|
||||
const signDiff = diffTaille > 0 ? 1 : -1
|
||||
|
||||
if (diffTailleAbs > 2) {
|
||||
return signDiff * (diffTailleAbs - 1)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async onAttaqueEmpoignadeValidee(attacker, defender) {
|
||||
let empoignade = RdDEmpoignade.getEmpoignade(attacker, defender)
|
||||
const isNouvelle = empoignade == undefined;
|
||||
empoignade = empoignade ?? (await RdDEmpoignade.createEmpoignade(attacker, defender))
|
||||
static isActionAutorisee(mode, attacker, defender) {
|
||||
const acting = RdDEmpoignade.isActionDefenseur(mode) ? defender : attacker;
|
||||
if (acting.getUserLevel(game.user) < CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER) {
|
||||
ui.notifications.warn(`Vous n'êtes pas autorisé à choisir l'action de ${acting.name}`)
|
||||
return false;
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
let mode = (empoignade && empoignade.system.empoigneurid == attacker.id) ? "empoigner" : "liberer"
|
||||
|
||||
let rollData = {
|
||||
mode: mode,
|
||||
isEmpoignade: true,
|
||||
competence: attacker.getCompetence("Corps à corps"),
|
||||
selectedCarac: attacker.system.carac.melee,
|
||||
empoignade: empoignade,
|
||||
attackerId: attacker.id,
|
||||
attackerName: attacker.name,
|
||||
defenderName: defender.name,
|
||||
defenderId: defender.id,
|
||||
malusTaille: RdDEmpoignade.getMalusTaille(empoignade, attacker, defender)
|
||||
}
|
||||
if (attacker.isCreatureEntite()) {
|
||||
RdDItemCompetenceCreature.setRollDataCreature(rollData)
|
||||
}
|
||||
if (empoignade.system.pointsemp >= 2) {
|
||||
let msg = await RdDResolutionTable.displayRollData(rollData, attacker, 'chat-empoignade-actions.html');
|
||||
ChatUtility.setMessageData(msg, "empoignade-roll-data", rollData)
|
||||
} else {
|
||||
await RdDEmpoignade.$rollAttaqueEmpoignade(attacker, rollData, isNouvelle);
|
||||
static isActionDefenseur(mode) {
|
||||
switch (mode) {
|
||||
case "liberer":
|
||||
case "contrer-empoigner":
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async onAttaqueEmpoignade(attacker, defender) {
|
||||
if (!RdDEmpoignade.isActionAutorisee("empoigner", attacker, defender)) {
|
||||
return
|
||||
}
|
||||
let empoignade = RdDEmpoignade.getEmpoignade(attacker, defender)
|
||||
const isNouvelle = empoignade == undefined;
|
||||
empoignade = empoignade ?? (await RdDEmpoignade.createEmpoignade(attacker, defender))
|
||||
|
@ -91,6 +166,38 @@ export class RdDEmpoignade {
|
|||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async onAttaqueEmpoignadeValidee(attacker, defender) {
|
||||
let empoignade = RdDEmpoignade.getEmpoignade(attacker, defender)
|
||||
const isNouvelle = empoignade == undefined;
|
||||
empoignade = empoignade ?? (await RdDEmpoignade.createEmpoignade(attacker, defender))
|
||||
|
||||
let mode = (empoignade && empoignade.system.empoigneurid == attacker.id) ? "empoigner" : "liberer"
|
||||
|
||||
if (!RdDEmpoignade.isActionAutorisee(mode, attacker, defender)) {
|
||||
return
|
||||
}
|
||||
|
||||
let rollData = {
|
||||
mode, empoignade, attacker, defender,
|
||||
isEmpoignade: true,
|
||||
competence: attacker.getCompetence("Corps à corps").clone(),
|
||||
selectedCarac: attacker.system.carac.melee,
|
||||
malusTaille: RdDEmpoignade.getMalusTaille(empoignade, attacker, defender)
|
||||
}
|
||||
if (attacker.isCreatureEntite()) {
|
||||
RdDItemCompetenceCreature.setRollDataCreature(rollData)
|
||||
}
|
||||
if (empoignade.system.pointsemp >= 2) {
|
||||
if (!empoignade.system.ausol) {
|
||||
let msg = await RdDResolutionTable.displayRollData(rollData, attacker, 'chat-empoignade-entrainer.html');
|
||||
RdDEmpoignade.$storeRollEmpoignade(msg, rollData);
|
||||
}
|
||||
} else {
|
||||
await RdDEmpoignade.$rollAttaqueEmpoignade(attacker, rollData, isNouvelle);
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async onAttaqueEmpoignadeFromItem(empoignade) {
|
||||
let attacker = game.actors.get(empoignade.system.empoigneurid)
|
||||
|
@ -98,6 +205,20 @@ export class RdDEmpoignade {
|
|||
await this.onAttaqueEmpoignadeValidee(attacker, defender)
|
||||
}
|
||||
|
||||
static async onImmobilisation(attacker, defender, empoignade) {
|
||||
const rollData = {
|
||||
mode: "immobilise",
|
||||
empoignade, attacker, defender,
|
||||
isEmpoignade: true,
|
||||
competence: attacker.getCompetence("Corps à corps").clone()
|
||||
}
|
||||
const msg = await ChatMessage.create({
|
||||
whisper: ChatUtility.getWhisperRecipientsAndGMs(attacker.name),
|
||||
content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-empoignade-immobilise.html`, rollData)
|
||||
})
|
||||
RdDEmpoignade.$storeRollEmpoignade(msg, rollData);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async $rollAttaqueEmpoignade(attacker, rollData, isNouvelle = false) {
|
||||
const dialog = await RdDRoll.create(attacker, rollData,
|
||||
|
@ -105,35 +226,40 @@ export class RdDEmpoignade {
|
|||
{
|
||||
name: 'jet-empoignade',
|
||||
label: 'Empoigner',
|
||||
callbacks: [
|
||||
{ condition: r => (r.rolled.isSuccess), action: async (r) => await RdDEmpoignade.$onRollEmpoignade(r, true, isNouvelle) },
|
||||
{ condition: r => (r.rolled.isEchec), action: async (r) => await RdDEmpoignade.$onRollEmpoignade(r, false, isNouvelle) },
|
||||
]
|
||||
callbacks: [{ action: async (r) => await RdDEmpoignade.$onRollEmpoignade(r, isNouvelle) },]
|
||||
});
|
||||
dialog.render(true);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async $onRollEmpoignade(rollData, isSuccess, isNouvelle = false) {
|
||||
let attacker = game.actors.get(rollData.attackerId)
|
||||
let defender = game.actors.get(rollData.defenderId)
|
||||
static async $onRollEmpoignade(rollData, isNouvelle = false) {
|
||||
let attacker = game.actors.get(rollData.attacker.id)
|
||||
let defender = game.actors.get(rollData.defender.id)
|
||||
|
||||
let empoignade = rollData.empoignade
|
||||
empoignade.isSuccess = isSuccess;
|
||||
|
||||
if (isSuccess && isNouvelle) {
|
||||
if (rollData.rolled.isSuccess && isNouvelle) {
|
||||
const objectEmpoignade = rollData.empoignade.toObject();
|
||||
// Creer l'empoignade sur attaquant/defenseur
|
||||
await attacker.createEmbeddedDocuments('Item', [empoignade.toObject()])
|
||||
await defender.createEmbeddedDocuments('Item', [empoignade.toObject()])
|
||||
attacker.creerObjetParMJ(objectEmpoignade);
|
||||
defender.creerObjetParMJ(objectEmpoignade);
|
||||
}
|
||||
|
||||
rollData.empoignade.isSuccess = rollData.rolled.isSuccess;
|
||||
if (rollData.rolled.isPart) {
|
||||
rollData.particuliere = "finesse";
|
||||
}
|
||||
let msg = await RdDResolutionTable.displayRollData(rollData, attacker, 'chat-empoignade-resultat.html');
|
||||
ChatUtility.setMessageData(msg, "empoignade-roll-data", rollData)
|
||||
RdDEmpoignade.$storeRollEmpoignade(msg, rollData);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async onDefenseEmpoignade(rollData, defenseMode, competenceName = "Corps à corps", carac = "melee") {
|
||||
let attacker = game.actors.get(rollData.attackerId)
|
||||
let defender = game.actors.get(rollData.defenderId)
|
||||
static async onDefenseEmpoignade(attackerRoll, mode, competenceName = "Corps à corps", carac = "melee") {
|
||||
let attacker = game.actors.get(attackerRoll.attacker.id)
|
||||
let defender = game.actors.get(attackerRoll.defender.id)
|
||||
if (!RdDEmpoignade.isActionAutorisee(mode, attacker, defender)) {
|
||||
return
|
||||
}
|
||||
|
||||
let empoignade = this.getEmpoignade(attacker, defender)
|
||||
|
||||
if (!empoignade) {
|
||||
|
@ -142,18 +268,23 @@ export class RdDEmpoignade {
|
|||
}
|
||||
|
||||
empoignade = duplicate(empoignade)
|
||||
rollData.mode = defenseMode
|
||||
rollData.empoignade = empoignade
|
||||
rollData.competence = defender.getCompetence(competenceName),
|
||||
rollData.selectedCarac = defender.system.carac[carac],
|
||||
rollData.malusTaille = RdDEmpoignade.getMalusTaille(empoignade, defender, attacker)
|
||||
|
||||
await RdDEmpoignade.$rollDefenseEmpoignade(defender, rollData);
|
||||
let defenderRoll = {
|
||||
mode, attacker, defender, empoignade, attackerRoll,
|
||||
diffLibre: attackerRoll.diffLibre,
|
||||
attaqueParticuliere: attackerRoll.particuliere,
|
||||
competence: defender.getCompetence(competenceName).clone(),
|
||||
surprise: defender.getSurprise(true),
|
||||
carac: defender.system.carac,
|
||||
selectedCarac: defender.system.carac[carac],
|
||||
malusTaille: RdDEmpoignade.getMalusTaille(empoignade, defender, attacker),
|
||||
show: {}
|
||||
};
|
||||
await RdDEmpoignade.$rollDefenseEmpoignade(defender, defenderRoll);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async $rollDefenseEmpoignade(defender, rollData) {
|
||||
const dialog = await RdDRoll.create(defender, rollData,
|
||||
static async $rollDefenseEmpoignade(defender, defenderRoll) {
|
||||
const dialog = await RdDRoll.create(defender, defenderRoll,
|
||||
{ html: 'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-defense-empoignade.html' },
|
||||
{
|
||||
name: 'empoignade',
|
||||
|
@ -169,7 +300,7 @@ export class RdDEmpoignade {
|
|||
/* -------------------------------------------- */
|
||||
static async $onRollContrerLiberer(rollData) {
|
||||
let empoignade = rollData.empoignade
|
||||
|
||||
|
||||
if (rollData.mode == "contrer-empoigner" && !rollData.rolled.isSuccess) {
|
||||
empoignade.system.pointsemp++
|
||||
RdDEmpoignade.$updateEtatEmpoignade(empoignade)
|
||||
|
@ -178,13 +309,12 @@ export class RdDEmpoignade {
|
|||
empoignade.system.pointsemp--
|
||||
RdDEmpoignade.$updateEtatEmpoignade(empoignade)
|
||||
}
|
||||
|
||||
if (empoignade.system.pointsemp >= 2) {
|
||||
let attacker = game.actors.get(empoignade.system.empoigneurid)
|
||||
let msg = await RdDResolutionTable.displayRollData(rollData, attacker, 'chat-empoignade-actions.html');
|
||||
ChatUtility.setMessageData(msg, "empoignade-roll-data", rollData)
|
||||
}
|
||||
|
||||
await RdDResolutionTable.displayRollData(rollData, rollData.defender, 'chat-empoignade-resultat.html')
|
||||
if (empoignade.system.pointsemp >= 2) {
|
||||
let msg = await RdDResolutionTable.displayRollData(rollData, rollData.attacker, 'chat-empoignade-entrainer.html');
|
||||
RdDEmpoignade.$storeRollEmpoignade(msg, rollData);
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
@ -209,16 +339,15 @@ export class RdDEmpoignade {
|
|||
let defender = game.actors.get(empoignade.system.empoigneid)
|
||||
let emp = RdDEmpoignade.getEmpoignadeById(defender, empoignade.system.empoignadeid)
|
||||
await defender.deleteEmbeddedDocuments('Item', [emp._id])
|
||||
|
||||
let attacker = game.actors.get(empoignade.system.empoigneurid)
|
||||
emp = RdDEmpoignade.getEmpoignadeById(attacker, empoignade.system.empoignadeid)
|
||||
await attacker.deleteEmbeddedDocuments('Item', [emp._id])
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async entrainerAuSol(rollData) {
|
||||
let attacker = game.actors.get(rollData.attackerId)
|
||||
let defender = game.actors.get(rollData.defenderId)
|
||||
let attacker = game.actors.get(rollData.attacker.id)
|
||||
let defender = game.actors.get(rollData.defender.id)
|
||||
if (!RdDEmpoignade.isActionAutorisee("immobilise", attacker, defender)) {
|
||||
return
|
||||
}
|
||||
let empoignade = this.getEmpoignade(attacker, defender)
|
||||
|
||||
empoignade.system.ausol = true
|
||||
|
@ -228,55 +357,60 @@ export class RdDEmpoignade {
|
|||
await defender.setEffect(STATUSES.StatusProne, true);
|
||||
|
||||
let msg = await RdDResolutionTable.displayRollData(rollData, attacker, 'chat-empoignade-entrainer-sol.html');
|
||||
ChatUtility.setMessageData(msg, "empoignade-roll-data", rollData)
|
||||
RdDEmpoignade.$storeRollEmpoignade(msg, rollData);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async projeterAuSol(rollData) {
|
||||
let attacker = game.actors.get(rollData.attackerId)
|
||||
let defender = game.actors.get(rollData.defenderId)
|
||||
let attacker = game.actors.get(rollData.attacker.id)
|
||||
let defender = game.actors.get(rollData.defender.id)
|
||||
if (!RdDEmpoignade.isActionAutorisee("immobilise", attacker, defender)) {
|
||||
return
|
||||
}
|
||||
let empoignade = this.getEmpoignade(attacker, defender)
|
||||
|
||||
await defender.setEffect(STATUSES.StatusProne, true);
|
||||
await this.$deleteEmpoignade(empoignade)
|
||||
|
||||
let msg = await RdDResolutionTable.displayRollData(rollData, attacker, 'chat-empoignade-projeter-sol.html');
|
||||
ChatUtility.setMessageData(msg, "empoignade-roll-data", rollData)
|
||||
RdDEmpoignade.$storeRollEmpoignade(msg, rollData);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async perteEndurance(rollData, perteMode) {
|
||||
let attacker = game.actors.get(rollData.attackerId)
|
||||
let defender = game.actors.get(rollData.defenderId)
|
||||
let attacker = game.actors.get(rollData.attacker.id)
|
||||
let defender = game.actors.get(rollData.defender.id)
|
||||
if (!RdDEmpoignade.isActionAutorisee("immobilise", attacker, defender)) {
|
||||
return
|
||||
}
|
||||
let empoignade = this.getEmpoignade(attacker, defender)
|
||||
|
||||
console.log("Perte d'endurance :!!!", perteMode)
|
||||
//console.log("Perte d'endurance :!!!", perteMode)
|
||||
let endValue = defender.system.sante.endurance.value
|
||||
if (perteMode == "end0") {
|
||||
await defender.santeIncDec("endurance", -defender.system.sante.endurance.value);
|
||||
await defender.santeIncDec("endurance", -endValue);
|
||||
}
|
||||
if (perteMode == "end1") {
|
||||
await defender.santeIncDec("endurance", -(defender.system.sante.endurance.value - 1));
|
||||
await defender.santeIncDec("endurance", -(endValue - 1));
|
||||
}
|
||||
if (perteMode == "endmoitie") {
|
||||
await defender.santeIncDec("endurance", -Math.floor(defender.system.sante.endurance.value / 2));
|
||||
await defender.santeIncDec("endurance", -Math.floor(endValue / 2));
|
||||
}
|
||||
if (perteMode == "endquart") {
|
||||
await defender.santeIncDec("endurance", -(3 * Math.floor(defender.system.sante.endurance.value / 4)));
|
||||
await defender.santeIncDec("endurance", -(3 * Math.floor(endValue / 4)));
|
||||
}
|
||||
let msg = await RdDResolutionTable.displayRollData(rollData, attacker, 'chat-empoignade-perte-endurance.html');
|
||||
ChatUtility.setMessageData(msg, "empoignade-roll-data", rollData)
|
||||
RdDEmpoignade.$storeRollEmpoignade(msg, rollData);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async deleteAllEmpoignades() {
|
||||
for (let actor of game.actors) {
|
||||
let empList = actor.items.filter(it => it.type == "empoignade")
|
||||
for (let emp of empList) {
|
||||
await actor.deleteEmbeddedDocuments('Item', [emp.id])
|
||||
}
|
||||
let empIds = actor.itemTypes["empoignade"].map(it => it.id)
|
||||
await actor.deleteEmbeddedDocuments('Item', empIds)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async deleteLinkedEmpoignade(actorId, empoignade) {
|
||||
let actorDeleteId = (actorId == empoignade.system.empoigneurid) ? empoignade.system.empoigneid : empoignade.system.empoigneurid
|
||||
|
@ -290,7 +424,8 @@ export class RdDEmpoignade {
|
|||
/* -------------------------------------------- */
|
||||
static async createEmpoignade(attacker, defender) {
|
||||
return await Item.create({
|
||||
name: "Empoignade en cours de " + attacker.name + ' sur ' + defender.name, type: 'empoignade',
|
||||
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: randomID(16), compteempoigne: 0, empoigneurid: attacker.id, empoigneid: defender.id, ptsemp: 0, empoigneurname: attacker.name, empoignename: defender.name }
|
||||
},
|
||||
|
|
|
@ -58,6 +58,7 @@ import { RdDConteneurItemSheet } from "./item/sheet-conteneur.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";
|
||||
|
||||
/**
|
||||
* RdD system
|
||||
|
@ -76,6 +77,7 @@ export class SystemReveDeDragon {
|
|||
this.RdDUtility = RdDUtility;
|
||||
this.RdDHotbar = RdDHotbar;
|
||||
this.itemClasses = {
|
||||
armure: RdDItemArmure,
|
||||
blessure: RdDItemBlessure,
|
||||
maladie: RdDItemMaladie,
|
||||
ombre: RdDItemOmbre,
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
/* -------------------------------------------- */
|
||||
import { RdDCombat } from "./rdd-combat.js";
|
||||
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 { TYPES } from "./item.js";
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/* On part du principe qu'une entité démarre tjs
|
||||
|
@ -20,9 +20,9 @@ export class RdDPossession {
|
|||
|
||||
/* -------------------------------------------- */
|
||||
static searchPossessionFromEntite(attacker, defender) {
|
||||
let poss = attacker.items.find(poss => poss.type == 'possession' && poss.system.possedeid == defender.id);
|
||||
let poss = attacker.items.find(poss => poss.type == TYPES.possession && poss.system.victime.actorid == defender.id);
|
||||
if (!poss) {
|
||||
poss = defender.items.find(poss => poss.type == 'possession' && poss.system.possedeid == defender.id);
|
||||
poss = defender.items.find(poss => poss.type == TYPES.possession && poss.system.victime.actorid == defender.id);
|
||||
}
|
||||
return poss && duplicate(poss) || undefined;
|
||||
}
|
||||
|
@ -31,39 +31,40 @@ export class RdDPossession {
|
|||
static async onAttaquePossession(target, attacker, competence, suitePossession = undefined) {
|
||||
const defender = target.actor;
|
||||
const fromEntite = RdDPossession.searchPossessionFromEntite(attacker, defender);
|
||||
const isNouvelle = !suitePossession && ! fromEntite;
|
||||
const isNouvelle = !suitePossession && !fromEntite;
|
||||
const possession = (suitePossession ?? fromEntite ?? (await RdDPossession.createPossession(attacker, defender)));
|
||||
|
||||
|
||||
RdDPossession.$updateEtatPossession(possession)
|
||||
|
||||
let rollData = {
|
||||
mode: "possession",
|
||||
mode: "attaque",
|
||||
isECNIDefender: false,
|
||||
competence: competence,
|
||||
competence: competence.clone(),
|
||||
possession: possession,
|
||||
attacker: attacker,
|
||||
defender: defender,
|
||||
targetToken: Targets.extractTokenData(target)
|
||||
};
|
||||
if (attacker.isCreatureEntite()) {
|
||||
RdDItemCompetenceCreature.setRollDataCreature(rollData)
|
||||
}
|
||||
|
||||
RdDPossession.selectCompetenceDraconicOuPossession(rollData, attacker)
|
||||
|
||||
await RdDPossession.$rollAttaquePossession(attacker, rollData, isNouvelle);
|
||||
}
|
||||
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async onConjurerPossession(attacker, competence, possession) {
|
||||
static async onConjurerPossession(attacker, possession) {
|
||||
possession = duplicate(possession);
|
||||
RdDPossession.$updateEtatPossession(possession)
|
||||
|
||||
const defender = game.actors.get(possession.system.entite.actorid);
|
||||
let rollData = {
|
||||
mode: "possession",
|
||||
mode: "attaque",
|
||||
isECNIDefender: true,
|
||||
competence: competence,
|
||||
possession: possession,
|
||||
attacker: attacker,
|
||||
defender: game.actors.get(possession.system.possesseurid)
|
||||
defender: defender,
|
||||
};
|
||||
RdDPossession.selectCompetenceDraconicOuPossession(rollData, attacker)
|
||||
|
||||
await RdDPossession.$rollAttaquePossession(attacker, rollData);
|
||||
}
|
||||
|
||||
|
@ -71,7 +72,7 @@ export class RdDPossession {
|
|||
static async onDefensePossession(attackerId, defenderId, possessionId) {
|
||||
let attacker = game.actors.get(attackerId)
|
||||
let possession = attacker?.getPossession(possessionId)
|
||||
defenderId = defenderId ?? possession?.system.possesseurid ?? undefined
|
||||
defenderId = defenderId ?? possession?.system.entite.actorid ?? undefined
|
||||
let defender = game.actors.get(defenderId)
|
||||
possession = possession ?? defender?.getPossession(possessionId) ?? undefined;
|
||||
|
||||
|
@ -82,19 +83,29 @@ export class RdDPossession {
|
|||
possession = duplicate(possession)
|
||||
// Update for draconic roll
|
||||
let rollData = {
|
||||
mode: "conjuration",
|
||||
mode: "defense",
|
||||
isECNIDefender: defender.type == "entite",
|
||||
possession: possession,
|
||||
attacker: attacker,
|
||||
defender: defender,
|
||||
competence: defender.getDraconicOuPossession(),
|
||||
selectedCarac: defender.system.carac.reve,
|
||||
forceCarac: { 'reve-actuel': { label: "Rêve Actuel", value: defender.getReveActuel() } }
|
||||
}
|
||||
rollData.competence.system.defaut_carac = 'reve-actuel'
|
||||
|
||||
RdDPossession.selectCompetenceDraconicOuPossession(rollData, defender)
|
||||
rollData.diffLibre = RdDPossession.getInfoAttaque(rollData).diffLibre
|
||||
|
||||
await RdDPossession.$rollDefensePossession(defender, rollData);
|
||||
}
|
||||
|
||||
static selectCompetenceDraconicOuPossession(rollData, rollingActor) {
|
||||
rollData.competence = rollingActor.getDraconicOuPossession();
|
||||
if (rollingActor.isCreatureEntite()) {
|
||||
RdDItemCompetenceCreature.setRollDataCreature(rollData)
|
||||
}
|
||||
else {
|
||||
rollData.selectedCarac = rollingActor.system.carac.reve
|
||||
rollData.forceCarac = { 'reve-actuel': { label: "Rêve Actuel", value: rollingActor.getReveActuel() } }
|
||||
rollData.competence.system.defaut_carac = 'reve-actuel'
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async $rollAttaquePossession(attacker, rollData, isNouvelle = false) {
|
||||
|
@ -104,21 +115,22 @@ export class RdDPossession {
|
|||
name: 'jet-possession',
|
||||
label: rollData.isECNIDefender ? 'Conjurer la possession' : 'Possession',
|
||||
callbacks: [
|
||||
{ condition: r => (r.rolled.isSuccess), action: async (r) => await RdDPossession.$onRollPossession(r, true, isNouvelle) },
|
||||
{ condition: r => (r.rolled.isEchec), action: async (r) => await RdDPossession.$onRollPossession(r, false, isNouvelle) },
|
||||
{ action: async (r) => await RdDPossession.$onRollPossession(r, isNouvelle) },
|
||||
]
|
||||
});
|
||||
dialog.render(true);
|
||||
dialog.render(true);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async $onRollPossession(rollData, isSuccess, isNouvelle = false) {
|
||||
rollData.possession.isSuccess = isSuccess;
|
||||
RdDPossession.$updateEtatPossession(rollData.possession);
|
||||
static async $onRollPossession(rollData, isNouvelle = false) {
|
||||
rollData.possession.isSuccess = rollData.rolled.isSuccess;
|
||||
RdDPossession.$updateEtatPossession(rollData.possession, rollData);
|
||||
if (isNouvelle) {
|
||||
// Creer la possession sur le defenseur
|
||||
rollData.defender.createEmbeddedDocuments('Item', [rollData.possession.toObject()])
|
||||
await rollData.defender.createEmbeddedDocuments('Item', [rollData.possession.toObject()])
|
||||
}
|
||||
const possession = (rollData.isECNIDefender ? rollData.attacker : rollData.defender).getPossession(rollData.possession.system.possessionid)
|
||||
RdDPossession.storePossessionAttaque(possession, rollData)
|
||||
await RdDResolutionTable.displayRollData(rollData, rollData.attacker, 'chat-resultat-possession.html');
|
||||
}
|
||||
|
||||
|
@ -127,35 +139,42 @@ export class RdDPossession {
|
|||
const dialog = await RdDRoll.create(defender, rollData,
|
||||
{ html: 'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-defense-possession.html' },
|
||||
{
|
||||
name: 'conjurer',
|
||||
name: 'possession',
|
||||
label: 'Conjurer une Possession',
|
||||
callbacks: [
|
||||
{ action: async (r) => await RdDPossession.$onRollConjuration(r) }
|
||||
]
|
||||
}
|
||||
);
|
||||
]
|
||||
}
|
||||
);
|
||||
dialog.render(true);
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async $onRollConjuration(rollData) {
|
||||
let actor = game.actors.get(rollData.possession.system.possedeid)
|
||||
let victime = game.actors.get(rollData.possession.system.victime.actorid)
|
||||
let compteur = rollData.possession.system.compteur
|
||||
if (!rollData.rolled.isSuccess) {
|
||||
if (rollData.isECNIDefender) {
|
||||
rollData.possession.system.compteur--
|
||||
compteur--
|
||||
} else {
|
||||
rollData.possession.system.compteur++
|
||||
compteur++
|
||||
}
|
||||
let update = { _id: rollData.possession._id, "system.compteur": rollData.possession.system.compteur }
|
||||
await actor.updateEmbeddedDocuments('Item', [update])
|
||||
}
|
||||
|
||||
const possession = victime.getPossession(rollData.possession.system.possessionid)
|
||||
await possession.update({
|
||||
system: {
|
||||
compteur: compteur,
|
||||
entite: { diffLibre: 0, finesse: false },
|
||||
victime: { diffLibre: 0, finesse: false }
|
||||
}
|
||||
})
|
||||
rollData.possession = possession
|
||||
RdDPossession.$updateEtatPossession(rollData.possession)
|
||||
|
||||
await RdDResolutionTable.displayRollData(rollData,rollData.defender, 'chat-resultat-possession.html')
|
||||
await RdDResolutionTable.displayRollData(rollData, rollData.defender, 'chat-resultat-possession.html')
|
||||
if (rollData.possession.isPosseder || rollData.possession.isConjurer) {
|
||||
// conjuration
|
||||
actor.deleteEmbeddedDocuments("Item", [rollData.possession._id])
|
||||
victime.deleteEmbeddedDocuments("Item", [rollData.possession._id])
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -180,13 +199,43 @@ export class RdDPossession {
|
|||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static isPossessionFinesse(rollData) {
|
||||
return RdDPossession.getInfoAttaque(rollData).finesse
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
static getInfoAttaque(rollData) {
|
||||
return rollData.possession.system[rollData.isECNIDefender ? 'victime' : 'entite'];
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
static isDefensePossession(rollData) {
|
||||
return rollData.possession && rollData.mode == "defense"
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
static storePossessionAttaque(possession, rollData = undefined) {
|
||||
const attaquant = rollData?.isECNIDefender ? 'victime' : 'entite'
|
||||
possession.update({
|
||||
[`system.${attaquant}`]: {
|
||||
diffLibre: rollData?.diffLibre ?? 0,
|
||||
finesse: rollData?.rolled.isPart ?? false
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async createPossession(attacker, defender) {
|
||||
return await Item.create({
|
||||
name: "Possession en cours de " + attacker.name, type: 'possession',
|
||||
img: "systems/foundryvtt-reve-de-dragon/icons/entites/possession2.webp",
|
||||
system: { description: "", typepossession: attacker.name, possede: false, possessionid: randomID(16), possesseurid: attacker.id, possedeid: defender.id, date: 0, compteur: 0 }
|
||||
},
|
||||
name: "Possession en cours de " + attacker.name, type: 'possession',
|
||||
img: "systems/foundryvtt-reve-de-dragon/icons/entites/possession2.webp",
|
||||
system: {
|
||||
description: "", typepossession: attacker.name,
|
||||
possede: false,
|
||||
possessionid: randomID(16),
|
||||
entite: { actorid: attacker.id },
|
||||
victime: { actorid: defender.id },
|
||||
compteur: 0
|
||||
}
|
||||
},
|
||||
{
|
||||
temporary: true
|
||||
})
|
||||
|
|
|
@ -91,13 +91,17 @@ export class RdDResolutionTable {
|
|||
|
||||
/* -------------------------------------------- */
|
||||
static async displayRollData(rollData, actor = undefined, template = 'chat-resultat-general.html') {
|
||||
return await ChatUtility.createChatWithRollMode(actor?.userName ?? game.user.name, {
|
||||
content: await RdDResolutionTable.buildRollDataHtml(rollData, actor, template)
|
||||
return await ChatUtility.createChatWithRollMode(RdDResolutionTable.actorChatName(actor), {
|
||||
content: await RdDResolutionTable.buildRollDataHtml(rollData, template)
|
||||
});
|
||||
}
|
||||
|
||||
static actorChatName(actor) {
|
||||
return actor?.userName ?? game.user.name;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async buildRollDataHtml(rollData, actor, template = 'chat-resultat-general.html') {
|
||||
static async buildRollDataHtml(rollData, template = 'chat-resultat-general.html') {
|
||||
rollData.show = rollData.show || {};
|
||||
return await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/${template}`, rollData);
|
||||
}
|
||||
|
|
|
@ -314,8 +314,8 @@ export class RdDRoll extends Dialog {
|
|||
HtmlUtility.showControlWhen(this.html.find(".use-encTotal"), rollData.ajustements.encTotal.visible && RdDCarac.isAgiliteOuDerobee(rollData.selectedCarac));
|
||||
HtmlUtility.showControlWhen(this.html.find(".use-surenc"), rollData.ajustements.surenc.visible && RdDCarac.isActionPhysique(rollData.selectedCarac));
|
||||
HtmlUtility.showControlWhen(this.html.find(".utilisation-moral"), rollData.use.appelAuMoral);
|
||||
HtmlUtility.showControlWhen(this.html.find(".diffMoral"), rollData.ajustements.moralTotal.used);
|
||||
HtmlUtility.showControlWhen(this.html.find(".divAppelAuMoral"), rollData.use.appelAuMoral);
|
||||
HtmlUtility.showControlWhen(this.html.find(".diffMoral"), rollData.ajustements.moralTotal.used);
|
||||
|
||||
// Mise à jour valeurs
|
||||
this.html.find(".dialog-roll-title").text(this._getTitle(rollData));
|
||||
|
|
|
@ -75,8 +75,8 @@ export class RdDTokenHud {
|
|||
(event) => {
|
||||
const actionIndex = event.currentTarget.attributes['data-action-index']?.value;
|
||||
const action = hudData.actions[actionIndex];
|
||||
if (action.action == 'conjurer') {
|
||||
const possession = combatant.actor.getPossession(action.system.possessionid);
|
||||
const possession = action.action == 'possession' ? combatant.actor.getPossession(action.system.possessionid) : undefined;
|
||||
if (possession) {
|
||||
combatant.actor.conjurerPossession(possession);
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -16,6 +16,7 @@ import { RdDResolutionTable } from "./rdd-resolution-table.js";
|
|||
import { RdDTimestamp } from "./time/rdd-timestamp.js";
|
||||
import { RdDRaretes } from "./item/raretes.js";
|
||||
import { RdDEmpoignade } from "./rdd-empoignade.js";
|
||||
import { ExperienceLog } from "./actor/experience-log.js";
|
||||
|
||||
/* -------------------------------------------- */
|
||||
// This table starts at 0 -> niveau -10
|
||||
|
@ -136,6 +137,7 @@ export class RdDUtility {
|
|||
'systems/foundryvtt-reve-de-dragon/templates/actor/blessure.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.html',
|
||||
'systems/foundryvtt-reve-de-dragon/templates/actor/taches.html',
|
||||
'systems/foundryvtt-reve-de-dragon/templates/actor/oeuvres.html',
|
||||
|
@ -180,7 +182,7 @@ export class RdDUtility {
|
|||
'systems/foundryvtt-reve-de-dragon/templates/enum-caracteristiques.html',
|
||||
'systems/foundryvtt-reve-de-dragon/templates/enum-base-competence.html',
|
||||
'systems/foundryvtt-reve-de-dragon/templates/enum-aspect-tarot.html',
|
||||
'systems/foundryvtt-reve-de-dragon/templates/enum-categorie-competence.html',
|
||||
'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/enum-categorie-potion.html',
|
||||
|
@ -283,6 +285,9 @@ export class RdDUtility {
|
|||
Handlebars.registerHelper('uniteQuantite', (itemId, actorId) => RdDUtility.getItem(itemId, actorId)?.getUniteQuantite());
|
||||
Handlebars.registerHelper('isFieldInventaireModifiable', (type, field) => RdDItem.isFieldInventaireModifiable(type, field));
|
||||
Handlebars.registerHelper('rarete-getChamp', (rarete, field) => RdDRaretes.getChamp(rarete, field));
|
||||
|
||||
Handlebars.registerHelper('experienceLog-topic', topic => ExperienceLog.labelTopic(topic));
|
||||
|
||||
return loadTemplates(templatePaths);
|
||||
}
|
||||
|
||||
|
@ -334,13 +339,13 @@ export class RdDUtility {
|
|||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static buildArbreDeConteneurs(conteneurs, objets) {
|
||||
static buildArbreDeConteneurs(conteneurs, inventaires) {
|
||||
let objetVersConteneur = {};
|
||||
// Attribution des objets aux conteneurs
|
||||
for (let conteneur of conteneurs) {
|
||||
conteneur.subItems = [];
|
||||
for (let id of conteneur.system.contenu ?? []) {
|
||||
let objet = objets.find(objet => (id == objet._id));
|
||||
let objet = inventaires.find(objet => (id == objet._id));
|
||||
if (objet) {
|
||||
objet.estContenu = true; // Permet de filtrer ce qui est porté dans le template
|
||||
objetVersConteneur[id] = conteneur._id;
|
||||
|
@ -349,20 +354,20 @@ export class RdDUtility {
|
|||
}
|
||||
}
|
||||
for (let conteneur of conteneurs) {
|
||||
conteneur.system.encTotal = RdDUtility.calculEncContenu(conteneur, objets);
|
||||
conteneur.system.encTotal = RdDUtility.calculEncContenu(conteneur, inventaires);
|
||||
}
|
||||
return objetVersConteneur;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static calculEncContenu(conteneur, objets) {
|
||||
static calculEncContenu(conteneur, inventaires) {
|
||||
const contenus = (conteneur.system.contenu ?? []).filter(id => id != undefined)
|
||||
.map(id => objets.find(it => (id == it.id)))
|
||||
.map(id => inventaires.find(it => (id == it.id)))
|
||||
.filter(it => it);
|
||||
let enc = Number(conteneur.system.encombrement ?? 0) * Number(conteneur.system.quantite ?? 1);
|
||||
for (let contenu of contenus) {
|
||||
if (contenu.type == 'conteneur') {
|
||||
enc += RdDUtility.calculEncContenu(contenu, objets);
|
||||
enc += RdDUtility.calculEncContenu(contenu, inventaires);
|
||||
}
|
||||
else {
|
||||
enc += Number(contenu.system.encombrement ?? 0) * Number(contenu.system.quantite ?? 1)
|
||||
|
@ -663,6 +668,7 @@ export class RdDUtility {
|
|||
/* -------------------------------------------- */
|
||||
static async chatListeners(html) {
|
||||
RdDCombat.registerChatCallbacks(html);
|
||||
RdDEmpoignade.registerChatCallbacks(html);
|
||||
|
||||
// Gestion spécifique message passeurs
|
||||
html.on("click", '.tmr-passeur-coord a', event => {
|
||||
|
@ -689,44 +695,6 @@ export class RdDUtility {
|
|||
RdDPossession.onDefensePossession(attackerId, defenderId, possessionId)
|
||||
});
|
||||
|
||||
html.on("click", '.defense-empoignade-cac', event => {
|
||||
const chatMessage = ChatUtility.getChatMessage(event);
|
||||
const rollData = ChatUtility.getMessageData(chatMessage, 'empoignade-roll-data');
|
||||
let defenseMode = event.currentTarget.attributes['data-defense-mode'].value
|
||||
RdDEmpoignade.onDefenseEmpoignade(rollData, defenseMode, "Corps à corps", "melee")
|
||||
});
|
||||
html.on("click", '.defense-empoignade-esquive', event => {
|
||||
const chatMessage = ChatUtility.getChatMessage(event);
|
||||
const rollData = ChatUtility.getMessageData(chatMessage, 'empoignade-roll-data');
|
||||
let defenseMode = event.currentTarget.attributes['data-defense-mode'].value
|
||||
RdDEmpoignade.onDefenseEmpoignade(rollData, defenseMode, "Esquive", "derobee")
|
||||
});
|
||||
html.on("click", '.empoignade-poursuivre', event => {
|
||||
let attackerId = event.currentTarget.attributes['data-attackerId'].value
|
||||
let defenderId = event.currentTarget.attributes['data-defenderId'].value
|
||||
RdDEmpoignade.onAttaqueEmpoignadeValidee(game.actors.get(attackerId), game.actors.get(defenderId))
|
||||
});
|
||||
html.on("click", '.empoignade-entrainer-sol', event => {
|
||||
const chatMessage = ChatUtility.getChatMessage(event);
|
||||
const rollData = ChatUtility.getMessageData(chatMessage, 'empoignade-roll-data');
|
||||
RdDEmpoignade.entrainerAuSol(rollData)
|
||||
ChatUtility.removeChatMessageId(chatMessage.id)
|
||||
});
|
||||
html.on("click", '.empoignade-projeter-sol', event => {
|
||||
const chatMessage = ChatUtility.getChatMessage(event);
|
||||
const rollData = ChatUtility.getMessageData(chatMessage, 'empoignade-roll-data');
|
||||
RdDEmpoignade.projeterAuSol(rollData)
|
||||
ChatUtility.removeChatMessageId(chatMessage.id)
|
||||
});
|
||||
html.on("change", '.empoignade-perte-endurance', event => {
|
||||
const chatMessage = ChatUtility.getChatMessage(event);
|
||||
const rollData = ChatUtility.getMessageData(chatMessage, 'empoignade-roll-data');
|
||||
if (event.currentTarget.value && event.currentTarget.value != "none") {
|
||||
RdDEmpoignade.perteEndurance(rollData, event.currentTarget.value)
|
||||
ChatUtility.removeChatMessageId(chatMessage.id)
|
||||
}
|
||||
});
|
||||
|
||||
// gestion bouton tchat Acheter
|
||||
html.on("click", '.button-acheter', event => {
|
||||
const venteData = DialogItemAchat.preparerAchat(event.currentTarget);
|
||||
|
@ -859,17 +827,13 @@ export class RdDUtility {
|
|||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static confirmerSuppressionSubacteur(sheet, subActor, htmlToDelete) {
|
||||
static confirmerSuppressionSubacteur(sheet, subActor, htmlToDelete, onSuppression = ()=>{}) {
|
||||
RdDConfirm.confirmer({
|
||||
settingConfirmer: "confirmation-supprimer-lien-acteur",
|
||||
content: `<p>Etes vous certain de vouloir supprimer le lien vers ${subActor.name} ?</p>`,
|
||||
title: 'Confirmer la suppression',
|
||||
buttonLabel: 'Supprimer le lien',
|
||||
onAction: () => {
|
||||
console.log('Delete : ', subActor.id);
|
||||
sheet.actor.removeSubacteur(subActor.id);
|
||||
RdDUtility.slideOnDelete(sheet, htmlToDelete);
|
||||
}
|
||||
onAction: onSuppression
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ import { RdDItemSort } from "./item-sort.js";
|
|||
import { Misc } from "./misc.js";
|
||||
import { RdDBonus } from "./rdd-bonus.js";
|
||||
import { RdDCarac } from "./rdd-carac.js";
|
||||
import { RdDPossession } from "./rdd-possession.js";
|
||||
import { RdDUtility } from "./rdd-utility.js";
|
||||
import { ReglesOptionelles } from "./settings/regles-optionelles.js";
|
||||
|
||||
|
@ -30,7 +31,7 @@ export const referenceAjustements = {
|
|||
},
|
||||
diffLibre: {
|
||||
isUsed: (rollData, actor) => rollData.diffLibre != undefined,
|
||||
getLabel: (rollData, actor) => rollData.selectedSort?.name ?? rollData.attackerRoll ? 'Imposée' : 'Libre',
|
||||
getLabel: (rollData, actor) => rollData.selectedSort?.name ?? rollData.attackerRoll ?? RdDPossession.isDefensePossession(rollData) ? 'Imposée' : 'Libre',
|
||||
getValue: (rollData, actor) => rollData.selectedSort
|
||||
? RdDItemSort.getDifficulte(rollData.selectedSort, rollData.diffLibre)
|
||||
: rollData.diffLibre ?? rollData.competence?.system.default_diffLibre ?? 0
|
||||
|
@ -51,7 +52,7 @@ export const referenceAjustements = {
|
|||
getValue: (rollData, actor) => RdDBonus.find(rollData.surpriseDefenseur).attaque,
|
||||
},
|
||||
etat: {
|
||||
isUsed: (rollData, actor) => !RdDCarac.isIgnoreEtatGeneral(rollData),
|
||||
isUsed: (rollData, actor) => !RollDataAjustements.isIgnoreEtatGeneral(rollData),
|
||||
getLabel: (rollData, actor) => 'Etat général',
|
||||
getValue: (rollData, actor) => actor.getEtatGeneral({ ethylisme: rollData.forceAlcool != undefined })
|
||||
},
|
||||
|
@ -177,4 +178,11 @@ export class RollDataAjustements {
|
|||
return sum;
|
||||
}
|
||||
|
||||
static isIgnoreEtatGeneral(rollData) {
|
||||
const selectedCarac = rollData.selectedCarac;
|
||||
return !selectedCarac ||
|
||||
rollData.ethylisme ||
|
||||
RdDCarac.isChance(selectedCarac) ||
|
||||
(RdDCarac.isReve(selectedCarac) && !rollData.competence);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -57,7 +57,7 @@ export class AppAstrologie extends Application {
|
|||
if (this.actor) {
|
||||
return {
|
||||
actor: this.actor,
|
||||
nombres: this._organizeNombresAstraux(this.actor.listItems('nombreastral')),
|
||||
nombres: this._organizeNombresAstraux(this.actor.itemTypes['nombreastral']),
|
||||
ajustements: CONFIG.RDD.difficultesLibres,
|
||||
etat: this.actor.getEtatGeneral(),
|
||||
astrologie: this.actor.getCompetence('Astrologie')
|
||||
|
|
|
@ -182,6 +182,16 @@ export class RdDCalendrier extends Application {
|
|||
return this.timestamp.formatDate();
|
||||
}
|
||||
|
||||
dateReel() {
|
||||
return new Date().toLocaleString("sv-SE", {
|
||||
year: "numeric",
|
||||
month: "2-digit",
|
||||
day: "2-digit",
|
||||
hour: "2-digit",
|
||||
minute: "2-digit"
|
||||
});
|
||||
}
|
||||
|
||||
isAfterIndexDate(indexDate) {
|
||||
// TODO: standardize
|
||||
return indexDate < this.timestamp.indexDate;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { Misc } from "../misc.js";
|
||||
import { TYPES } from "../item.js";
|
||||
import { TMRUtility } from "../tmr-utility.js";
|
||||
import { PixiTMR } from "./pixi-tmr.js";
|
||||
|
||||
|
@ -9,10 +9,10 @@ const registeredEffects = [
|
|||
* Définition des informations d'une "draconique" (queue, ombre, tête, souffle) qui influence les TMR
|
||||
*/
|
||||
export class Draconique {
|
||||
static isCaseTMR(item) { return item.type == 'casetmr'; }
|
||||
static isQueueDragon(item) { return item.type == 'queue' || item.type == 'ombre'; }
|
||||
static isSouffleDragon(item) { return item.type == 'souffle'; }
|
||||
static isTeteDragon(item) { return item.type == 'tete'; }
|
||||
static isCaseTMR(item) { return item.type == TYPES.casetmr; }
|
||||
static isQueueDragon(item) { return item.isQueueDragon(); }
|
||||
static isSouffleDragon(item) {return item.type == TYPES.souffle; }
|
||||
static isTeteDragon(item) { return item.type == TYPES.tete; }
|
||||
static isQueueSouffle(item) { return Draconique.isQueueDragon(item) || Draconique.isSouffleDragon(item); }
|
||||
|
||||
tmrLabel(linkData) { return TMRUtility.getTMRLabel(linkData.system.coord); }
|
||||
|
|
|
@ -18,6 +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 { TYPES } from "../item.js";
|
||||
|
||||
|
||||
export class EffetsDraconiques {
|
||||
|
@ -114,46 +115,57 @@ export class EffetsDraconiques {
|
|||
);
|
||||
}
|
||||
|
||||
static filterItems(actor, filter, name) {
|
||||
return actor.filterItems(filter)
|
||||
.filter(it => Grammar.includesLowerCaseNoAccent(it.name, name));
|
||||
static tetesDragon(actor, name) {
|
||||
return actor.itemTypes[TYPES.tete].filter(it => Grammar.includesLowerCaseNoAccent(it.name, name));
|
||||
}
|
||||
|
||||
static soufflesDragon(actor, name) {
|
||||
return actor.itemTypes[TYPES.souffle].filter(it => Grammar.includesLowerCaseNoAccent(it.name, name));
|
||||
}
|
||||
|
||||
static queuesDragon(actor, name) {
|
||||
return actor.filterItems(it => it.isQueueDragon() && Grammar.includesLowerCaseNoAccent(it.name, name));
|
||||
}
|
||||
|
||||
static queuesSoufflesDragon(actor, name) {
|
||||
return actor.filterItems(it => [TYPES.queue, TYPES.ombre, TYPES.souffle].includes(it.type) && Grammar.includesLowerCaseNoAccent(it.name, name));
|
||||
}
|
||||
|
||||
static countAugmentationSeuil(actor) {
|
||||
return EffetsDraconiques.filterItems(actor, Draconique.isTeteDragon, 'Augmentation du seuil de rêve').length;
|
||||
return EffetsDraconiques.tetesDragon(actor, 'Augmentation du seuil de rêve').length;
|
||||
}
|
||||
|
||||
static isDonDoubleReve(actor) {
|
||||
return EffetsDraconiques.filterItems(actor, Draconique.isTeteDragon, 'Don de double-rêve').length>0;
|
||||
return EffetsDraconiques.tetesDragon(actor, 'Don de double-rêve').length > 0;
|
||||
}
|
||||
|
||||
static isConnaissanceFleuve(actor) {
|
||||
return EffetsDraconiques.filterItems(actor, Draconique.isTeteDragon, 'connaissance du fleuve').length>0;
|
||||
return EffetsDraconiques.tetesDragon(actor, 'connaissance du fleuve').length > 0;
|
||||
}
|
||||
|
||||
static isReserveEnSecurite(actor) {
|
||||
return EffetsDraconiques.filterItems(actor, Draconique.isTeteDragon, 'réserve en sécurité').length>0;
|
||||
return EffetsDraconiques.tetesDragon(actor, 'réserve en sécurité').length > 0;
|
||||
}
|
||||
|
||||
static isDeplacementAccelere(actor) {
|
||||
return EffetsDraconiques.filterItems(actor, Draconique.isTeteDragon, ' déplacement accéléré').length>0;
|
||||
return EffetsDraconiques.tetesDragon(actor, 'déplacement accéléré').length > 0;
|
||||
}
|
||||
|
||||
static isDoubleResistanceFleuve(actor) {
|
||||
return EffetsDraconiques.filterItems(actor, Draconique.isSouffleDragon, 'résistance du fleuve').length>0;
|
||||
return EffetsDraconiques.soufflesDragon(actor, 'résistance du fleuve').length > 0;
|
||||
}
|
||||
|
||||
static countInertieDraconique(actor) {
|
||||
return EffetsDraconiques.filterItems(actor, Draconique.isQueueDragon, 'inertie draconique').length;
|
||||
return EffetsDraconiques.queuesDragon(actor, 'inertie draconique').length;
|
||||
}
|
||||
|
||||
static countMonteeLaborieuse(actor) {
|
||||
return EffetsDraconiques.filterItems(actor, Draconique.isQueueSouffle, 'montée laborieuse').length;
|
||||
return EffetsDraconiques.queuesSoufflesDragon(actor, 'montée laborieuse').length;
|
||||
}
|
||||
|
||||
static mauvaiseRencontre(actor) {
|
||||
const mauvaisesRencontres = EffetsDraconiques.filterItems(actor, Draconique.isQueueSouffle, 'mauvaise rencontre');
|
||||
return mauvaisesRencontres.length>0 ? mauvaisesRencontres[0] : undefined;
|
||||
const mauvaisesRencontres = EffetsDraconiques.queuesSoufflesDragon(actor, 'mauvaise rencontre');
|
||||
return mauvaisesRencontres.length > 0 ? mauvaisesRencontres[0] : undefined;
|
||||
}
|
||||
|
||||
static isPontImpraticable(actor) {
|
||||
|
@ -165,11 +177,11 @@ export class EffetsDraconiques {
|
|||
}
|
||||
|
||||
static isSujetInsomnie(actor) {
|
||||
return actor.items.find(it => ['queue', 'ombre'].includes(it.type) && Grammar.includesLowerCaseNoAccent(it.name, 'Insomnie')) ? true : false;
|
||||
return EffetsDraconiques.queuesDragon(actor, 'Insomnie').length > 0 ? true : false;
|
||||
}
|
||||
|
||||
static isPeage(actor) {
|
||||
return EffetsDraconiques.filterItems(actor, Draconique.isSouffleDragon, 'péage').length > 0;
|
||||
return EffetsDraconiques.soufflesDragon(actor, 'péage').length > 0;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import { ExperienceLog, XP_TOPIC } from "../actor/experience-log.js";
|
||||
import { ChatUtility } from "../chat-utility.js";
|
||||
import { Poetique } from "../poetique.js";
|
||||
import { RdDDice } from "../rdd-dice.js";
|
||||
|
@ -53,9 +54,10 @@ export class EffetsRencontre {
|
|||
static xp_sort_force = async (dialog, context) => {
|
||||
let competence = context.competence;
|
||||
if (competence) {
|
||||
const xpSort = Misc.toInt(competence.system.xp_sort) + context.rencontre.system.force;
|
||||
await this.updateEmbeddedDocuments("Item", [{ _id: compData._id, 'system.xp_sort': xpSort }]);
|
||||
await this.updateExperienceLog("XP Sort", xpSort, `Rencontre d'un ${context.rencontre.name} en TMR`);
|
||||
const fromXpSort = Number(competence.system.xp_sort);
|
||||
const toXpSort = fromXpSort + context.rencontre.system.force;
|
||||
await this.updateEmbeddedDocuments("Item", [{ _id: compData._id, 'system.xp_sort': toXpSort }]);
|
||||
await ExperienceLog.add(this, XP_TOPIC.XPSORT, fromXpSort, toXpSort, `${competence.name} - ${context.rencontre.name} en TMR`);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -1,12 +1,13 @@
|
|||
{
|
||||
"id": "foundryvtt-reve-de-dragon",
|
||||
"title": "Rêve de Dragon",
|
||||
"version": "10.7.9",
|
||||
"download": "https://www.uberwald.me/gitea/public/foundryvtt-reve-de-dragon/archive/foundryvtt-reve-de-dragon-10.7.9.zip",
|
||||
"version": "10.7.21",
|
||||
"download": "https://www.uberwald.me/gitea/public/foundryvtt-reve-de-dragon/archive/foundryvtt-reve-de-dragon-10.7.21.zip",
|
||||
"manifest": "https://www.uberwald.me/gitea/public/foundryvtt-reve-de-dragon/raw/v10/system.json",
|
||||
"compatibility": {
|
||||
"minimum": "10",
|
||||
"verified": "10"
|
||||
"verified": "10",
|
||||
"maximum": "10"
|
||||
},
|
||||
"description": "Rêve de Dragon RPG for FoundryVTT",
|
||||
"authors": [
|
||||
|
@ -379,4 +380,4 @@
|
|||
"flags": {}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -586,11 +586,11 @@
|
|||
},
|
||||
"competencecreature": {
|
||||
"templates": ["description"],
|
||||
"categorie_parade": "",
|
||||
"carac_value": 0,
|
||||
"niveau": 0,
|
||||
"default_diffLibre": 0,
|
||||
"categorie": "",
|
||||
"carac_value": 0,
|
||||
"categorie_parade": "",
|
||||
"iscombat": false,
|
||||
"isnaturelle": true,
|
||||
"ispossession": false,
|
||||
|
@ -611,10 +611,17 @@
|
|||
"typepossession": "",
|
||||
"possede": false,
|
||||
"possessionid": "",
|
||||
"possesseurid": "",
|
||||
"possedeid": "",
|
||||
"compteur": 0,
|
||||
"date": 0
|
||||
"entite": {
|
||||
"actorid": "",
|
||||
"diffLibre": 0,
|
||||
"finesse": false
|
||||
},
|
||||
"victime": {
|
||||
"actorid": "",
|
||||
"diffLibre": 0,
|
||||
"finesse": false
|
||||
},
|
||||
"compteur": 0
|
||||
},
|
||||
"blessure": {
|
||||
"templates": ["temporel"],
|
||||
|
@ -692,7 +699,7 @@
|
|||
"capacite": 0
|
||||
},
|
||||
"objet": {
|
||||
"templates": ["description", "inventaire"]
|
||||
"templates": ["description", "equipement", "inventaire"]
|
||||
},
|
||||
"monnaie": {
|
||||
"templates": ["description", "inventaire"]
|
||||
|
|
|
@ -41,6 +41,9 @@
|
|||
{{>"systems/foundryvtt-reve-de-dragon/templates/actor/comp-creature.html"}}
|
||||
{{>"systems/foundryvtt-reve-de-dragon/templates/actor/comp-possession.html"}}
|
||||
</div>
|
||||
<div>
|
||||
{{>"systems/foundryvtt-reve-de-dragon/templates/actor/resonances.hbs"}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group large-editor">
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{{#if recettesAlchimiques.length}}
|
||||
<h3>Recettes Alchimiques</h3>
|
||||
<ul class="item-list alterne-list">
|
||||
{{#each recettesAlchimiques as |recette id|}}
|
||||
{{#each (trier recettesAlchimiques) as |recette id|}}
|
||||
<li class="item flexrow list-item" data-item-id="{{recette._id}}"><span class="competence-title recette-label item-edit"><a>{{recette.name}}</a></span>
|
||||
<div class="item-controls flex-shrink">
|
||||
<a class="item-edit" title="Edit Item"><i class="fas fa-edit"></i></a>
|
||||
|
|
|
@ -61,7 +61,7 @@
|
|||
{{/unless}}
|
||||
</label>
|
||||
</li>
|
||||
{{#each system.services as |service key|}}
|
||||
{{#each (trier system.services) as |service key|}}
|
||||
<li class="item flexrow list-item" data-key="{{key}}">
|
||||
<input {{@root.disabled}} type="text" name="services[{{key}}].name" value="{{service.name}}" data-dtype="String" />
|
||||
<input {{@root.disabled}} type="checkbox" name="services[{{key}}].system.moral" {{#if service.system.moral}}checked{{/if}} />
|
||||
|
|
|
@ -25,14 +25,14 @@
|
|||
<span class="equipement-detail">Prix (sols)</span>
|
||||
<span class="equipement-actions">Actions</span>
|
||||
</li>
|
||||
{{#each objets as |item id|}}
|
||||
{{#each (trier inventaires) as |item id|}}
|
||||
{{#unless item.estContenu}}
|
||||
{{#if (ne item.type 'conteneur')}}
|
||||
{{buildLigneInventaire item ../options}}
|
||||
{{/if}}
|
||||
{{/unless}}
|
||||
{{/each}}
|
||||
{{#each conteneurs as |conteneur id|}}
|
||||
{{#each (trier conteneurs) as |conteneur id|}}
|
||||
{{buildLigneInventaire conteneur ../options}}
|
||||
{{/each}}
|
||||
</ul>
|
||||
|
|
|
@ -9,18 +9,24 @@
|
|||
<input class="competence-carac creature-carac" type="text" compname="{{comp.name}}" name="{{comp._id}}.carac"
|
||||
value="{{comp.system.carac_value}}" data-dtype="number"
|
||||
{{#unless @root.options.vueDetaillee}}disabled{{/unless}}/>
|
||||
<input class="competence-value creature-niveau" type="text" compname="{{comp.name}}" name="{{comp._id}}.niveau"
|
||||
value="{{numberFormat comp.system.niveau decimals=0 sign=true}}" data-dtype="number"
|
||||
{{#unless @root.options.vueDetaillee}}disabled{{/unless}}/>
|
||||
<input class="competence-damage creature-dommages" type="text" compname="{{comp.name}}" name="{{comp._id}}.dommages"
|
||||
value="{{numberFormat comp.system.dommages decimals=0 sign=true}}" data-dtype="number"
|
||||
{{#unless @root.options.vueDetaillee}}disabled{{/unless}}/>
|
||||
{{#if @root.options.vueDetaillee}}
|
||||
<div class="item-controls">
|
||||
<a class="item-edit" title="Edit Item"><i class="fas fa-edit"></i></a>
|
||||
<a class="item-delete" title="Delete Item"><i class="fas fa-trash"></i></a>
|
||||
</div>
|
||||
{{/if}}
|
||||
<input class="competence-value creature-niveau" type="text" data-dtype="number"
|
||||
compname="{{comp.name}}" name="{{comp._id}}.niveau"
|
||||
value="{{numberFormat comp.system.niveau decimals=0 sign=true}}"
|
||||
{{#unless @root.options.vueDetaillee}}disabled{{/unless}}
|
||||
/>
|
||||
<input class="competence-damage creature-dommages" type="text" data-dtype="number"
|
||||
{{#if comp.isdommages}}
|
||||
compname="{{comp.name}}" name="{{comp._id}}.dommages"
|
||||
value="{{numberFormat comp.system.dommages decimals=0 sign=true}}"
|
||||
{{#unless @root.options.vueDetaillee}}disabled{{/unless}}
|
||||
{{else}}disabled{{/if}}
|
||||
/>
|
||||
{{#if @root.options.vueDetaillee}}
|
||||
<div class="item-controls">
|
||||
<a class="item-edit" title="Edit Item"><i class="fas fa-edit"></i></a>
|
||||
<a class="item-delete" title="Delete Item"><i class="fas fa-trash"></i></a>
|
||||
</div>
|
||||
{{/if}}
|
||||
</li>
|
||||
{{/each}}
|
||||
</ol>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{{#if meditations.length}}
|
||||
<h3>Méditations</h3>
|
||||
<ul class="item-list">
|
||||
{{#each meditations as |meditation key|}}
|
||||
{{#each (trier meditations) as |meditation key|}}
|
||||
<li class="item flexrow" data-item-id="{{meditation._id}}" data-attribute="{{key}}">
|
||||
<img class="sheet-competence-img" src="{{meditation.img}}" />
|
||||
<span class="meditation-label flex-grow"><a data-item-id="{{meditation._id}}">{{meditation.name}} - {{meditation.system.competence}}</a></span>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{{#if sortsReserve.length}}
|
||||
<h3>Sorts en Réserve</h3>
|
||||
<ul class="item-list alterne-list">
|
||||
{{#each sortsReserve as |sort key|}}
|
||||
{{#each (trier sortsReserve) as |sort key|}}
|
||||
<li class="item list-item flexrow" data-item-id="{{sort._id}}" data-attribute="{{key}}">
|
||||
<img class="sheet-competence-img" src="{{sort.img}}" />
|
||||
<span class="item-edit"><a>{{#if sort.system.echectotal}}Echec total: {{/if}}{{sort.name}} r{{sort.system.ptreve}}</a></span>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{{#if sorts.length}}
|
||||
<h3>Sorts</h3>
|
||||
<ul class="item-list alterne-list">
|
||||
{{#each sorts as |sort key|}}
|
||||
{{#each (trier sorts) as |sort key|}}
|
||||
<li class="item list-item flexrow" data-item-id="{{sort._id}}" data-attribute="{{key}}">
|
||||
<img class="sheet-competence-img" src="{{sort.img}}" />
|
||||
<span class="item-edit flex-grow-2">
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
<span class="equipement-actions item-controls">
|
||||
{{#if options.isOwner}}
|
||||
{{#unless item.estContenu}}
|
||||
{{#if (or (eq item.type 'arme') (eq item.type 'armure') )}}
|
||||
{{#if item.equipable}}
|
||||
<a class="item-equip" title="Equiper">{{#if item.system.equipe}}<i class="fas fa-hand-rock"></i>{{else}}<i class="far fa-hand-paper"></i>{{/if}}</a>
|
||||
{{/if}}
|
||||
{{/unless}}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{{#if @root.options.isObserver}}
|
||||
<span class="item-name"><h4>Argent et Monnaies (fortune: {{calc.fortune.sols}} sols {{calc.fortune.deniers}} deniers)</h4></span>
|
||||
<ul class="item-list alterne-list">
|
||||
{{#each monnaie as |piece id|}}
|
||||
{{#each monnaies as |piece id|}}
|
||||
<li class="item flexrow list-item" data-item-id="{{piece._id}}">
|
||||
<img class="sheet-competence-img" src="{{piece.img}}" title="{{piece.name}}"/>
|
||||
<span class="equipement-nom">{{piece.name}}</span>
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
<span class="equipement-detail">Enc.</span>
|
||||
<span class="equipement-actions">Actions</span>
|
||||
</li>
|
||||
{{#each objets as |item id|}}
|
||||
{{#each inventaires as |item id|}}
|
||||
{{#unless item.estContenu}}
|
||||
{{#if (ne item.type 'conteneur')}}
|
||||
{{buildLigneInventaire item @root.options}}
|
||||
|
|
|
@ -1,18 +1,18 @@
|
|||
<h3>Oeuvres diverses</h3><a class="chat-card-button creer-une-oeuvre">Créer une oeuvre</a>
|
||||
<ul class="item-list alterne-list">
|
||||
{{#each chants as |chant id|}}
|
||||
{{#each (trier chants) as |chant id|}}
|
||||
{{> "systems/foundryvtt-reve-de-dragon/templates/actor/oeuvre.html" oeuvre=chant typeOeuvre="Chant" classOeuvre="chant-label"}}
|
||||
{{/each}}
|
||||
{{#each musiques as |musique id|}}
|
||||
{{#each (trier musiques) as |musique id|}}
|
||||
{{> "systems/foundryvtt-reve-de-dragon/templates/actor/oeuvre.html" oeuvre=musique typeOeuvre="Musique" classOeuvre="musique-label"}}
|
||||
{{/each}}
|
||||
{{#each danses as |danse id|}}
|
||||
{{#each (trier danses) as |danse id|}}
|
||||
{{> "systems/foundryvtt-reve-de-dragon/templates/actor/oeuvre.html" oeuvre=danse typeOeuvre="Danse" classOeuvre="danse-label"}}
|
||||
{{/each}}
|
||||
{{#each oeuvres as |oeuvre id|}}
|
||||
{{#each (trier oeuvres) as |oeuvre id|}}
|
||||
{{> "systems/foundryvtt-reve-de-dragon/templates/actor/oeuvre.html" oeuvre=oeuvre typeOeuvre=oeuvre.system.competence classOeuvre="oeuvre-label"}}
|
||||
{{/each}}
|
||||
{{#each recettescuisine as |recette id|}}
|
||||
{{#each (trier recettescuisine) as |recette id|}}
|
||||
{{> "systems/foundryvtt-reve-de-dragon/templates/actor/oeuvre.html" oeuvre=recette typeOeuvre="Recette de cuisine" classOeuvre="recettecuisine-label"}}
|
||||
{{/each}}
|
||||
</ul>
|
||||
|
|
12
templates/actor/resonances.hbs
Normal file
12
templates/actor/resonances.hbs
Normal file
|
@ -0,0 +1,12 @@
|
|||
<span class="item-name"><h4>Personnages accordés</h4></span>
|
||||
<ul class="item-list alterne-list">
|
||||
{{#each resonances as |actor|}}
|
||||
<li class="item flexrow list-item" data-actor-id="{{actor.id}}">
|
||||
<img class="sheet-competence-img" src="{{actor.img}}" title="{{actor.name}}"/>
|
||||
<span class="subacteur-label"><a>{{actor.name}}</a></span>
|
||||
<div class="flex-shrink">
|
||||
<a class="resonance-delete" title="Supprimer"><i class="fas fa-trash"></i></a>
|
||||
</div>
|
||||
</li>
|
||||
{{/each}}
|
||||
</ul>
|
|
@ -3,7 +3,7 @@
|
|||
<li class="item flexrow">
|
||||
<label class="derivee-label" for="system.compteurs.experience.value">Stress transformé</label>
|
||||
{{#if options.vueDetaillee}}
|
||||
<input type="number" name="system.compteurs.experience.value" value="{{system.compteurs.experience.value}}" data-dtype="number" size="3"/>
|
||||
<input class="derivee-value" type="number" name="system.compteurs.experience.value" value="{{system.compteurs.experience.value}}" data-dtype="number" size="3"/>
|
||||
{{else}}
|
||||
<label name="system.compteurs.experience.value">{{system.compteurs.experience.value}}</label>
|
||||
{{/if}}
|
||||
|
|
|
@ -1,14 +1,18 @@
|
|||
<h3>Journal d'Experience</h3>
|
||||
<div class="form-group large-editor">
|
||||
<ul class="item-list alterne-list">
|
||||
{{#each system.experiencelog as |xp key|}}
|
||||
{{#each system.experiencelog as |xplog key|}}
|
||||
<li class="experiencelog flexrow list-item" data-key="{{key}}">
|
||||
<label class="flex-grow">{{xp.valeur}} {{xp.raison}}</label>
|
||||
<label class="flex-shrink">{{xp.mode}}</label>
|
||||
<label class="flex-shrink">{{xp.daterdd}}</label>
|
||||
<label class="flex-shrink">{{xp.datereel}}</label>
|
||||
<label class="flex-shrink">{{xplog.valeur}} {{experienceLog-topic xplog.mode}} </label>
|
||||
{{#if (or xplog.from xplog.to)}}
|
||||
<label class="flex-grow">{{xplog.raison}}: de {{xplog.from}} à {{xplog.to}}</label>
|
||||
{{else}}
|
||||
<label class="flex-grow">{{xplog.raison}}</label>
|
||||
{{/if}}
|
||||
<label class="flex-shrink">{{xplog.daterdd}}</label>
|
||||
<label class="flex-shrink">{{xplog.datereel}}</label>
|
||||
{{#if @root.options.isGM}}
|
||||
<span>
|
||||
<span class="flex-shrink">
|
||||
<a class="experiencelog-delete" title="Supprimer">
|
||||
<i class="fas fa-trash"></i>
|
||||
</a>
|
||||
|
|
|
@ -1,39 +0,0 @@
|
|||
<img class="chat-icon" src="{{competence.img}}" />
|
||||
<h4>
|
||||
{{attackerName}} a empoigné {{defenderName}}
|
||||
</h4>
|
||||
<hr>
|
||||
<div>
|
||||
|
||||
<span class='chat-card-button-area'>
|
||||
Au round suivant l'acquisition des 2 points d'Emp, {{attackerName}} peut faire perdre autant de points d'Endurance qu'il souhaite à {{defenderName}}
|
||||
<br>
|
||||
<a class='empoignade-perte-endurance chat-card-button'>
|
||||
<select class='empoignade-perte-endurance'>
|
||||
<option value="none">Faire perdre de l'endurance (selectionnez)</option>
|
||||
<option value="end0">Endurance à 0</option>
|
||||
<option value="end1">Endurance à 1</option>
|
||||
<option value="endmoitie">La moitié de l'endurance</option>
|
||||
<option value="endquart">Le quart de l'endurance</option>
|
||||
</select>
|
||||
</a>
|
||||
|
||||
{{#if empoignade.system.ausol}}
|
||||
|
||||
{{else}}
|
||||
<br>
|
||||
Dès l'acquisition des 2 points d'Emp, {{attackerName}} peut entraîner {{defenderName}} au sol. Les deux protagonistes restent empoignés.
|
||||
<br>
|
||||
<a class='empoignade-entrainer-sol chat-card-button'>
|
||||
Entraîner au sol
|
||||
</a>
|
||||
<br>
|
||||
A la fin du round ou les 2 points d'Emp sont acquis, {{attackerName}} peut projeter {{defenderName}} au sol. Les deux protagonistes ne sont plus empoignés.
|
||||
<br>
|
||||
<a class='empoignade-projeter-sol chat-card-button'>
|
||||
Projeter au sol
|
||||
</a>
|
||||
{{/if}}
|
||||
|
||||
|
||||
</div>
|
|
@ -1,7 +1,8 @@
|
|||
<img class="chat-icon" src="{{competence.img}}" />
|
||||
<h4>
|
||||
{{attackerName}} a entraîné {{defenderName}} au sol. L'empoignade peut continuer.
|
||||
{{attacker.name}} a entraîné {{defender.name}} au sol
|
||||
</h4>
|
||||
<hr>
|
||||
<div>
|
||||
L'empoignade peut continuer.
|
||||
</div>
|
||||
|
|
16
templates/chat-empoignade-entrainer.html
Normal file
16
templates/chat-empoignade-entrainer.html
Normal file
|
@ -0,0 +1,16 @@
|
|||
<img class="chat-icon" src="{{competence.img}}" />
|
||||
<h4>
|
||||
{{attacker.name}} a empoigné {{defender.name}}
|
||||
</h4>
|
||||
<hr>
|
||||
<div>
|
||||
<span class='chat-card-button-area'>
|
||||
{{attacker.name}} vient d'obtenir 2 points d'Emp, et peut
|
||||
entraîner {{defender.name}} au sol. Les deux protagonistes
|
||||
restent empoignés.
|
||||
<br>
|
||||
<a class='empoignade-entrainer-sol chat-card-button'>
|
||||
Entraîner au sol
|
||||
</a>
|
||||
</span>
|
||||
</div>
|
35
templates/chat-empoignade-immobilise.html
Normal file
35
templates/chat-empoignade-immobilise.html
Normal file
|
@ -0,0 +1,35 @@
|
|||
<img class="chat-icon" src="{{competence.img}}" />
|
||||
<h4>
|
||||
{{attacker.name}} a empoigné {{defender.name}}
|
||||
</h4>
|
||||
<hr>
|
||||
<div>
|
||||
<span class='chat-card-button-area'>
|
||||
<p>
|
||||
{{attacker.name}} a obtenu 2 points d'Emp à la fin du round précédent, et peut:
|
||||
|
||||
<ul><li>
|
||||
faire perdre des points d'Endurance à {{defender.name}}
|
||||
<br>
|
||||
<a class='empoignade-perte-endurance chat-card-button'>
|
||||
<select class='empoignade-perte-endurance'>
|
||||
<option value="none">Faire perdre de l'endurance (selectionnez)</option>
|
||||
<option value="end0">Endurance à 0</option>
|
||||
<option value="end1">Endurance à 1</option>
|
||||
<option value="endmoitie">La moitié de l'endurance</option>
|
||||
<option value="endquart">Le quart de l'endurance</option>
|
||||
</select>
|
||||
</a>
|
||||
{{#if empoignade.system.ausol}}
|
||||
{{else}}
|
||||
</li><li>
|
||||
projeter {{defender.name}} au sol. Les deux protagonistes ne sont plus empoignés.
|
||||
<br>
|
||||
<a class='empoignade-projeter-sol chat-card-button'>
|
||||
Projeter au sol
|
||||
</a>
|
||||
{{/if}}
|
||||
</li></ul>
|
||||
</p>
|
||||
</span>
|
||||
</div>
|
|
@ -1,7 +1,8 @@
|
|||
<img class="chat-icon" src="{{competence.img}}" />
|
||||
<h4>
|
||||
{{attackerName}} a fait perdre de l'endurance à {{defenderName}}, qui reste immobilisé. L'empoignade peut continuer.
|
||||
{{attacker.name}} a fait perdre de l'endurance à {{defender.name}}
|
||||
</h4>
|
||||
<hr>
|
||||
<div>
|
||||
{{defender.name}} reste immobilisé. L'empoignade peut continuer.
|
||||
</div>
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
<img class="chat-icon" src="{{competence.img}}" />
|
||||
<h4>
|
||||
{{attackerName}} a projeté {{defenderName}} au sol. L'empoignade est terminée et a été supprimée.
|
||||
{{attacker.name}} a projeté {{defender.name}} au sol
|
||||
</h4>
|
||||
<hr>
|
||||
<div>
|
||||
L'empoignade est terminée et a été supprimée.
|
||||
</div>
|
||||
|
|
|
@ -1,16 +1,17 @@
|
|||
<img class="chat-icon" src="{{competence.img}}" />
|
||||
<h4>
|
||||
{{log 'rollData' this}}
|
||||
{{#if (eq mode "empoigner")}}
|
||||
{{attackerName}} tente d'empoigner {{defenderName}}
|
||||
{{attacker.name}} tente d'empoigner {{defender.name}}
|
||||
{{/if}}
|
||||
{{#if (eq mode "contrer-empoigner")}}
|
||||
{{defenderName}} tente de contrer l'empoignade de {{attackerName}}
|
||||
{{defender.name}} tente de contrer l'empoignade de {{attacker.name}}
|
||||
{{/if}}
|
||||
{{#if (eq mode "liberer")}}
|
||||
{{attackerName}} tente de se libérer de l'empoignade de {{defenderName}}
|
||||
{{attacker.name}} tente de se libérer de l'empoignade de {{defender.name}}
|
||||
{{/if}}
|
||||
{{#if (eq mode "contrer-liberer")}}
|
||||
{{defenderName}} tente de contrer la libération de {{attackerName}}
|
||||
{{defender.name}} tente de contrer la libération de {{attacker.name}}
|
||||
{{/if}}
|
||||
</h4>
|
||||
{{> "systems/foundryvtt-reve-de-dragon/templates/chat-infojet.html"}}
|
||||
|
@ -20,7 +21,7 @@
|
|||
|
||||
{{#if (gte empoignade.system.pointsemp 2)}}
|
||||
|
||||
<br><strong>{{defenderName}} est empoigné et immobilisé par {{attackerName}} !</strong>
|
||||
<br><strong>{{defender.name}} est empoigné et immobilisé par {{attacker.name}} !</strong>
|
||||
|
||||
{{else}}
|
||||
<span class='chat-card-button-area'>
|
||||
|
@ -29,16 +30,12 @@
|
|||
{{#if (eq mode "empoigner")}}
|
||||
{{#if empoignade.isSuccess}}
|
||||
<a class='defense-empoignade-cac chat-card-button'
|
||||
data-attackerId='{{attacker.id}}'
|
||||
data-defenderId='{{defender.id}}'
|
||||
data-diff-libre='{{diffLibre}}'
|
||||
data-defense-mode="contrer-empoigner">
|
||||
Contrer l'empoignade (Corps à Corps)
|
||||
</a>
|
||||
{{#if (eq empoignade.system.pointsemp 0)}}
|
||||
<a class='defense-empoignade-esquive chat-card-button'
|
||||
data-attackerId='{{attacker.id}}'
|
||||
data-defenderId='{{defender.id}}'
|
||||
data-diff-libre='{{diffLibre}}'
|
||||
data-defense-mode="contrer-empoigner">
|
||||
Contrer l'empoignade (Esquive)
|
||||
|
@ -52,8 +49,6 @@
|
|||
{{#if (eq mode "liberer")}}
|
||||
{{#if empoignade.isSuccess}}
|
||||
<a class='defense-empoignade-cac chat-card-button'
|
||||
data-attackerId='{{attacker.id}}'
|
||||
data-defenderId='{{defender.id}}'
|
||||
data-diff-libre='{{diffLibre}}'
|
||||
data-defense-mode="contrer-liberer">
|
||||
Contrer la libération (Corps à Corps)
|
||||
|
@ -78,8 +73,7 @@
|
|||
La tentative de contrer la libération est un échec!
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
|
||||
<br>Points d'Emp: {{empoignade.system.pointsemp}}
|
||||
|
||||
</span>
|
||||
<br>Points d'Emp: {{empoignade.system.pointsemp}}
|
||||
{{/if}}
|
||||
</div>
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
<img class="chat-icon" src="{{competence.img}}" />
|
||||
<h4>
|
||||
{{attackerName}} tente d'empoigner {{defenderName}}
|
||||
{{attacker.name}} tente d'empoigner {{defender.name}}
|
||||
</h4>
|
||||
<hr>
|
||||
<div>
|
||||
|
||||
<span class='chat-card-button-area'>
|
||||
<br>
|
||||
<strong>{{attacker.name}} tente d'empoigner {{defender.name}}, qui est équipé d'une arme de mêlée. {{defender.name}}
|
||||
|
@ -16,5 +15,5 @@
|
|||
data-defenderId='{{defender.id}}'>
|
||||
Poursuivre l'empoignade
|
||||
</a>
|
||||
|
||||
</span>
|
||||
</div>
|
|
@ -1,6 +1,6 @@
|
|||
<img class="chat-icon" src="{{competence.img}}" />
|
||||
<h4>
|
||||
{{#if (eq mode "possession")}}
|
||||
{{#if (eq mode "attaque")}}
|
||||
{{attacker.name}} tente de {{#if isECNIDefender}}conjurer la possession de{{else}}posséder{{/if}} {{defender.name}}
|
||||
{{else}}
|
||||
{{defender.name}} tente de {{#if isECNIDefender}}résister à{{else}}conjurer la possession de{{/if}} {{attacker.name}}
|
||||
|
@ -12,7 +12,7 @@
|
|||
<div>
|
||||
<span class='chat-card-button-area'>
|
||||
<br>
|
||||
{{#if (eq mode "possession")}}
|
||||
{{#if (eq mode "attaque")}}
|
||||
{{#if possession.isSuccess}}
|
||||
<a class='defense-possession chat-card-button'
|
||||
data-attackerId='{{attacker.id}}'
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<form class="skill-roll-dialog">
|
||||
<h2>
|
||||
{{defenderName}} tente de contrer l'empoignade de {{attackerName}}
|
||||
{{defender.name}} tente de contrer l'empoignade de {{attacker.name}}
|
||||
</h2>
|
||||
<div class="grid grid-2col">
|
||||
<div class="flex-group-left">
|
||||
|
|
3
templates/enum-categorie-competencecreature.html
Normal file
3
templates/enum-categorie-competencecreature.html
Normal file
|
@ -0,0 +1,3 @@
|
|||
{{#each @root.categoriesCompetencesCreature as |categorie key|}}
|
||||
<option value="{{@key}}">{{categorie.label}}</option>
|
||||
{{/each}}
|
|
@ -1,3 +1,3 @@
|
|||
{{#each @root.categorieCompetences as |categorie key|}}
|
||||
{{#each @root.categories as |categorie key|}}
|
||||
<option value="{{@key}}">{{categorie.label}}</option>
|
||||
{{/each}}
|
|
@ -18,7 +18,7 @@
|
|||
<label for="system.categorie">Catégorie </label>
|
||||
<select name="system.categorie" class="categorie" data-dtype="String">
|
||||
{{#select system.categorie}}
|
||||
{{>"systems/foundryvtt-reve-de-dragon/templates/enum-categorie-competence.html"}}
|
||||
{{>"systems/foundryvtt-reve-de-dragon/templates/enum-categories.html"}}
|
||||
{{/select}}
|
||||
</select>
|
||||
</div>
|
||||
|
|
|
@ -6,50 +6,38 @@
|
|||
<label for="system.categorie">Catégorie</label>
|
||||
<select name="system.categorie" class="categorie" data-dtype="String">
|
||||
{{#select system.categorie}}
|
||||
{{>"systems/foundryvtt-reve-de-dragon/templates/enum-categorie-competence.html"}}
|
||||
{{>"systems/foundryvtt-reve-de-dragon/templates/enum-categories.html"}}
|
||||
{{/select}}
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="niveau">Valeur de Caractéristique </label>
|
||||
<label for="niveau">Valeur de Caractéristique</label>
|
||||
<input class="attribute-value" type="text" name="system.carac_value" value="{{system.carac_value}}" data-dtype="Number"/>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="niveau">Niveau </label>
|
||||
<label for="niveau">Niveau</label>
|
||||
<input class="attribute-value" type="text" name="system.niveau" value="{{system.niveau}}" data-dtype="Number"/>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="default_diffLibre">Difficulté libre par défaut</label>
|
||||
<input class="attribute-value" type="text" name="system.default_diffLibre" value="{{system.default_diffLibre}}" data-dtype="Number"/>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="system.ispossession">Attaque de possession</label>
|
||||
<input class="attribute-value" type="checkbox" name="system.ispossession" {{#if system.ispossession}}checked{{/if}}/>
|
||||
</div>
|
||||
{{#unless system.ispossession}}
|
||||
<div class="form-group">
|
||||
<label for="system.iscombat">Compétence d'attaque</label>
|
||||
<input class="attribute-value" type="checkbox" name="system.iscombat" {{#if system.iscombat}}checked{{/if}}/>
|
||||
</div>
|
||||
{{#if system.iscombat}}
|
||||
<div class="form-group">
|
||||
<label for="system.isnaturelle">Arme naturelle</label>
|
||||
<input class="attribute-value" type="checkbox" name="system.isnaturelle" {{#if system.isnaturelle}}checked{{/if}}/>
|
||||
</div>
|
||||
{{#if isdommages}}
|
||||
<div class="form-group">
|
||||
<label for="niveau">Dommages (+dom)</label>
|
||||
<input class="attribute-value" type="text" name="system.dommages" value="{{system.dommages}}" data-dtype="Number"/>
|
||||
</div>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
{{#if isparade}}
|
||||
<div class="form-group">
|
||||
<label>Catégorie parade </label>
|
||||
<label>Catégorie parade</label>
|
||||
<select name="system.categorie_parade" id="categorie_parade" data-dtype="String">
|
||||
{{#select system.categorie_parade}}
|
||||
{{>"systems/foundryvtt-reve-de-dragon/templates/enum-categorie-parade.html"}}
|
||||
{{/select}}
|
||||
</select>
|
||||
</div>
|
||||
{{/unless}}
|
||||
{{/if}}
|
||||
|
||||
{{>"systems/foundryvtt-reve-de-dragon/templates/partial-item-description.html"}}
|
||||
</section>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<h2>{{name}} se repose</h2>
|
||||
</span></div>
|
||||
<div class="flexrow"><span>
|
||||
<input class type="radio" name="repos" id="sieste" value="sieste">
|
||||
<input type="radio" name="repos" id="sieste" value="sieste" {{#unless system.sommeil.nouveaujour}}checked{{/unless}}>
|
||||
<label for="sieste">Sieste de
|
||||
<input type="number" name="sieste.heures" value="1" data-dtype="Number" />
|
||||
heures</label>
|
||||
|
|
Loading…
Reference in New Issue
Block a user