Compare commits

..
Author SHA1 Message Date
VincentVk 1238460cc8 Fix: quantité d'achat depuis commerce illimité
Lors d'un achat depuis un commerce illimité, la quantité du commerce
(non visible) était utilisée au lieux de la quantité réellement achetée
2026-08-07 15:25:35 +02:00
VincentVk d590dfce7f Fix: ne pas créer d'Item "Sans compétence" 2026-08-07 14:53:58 +02:00
fabres 332da735f8 Re-org CSS title a bit
Release Creation / build (release) Successful in 2m57s
2026-08-06 20:53:40 +02:00
fabres 4a6913a2ba fix: XP compétences négatives (base de catégorie)
Le champ base (INTEGER, min 0) rejetait les bases négatives
(-4/-6/-8/-11) : toute compétence voyait sa base forcée à 0, d'où un
total d'XP compétences fortement négatif (ex. -5790 sur un personnage
neuf).
- competence.mjs : base en INTEGER_SIGNED
- item-competence.js : _preCreate affecte la base de la catégorie
- migrations.js : migration 14.0.3 corrige les compétences existantes
- compendiums repackés (bases de catégorie présentes dans les packs)
2026-08-06 14:27:39 +02:00
fabres 3a55d8e912 Update changelog.md
Release Creation / build (release) Successful in 1m2s
2026-08-06 09:07:33 +02:00
fabres 7caeb0c918 Update changelog.md 2026-08-06 09:06:49 +02:00
fabres 188e7676fa docs: changelog des updates depuis 14.0.0 (migration V14, sommeil, tests) 2026-08-06 09:04:17 +02:00
fabres bb56a3a809 docs: documentation des tests (orchestrateur, liste, API) 2026-08-04 21:37:37 +02:00
fabres ac2e2027a0 test: orchestrateur run-all-tests.sh (demande démarrage monde, rapport final) 2026-08-04 21:36:12 +02:00
fabres dca201c5e2 fix: tc-header.sh utilise adminPassword au lieu de password (review #1) 2026-08-04 21:13:57 +02:00
fabres 5db30ddeb3 test: ajout 22 scripts TC (TC-08 a TC-31) + tc-header.sh partage 2026-08-04 21:08:43 +02:00
fabres 3758d0ca85 fix: compat V14 - _onFirstRender (HTMLElement.show), fermeture dialog TMR 2026-07-27 21:17:50 +02:00
VincentVk d8cfd02807 Regrouper les classes de combat
Elles sont souvent touchées ensemble

Préparation aux changements pour utiliser les Combatants
(pour gérer les empoignades/possessions en cours)

Renommages:
- RdDCombat -> PasseArmes
- RdDCombatManager -> RdDCombat
2026-07-26 22:58:25 +02:00
VincentVk 9aca2c32ef Fix assign dans constructeur
Pas possible de faire Object.assign(this.position car position == null
2026-07-26 22:57:17 +02:00
fabres 882aa5fbcb test: TC-07 feuilles item (44 types)
- creation + ouverture sheet pour les 44 types d'item
- verification scroll via .sheet-body overflow-y:auto
- 4/4 passed, 0 failed
2026-07-24 08:51:07 +02:00
fabres 1272cfdfd1 test: ajout plan de test et scripts TC-01 a TC-06
- rdd_test_plan.md : plan global, 227 cas, 33 sections
- TC-01 : infrastructure coeur (15/15)
- TC-02 : acteur personnage (7/7)
- TC-03 : acteur creature (11/11)
- TC-04 : acteur entite + subtypes + possession (14/14)
- TC-05 : acteur vehicule + structure/resistance (10/10)
- TC-06 : acteur commerce + achat/vente simules (14/14)

Scripts atomiques, async polling, page-state race-free
2026-07-24 08:08:04 +02:00
fabres 2348b2262b fix: champ age en StringField pour compat V14
- age passe de NumberField a StringField (evite erreur validation V14
  'must be a number' sur les acteurs existants)
- beaute reste en NumberField (utilise en calcul)
- expose RdDDice sur game.system.rdd.Dice
2026-07-24 08:07:10 +02:00
fabres 81cb3bb6bd fix: DialogV2 - formes imbriquees, boutons, styles et positionnement
- retire les <form> dans les templates DialogV2 (absorbe par V2)
- ajoute window: {frame, positioned} et enleve height:fit-content (bloquait deplacement vertical)
- ajoute buttons: [Fermer] sur tous les DialogV2 qui en manquaient
- style des dialogs chronologie, calendar-editor, stress
- corrige duplication des boutons calendrier a chaque re-render
- HandlebarsApplicationMixin sur FenetreRechercheTirage
- corrige selecteurs :input→input,select,textarea (jQuery→natif)
- ajoute banniere ASCII console au demarrage
2026-07-22 01:10:24 +02:00
fabres e0e3d4f230 fix: DialogV2 requiert au moins un bouton (buttons vides interdit en V14) 2026-07-22 00:35:47 +02:00
fabres 3afd111711 PUsh all v14 Stuff 2026-07-22 00:31:16 +02:00
fabres 1c288b654a fix: migration V14 - rollMode→messageMode, Token HUD, data-message-id
- remplace core.rollMode → core.messageMode (setting V14)
- migre toutes les cles (gmroll→gm, selfroll→self, blindroll→blind)
- corrige le hook renderTokenHUD pour recuperer le tokenId via app.document
- ajoute un bouton combat personnalise si absent du HUD V14
- corrige le toggle combat : isCombat manquant et guard si hors combat
- chat-utility : data-document-id→data-message-id pour les messages V14
- rdd-utility : idem pour findChatMessage/getChatMessageId
- roll-part-possession : getBestDraconic peut retourner undefined
- distance.mjs : Token→foundry.canvas.placeables.Token
2026-07-22 00:29:56 +02:00
fabres a5843888c0 fix: migration V14 et corrections diverses
migration v14:
- remplace CONFIG.Dice.rollModes → CONFIG.ChatMessage.modes
- canvas optionnel (?.tokens) dans ~27 fichiers
- async/await migrations, waitForRoll, effet draconique
- supprime _warnedAppV1, data-message-id→data-document-id
- corrige sheet registration Items.registerSheet

tmr:
- bouton Lancer un Sort visible en mode visu
- _ensureTMRButtons() en fallback JS
- await d'animation avant render
- corrigé doublon carteTMR.js

css:
- scrollbar (.item-sheet-scrollable-body) sur les 44 fiches item
- normalisation multiligne de tous les less/item/*.less
- style du dialogue description aléatoire (app-personnage-aleatoire)
- hr-sorts et sort réserves en flex-row

dialogue description:
- type=button sur les boutons (évite submit form → crash)
- randomControl passe this.actor au lieu de this.current
- DEFINITION_HEURES : ajout propriété manquante heure

d意:
- supprime 6 fichiers debug (phase*.txt/png, sheets-*.txt/png)
- system.json nom anglais→français
- token-hud : guard token undefined
- item-sort.js : guard sort?.system dans helpers Handlebars
2026-07-22 00:29:56 +02:00
fabres 7d9ebd601a chore: deplace 10 fichiers .js V1 inutilises vers _deprecated/ 2026-07-22 00:29:56 +02:00
fabres 25e3df1f5d Migration Foundry v14 : classes V1→V2, corrections CSS et bugs
- 21 classes Dialog → DialogV2
- 2 classes Application → ApplicationV2 + HandlebarsApplicationMixin
- 1 classe FormApplication → ApplicationV2
- 10 appels new Dialog() → DialogV2 (rdd-confirm, rdd-commands, etc.)
- base-actor-sheet.mjs : 3 appels new Dialog → DialogV2
- Sheet journal : JournalTextPageSheet → JournalEntryPageProseMirrorSheet
- CSS : backdrop-filter, box-shadow, bordures V2 supprimes pour calendar/astrologie
- FenetreRechercheTirage : _getWindowControls + dragDrop ajoutes
- HtmlUtility.showControlWhen : compat jQuery + DOM natif
- rdd-main.js : init calendrier en setTimeout
- Constantes : duplicate → deepClone, _id → id
- renderTemplate global → foundry.applications.handlebars.renderTemplate
2026-07-22 00:29:56 +02:00
fabres 84ce2f78d7 appv2: correction des éditeurs ProseMirror et scrollbar sur les fiches d'acteur
- Migration des fiches acteur V2 : racine <form> → <section>
  (DocumentSheetV2 encapsule déjà dans <form>, élimine les formulaires imbriqués)
- Ajout de submitOnChange: true sur la feuille de base acteur
  (nécessaire pour que les événements change des éditeurs déclenchent la mise à jour)
- Ajout de toggled=true + wrapper <fieldset><div><label> sur tous les formInput
  (comportement identique aux fiches d'objet)
- CSS : .window-content > section ajouté à côté de > form
  (évite la perte du flex layout et des scrollbar en passant de form à section)
- Modèles acteur : passage de StringField à HTMLField pour les champs
  description/notes/biographie/notesmj (permet le rendu ProseMirror)
- Ajout de systemFields dans le contexte _prepareContext()
2026-07-22 00:29:56 +02:00
fabres 8fddbe698c docs: ajoute TODO-v14.md pour suivi compatibilité Foundry v14 2026-07-22 00:29:56 +02:00
fabres d0a434fb0b refactor(styles): migre toutes les directives CSS inline vers LESS
- Remplace les vieilles règles table (mortes) des dialog-gerer-herbes
  et dialog-gerer-ingredients par des règles flex scoped
- Dialog-gerer-herbes/potions/ingredients/deniers : style= flex/gap/padding
  → classes LESS par dialog avec nth-child
- actor-sheet.hbs : gap+flex-wrap → .oeuvre-buttons,
  height:200px → .tab.hautreve
- carac-derivee.hbs : style sur .sust-buttons → déplacé dans LESS
- regles-optionnelles.hbs : width:100% → .btn-voir-tables-encaissement
- dialog-lancer-recette (hbs+js) : status colors → classes .status-*
- roll-part-appelmoral.hbs : font-size conditionnel → classe .moral-low
- rdd-utility.js : span style → .resultat-created
- rdd-import-stats.js : textarea style → #statBlock
- base-actor-sheet.js : select style → .qty-amount
- export-scriptarium/*.hbs : flex-grow, margin-bottom → classes
- app-personnage-aleatoire.hbs : text-align → .random-char-right

Seuls 2 styles dynamiques persistent : background-image option
(partial-roll-coeur.hbs) et width fillPercent barre (inventaire-item.hbs).
2026-07-22 00:29:56 +02:00
fabres 27b232776c fix(dialogs): évite bringToFront du dialog lors du re-render hook
Le hook updateItem/createItem/deleteItem appelait render(true)
déclenchant bringToFront() (ligne 598 ApplicationV2) qui
passait le dialog devant la fiche item ouverte. Utilise
render() sans force pour re-rendre sans changer le z-index.
2026-07-22 00:29:56 +02:00
fabres d06f1de433 fix(dialogs): refresh gestion herbes/potions/ingredients après édition fiche
Souscrit aux hooks updateItem/createItem/deleteItem pour
re-render le dialog quand un item de l'acteur change.
Nettoyage des hooks via _onClose().
2026-07-22 00:29:56 +02:00
fabres 54fc1e8e1a fix(migration): StatusEffects + SystemCompendiums -> ApplicationV2
Plus aucun FormApplication V1 dans module/settings/.
- Tous les settings menus migrés vers HandlebarsApplicationMixin(ApplicationV2)
- Templates sans wrapper <form>
- Scrollbar via LESS pour #status-effects et #system-compendiums
- Listeners jQuery -> DOM natif dans _onRender
2026-07-22 00:29:56 +02:00
fabres 70092ffd8f fix(migration): OptionsAvancees -> ApplicationV2
Migration V1→V2 identique à ReglesOptionnelles.
+ scrollbar dans LESS (#options-avancees > .window-content)
2026-07-22 00:29:56 +02:00
fabres 36b33890db fix(css): titres tables encaissement alternatives lisibles
h2 dans .encaissement-tables utilise --rdd-color-text-primary
(noir) au lieu de l'héritage blanc/clair du thème.
2026-07-22 00:29:56 +02:00
fabres ec2bf050d4 fix(v2): scrollbar ReglesOptionnelles -> .window-content overflow-y:auto
Le DOM réel n'a PAS .window-app ni .applicationv2 sur le form.
La structure: <form id=regles-optionnelles class=application> >
  .window-content. overflow: hidden dans le core V2 étouffe
le contenu. Fix: #regles-optionnelles > .window-content { overflow-y: auto; }
2026-07-22 00:29:56 +02:00
fabres 00edfe8201 fix(v2): scrollbar dans LESS, pas de style inline/template
Les rules flex+overflow pour les forms AppV2 sont dans
foundryvtt-reve-de-dragon.less. Plus aucun style inline
dans _onRender ni <style> dans les templates.
2026-07-22 00:29:56 +02:00
fabres 6fdb07a4e8 fix(v2): scrollbar via .regles-optionnelles.applicationv2 > .window-content
Le id de DEFAULT_OPTIONS est l'id d'application ui.windows,
PAS l'id DOM (#application-N). Les classes ({classes}) sont
appliquées sur .window-app. CSS ciblé via la classe fonctionne.
2026-07-22 00:29:56 +02:00
fabres c4f9150fdb fix(v2): scrollbar inline via _onRender flex styles
Le CSS via template ne fonctionnait pas car l'id V2 n'est pas
un sélecteur DOM fiable. On apply les styles flex/overflow
directement sur this.element et son premier enfant dans _onRender.
2026-07-22 00:29:56 +02:00
fabres 8400d88677 fix(v2): scrollbar dans DialogEncaissementTables aussi 2026-07-22 00:29:56 +02:00
fabres 93a1478cba fix(v2): scrollbar dans ReglesOptionnelles form overflow-y
Le formulaire ne scrollait pas car le form V2 (tag:'form')
n'avait pas de hauteur contrainte + overflow. Fix via CSS
ciblant #regles-optionnelles .window-content form > div.
2026-07-22 00:29:56 +02:00
fabres 51b05d025a fix(v2): wrapper single root element dans les templates
ApplicationV2 exige un unique élément racine par part.
regles-optionnelles.hbs et dialog-encaissement-tables.hbs
enveloppés dans un <div>.
2026-07-22 00:29:56 +02:00
fabres 348536556a fix(migration): ReglesOptionnelles + DialogEncaissementTables -> ApplicationV2
V1 FormApplication déprécié depuis Foundry v13. Migration vers
HandlebarsApplicationMixin(ApplicationV2) :
- DEFAULT_OPTIONS statique remplace defaultOptions getter
- _prepareContext() async remplace getData()
- _onRender() avec DOM natif remplace activateListeners(html)
- PARTS remplace template
- form: {} sub-object remplace closeOnSubmit/submitOnChange plats
- Templates sans <form> wrapper (V2 l'injecte via tag:'form')
2026-07-22 00:29:56 +02:00
fabres afabba430a feat(encaissement): tables révisées optionnelles + consultation dialog
- Nouveau setting 'tables-encaissement-revisees' dans Options alternatives
- Paliers fins (01-20+), pertes statiques, '@end0' vide endurance à 0
- Dialog de consultation avec les 2 tables (mortel/non-mortel)
- Lien 'Voir les tables d'encaissement' dans le menu Règles optionnelles (MJ)
2026-07-22 00:29:56 +02:00
fabres 3e63054b9d refactor(regles): fusion des Règles customs dans Règles optionnelles -> section Options alternatives, suppress fichiers 2026-07-22 00:29:56 +02:00
fabres 07997576cd style(sust): boutons Repas externe et Rations harmonisés avec chat-card-button 2026-07-22 00:29:56 +02:00
fabres d216e8fcf6 fix(sheets): ajout des sections environnement (inventaire) et temporel (blessure, maladie, poison, rencontre, signedraconique) manquantes dans les sheets V2 2026-07-22 00:29:56 +02:00
fabres 29cdcca1bb fix(cd): message stress journal : perte fixe de 1, reste X, conversion Y en xp 2026-07-22 00:29:56 +02:00
fabres 8c9c8f3345 feat(cd): journal enrichi avec stress, perte enchantements, moral 2026-07-22 00:29:56 +02:00
fabres 8e748a1d94 feat(cd): message statut MJ + journal de suivi stress/moral/events par jour 2026-07-22 00:29:56 +02:00
fabres 7599db07ad feat(repos): nouveau mode sommeil avec sélection heures, dialogs CD intégrés, toolbar équipement 2026-07-22 00:29:56 +02:00
fabres 1db733f379 fix(rations): ne plus afficher 'rien à manger' quand les compteurs sont déjà pleins 2026-07-22 00:29:56 +02:00
fabres 07a48fb3cc refactor(sheets): migration item sheets v13 (models, apps, templates, moins + common/mixins) 2026-07-22 00:29:53 +02:00
fabres f52575f413 fix(rations): consomme assez d'unités pour remplir sust/eau en 1 clic + alerte si vide 2026-07-22 00:26:52 +02:00
fabres 5969009eb1 feat(inventaire): boutons +Ration/+Eau, cartouche chat compact
- Boutons +Ration et +Eau dans l'onglet Équipement
- Incrémente la quantité si l'item existe déjà, sinon le crée
- Nouveau template post-item-compact.hbs pour l'aperçu chat
- _MONTRER utilise désormais le cartouche compact
- postItemToChatCompact() awaitable, champs filtrés par type d'inventaire
2026-07-22 00:26:52 +02:00
VincentVk 37a33691ff 14.0.1 - Les imprécisions de Tétragor
Release Creation / build (release) Failing after 14s
2026-07-21 22:45:47 +02:00
VincentVk ce7271b569 Fix: ouverture des items
Fix appel methode sur objet SANS_COMPETENCE, qui n'etait pas
un RdDItem / RdDItemCompetence
2026-07-21 22:28:06 +02:00
VincentVk 5dbd7c3784 Fix Description aléatoire 2026-07-17 03:07:30 +02:00
fabres a55904742b fix(encombrement): exclure le poids propre des conteneurs du total
- Les conteneurs n'ajoutent plus leur propre encombrement au total
  (seuls les objets qu'ils contiennent sont comptés)
- Ajout indicateur visuel quand une compétence atteint son niveau d'archétype
  (bordure dorée + icône ✓)
2026-07-14 22:08:32 +02:00
fabres ded584ccc8 feat(inventaire): tri par quantité, dialogues de gestion, duplication cachée des livres lus
Release Creation / build (release) Successful in 1m45s
- Remplace le tri 'Manuel' par un tri 'Quantité' dans l'inventaire
- Supprime _onDrop / _onSortItem (obsolètes sans tri manuel)
- Nouveau dialogue 'Gérer ses deniers' (ApplicationV2)
- Nouveau dialogue 'Gérer ses potions' (ApplicationV2)
- Boutons herbes/ingrédients/potions/deniers déplacés dans l'onglet Équipement
- Dialogues herbes/ingrédients harmonisés (alterne-list, contrôles +/-)
- Ajout titre 'Livres lus' et en-têtes alignés
- Ajout estCopieLue au schéma livre (template.json)
- creerCopieLue() extrait dans base-actor.js
- Filtre estCopieLue dans prepareInventaire/buildContenuConteneur
2026-07-14 18:56:38 +02:00
fabres ac10de85cf Gestion des livres lus et des herbes 2026-07-14 08:28:44 +02:00
VincentVk b9fec47311 Correction du but des recettes alchimiques 2026-07-14 01:21:52 +02:00
VincentVk 7d5903aa84 Support des tâches à plusieurs
Release Creation / build (release) Successful in 1m50s
2026-07-11 16:12:15 +02:00
VincentVk 66a8eb0e8a Images de la barre de menu droite 2026-07-11 01:16:10 +02:00
VincentVk 6636ebb77c Améliorations des titres des fenêtres de jets 2026-07-10 23:37:42 +02:00
VincentVk 89207df01d Correction d'updates non affichés 2026-07-10 20:34:16 +02:00
VincentVk 000e16f8b7 Amélioration sur les voies de Draconic
- Ne pas proposer les voies de Draconic à -11 pour lire un signe
  draconic ou lancer un sort
- Trier les voies par ordre décroissant pour le sorts à voies multiples
- Les rencontres et les maîtrises dans les TMR peuvent être vaincues
  sans draconic si les voies sont négatives
2026-07-10 19:26:34 +02:00
VincentVk bbbc817e5f Pas de lecture avec Draconic à -11 2026-07-10 18:13:29 +02:00
VincentVk b89dd3845a Visibilité des jets /rdd 2026-07-10 18:07:08 +02:00
VincentVk 6c239b8ed9 Suppression de TMR "Inconnu" pour signes 2026-07-10 16:50:41 +02:00
VincentVk e42e12f56f Publish version 1.1.1
Release Creation / build (release) Successful in 1m1s
2026-06-29 23:11:01 +02:00
VincentVk 32f99e35ef Using nodejs 24 for release actions
Release Creation / build (release) Failing after 1m19s
2026-06-29 01:00:17 +02:00
VincentVk ae42bc4aa4 Using nodejs 24 for release actions 2026-06-29 00:56:07 +02:00
VincentVk 089c0c2243 Correction des couleurs des tooltips d'aide foundry
Release Creation / build (release) Failing after 1m1s
2026-06-28 23:49:56 +02:00
VincentVk e34449631c Optimisation fenêtre de jets
La fenêtre de jet pour les attaques à distance prenait
trop de hauteur sur petit écran.

La difficulté était mal visualisée par les joueurs (et confondue
avec les conditions)

Le d100 de la zone "tricher" était un peu trop gros

Les ajustements sont organisés plus logiquement: difficulté,
conditions, ajustements à cocher
2026-06-20 18:38:48 +02:00
VincentVk f8a20b90ff Génération aléatoire d'archétype 2026-06-20 18:38:48 +02:00
VincentVk 749eb5ee13 upgrade publish action 2026-06-20 18:38:47 +02:00
VincentVk 17cb8a2e06 13.0.45
Release Creation / build (release) Successful in 1m23s
2026-06-16 23:02:39 +02:00
VincentVk 933256da66 Nouvelle correction du manifest
Release Creation / build (release) Has been cancelled
Le manifest versionné, téléchargé dans le système, pointe maintenant
sur le manifest latest.

Le lien manifest foundry est celui du manifest de la version.
2026-06-16 22:59:36 +02:00
VincentVk a58b171fb4 13.0.44 - Le dépôt d'Illisys
Release Creation / build (release) Successful in 1m5s
- le manifest pointe maintenant toujours vers la dernière version
- changement des liens dans le system.json
2026-06-15 21:26:03 +02:00
VincentVk 2eac969261 Update system.json
even if not necessary, it was referencing previous repository
2026-06-14 22:41:04 +02:00
fabres e6612fe024 Make default release as latest 2026-06-14 21:57:55 +02:00
fabres 18b9e4c7a8 Updte gitignore 2026-06-14 21:55:48 +02:00
VincentVk fcaebe6334 Correction des jets impossibles
Release Creation / build (release) Successful in 1m58s
2026-06-12 00:26:54 +02:00
VincentVk c4033707be macro signe draconique
Release Creation / build (release) Successful in 1m48s
2026-06-03 00:56:52 +02:00
VincentVk 8b83369d5a On peut choisir la difficulté de résistance
La difficulté des jets de résistance est libre
2026-06-03 00:46:15 +02:00
VincentVk e9183df59c le Guerrier Sorde n'est pas joueur 2026-06-03 00:46:15 +02:00
VincentVk 45ccac3489 Mineur - rendu monnaies 2026-06-03 00:39:12 +02:00
VincentVk c41db974ff Corrections description aléatoire 2026-06-03 00:39:12 +02:00
555 changed files with 23004 additions and 8759 deletions
+28
View File
@@ -0,0 +1,28 @@
# Session Summary: v13 Migration — DataModel + _id/duplicate Cleanup + template.json removal
## Done
### `duplicate()` → `deepClone()` (finding #10, 36 files)
`foundry.utils.duplicate()``foundry.utils.deepClone()` across the system. `deepClone` preserves Document prototypes where `duplicate` stripped them.
### `_id` → `id` on Documents (finding #11, finding #7, ~25 sites)
- 21 read accesses migrated during initial sweep
- Review sweep caught 3 more: `rdd-combat.js:148` (combatant._id), `rdd-combat.js:898` (esquive e._id), `rdd-tmr-dialog.js:261` (casetmr._id)
- Also fixed: `actor.js:1844` (selectedSort._id), `actor.js:2884` (herbeData._id), `base-actor.js:404` (conteneur c._id)
- Remaining `_id` references are on POJOs (`toObject()`/migration data) — correct.
### `_onClose` → `super._onClose()` (finding #9)
All dialog `_onClose` overrides now call `super._onClose()` for proper HandlebarsApplicationMixin cleanup.
### Actor DataModel Migration (3 phases)
- Phase 1: 5 DataModels in `module/models/` + helpers + `CONFIG.Actor.dataModels` registration
- Phase 2: `prepareActorData()` chain → DataModel `prepareDerivedData()` in each model
- Phase 3: template.json deletion, dead code cleanup
### `template.json` elimination (like `fvtt-hawkmoon-cyd`)
- `template.json` deleted. Foundry v13+ uses `documentTypes` in system.json.
- Added `documentTypes.Actor` (5 types) + `documentTypes.Item` (44 types) with `htmlFields`
- Fixed CI/CD files referencing template.json
## Still remaining (v14-blocking)
V1 Application/Dialog classes (24 `extends Dialog`, 6+ V1 sheets) cannot run in v14 — findings #1#6.
+6 -5
View File
@@ -32,13 +32,13 @@ jobs:
env:
version: ${{steps.get_version.outputs.version-without-v}}
url: https://gitea.scriptarium.org/${{gitea.repository}}
manifest: https://gitea.scriptarium.org/${{gitea.repository}}/releases/download/${{github.event.release.tag_name}}/system.json
manifest: "https://gitea.scriptarium.org/Scriptarium/foundryvtt-reve-de-dragon/releases/download/latest/system.json"
download: https://gitea.scriptarium.org/${{gitea.repository}}/releases/download/${{github.event.release.tag_name}}/rddsystem.zip
- name: Set up Node.js
uses: actions/setup-node@v2
with:
node-version: "18" # Use the node version your project requires
node-version: "24" # Use the node version your project requires
- name: Install dependencies
run: npm install
@@ -47,7 +47,7 @@ jobs:
run: node ./tools/packCompendiumsToDist.mjs
- name: Create ZIP file
run: zip -r ./rddsystem.zip system.json template.json README.md LICENSE.txt assets/ css/ fonts/ icons lang/ module/ packs/ pic/ sounds/ styles/ templates/
run: zip -r ./rddsystem.zip system.json README.md LICENSE.txt assets/ css/ fonts/ icons lang/ module/ packs/ pic/ sounds/ styles/ templates/
- name: setup go
uses: actions/setup-go@v3
@@ -64,12 +64,13 @@ jobs:
api_key: "${{secrets.RDD_PUBLISH_RELEASE}}"
- name: Publish to Foundry server
uses: djlechuck/foundryvtt-publish-package-action@v1
uses: djlechuck/foundryvtt-publish-package-action@v1.1.1
with:
token: ${{ secrets.RDD_PUBLISH_RELEASE_FOUNDRY }}
id: "foundryvtt-reve-de-dragon"
version: ${{github.event.release.tag_name}}
manifest: "https://gitea.scriptarium.org/${{gitea.repository}}/releases/download/${{github.event.release.tag_name}}/system.json"
manifest: https://gitea.scriptarium.org/${{gitea.repository}}/releases/download/${{github.event.release.tag_name}}/system.json
notes: "https://gitea.scriptarium.org/Scriptarium/foundryvtt-reve-de-dragon/raw/branch/v13/changelog.md"
compatibility-minimum: "13"
compatibility-verified: "13"
node-version: "24"
+4
View File
@@ -12,3 +12,7 @@ todo.md
/packs/*/CURRENT
/packs/*/LOG
/packs/*/LOCK
.github/
*.bak
/AGENTS.md
/regles/
-1
View File
@@ -12,7 +12,6 @@ test:
stage: test
script:
- python -mjson.tool 'system.json' > /dev/null
- python -mjson.tool 'template.json' > /dev/null
build:
stage: build
+68
View File
@@ -0,0 +1,68 @@
# TODO v14 — Compatibilité Foundry VTT
## ✅ Bloquant — terminé
### 1. ✅ Sheets acteur V1 → V2
- V1 déplacés vers `_deprecated/module/actor/` (10 fichiers `.js`)
- V2 dans `module/applications/sheets/` (fichiers `.mjs`)
### 2. ✅ Sheet journal V1 → V2
- `module/journal/journal-sheet.mjs``extends JournalEntryPageProseMirrorSheet`
- `_prepareContentContext` override → `RdDTextEditor.enrichHTML()`
- `_onRender` → roll-text/chat-roll-text click listeners
### 3. ✅ 24 classes `extends Dialog` → V2
- Toutes converties en `extends foundry.applications.api.DialogV2`
- `module/tirage/fenetre-recherche-tirage.js``FenetreRechercheTirage` migré V1 App → V2 ApplicationV2
- `module/sommeil/dialog-nouveau-repos-cd.js``new Dialog(...)` direct → `DialogV2.wait()`
### 4. ✅ 3 classes `extends Application` → V2
- `module/tirage/fenetre-recherche-tirage.js` — FAIT (ApplicationV2)
- `module/time/rdd-calendrier.js` (RdDCalendrier) — FAIT (ApplicationV2)
- `module/sommeil/app-astrologie.js` (AppAstrologie) — FAIT (ApplicationV2)
### 5. ✅ 1 classe `extends FormApplication` → V2
- `module/actor/random/app-personnage-aleatoire.js` — FAIT (ApplicationV2)
### 6. ✅ 7 appels `new Dialog({...})` directs → DialogV2
Tous convertis. +3 autres dans `module/applications/sheets/base-actor-sheet.mjs` & `personnage-sheet.mjs`.
## 🟠 Haute priorité
### 7. ✅ `_id` dans `updateEmbeddedDocuments` → utiliser `.id` — **FAIT** (10 occ. changées, 2 déjà OK, 1 string param)
### 8. ✅ `bringToFront()` sur apps V1 → adapter
Rétrocompatibilité V2 gère. Pas d'erreur constatée (les apps converties utilisent V2).
### 9. ✅ `_onClose()` sans `super._onClose()` → **FAIT**
- `module/dialog-gerer-potions.js:45-49`
- `module/dialog-gerer-ingredients.js:45-49`
- `module/dialog-gerer-herbes.js:47-51`
## 🟡 Priorité moyenne
### 10. ✅ `foundry.utils.duplicate()` → `deepClone()` — **FAIT** (36 fichiers)
### 11. ✅ `._id` en lecture → `.id` — **FAIT** (21 occ. changées, 11 conservées sur objets de données)
~45 occurrences : `item._id`, `actor._id`, `combatant._id`, `token._id`
### 12. `render(true)` sur apps V2 → `render({force: true})`
Rétrocompatibilité V2 normalise booléen → pas prioritaire.
~60 occurrences dans module/ — nos fichiers convertis l'utilisent déjà.
### 13. ✅ Incohérence registration sheets
`module/applications/sheets/common-item-sheet.mjs``Items.registerSheet()``foundry.documents.collections.Items.registerSheet()`
## 🟢 Basse priorité / Info
### 14. ✅ `canvas` sans vérification `ready`
27 occurrences dans 11 fichiers sécurisées avec `?.`
### 15. ✅ `element[0]` jQuery
`module/tirage/fenetre-recherche-tirage.js:213` — déjà résolu par refacto antérieur
### 16. ✅ `_warnedAppV1 = true`
Supprimé de `rdd-calendrier.js`; restant dans `_deprecated/` ignoré
### 17. ✅ `system.json` — nom de langue
`"name": "English"``"Français"` pour ne pas tromper sur `lang/fr.json`
@@ -2,7 +2,7 @@ import { RdDUtility } from "./rdd-utility.js";
import { HtmlUtility } from "./html-utility.js";
import { RdDBonus } from "./rdd-bonus.js";
import { Misc } from "./misc.js";
import { RdDCombatManager } from "./rdd-combat.js";
import { RdDCombat } from "./combat/rdd-combat.js";
import { CARACS, RdDCarac } from "./rdd-carac.js";
import { DialogSplitItem } from "./dialog-split-item.js";
import { ReglesOptionnelles } from "./settings/regles-optionnelles.js";
@@ -13,7 +13,7 @@ import { ACTOR_TYPES, ITEM_TYPES } from "./constants.js";
import { RdDItem } from "./item.js";
import { RdDItemCompetence } from "./item-competence.js";
import { RdDItemBlessure } from "./item/blessure.js";
import { RdDEmpoignade } from "./rdd-empoignade.js";
import { RdDEmpoignade } from "./combat/rdd-empoignade.js";
import { RdDBaseActorSangSheet } from "./actor/base-actor-sang-sheet.js";
import { RdDCoeur } from "./coeur/rdd-coeur.js";
import { AppPersonnageAleatoire } from "./actor/random/app-personnage-aleatoire.js";
@@ -31,7 +31,7 @@ export class RdDActorSheet extends RdDBaseActorSangSheet {
static get defaultOptions() {
return foundry.utils.mergeObject(RdDBaseActorReveSheet.defaultOptions, {
template: "systems/foundryvtt-reve-de-dragon/templates/actor-sheet.hbs",
width: 550,
width: 640,
showCompNiveauBase: false,
vueArchetype: false,
}, { inplace: false })
@@ -70,6 +70,7 @@ export class RdDActorSheet extends RdDBaseActorSangSheet {
fatigue: RdDUtility.calculFatigueHtml(formData.system.sante.fatigue.value, formData.system.sante.endurance.max)
})
this.amendTacheCommunes(formData)
formData.competences.forEach(item => {
item.system.isHidden = this.options.recherche
@@ -100,20 +101,38 @@ export class RdDActorSheet extends RdDBaseActorSangSheet {
cacheTMR: this.actor.isTMRCache()
}
formData.livresLus = formData.livres.filter(l => l.system.estCopieLue)
formData.livres = formData.livres.filter(l => !l.system.estCopieLue)
formData.race = actor.itemTypes[ITEM_TYPES.race].find(it => true)
formData.subacteurs = {
vehicules: this.actor.listeVehicules(),
montures: this.actor.listeMontures(),
suivants: this.actor.listeSuivants()
}
if (this.actor.getBestDraconic().system.niveau > -11 && !this.actor.isHautRevant()) {
if (this.actor.getDraconics().find(it => it.system.niveau > -11) && !this.actor.isHautRevant()) {
ui.notifications.error(`${this.actor.name} a des compétences draconiques, mais pas le don de Haut-Rêve!
<br>Ajoutez-lui la tête "Don de Haut-Rêve" pour lui permettre d'utiliser ses compétences et d'accéder aux terres médianes du rêve`);
}
}
else {
console.error("Ouverture actor-sheet avec un acteur non personnage")
}
return formData;
}
amendTacheCommunes(formData) {
formData.taches
.forEach(tache => {
if (tache.isTacheCommune()) {
const tacheCommune = tache.getTacheOuCommune()
tache.system = foundry.utils.deepClone(tacheCommune.system)
tache.system.tacheCommuneId = tache.system.tacheCommuneId
}
return tache
})
}
/* -------------------------------------------- */
/** @override */
activateListeners(html) {
@@ -195,7 +214,24 @@ export class RdDActorSheet extends RdDBaseActorSangSheet {
this.html.find('.action-jeu').click(async event => await this.actor.rollJeu(RdDSheetUtility.getItemId(event)))
this.html.find('.action-recettecuisine').click(async event => await this.actor.rollRecetteCuisine(RdDSheetUtility.getItemId(event)))
this.html.find('.description-aleatoire').click(async event => new AppPersonnageAleatoire(this.actor).render(true))
this.html.find('.description-aleatoire').click(async event => new AppPersonnageAleatoire(this.actor).render({ force: true }))
this.html.find('.gerer-herbes').click(async event => {
const { DialogGererHerbes } = await import("./dialog-gerer-herbes.js")
DialogGererHerbes.create(this.actor)
})
this.html.find('.gerer-ingredients').click(async event => {
const { DialogGererIngredients } = await import("./dialog-gerer-ingredients.js")
DialogGererIngredients.create(this.actor)
})
this.html.find('.gerer-deniers').click(async event => {
const { DialogGererDeniers } = await import("./dialog-gerer-deniers.js")
DialogGererDeniers.create(this.actor)
})
this.html.find('.gerer-potions').click(async event => {
const { DialogGererPotions } = await import("./dialog-gerer-potions.js")
DialogGererPotions.create(this.actor)
})
if (game.user.isGM) {
// experience log
this.html.find('.experiencelog-delete').click(async event => {
@@ -229,7 +265,7 @@ export class RdDActorSheet extends RdDBaseActorSangSheet {
this.html.find('.roll-init-arme').click(async event => {
let combatant = game.combat.combatants.find(c => c.actor.id == this.actor.id)
if (combatant) {
RdDCombatManager.rollInitiativeAction(combatant._id, this._getActionCombat(event));
RdDCombat.rollInitiativeAction(combatant.id, this._getActionCombat(event));
} else {
ui.notifications.info("Impossible de lancer l'initiative sans être dans un combat.");
}
@@ -275,6 +311,7 @@ export class RdDActorSheet extends RdDBaseActorSangSheet {
await this.actor.updateCompetenceArchetype(compName, parseInt(event.target.value));
});
this.html.find('.nouvelle-incarnation').click(async event => await this.actor.nouvelleIncarnation())
this.html.find('.repartition-archetype-aleatoire').click(async event => await this.actor.repartitionArchetypeAleatoire())
}
// On pts de reve change
@@ -286,6 +323,8 @@ export class RdDActorSheet extends RdDBaseActorSangSheet {
this.html.find('.moral-neutre').click(async event => await this.actor.jetDeMoral(MORAL.NEUTRE))
this.html.find('.moral-heureux').click(async event => await this.actor.jetDeMoral(MORAL.HEUREUX))
this.html.find('.button-ethylisme').click(async event => await this.actor.jetEthylisme())
this.html.find('.btn-sust-externe').click(async event => await this.actor.mangerExterne())
this.html.find('.btn-sust-rations').click(async event => await this.actor.mangerRations())
this.html.find('.ptreve-actuel-plus').click(async event => await this.actor.reveActuelIncDec(1))
this.html.find('.ptreve-actuel-moins').click(async event => await this.actor.reveActuelIncDec(-1))
@@ -334,18 +373,13 @@ export class RdDActorSheet extends RdDBaseActorSangSheet {
content += `<option value="${typeName}">${Misc.typeName('Item', typeName)}</option>`
}
content += '</select>';
let dialog = new Dialog({
new foundry.applications.api.DialogV2({
title: "Créer une oeuvre",
content: content,
buttons: {
create: {
icon: '<i class="fas fa-check"></i>',
label: "Créer l'oeuvre",
callback: () => this.actor.createItem($(".item-type").val())
}
}
});
dialog.render(true);
content,
buttons: [
{ label: "Créer l'oeuvre", action: "create", icon: "fa-solid fa-check", callback: () => this.actor.createItem($(".item-type").val()) }
]
}).render({ force: true });
}
/* -------------------------------------------- */
@@ -391,7 +425,7 @@ export class RdDActorSheet extends RdDBaseActorSangSheet {
async _onSplitItem(item, split) {
if (split >= 1 && split < item.system.quantite) {
await item.diminuerQuantite(split);
const splitItem = foundry.utils.duplicate(item);
const splitItem = foundry.utils.deepClone(item);
splitItem.system.quantite = split;
await this.actor.createEmbeddedDocuments('Item', [splitItem])
}
@@ -14,7 +14,7 @@ export class RdDBaseActorReveSheet extends RdDBaseActorSheet {
/** @override */
static get defaultOptions() {
return foundry.utils.mergeObject(RdDBaseActorSheet.defaultOptions, {
width: 550
width: 640
});
}
@@ -8,6 +8,8 @@ import { RdDItem } from "../item.js";
import { RdDTextEditor } from "../apps/rdd-text-roll-editor.js";
import { ItemAction } from "../item/item-actions.js";
import { RdDItemCompetenceCreature } from "../item-competencecreature.js";
import { DialogVerifierIngredients } from "../dialog-verifier-ingredients.js";
import { DialogLancerRecette } from "../dialog-lancer-recette.js";
/* -------------------------------------------- */
/**
@@ -23,7 +25,9 @@ export class RdDBaseActorSheet extends foundry.appv1.sheets.ActorSheet {
classes: ["rdd", "sheet", "actor"],
tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "carac" }],
dragDrop: [{ dragSelector: ".item-list .item", dropSelector: undefined }],
vueDetaillee: false
scrollY: [".sheet-body"],
vueDetaillee: false,
triEquipement: 'name'
}, { inplace: false })
}
@@ -45,7 +49,7 @@ export class RdDBaseActorSheet extends foundry.appv1.sheets.ActorSheet {
effects: this.actor.effects
}
RdDUtility.filterItemsPerTypeForSheet(formData, this.actor.itemTypes);
RdDUtility.filterItemsPerTypeForSheet(formData, this.actor.itemTypes, this.options.triEquipement);
formData.calc = {
fortune: Monnaie.toSolsDeniers(this.actor.getFortune()),
prixTotalEquipement: this.actor.computePrixTotalEquipement(),
@@ -88,6 +92,8 @@ export class RdDBaseActorSheet extends foundry.appv1.sheets.ActorSheet {
this.html.find('.actionItem').click(async event => await ItemAction.onActionItem(event, this.actor, this.options))
this.html.find('.item-edit').click(async event => await this.itemActionEdit(event))
this.html.find('.item-verify-ingredients').click(async event => await this._onVerifyIngredients(event))
this.html.find('.item-lancer-recette').click(async event => await this._onLancerRecette(event))
this.html.find('.conteneur-name a').click(async event => {
RdDUtility.toggleAfficheContenu(this.getItemId(event))
this.render(true)
@@ -104,6 +110,16 @@ export class RdDBaseActorSheet extends foundry.appv1.sheets.ActorSheet {
this.html.find('.recherche').prop("disabled", false)
this.html.find('.item-list .item').dblclick(async event => {
const item = this.getItem(event)
if (item) item.sheet.render(true)
})
this.html.find('.tri-equipement').change(event => {
this.options.triEquipement = event.currentTarget.value;
this.render(true);
})
// Everything below here is only needed if the sheet is editable
if (!this.options.editable) return;
@@ -111,9 +127,71 @@ export class RdDBaseActorSheet extends foundry.appv1.sheets.ActorSheet {
this.html.find('.item-delete').click(async event => await RdDUtility.confirmActorItemDelete(this.getItem(event), this.actor));
this.html.find('.item-quantite-plus').click(async event => await this.actor.itemQuantiteIncDec(this.getItemId(event), 1));
this.html.find('.item-quantite-moins').click(async event => await this.actor.itemQuantiteIncDec(this.getItemId(event), -1));
this.html.find('.item-quantite').change(async event => {
const input = event.currentTarget;
const item = this.actor.items.get(input.dataset.itemId);
if (item) {
const newQty = Math.max(0, parseInt(input.value) || 0);
await item.update({ 'system.quantite': newQty });
if (newQty === 0) this.render(true);
}
})
this.html.find('.item-quantite').on('contextmenu', async event => {
event.preventDefault()
const item = this.getItem(event)
if (!item?.isInventaire()) return
new foundry.applications.api.DialogV2({
title: `Quantité — ${item.name}`,
content: `<p>Réduire la quantité de :</p>
<select class="qty-amount">
<option value="1">1</option>
<option value="5">5</option>
<option value="10">10</option>
<option value="all">Tout jeter</option>
</select>`,
buttons: [
{ action: "reduce", label: "Retirer", icon: "fa-solid fa-minus", callback: (event, button, dialog) => {
const amount = dialog.element.querySelector('.qty-amount').value
if (amount === 'all') {
item.delete()
this.render({ force: true })
} else {
item.update({ 'system.quantite': Math.max(0, item.system.quantite - parseInt(amount)) })
}
}}
]
}).render({ force: true })
})
this.html.find('.creer-un-objet').click(async event => await this.selectObjetTypeToCreate())
this.html.find('.nettoyer-conteneurs').click(async event => await this.actor.nettoyerConteneurs())
this.html.find('.quick-add-ration').click(async event => {
const existante = this.actor.items.find(it => it.type === "nourritureboisson" && it.name === "Ration")
if (existante) {
await existante.update({ "system.quantite": Math.max(0, Number(existante.system.quantite) + 1) })
} else {
await this.actor.createEmbeddedDocuments('Item', [{
name: "Ration", type: "nourritureboisson",
img: "systems/foundryvtt-reve-de-dragon/icons/objets/provision_crue.webp",
system: { sust: 1, encombrement: 0.1, quantite: 1, cout: 0.1, boisson: false }
}], { renderSheet: false })
}
this.render(true)
})
this.html.find('.quick-add-eau').click(async event => {
const existante = this.actor.items.find(it => it.type === "nourritureboisson" && it.name === "Eau")
if (existante) {
await existante.update({ "system.quantite": Math.max(0, Number(existante.system.quantite) + 1) })
} else {
await this.actor.createEmbeddedDocuments('Item', [{
name: "Eau", type: "nourritureboisson",
img: "systems/foundryvtt-reve-de-dragon/icons/objets/outre.webp",
system: { desaltere: 1, encombrement: 0.1, quantite: 1, cout: 0.05, boisson: true }
}], { renderSheet: false })
}
this.render(true)
})
this.html.find('.vue-detaillee').click(async event => {
this.options.vueDetaillee = !this.options.vueDetaillee
@@ -122,8 +200,29 @@ export class RdDBaseActorSheet extends foundry.appv1.sheets.ActorSheet {
}
itemActionEdit(event) {
const item = this.getItem(event);
return item?.sheet.render(true);
const item = this.getItem(event)
if (item) item.sheet.render(true)
}
/* -------------------------------------------- */
async _onVerifyIngredients(event) {
event.preventDefault()
const item = this.getItem(event)
if (!item || item.type !== ITEM_TYPES.recettealchimique) return
DialogVerifierIngredients.create(item, this.actor)
}
/* -------------------------------------------- */
async _onLancerRecette(event) {
event.preventDefault()
const item = this.getItem(event)
if (!item || item.type !== ITEM_TYPES.recettealchimique) return
const ingredients = Misc.safeJsonParse(item.system.ingredients, [])
if (!ingredients.length) {
ui.notifications.warn('Cette recette n\'a pas d\'ingrédients définis.')
return
}
DialogLancerRecette.create(item, this.actor)
}
_rechercherKeyup(event) {
@@ -180,15 +279,28 @@ export class RdDBaseActorSheet extends foundry.appv1.sheets.ActorSheet {
/* -------------------------------------------- */
async _onDropItem(event, dragData) {
const destItemId = this.html.find(event.target)?.closest('.item').attr('data-item-id')
const previousItemIds = new Set(this.actor.items.keys())
const dropParams = await RdDSheetUtility.prepareItemDropParameters(destItemId, this.actor, dragData, this.objetVersConteneur)
if (dropParams) {
const callSuper = await this.actor.processDropItem(dropParams)
if (callSuper) {
await super._onDropItem(event, dragData)
}
// For external drops onto a container row, place the new item inside
if (destItemId && dropParams.sourceActorId !== this.actor.id) {
const container = this.actor.items.get(destItemId)
if (container?.isConteneur()) {
const dropped = [...this.actor.items].find(i => !previousItemIds.has(i.id))
if (dropped && !this.actor.findConteneur(dropped)) {
await this.actor.ajouterDansConteneur(dropped, container, () => {})
}
}
}
}
}
/* -------------------------------------------- */
async selectObjetTypeToCreate() {
let types = this.getTypesInventaire().sort(Misc.ascending(type => Misc.typeName('Item', type)));
@@ -197,18 +309,13 @@ export class RdDBaseActorSheet extends foundry.appv1.sheets.ActorSheet {
content += `<option value="${typeName}">${Misc.typeName('Item', typeName)}</option>`
}
content += '</select>';
let d = new Dialog({
new foundry.applications.api.DialogV2({
title: "Créer un équipement",
content: content,
buttons: {
create: {
icon: '<i class="fas fa-check"></i>',
label: "Créer l'objet",
callback: () => this.actor.createItem($(".item-type").val())
}
}
});
d.render(true);
content,
buttons: [
{ action: "create", label: "Créer l'objet", icon: "fa-solid fa-check", callback: () => this.actor.createItem($(".item-type").val()) }
]
}).render({ force: true });
}
getTypesInventaire() {
@@ -237,7 +344,7 @@ export class RdDBaseActorSheet extends foundry.appv1.sheets.ActorSheet {
async _onSplitItem(item, split) {
if (split >= 1 && split < item.system.quantite) {
await item.diminuerQuantite(split);
const splitItem = foundry.utils.duplicate(item);
const splitItem = foundry.utils.deepClone(item);
splitItem.system.quantite = split;
await this.actor.createEmbeddedDocuments('Item', [splitItem])
}
+87 -1
View File
@@ -1 +1,87 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" style="height: 256px; width: 256px;"><defs><filter id="shadow-1" height="300%" width="300%" x="-100%" y="-100%"><feFlood flood-color="rgba(201, 201, 201, 1)" result="flood"></feFlood><feComposite in="flood" in2="SourceGraphic" operator="atop" result="composite"></feComposite>0<feOffset dx="230" dy="300" result="offset"></feOffset><feComposite in="SourceGraphic" in2="offset" operator="over"></feComposite></filter></defs><g class="" transform="translate(-100,0)" style=""><path d="m375.483 251.243-109.98 51.138.213 183.381L477.01 266.346l-86.993-21.81zm-12.736 108.626-5.947 14.699-48.604-8.955 5.007-12.832a141.306 141.306 0 0 0 13.51-11.358 167.184 167.184 0 0 0 16.566-17.517 170.478 170.478 0 0 0 12.606-17.958 115.607 115.607 0 0 0 9.514-17.97l14.068 2.51q-9.37 22.334-30.361 44.43-13.296 13.64-20.645 18.636zM121.603 244.334l-84.71 21.763L246.474 486V302.38l-109.946-51.137zm19.147 50.852a28.72 28.72 0 0 1 24.273 6.802 53.052 53.052 0 0 1 11.226 14.188l-13.081 2.676a28.542 28.542 0 0 0-5.388-7.374q-5.185-4.876-11.262-3.853l-.487.095a6.458 6.458 0 0 0-5.162 4.448c-.856 2.378-.238 5.554 1.796 9.371q4.08 7.6 10.81 9.027a23.785 23.785 0 0 0 8.563-.203l1.867-.344 5.791 10.822q-6.398 1.427-8.23 3.282-3.21 3.14.429 9.93a17.042 17.042 0 0 0 6.089 6.696 10.406 10.406 0 0 0 7.385 1.534l.416-.083q4.757-.964 5.079-4.757c.261-2.57-.655-5.744-2.748-9.514l12.38-2.545a49.247 49.247 0 0 1 4.103 11.226 19.956 19.956 0 0 1-.642 9.383 11.702 11.702 0 0 1-3.96 5.411 19.575 19.575 0 0 1-8.027 3.235l-1.19.214a27.971 27.971 0 0 1-17.494-2.7 32.193 32.193 0 0 1-14.128-14.092q-3.627-6.79-2.604-12.19a8.396 8.396 0 0 1 2.521-4.947h-.071q-1.844.31-7.04-2.497a32.11 32.11 0 0 1-12.916-13.593q-5.245-9.764-3.282-18.398 1.962-8.634 13.676-11zM27.19 248.865l108.78-116.309a7.135 7.135 0 0 1 1.427 0h.154q3.14.345 2.842 3.71a19.36 19.36 0 0 1-3.294 8.1 39.376 39.376 0 0 1-9.728 10.405q-3.912 2.938-15.044 9.514-12.796 7.505-19.55 14.77a92.535 92.535 0 0 0-11.513 14.486l32.907 3.758 8.182-12.963-20.967-2.378a36.415 36.415 0 0 1 4.757-3.83q2.379-1.605 8.444-5.125l6.422-3.747a92.975 92.975 0 0 0 12.903-8.776 61.472 61.472 0 0 0 12.51-14.414q6.84-10.846 6.494-17.957c-.19-3.949-2.105-6.434-5.684-7.505l79.798-85.161-102.097 179.576-5.708 10.06zm367.238-71.974q-3.817-5.458-3.758-8.515c0-2.033 1.19-3.199 3.568-3.448h.57a11.892 11.892 0 0 1 6.91 2.247 29.85 29.85 0 0 1 7.837 8.051q3.687 5.28 3.71 8.397c0 2.093-1.188 3.258-3.496 3.567h-.594a11.75 11.75 0 0 1-6.957-2.378 29.79 29.79 0 0 1-7.79-7.885zm-109.41-141.52 83.948 89.634h-1.189c-.38 0-.975 0-1.463.107q-7.825.892-8.324 6.862-.5 5.97 5.03 13.747a53.778 53.778 0 0 0 6.375 7.374 37.901 37.901 0 0 0 10.144 6.897q-2.117 2.89-.702 7.98a37.283 37.283 0 0 0 5.613 11.096 55.122 55.122 0 0 0 15.223 14.806q8.098 5.268 16.066 4.935.81 0 1.618-.13 8.776-.988 9.228-7.873a16.114 16.114 0 0 0-.463-4.853l58.689 62.686-91.572-22.941-6.1-10.703zm98.22 104.927 2.45 2.617c.451.57.903 1.189 1.355 1.784 1.808 2.592 2.723 4.757 2.723 6.529 0 1.771-1.034 2.782-3.127 3.02h-.512a10.346 10.346 0 0 1-6.077-1.95 22.596 22.596 0 0 1-6.184-6.137c-1.974-2.83-2.937-5.102-2.878-6.814.06-1.713 1.118-2.7 3.187-2.937h.524a10.263 10.263 0 0 1 6.005 1.879 19.147 19.147 0 0 1 2.533 2.01zM255.987 26 137.456 231.026l118.532 55.05 118.604-55.05zm-1.19 208.463q-17.529 0-24.58-12.273-7.053-12.273-7.053-34.988 0-22.714 7.052-35.047 7.052-12.332 24.582-12.344 17.53 0 24.582 12.332 7.052 12.333 7.052 35.047 0 22.715-7.052 34.988-7.053 12.273-24.582 12.285zm10.538-71.807q2.497 7.968 2.497 24.546 0 15.817-2.497 24.201-2.498 8.384-10.537 8.325-8.04 0-10.632-8.325-2.593-8.324-2.593-24.2 0-16.579 2.593-24.547t10.632-7.968q8.015-.012 10.513 7.956z" fill="#fff" fill-opacity="1" filter="url(#shadow-1)" transform="translate(128, 128) scale(0.5, 0.5) rotate(-30, 256, 256) skewX(0) skewY(0)"></path></g></svg>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
viewBox="0 0 649.20972 359.75745"
version="1.1"
id="svg6"
sodipodi:docname="_d100.svg"
width="649.20972"
height="359.75745"
inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)">
<metadata
id="metadata12">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs10" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="2202"
inkscape:window-height="1379"
id="namedview8"
showgrid="true"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:zoom="1.4355469"
inkscape:cx="366.48667"
inkscape:cy="102.06012"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="0"
inkscape:current-layer="svg6">
<inkscape:grid
type="xygrid"
id="grid837"
originx="110.48667"
originy="-153.93988" />
</sodipodi:namedview>
<g
class=""
id="g4"
style="fill:#ffffff"
transform="translate(-94.621782,-91.536548)">
<path
d="m 375.483,251.243 -109.98,51.138 0.213,183.381 211.294,-219.416 -86.993,-21.81 z m -12.736,108.626 -5.947,14.699 -48.604,-8.955 5.007,-12.832 a 141.306,141.306 0 0 0 13.51,-11.358 167.184,167.184 0 0 0 16.566,-17.517 170.478,170.478 0 0 0 12.606,-17.958 115.607,115.607 0 0 0 9.514,-17.97 l 14.068,2.51 q -9.37,22.334 -30.361,44.43 -13.296,13.64 -20.645,18.636 z M 121.603,244.334 36.893,266.097 246.474,486 V 302.38 L 136.528,251.243 Z m 19.147,50.852 a 28.72,28.72 0 0 1 24.273,6.802 53.052,53.052 0 0 1 11.226,14.188 l -13.081,2.676 a 28.542,28.542 0 0 0 -5.388,-7.374 q -5.185,-4.876 -11.262,-3.853 l -0.487,0.095 a 6.458,6.458 0 0 0 -5.162,4.448 c -0.856,2.378 -0.238,5.554 1.796,9.371 q 4.08,7.6 10.81,9.027 a 23.785,23.785 0 0 0 8.563,-0.203 l 1.867,-0.344 5.791,10.822 q -6.398,1.427 -8.23,3.282 -3.21,3.14 0.429,9.93 a 17.042,17.042 0 0 0 6.089,6.696 10.406,10.406 0 0 0 7.385,1.534 l 0.416,-0.083 q 4.757,-0.964 5.079,-4.757 c 0.261,-2.57 -0.655,-5.744 -2.748,-9.514 l 12.38,-2.545 a 49.247,49.247 0 0 1 4.103,11.226 19.956,19.956 0 0 1 -0.642,9.383 11.702,11.702 0 0 1 -3.96,5.411 19.575,19.575 0 0 1 -8.027,3.235 l -1.19,0.214 a 27.971,27.971 0 0 1 -17.494,-2.7 32.193,32.193 0 0 1 -14.128,-14.092 q -3.627,-6.79 -2.604,-12.19 a 8.396,8.396 0 0 1 2.521,-4.947 h -0.071 q -1.844,0.31 -7.04,-2.497 a 32.11,32.11 0 0 1 -12.916,-13.593 q -5.245,-9.764 -3.282,-18.398 1.962,-8.634 13.676,-11 z M 27.19,248.865 135.97,132.556 a 7.135,7.135 0 0 1 1.427,0 h 0.154 q 3.14,0.345 2.842,3.71 a 19.36,19.36 0 0 1 -3.294,8.1 39.376,39.376 0 0 1 -9.728,10.405 q -3.912,2.938 -15.044,9.514 -12.796,7.505 -19.55,14.77 a 92.535,92.535 0 0 0 -11.513,14.486 l 32.907,3.758 8.182,-12.963 -20.967,-2.378 a 36.415,36.415 0 0 1 4.757,-3.83 q 2.379,-1.605 8.444,-5.125 l 6.422,-3.747 a 92.975,92.975 0 0 0 12.903,-8.776 61.472,61.472 0 0 0 12.51,-14.414 q 6.84,-10.846 6.494,-17.957 c -0.19,-3.949 -2.105,-6.434 -5.684,-7.505 l 79.798,-85.161 -102.097,179.576 -5.708,10.06 z m 367.238,-71.974 q -3.817,-5.458 -3.758,-8.515 c 0,-2.033 1.19,-3.199 3.568,-3.448 h 0.57 a 11.892,11.892 0 0 1 6.91,2.247 29.85,29.85 0 0 1 7.837,8.051 q 3.687,5.28 3.71,8.397 c 0,2.093 -1.188,3.258 -3.496,3.567 h -0.594 a 11.75,11.75 0 0 1 -6.957,-2.378 29.79,29.79 0 0 1 -7.79,-7.885 z m -109.41,-141.52 83.948,89.634 h -1.189 c -0.38,0 -0.975,0 -1.463,0.107 q -7.825,0.892 -8.324,6.862 -0.5,5.97 5.03,13.747 a 53.778,53.778 0 0 0 6.375,7.374 37.901,37.901 0 0 0 10.144,6.897 q -2.117,2.89 -0.702,7.98 a 37.283,37.283 0 0 0 5.613,11.096 55.122,55.122 0 0 0 15.223,14.806 q 8.098,5.268 16.066,4.935 0.81,0 1.618,-0.13 8.776,-0.988 9.228,-7.873 a 16.114,16.114 0 0 0 -0.463,-4.853 l 58.689,62.686 -91.572,-22.941 -6.1,-10.703 z m 98.22,104.927 2.45,2.617 c 0.451,0.57 0.903,1.189 1.355,1.784 1.808,2.592 2.723,4.757 2.723,6.529 0,1.771 -1.034,2.782 -3.127,3.02 h -0.512 a 10.346,10.346 0 0 1 -6.077,-1.95 22.596,22.596 0 0 1 -6.184,-6.137 c -1.974,-2.83 -2.937,-5.102 -2.878,-6.814 0.06,-1.713 1.118,-2.7 3.187,-2.937 h 0.524 a 10.263,10.263 0 0 1 6.005,1.879 19.147,19.147 0 0 1 2.533,2.01 z M 255.987,26 137.456,231.026 l 118.532,55.05 118.604,-55.05 z m -1.19,208.463 q -17.529,0 -24.58,-12.273 -7.053,-12.273 -7.053,-34.988 0,-22.714 7.052,-35.047 7.052,-12.332 24.582,-12.344 17.53,0 24.582,12.332 7.052,12.333 7.052,35.047 0,22.715 -7.052,34.988 -7.053,12.273 -24.582,12.285 z m 10.538,-71.807 q 2.497,7.968 2.497,24.546 0,15.817 -2.497,24.201 -2.498,8.384 -10.537,8.325 -8.04,0 -10.632,-8.325 -2.593,-8.324 -2.593,-24.2 0,-16.579 2.593,-24.547 2.593,-7.968 10.632,-7.968 8.015,-0.012 10.513,7.956 z"
fill="#ffffff"
fill-opacity="1"
transform="matrix(0.69282032,-0.4,0.4,0.69282032,-23.762003,181.038)"
id="path2"
style="fill:#ffffff" />
</g>
<g
class=""
id="g4-4"
style="fill:#ffffff"
transform="rotate(12.267903,709.7839,1245.6727)">
<path
d="m 375.483,251.243 -109.98,51.138 0.213,183.381 211.294,-219.416 -86.993,-21.81 z m -12.736,108.626 -5.947,14.699 -48.604,-8.955 5.007,-12.832 a 141.306,141.306 0 0 0 13.51,-11.358 167.184,167.184 0 0 0 16.566,-17.517 170.478,170.478 0 0 0 12.606,-17.958 115.607,115.607 0 0 0 9.514,-17.97 l 14.068,2.51 q -9.37,22.334 -30.361,44.43 -13.296,13.64 -20.645,18.636 z M 121.603,244.334 36.893,266.097 246.474,486 V 302.38 L 136.528,251.243 Z m 19.147,50.852 a 28.72,28.72 0 0 1 24.273,6.802 53.052,53.052 0 0 1 11.226,14.188 l -13.081,2.676 a 28.542,28.542 0 0 0 -5.388,-7.374 q -5.185,-4.876 -11.262,-3.853 l -0.487,0.095 a 6.458,6.458 0 0 0 -5.162,4.448 c -0.856,2.378 -0.238,5.554 1.796,9.371 q 4.08,7.6 10.81,9.027 a 23.785,23.785 0 0 0 8.563,-0.203 l 1.867,-0.344 5.791,10.822 q -6.398,1.427 -8.23,3.282 -3.21,3.14 0.429,9.93 a 17.042,17.042 0 0 0 6.089,6.696 10.406,10.406 0 0 0 7.385,1.534 l 0.416,-0.083 q 4.757,-0.964 5.079,-4.757 c 0.261,-2.57 -0.655,-5.744 -2.748,-9.514 l 12.38,-2.545 a 49.247,49.247 0 0 1 4.103,11.226 19.956,19.956 0 0 1 -0.642,9.383 11.702,11.702 0 0 1 -3.96,5.411 19.575,19.575 0 0 1 -8.027,3.235 l -1.19,0.214 a 27.971,27.971 0 0 1 -17.494,-2.7 32.193,32.193 0 0 1 -14.128,-14.092 q -3.627,-6.79 -2.604,-12.19 a 8.396,8.396 0 0 1 2.521,-4.947 h -0.071 q -1.844,0.31 -7.04,-2.497 a 32.11,32.11 0 0 1 -12.916,-13.593 q -5.245,-9.764 -3.282,-18.398 1.962,-8.634 13.676,-11 z M 27.19,248.865 135.97,132.556 a 7.135,7.135 0 0 1 1.427,0 h 0.154 q 3.14,0.345 2.842,3.71 a 19.36,19.36 0 0 1 -3.294,8.1 39.376,39.376 0 0 1 -9.728,10.405 q -3.912,2.938 -15.044,9.514 -12.796,7.505 -19.55,14.77 a 92.535,92.535 0 0 0 -11.513,14.486 l 32.907,3.758 8.182,-12.963 -20.967,-2.378 a 36.415,36.415 0 0 1 4.757,-3.83 q 2.379,-1.605 8.444,-5.125 l 6.422,-3.747 a 92.975,92.975 0 0 0 12.903,-8.776 61.472,61.472 0 0 0 12.51,-14.414 q 6.84,-10.846 6.494,-17.957 c -0.19,-3.949 -2.105,-6.434 -5.684,-7.505 l 79.798,-85.161 -102.097,179.576 -5.708,10.06 z m 367.238,-71.974 q -3.817,-5.458 -3.758,-8.515 c 0,-2.033 1.19,-3.199 3.568,-3.448 h 0.57 a 11.892,11.892 0 0 1 6.91,2.247 29.85,29.85 0 0 1 7.837,8.051 q 3.687,5.28 3.71,8.397 c 0,2.093 -1.188,3.258 -3.496,3.567 h -0.594 a 11.75,11.75 0 0 1 -6.957,-2.378 29.79,29.79 0 0 1 -7.79,-7.885 z m -109.41,-141.52 83.948,89.634 h -1.189 c -0.38,0 -0.975,0 -1.463,0.107 q -7.825,0.892 -8.324,6.862 -0.5,5.97 5.03,13.747 a 53.778,53.778 0 0 0 6.375,7.374 37.901,37.901 0 0 0 10.144,6.897 q -2.117,2.89 -0.702,7.98 a 37.283,37.283 0 0 0 5.613,11.096 55.122,55.122 0 0 0 15.223,14.806 q 8.098,5.268 16.066,4.935 0.81,0 1.618,-0.13 8.776,-0.988 9.228,-7.873 a 16.114,16.114 0 0 0 -0.463,-4.853 l 58.689,62.686 -91.572,-22.941 -6.1,-10.703 z m 98.22,104.927 2.45,2.617 c 0.451,0.57 0.903,1.189 1.355,1.784 1.808,2.592 2.723,4.757 2.723,6.529 0,1.771 -1.034,2.782 -3.127,3.02 h -0.512 a 10.346,10.346 0 0 1 -6.077,-1.95 22.596,22.596 0 0 1 -6.184,-6.137 c -1.974,-2.83 -2.937,-5.102 -2.878,-6.814 0.06,-1.713 1.118,-2.7 3.187,-2.937 h 0.524 a 10.263,10.263 0 0 1 6.005,1.879 19.147,19.147 0 0 1 2.533,2.01 z M 255.987,26 137.456,231.026 l 118.532,55.05 118.604,-55.05 z m -1.19,208.463 q -17.529,0 -24.58,-12.273 -7.053,-12.273 -7.053,-34.988 0,-22.714 7.052,-35.047 7.052,-12.332 24.582,-12.344 17.53,0 24.582,12.332 7.052,12.333 7.052,35.047 0,22.715 -7.052,34.988 -7.053,12.273 -24.582,12.285 z m 10.538,-71.807 q 2.497,7.968 2.497,24.546 0,15.817 -2.497,24.201 -2.498,8.384 -10.537,8.325 -8.04,0 -10.632,-8.325 -2.593,-8.324 -2.593,-24.2 0,-16.579 2.593,-24.547 2.593,-7.968 10.632,-7.968 8.015,-0.012 10.513,7.956 z"
fill="#ffffff"
fill-opacity="1"
transform="matrix(0.69282032,-0.4,0.4,0.69282032,-23.762003,181.038)"
id="path2-6"
style="fill:#ffffff" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 9.3 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 6.7 KiB

-449
View File
@@ -1,449 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 24.1.2, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 512.07 512" style="enable-background:new 0 0 512.07 512;" xml:space="preserve">
<style type="text/css">
.st0{display:none;}
.st1{display:inline;}
.st2{fill:#DCDCDC;stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;}
</style>
<g id="icon_x5F_sidebar_x5F_chat" class="st0">
<g class="st1">
<g>
<g>
<path class="st2" d="M180,480.93c14-15.25,27.95-29.3,40.56-44.47c14.18-17.05,23.54-36.69,26.34-59.05
c1.66-13.29-0.67-25.98-5.04-38.48c-1.8-5.15-5.7-5.52-10.23-5.78c-18.92-1.08-37.99-1.21-56.71-3.83
c-40-5.59-76.63-19.99-107.18-47.16c-36.18-32.19-46.99-77.73-26.93-122.29c15.37-34.14,40.96-59.17,71.93-78.94
c47.68-30.44,100.22-45.65,156.55-49.23c41.61-2.64,81.81,2.91,120.81,17.42c26.15,9.73,48.71,24.87,66.74,46.2
c29.1,34.42,32.23,80.62,8.86,120.58c-23.61,40.37-58.93,67.06-100.58,86.28c-10.17,4.7-20.81,8.38-31.3,12.36
c-4.3,1.63-6.47,4.24-6.8,9.02c-2.04,29.43-14.23,54.78-32.77,77.05c-29.18,35.06-66,59.86-107.6,77.9
C184.67,479.39,182.56,480.01,180,480.93z"/>
</g>
</g>
</g>
</g>
<g id="icon_x5F_sidebar_x5F_rolltable">
<g>
<g>
<g>
<path class="st2" d="M255.1,55.46c6.7,2.37,12.64,3.53,17.63,6.38c47.83,27.36,95.49,55,143.19,82.58
c1.76,1.02,3.5,2.14,5.06,3.43c4.67,3.85,4.73,8.08-0.19,11.57c-4.48,3.18-9.3,5.9-14.07,8.66
c-43.81,25.34-87.68,50.58-131.43,76.01c-12.79,7.43-25.19,8.02-38.18,0.44c-47.26-27.53-94.66-54.81-141.95-82.29
c-11.67-6.78-11.5-10.86,0.17-17.61c45.93-26.57,91.78-53.27,137.82-79.64C240.07,61.03,247.84,58.57,255.1,55.46z
M256.6,177.07c8.18-2.74,15.83-4.76,23.02-7.85c6.75-2.9,11.12-8.42,11.32-16.12c0.2-7.86-4.55-13.18-10.98-16.36
c-16.34-8.07-32.92-8.99-48.94,0.93c-13.18,8.17-13.33,23.46,0.28,30.9C238.94,172.75,248.01,174.3,256.6,177.07z
M139.44,174.49c10.51,0.36,20.31-1.78,28.43-8.85c7.92-6.9,8.07-17.96,0.6-25.36c-13.09-12.97-44.39-13.07-57.62-0.19
c-8.94,8.7-8.15,19.73,2.02,27.08C120.8,172.91,129.82,174.83,139.44,174.49z M371.05,174.5c13.13,0.01,20.45-1.93,27.72-7.04
c11.22-7.88,11.04-21.8-0.38-29.44c-14.58-9.76-37.05-9.78-51.54-0.06c-11.6,7.78-11.75,21.98-0.23,29.88
C354.29,173.1,362.88,175.12,371.05,174.5z M257.2,200.1c-10.74-0.21-20.43,1.8-28.51,8.53c-9.63,8.02-9.2,19.91,0.7,27.6
c13.81,10.71,40.59,10.4,54.05-0.63c9.82-8.05,9.29-21.21-1.19-28.54C274.59,201.7,265.94,199.86,257.2,200.1z M255.77,105.95
c10.86-0.08,20.49-2.25,28.35-9.28c8.51-7.61,8.52-17.75,0.3-25.54c-13.52-12.81-43.78-12.59-57.1,0.4
c-7.45,7.27-7.44,17.61,0.19,24.78C235.62,103.93,245.78,105.61,255.77,105.95z"/>
</g>
<g>
<path class="st2" d="M73.56,270.29c-0.01-23.47-0.01-46.95,0-70.42c0-2.24-0.04-4.5,0.09-6.73c0.55-9.08,4.45-11.43,12.3-7.03
c14.77,8.29,29.43,16.78,44.1,25.25c31.29,18.06,62.49,36.27,93.87,54.16c13.59,7.75,19.9,19.03,19.84,34.61
c-0.18,47.56-0.07,95.12-0.07,142.68c0,1.02,0,2.04-0.03,3.06c-0.37,10.88-4.46,13.26-13.91,7.81
c-46.51-26.8-93.02-53.6-139.43-80.56c-11.08-6.44-16.76-16.38-16.77-29.35C73.56,319.28,73.57,294.79,73.56,270.29z
M238.89,301.12c-1.04-15.22-9.94-29.1-25.87-37.67c-12.78-6.88-25.53,0.97-25.17,15.07c0.45,18,8.76,32.2,24.15,41.47
C226.27,328.58,238.87,320.93,238.89,301.12z M238.88,424.25c-0.03-14.84-11.77-33.85-24.91-40.35
c-13.82-6.83-27.24,1.36-26.24,16.4c1.14,17.22,9.44,30.68,24.03,39.63C226.22,448.8,238.92,441.17,238.88,424.25z
M78.36,336.56c-0.07,16.35,12.18,35.46,26.64,41.57c13.6,5.74,24.53-1.52,24.14-16.28c-0.47-17.75-9.44-30.82-23.63-40.54
c-5.85-4.01-12.62-5.05-19.12-1.43C80,323.43,78.2,329.62,78.36,336.56z M78.16,216.83c1.81,17.43,9.33,31.66,25.03,40.21
c13.84,7.55,26.4-0.25,25.96-15.46c-0.51-17.56-9.43-30.51-23.26-40.31c-5.78-4.1-12.64-5.27-19.16-1.76
C80.09,203.09,78.12,209.49,78.16,216.83z"/>
</g>
<g>
<path class="st2" d="M438.48,269.36c0,23.88-0.09,47.77,0.04,71.65c0.08,14.95-5.66,26.05-19.04,33.69
c-45.56,26.01-90.87,52.43-136.3,78.66c-1.93,1.11-4.02,2.03-6.14,2.72c-4.13,1.36-6.9-0.45-7.9-4.42
c-0.69-2.73-0.78-5.65-0.78-8.49c-0.04-48.18,0.04-96.35-0.07-144.53c-0.03-14.73,6.49-25.32,19.04-32.56
c44.18-25.53,88.36-51.07,132.54-76.6c1.24-0.71,2.5-1.39,3.75-2.08c11.32-6.2,14.8-4.14,14.84,9.08
C438.53,220.78,438.48,245.07,438.48,269.36z M273.14,421.22c0.05,19.9,12.39,27.34,26.79,18.9
c14.92-8.75,23.03-22.32,24.24-39.46c1.09-15.44-12.22-24.3-25.6-16.81C282.99,392.57,274.73,406.59,273.14,421.22z
M273.19,300.58c-0.25,19.57,10.43,26.62,25.43,19.95c14.02-6.23,26.59-26.94,25.75-42.41c-0.77-14.26-13.04-21.55-25.73-14.51
C283.1,272.22,275.12,286.19,273.19,300.58z M378.55,373.28c0.05-21.14-11.77-28.95-25.77-20.61
c-15.26,9.09-24.61,22.51-24.5,41.07c0.1,15.52,11.79,22.77,25.39,15.25C369.25,400.38,377.63,386.78,378.55,373.28z
M433.65,340.47c0.1-20.18-12.26-27.99-26.62-19.24c-14.51,8.85-23.33,22.09-24,39.66c-0.62,16.14,11.34,23.92,25.59,16.37
C424.57,368.82,431.83,354.54,433.65,340.47z M378.56,249.19c0.11-16.72-10.87-24.46-24.88-17.53
c-15.12,7.48-26.59,27.54-25.35,44.37c0.88,11.94,10.06,18.07,21.51,14.37C365.3,285.38,378.44,266.54,378.56,249.19z
M433.67,217.08c0.11-15.23-9.9-22.9-23.27-17.86c-16.2,6.12-29.92,29.74-27.12,46.71c1.73,10.53,10.4,15.95,20.67,12.93
C419.6,254.24,433.54,234.65,433.67,217.08z"/>
</g>
</g>
</g>
</g>
<g id="icon_x5F_sidebar_x5F_actor" class="st0">
<g class="st1">
<g>
<g>
<path class="st2" d="M194.72,240.85c-18.71-10.84-37.43-21.65-56.1-32.56c-4.38-2.56-3.72-6.78-3.09-10.93
c4.53-29.87,16.49-56.68,33.54-81.37c22.53-32.64,51.22-59.09,83.04-82.38c1.94-1.42,4.08-2.55,6.44-4.01
c2.95,1.91,5.76,3.52,8.35,5.44c34.2,25.36,64.61,54.39,87.21,90.87c13.92,22.47,23.34,46.63,27.11,72.93
c0.74,5.19-0.6,8.42-5.19,11.05c-17.12,9.83-34.08,19.93-51.1,29.92c-0.35-0.42-0.7-0.84-1.06-1.26
c7.2-7.59,13.9-15.74,21.74-22.61c6.97-6.11,8.08-12.73,6.54-21.27c-5.03-27.96-18.41-51.68-36.13-73.32
c-14.99-18.3-32.86-33.43-51.91-47.27c-3.26-2.37-6.29-3.56-10-0.89c-28.94,20.8-54.74,44.63-72.73,75.88
c-9.25,16.07-15.58,33.21-17.65,51.81c-0.5,4.49,0.65,7.78,3.76,10.99c9.23,9.52,18.23,19.25,27.32,28.9L194.72,240.85z"/>
</g>
<g>
<path class="st2" d="M168.55,345.65c-12.76,3.01-23.81-2.22-35.94-5.83c-3.63,12.02-1.15,22.71,4.28,33.16
c-0.52,0.49-1.04,0.98-1.56,1.47c-7.28-3.95-14.57-7.89-22.66-12.28c-0.94,40.71,5.85,79.96,12.76,120.22
c-9.73,0-18.21,0-28.31,0c0-4.71-0.17-8.65,0.03-12.57c2.77-54.5,0.73-108.5-16.69-160.88c-1.7-5.12-1.02-8.86,2.98-12.56
c15.25-14.13,30.3-28.49,45.51-42.67c1.86-1.73,4.21-2.92,7.2-4.95c12.66,31.79,36.38,51.55,65.92,65.71
c-23.56,4.18-43.99-5.23-64.98-14.12C142.45,319.03,153.45,333.5,168.55,345.65z"/>
</g>
<g>
<path class="st2" d="M378.56,342.15c-11.2,1.29-21.2,6.91-34.38,4.02c17.38-13.12,29.62-28.02,35.34-49.86
c-22.86,11.18-44.29,22.27-69.86,17.87c29.22-14.58,53.47-34,65.19-66.51c3.09,2.11,5.44,3.31,7.29,5.04
c15.49,14.48,30.83,29.13,46.36,43.57c3.94,3.66,4.92,7.36,3.13,12.52c-12.8,37.05-17.33,75.43-17.57,114.4
c-0.11,17.53,0.54,35.07,0.78,52.6c0.02,1.77-0.35,3.55-0.66,6.4c-8.97,0-17.6,0-27.36,0c6.32-39.97,13.54-79.18,12.38-120.61
c-8.84,4.81-16.27,8.85-23.71,12.89c-0.49-0.48-0.97-0.96-1.46-1.44C378.33,363.41,381.6,353.68,378.56,342.15z"/>
</g>
<g>
<path class="st2" d="M207.81,179.57c3.71-5.83,8.78-8.93,15.2-8.75c5.91,0.17,10.65,3.14,13.82,8.68
c-3.37,5.93-8.7,7.74-14.45,7.81C216.53,187.39,211.48,185.04,207.81,179.57z"/>
</g>
<g>
<path class="st2" d="M277.66,179.72c3.23-6.12,7.85-9.04,14-9c6.15,0.04,10.67,3.08,13.58,8.58c-2.43,6.15-7.58,7.55-12.87,7.82
C286.5,187.42,281.29,185.46,277.66,179.72z"/>
</g>
<g>
<path class="st2" d="M194.81,240.77c0,0-0.08,0.08-0.08,0.08C194.72,240.85,194.81,240.77,194.81,240.77z"/>
</g>
</g>
</g>
</g>
<g id="icon_x5F_sidebar_x5F_scene" class="st0">
<g class="st1">
<g>
<g>
<path class="st2" d="M141.31,362.45c10.55-10.81,21.11-21.61,32.39-33.17c-4.23-4.4-7.78-8.52-11.78-12.13
c-4.39-3.96-5.23-7.87-1.64-12.78c2.36-3.24,4.31-6.78,7.52-11.92c29.68,29.65,58.51,58.45,88.28,88.2
c29.63-29.58,58.38-58.28,88.43-88.27c3.76,6.48,7.17,11.44,9.48,16.88c0.68,1.6-1.26,4.92-2.82,6.75
c-3.78,4.43-8.04,8.45-12.61,13.15c3.87,4.06,7.01,7.46,10.26,10.75c6.02,6.1,12.2,12.04,18.09,18.27
c1.5,1.58,2.14,3.98,2.19,6.78c-11.12-2.35-15.32-13.36-25.7-18.87c-4.53,5.37-9.27,11-14.4,17.08
c4.03,8.46,15.77,12.55,18.84,22.89c-0.64,0.7-1.28,1.4-1.92,2.1c-2.18-1.32-4.7-2.29-6.49-4.01
c-7.5-7.21-14.75-14.68-22.17-21.99c-1.69-1.67-3.67-3.05-6.41-5.3c-5.41,5.88-10.51,11.42-16,17.4
c1.57,1.94,2.93,3.92,4.6,5.61c7.3,7.42,14.75,14.69,22,22.16c1.66,1.71,2.69,4.01,3.13,6.87
c-10.84-2.35-15.01-13.32-25.2-18.68c-4.93,5.38-10.02,10.94-15.43,16.85c4.67,9.02,15.38,13.49,19.26,23.07
c-0.54,0.67-1.09,1.34-1.63,2.01c-2.14-1.31-4.59-2.29-6.35-3.98c-7.49-7.22-14.75-14.69-22.17-21.99
c-1.69-1.66-3.68-3.01-5.89-4.79c-3.8,3-7.23,5.71-11.03,8.71c-3.77-2.97-7.19-5.68-11.01-8.69c-2.19,1.75-4.19,3.08-5.87,4.74
c-7.42,7.3-14.69,14.75-22.16,22c-1.73,1.67-4.02,2.76-6.91,3.23c2.31-10.77,13.12-15.02,18.63-25.24
c-5.42-4.76-11.09-9.74-17.21-15.11c-8.81,4.1-12.9,15.32-22.79,18.83c-0.62-0.47-1.25-0.95-1.87-1.42
c1.25-2.13,2.15-4.6,3.81-6.33c7.21-7.5,14.68-14.75,21.99-22.17c1.67-1.7,3.05-3.67,5.27-6.37
c-5.69-5.59-11.06-10.87-16.79-16.51c-2.48,2-4.47,3.36-6.16,5.02c-7.42,7.3-14.69,14.75-22.16,22c-1.71,1.66-4,2.72-6.87,3.19
c2.16-10.9,13.44-14.89,18.41-25.47c-5.23-4.81-10.76-9.89-16.39-15.06c-9.69,4.24-13.75,16.43-24.15,19.15
C143.03,364.74,142.17,363.6,141.31,362.45z"/>
</g>
<g>
<path class="st2" d="M441,403.48c-16.69-27.59-33.44-55.13-50.04-82.77c-42.46-70.68-84.85-141.39-127.26-212.1
c-1.34-2.23-2.47-4.58-4.3-8.02c13.34-3.15,24.63-8.77,32.97-20.46c1.71,2.53,2.89,3.85,3.6,5.4
c28.28,61.55,56.51,123.12,84.77,184.68c19.15,41.72,38.37,83.41,57.51,125.14c1.18,2.58,1.92,5.36,2.86,8.04L441,403.48z"/>
</g>
<g>
<path class="st2" d="M217.61,82.38c2.39,3.13,3.85,4.73,4.95,6.53c4.59,7.48,8.69,15.3,13.71,22.47
c4.35,6.21,4.12,11.18,0.16,17.73c-47.28,78.28-94.26,156.74-141.31,235.16c-6.51,10.85-13.01,21.71-19.54,32.55
c-1.13,1.88-2.39,3.68-4.72,4.92C119.57,295.76,168.27,189.77,217.61,82.38z"/>
</g>
<g>
<path class="st2" d="M477.25,255.92c-10.87-10.64-21.54-21.09-32.91-32.23c-5.58,5.75-10.68,11.01-16.24,16.75
c1.84,2.26,3.31,4.39,5.1,6.21c7.43,7.56,15,15,22.43,22.56c2.12,2.16,4.52,4.52-0.17,8.58c-7.22-6.76-14.48-13.55-21.88-20.47
c-6.08,5.51-11.66,10.57-17.97,16.3c7.88,8.42,14.65,15.65,21.42,22.88c-0.62,0.85-1.25,1.7-1.87,2.56
c-2.14-1.03-4.53-1.72-6.36-3.13c-13.8-10.59-21.18-25.52-27.46-41.16c-5.78-14.38-8.33-11.03,4.45-23.75
c7.23-7.19,14.4-14.44,21.65-21.61c1.71-1.69,3.62-3.17,5.84-5.08c1.73,1.12,3.41,1.86,4.63,3.06
c13.32,13.21,26.59,26.48,39.81,39.79C479.85,249.34,482.22,251.73,477.25,255.92z"/>
</g>
<g>
<path class="st2" d="M68.55,223.56c-12.92,10.59-22.16,23.11-34.32,32.22c-0.78-0.53-1.57-1.06-2.35-1.59
c0.43-1.85,0.25-4.3,1.39-5.46c14.33-14.51,28.84-28.83,43.34-43.18c0.39-0.38,1.12-0.42,1.97-0.71
c0.75,0.34,1.86,0.54,2.53,1.2c10.88,10.75,21.84,21.43,32.39,32.51c1.47,1.54,1.83,5.55,0.94,7.69
c-4.29,10.36-8.17,21.11-14.15,30.47c-5.16,8.08-12.9,14.53-19.62,21.58c-0.65,0.69-2.18,0.54-5.2,1.2
c3.65-11.71,15.03-15.79,20.22-26.77c-5.23-4.62-10.83-9.57-16.64-14.7c-9.41,4.67-13.78,15.49-23.35,19.4
c-0.67-0.54-1.35-1.07-2.02-1.61c1.11-1.99,1.87-4.32,3.4-5.91c7.07-7.35,14.38-14.47,21.55-21.72c1.84-1.86,3.48-3.92,6.4-7.23
C79.61,235.25,74.35,229.69,68.55,223.56z"/>
</g>
<g>
<path class="st2" d="M256.05,428.1c7.93,7.53,16.37,15.55,24.7,23.47c-8.21,8.27-16.4,16.51-24.37,24.54
c-8.23-7.98-16.67-16.16-25.11-24.34C239.8,443.62,248.21,435.58,256.05,428.1z"/>
</g>
<g>
<path class="st2" d="M254.88,73.27c6.48-5.93,12.68-11.6,18.52-16.94C275.4,65.47,265.2,75.93,254.88,73.27z"/>
</g>
<g>
<path class="st2" d="M238.87,49.47c0.54-7.99,6.12-13.62,15.88-13.57c-4.81,4.98-9.61,9.96-14.42,14.93
C239.84,50.38,239.35,49.92,238.87,49.47z"/>
</g>
<g>
<polygon class="st2" points="441.11,403.38 441.22,403.67 441,403.48 "/>
</g>
</g>
</g>
</g>
<g id="icon_x5F_sidebar_x5F_item" class="st0">
<g class="st1">
<g>
<g>
<path class="st2" d="M86.57,379.95c0-48.58,0-96.33,0-143.79c5.64-2.82,112.01-3.19,119.52-0.33c0.25,2.68,0.79,5.83,0.8,8.98
c0.07,26.94,0.01,53.88,0.08,80.83c0.01,3.17,0.51,6.33,0.85,10.3c32.36,0,63.92,0,97.01,0c0-33.87,0-66.95,0-99.19
c6.41-3.36,112.58-3.86,119.48-1.35c2.55,5.28,2.8,137.43-0.09,144.56C312.19,379.95,199.8,379.95,86.57,379.95z"/>
</g>
<g>
<path class="st2" d="M351.95,96.52c0,37.52,0,74.24,0,111.87c-15.41,0-30.07,0-45.61,0c-0.81-5.04-1.56-9.72-2.59-16.15
c-31.78-0.12-63.35-0.24-95.41,0.16c-1.01,5.85-1.81,10.52-2.76,16c-15.49,0-30.54,0-46.27,0c-0.48-3.17-1.18-5.7-1.19-8.24
c-0.08-31.43-0.09-62.85-0.03-94.28c0.02-8.73,1.64-10.33,10.48-10.33c58.36-0.05,116.72-0.03,175.09,0.01
C346.04,95.56,348.42,96.09,351.95,96.52z"/>
</g>
<g>
<path class="st2" d="M132.51,208.42c-9.52,0-18.03,0-27.47,0c0-37.52,0-74.16,0-111.86c9.22,0,17.87,0,27.47,0
C132.51,133.9,132.51,170.54,132.51,208.42z"/>
</g>
<g>
<path class="st2" d="M378.57,96.39c10.31,0,18.82,0,29.12,0c0.27,37.43,0.14,74.07,0.08,111.82c-10.01,0-18.66,0-29.13,0
C378.39,170.99,378.51,134.35,378.57,96.39z"/>
</g>
<g>
<path class="st2" d="M107.03,407.31c99.7,0,198.42,0,297.14,0c0.31,0.74,0.62,1.47,0.93,2.21c-3.8,2.18-7.48,4.61-11.44,6.42
c-1.72,0.78-4.02,0.36-6.06,0.36c-87.72,0.01-175.44-0.01-263.17,0.06C117.35,416.37,111.13,415.25,107.03,407.31z"/>
</g>
<g>
<path class="st2" d="M280.03,311.38c-16.62,0-31.68,0-47.61,0c0-31.35,0-61.94,0-93.7c15.6-1.68,30.82-0.85,47.53-0.45
C280.76,248.97,280.56,279.53,280.03,311.38z M267.36,293.14c0.39-3.77,0.85-6.35,0.89-8.94c0.12-7.13-0.2-14.28,0.21-21.39
c0.17-2.85,1.14-6.13,2.88-8.31c8.15-10.27,8.56-19.5,0.67-27.25c-8.45-8.3-21.51-8.87-30.61-1.33
c-8.41,6.98-10.24,17.21-3.09,25.35c4.73,5.38,5.6,10.91,5.4,17.36c-0.17,5.7-0.14,11.42,0.05,17.12
c0.08,2.32,0.82,4.63,1.34,7.39C252.64,293.14,259.56,293.14,267.36,293.14z"/>
</g>
<g>
<path class="st2" d="M459.64,208.46c-9.05,0-17.17,0-26.05,0c-0.44-3.46-1.09-6.2-1.09-8.93c-0.07-31.16-0.05-62.33-0.04-93.49
c0-1.22,0.07-2.44,0.15-3.66c0.3-4.41,2.7-6.57,7.1-6.7c4.5-0.13,6.66,2.09,7.24,6.46c4.34,32.91,8.76,65.81,13.07,98.73
C460.3,202.98,459.83,205.2,459.64,208.46z"/>
</g>
<g>
<path class="st2" d="M77.56,97.23c0,36.74,0,73.41,0,111.08c-8.48,0-16.35,0-25.02,0c-0.25-2.71-0.9-5.08-0.6-7.34
c4.21-32.52,8.49-65.04,12.9-97.53C65.84,96.02,68.83,94.5,77.56,97.23z"/>
</g>
<g>
<path class="st2" d="M451.71,362.72c0-42.84,0-84.74,0-127.72c3.45-0.21,6.42-0.39,10.08-0.61c0.46,3.5,1.09,6.04,1.1,8.58
c0.06,34.46-0.08,68.92,0.12,103.38C463.06,354.24,458.99,358.62,451.71,362.72z"/>
</g>
<g>
<path class="st2" d="M50.26,234.87c2.86,0,5.32,0,7.56,0c2.47,5.02,3.24,118.46,0.9,126.79c-5.37-3.13-9.67-6.58-9.66-13.41
c0.02-35.65-0.01-71.31,0.05-106.96C49.12,239.34,49.79,237.4,50.26,234.87z"/>
</g>
<g>
<path class="st2" d="M51.56,390.71c7.99,7.72,15.99,15.44,25.01,24.15c-9.12,2.16-16.82,2.02-24.49,0.42
c-1.03-0.21-2.41-2.03-2.45-3.14c-0.23-6.78-0.11-13.57-0.11-20.36C50.2,391.43,50.88,391.07,51.56,390.71z"/>
</g>
<g>
<path class="st2" d="M436.46,413.79c8.05-7.65,16.1-15.3,24.15-22.95c0.61,0.34,1.23,0.69,1.84,1.03
c0,6.76,0.19,13.52-0.17,20.26c-0.07,1.29-2.24,3.46-3.53,3.53c-7.16,0.35-14.35,0.17-21.53,0.17
C436.96,415.15,436.71,414.47,436.46,413.79z"/>
</g>
</g>
</g>
</g>
<g id="icon_x5F_sidebar_x5F_fight" class="st0">
<g class="st1">
<g>
<g>
<path class="st2" d="M98.54,121.71c7.19,0.33,14.38,0.67,22.81,1.06c1.18-7.93,2.28-15.34,3.38-22.75
c0.65-0.23,1.3-0.46,1.95-0.69c70.17,84.04,140.34,168.07,211.57,253.38c-9.84,8.24-18.85,15.78-28.82,24.13
C238.18,291.6,167.84,207.47,97.5,123.34C97.85,122.8,98.2,122.26,98.54,121.71z"/>
</g>
<g>
<path class="st2" d="M74.25,462.04c-10.75-7.58-20.15-14.21-30.69-21.64C87.39,378.65,130.68,317.64,175,255.19
c8.95,10.7,16.69,19.95,24.95,29.82C158.02,344.06,116.54,402.48,74.25,462.04z"/>
</g>
<g>
<path class="st2" d="M425.22,103.01c0.37,2.17,1.08,4.12,0.96,6.02c-1.52,23.89-10.41,44.55-26.71,62.21
c-17.85,19.34-40.04,31.93-63.81,42.21c-1.98,0.86-4.11,1.36-7.64,2.49c1.24-4.12,1.91-6.97,2.94-9.69
c6.52-17.26,11.93-34.75,11.33-53.5c-0.09-2.84-0.01-5.86-0.93-8.47c-2.37-6.7,0.06-11.13,5.24-15.36
c8.52-6.96,16.52-14.54,24.94-21.63c1.91-1.61,4.59-3.05,6.99-3.2c14.23-0.85,28.48-1.32,42.72-1.86
C422.24,102.2,423.23,102.61,425.22,103.01z"/>
</g>
<g>
<path class="st2" d="M291.85,453.14c-4.87-5.91-8.93-10.84-14.08-17.09c41.71-34.89,82.71-69.18,124.58-104.2
c4.79,5.78,8.96,10.8,14.01,16.89C374.53,383.82,333.55,418.17,291.85,453.14z"/>
</g>
<g>
<path class="st2" d="M273.79,115.61c10.76,7.57,20.25,14.24,30.73,21.61c-17.52,24.77-34.23,48.41-51.86,73.34
c-8.76-10.27-16.69-19.55-25.21-29.54C242.84,159.29,257.83,138.14,273.79,115.61z"/>
</g>
<g>
<path class="st2" d="M310.02,250.99c3.13-1.7,6.08-3.97,9.41-5.02c21.89-6.92,42.92-15.68,62.36-28.02
c29.04-18.43,51.93-42.06,63.17-75.38c4.67-13.85,6.52-28.16,6.18-42.77c-0.05-2.01-0.01-4.02-0.01-6.78
c3.9-2.17,7.86-4.37,12.69-7.05c1.31,3.33,2.56,5.61,3.12,8.05c3.1,13.52,1.31,26.78-2.57,39.85
c-16.18,54.48-81.45,113.08-140.32,120.1c-4.27,0.51-8.65,0.07-12.98,0.07C310.71,253.03,310.37,252.01,310.02,250.99z"/>
</g>
<g>
<path class="st2" d="M389.79,472.78c-11.28-13.51-21.9-26.23-33.01-39.54c8.13-9.93,17.68-16.81,28.3-24.44
c11.08,13.21,21.71,25.89,33.02,39.37C409.83,457.64,400.05,464.37,389.79,472.78z"/>
</g>
<g>
<path class="st2" d="M321.15,118.13c-11.98-8.39-23.18-16.22-35.16-24.61c4.46-12.23,8.63-23.66,13.37-36.67
c17.45,12.36,33.25,23.54,50.46,35.73C339.82,101.49,330.87,109.47,321.15,118.13z"/>
</g>
<g>
<path class="st2" d="M98.58,95.77c-7.12-0.81-13.28-1.35-19.35-2.36c-1.23-0.2-2.8-2.02-3.15-3.37
c-2.23-8.67-4.18-17.41-6.14-26.14c-0.15-0.68,0.35-1.51,0.74-2.98c1.89,0.47,3.64,0.68,5.2,1.33
c6.2,2.59,12.29,5.47,18.53,7.94c4.9,1.94,7.04,5.25,6.33,10.43C100.13,85.01,99.49,89.39,98.58,95.77z"/>
</g>
<g>
<path class="st2" d="M263.6,72.75c-4.58-8.72-9.17-17.44-14.34-27.29c9.64-1.5,17.2,0.6,26.32,3.04
c-3.26,8.72-6.26,16.73-9.26,24.75C265.41,73.08,264.5,72.92,263.6,72.75z"/>
</g>
<g>
<path class="st2" d="M328.1,39.22c10.42,7.7,21.69,12.69,29.96,23.17C349.73,64.21,326.41,46.59,328.1,39.22z"/>
</g>
</g>
</g>
</g>
<g id="icon_x5F_sidebar_x5F_compendium" class="st0">
<g class="st1">
<g>
<g>
<path class="st2" d="M172.73,49.37c21.98,0,43.98,0,66.87,0c0,137.52,0,274.28,0,412.73c-22.56,0.64-44.71,0.55-66.23,0.05
C170.22,455.66,169.78,57.56,172.73,49.37z M200.52,429.88c3.18-7.29,2.79-312.57-0.29-318.12c-6.66,0-13.58,0-20.13,0
c-3.18,7.31-2.79,312.56,0.29,318.12C187.06,429.88,193.98,429.88,200.52,429.88z M210.72,299.22
c-3.15,7.38-2.74,125.16,0.33,130.65c6.67,0,13.59,0,21.35,0c0-43.84,0-86.81,0-130.65
C224.64,299.22,217.72,299.22,210.72,299.22z"/>
</g>
<g>
<path class="st2" d="M145.38,142.76c0,85.62,0,170.31,0,256.67c-17.42,1.03-34.25,0.66-51.8,0.12
c-0.49-3.88-1.14-6.62-1.14-9.36c-0.05-79.17-0.06-158.34-0.03-237.52c0-9.54,1.47-10.94,11.07-11
c11.02-0.07,22.04-0.07,33.06,0.03C139.11,141.74,141.67,142.3,145.38,142.76z"/>
</g>
<g>
<path class="st2" d="M363.52,456.03c-12.7,2.35-23.74,4.39-35.68,6.6c-1.26-4.11-2.57-7.24-3.16-10.5
c-10.85-60.07-21.6-120.15-32.38-180.23c-7.75-43.2-15.53-86.4-23.26-129.6c-0.49-2.72-0.59-5.51-1-9.55
c12.13-2.2,23.57-4.27,36.31-6.58C324.11,236.33,343.65,345.24,363.52,456.03z"/>
</g>
<g>
<path class="st2" d="M30.77,95.93c12.29,0,23.52,0,35.63,0c0.49,3.12,1.29,5.83,1.29,8.53c0.07,53.47,0.07,106.95,0.02,160.42
c0,2.37-0.57,4.75-0.98,8c-11.97,0-23.53,0-35.96,0C30.77,213.88,30.77,155.54,30.77,95.93z"/>
</g>
<g>
<path class="st2" d="M367.58,238.23c7-3.03,12.81-5.54,20.08-8.69c31.66,74.22,62.88,147.39,94.52,221.55
c-7.17,3.14-12.98,5.68-20.06,8.77C430.48,385.69,399.26,312.48,367.58,238.23z"/>
</g>
<g>
<path class="st2" d="M65.98,461.62c-11.43,0-22.81,0-35.96,0c-0.23-38.48-0.1-76.1-0.08-114.56c13.02,0,24.42,0,35.56,0
C68.27,352.44,68.8,453.4,65.98,461.62z"/>
</g>
<g>
<path class="st2" d="M145.31,461.62c-17.64,0-34.34,0-51.98,0c0-12.22,0-23.59,0-34.65c5.83-2.99,44.82-3.3,51.98-0.36
C145.31,437.66,145.31,449.07,145.31,461.62z"/>
</g>
<g>
<path class="st2" d="M66.94,299.04c0,7.68,0,14,0,20c-5.68,3.23-28.48,3.6-36.48,0.32c0-5.15-0.23-10.92,0.17-16.64
c0.09-1.3,2.32-3.48,3.61-3.52C44.72,298.91,55.21,299.04,66.94,299.04z"/>
</g>
<g>
<path class="st2" d="M344.77,183.51c1.37-6.24,13.25-11.41,18.86-8.56C361.93,179.91,351.56,184.78,344.77,183.51z"/>
</g>
<g>
<path class="st2" d="M376.69,203.79c-1.47,1.58-2.66,3.99-4.46,4.57c-4.85,1.58-9.26,6.71-16.33,2.77
c5.69-6.11,12.27-7.7,18.8-9.41C375.37,202.41,376.03,203.1,376.69,203.79z"/>
</g>
</g>
</g>
</g>
<g id="icon_x5F_sidebar_x5F_settings" class="st0">
<g class="st1">
<g>
<g>
<path class="st2" d="M167.35,468.66c-13.39-1.77-50.61-24-55.69-33.14c1.08-1.73,2.27-3.8,3.62-5.75
c9.08-13.11,15.46-27.19,17.17-43.32c2.08-19.66-8.6-38.21-26.93-45.65c-18.45-7.49-36.8-5.28-55.13,0.52
c-2.27,0.72-4.61,1.24-7.95,2.13c-8.74-20.07-13.97-40.42-16.04-62.21c3.72-1,6.27-1.51,8.71-2.36
c10.15-3.55,20.93-5.98,30.28-11.03c32.02-17.29,37.2-51.45,11.57-77.58c-7.69-7.84-18.02-13.11-27.21-19.46
c-1.8-1.24-3.88-2.08-6.88-3.65c7.46-20.81,19.04-38.63,32.65-56.07c2.6,1.58,4.49,2.63,6.28,3.83
c12.84,8.66,26.44,15.16,42.16,16.87c27.62,3.01,49.81-16.05,50.75-43.89c0.44-12.98-0.7-25.69-5.26-37.95
c-0.57-1.52-0.94-3.13-1.27-4.72c-0.16-0.77-0.03-1.6-0.03-3.56c19.48-9.06,40.19-13.46,62.14-15.74
c1.02,3.75,1.82,6.21,2.34,8.72c3.47,16.64,9.06,32.26,21.51,44.52c15.73,15.49,38.24,17.59,56.71,5.52
c12.09-7.9,21.07-18.51,27.72-31.22c1.77-3.4,3.56-6.79,5.82-11.11c21.09,7.8,39.67,18.42,56.8,32.93
c-1.64,2.8-2.68,4.95-4.05,6.86C388.21,94.64,382,108.15,380,123.56c-3.04,23.55,11.24,44.26,34.61,49.71
c15.81,3.69,31.2,1.62,46.42-3.22c2.48-0.79,5-1.42,8.46-2.39c8.98,19.98,13.9,40.42,16.18,62.37c-3.8,0.94-6.46,1.76-9.18,2.25
c-16.65,3.01-31.7,9.36-43.86,21.42c-17.55,17.41-17.87,44.76-1.08,62.94c9.09,9.85,19.19,18.29,31.47,23.91
c1.97,0.9,3.73,2.29,6.35,3.94c-7.98,20.35-18.77,38.4-32.84,55.12c-3.06-1.75-5.24-2.79-7.18-4.15
c-11.9-8.34-24.87-13.72-39.36-15.81c-25.9-3.73-48.07,12.39-52.41,38.17c-2.51,14.96-0.26,29.24,4.49,43.36
c0.89,2.64,1.57,5.34,2.63,8.96c-20.39,9.22-41.13,13.92-63.52,15.93c-1.27-5.66-2.36-10.56-3.47-15.47
c-2.68-11.93-7.48-22.97-15.18-32.45c-19.22-23.66-48.23-25.35-70.63-3.31c-8,7.87-13.67,18.12-20.35,27.33
C170.02,464.25,168.74,466.5,167.35,468.66z M255.86,400.9c76.17,1.14,145.09-60.6,145.17-144.58
c0.07-81.43-64.18-146.3-147.02-145.43c-80.82,0.84-143.17,67.24-143.11,145.2C110.95,336.29,175.57,400.89,255.86,400.9z"/>
</g>
<g>
<path class="st2" d="M255.9,375.07c-66.32-0.01-119.05-52.79-119.18-119.01c-0.12-60.41,46.51-119.03,119.17-119.37
c66.88-0.31,119,51.98,119.5,119.66C375.87,322.28,322.28,375.08,255.9,375.07z M256.32,367.82
c61.81,0.01,112.28-50.05,111.82-111.65c-0.45-60.76-47.78-111.81-111.76-112.13c-63.11-0.31-112.37,51.07-112.41,112.06
C143.95,318.19,193.87,367.82,256.32,367.82z"/>
</g>
</g>
</g>
</g>
<g id="icon_x5F_sidebar_x5F_journal" class="st0">
<g class="st1">
<g>
<g>
<path class="st2" d="M448.42,92.12c-17.01,7.17-36.38,3.32-52.81,13.34c13.35,7.59,25.04,14.25,36.73,20.9
c-0.07,0.7-0.15,1.39-0.22,2.09c-10.32,2.08-20.63,4.16-30.95,6.23c-0.13,0.63-0.27,1.25-0.4,1.88
c14.07,8.7,28.14,17.4,42.66,26.38c-0.79,3.42-1.29,6.39-2.17,9.24c-9.51,30.75-25.84,57.54-47.17,81.49
c-28.41,31.88-43.98,69.29-47.66,111.76c-0.21,2.39-0.8,4.75-1.37,8.08c-3.69,0.38-7.21,1.06-10.74,1.07
c-52.87,0.07-105.74-0.15-158.6,0.15c-23.87,0.13-41.44,11.18-51.15,33.28c-13.04,29.65,8.96,66.89,45.53,62.06
c6.73-0.89,13.59-0.76,20.39-1.1c0.18,0.69,0.36,1.39,0.54,2.08c-1.95,1.11-3.78,2.8-5.87,3.23
c-13.93,2.87-27.83,6.21-41.92,7.89c-9.63,1.15-19.71,0.93-29.3-0.54c-25.73-3.96-39.5-20.96-46.09-44.94
c-7.68-27.98-4.86-55.9,1.11-83.65c2.48-11.54,6.41-22.77,9.52-34.19c1.48-5.44,4.92-7.99,10.38-8.84
c14.32-2.22,28.6-4.7,42.88-7.15c2.31-0.4,4.55-1.17,8.35-2.18c-12.43-12.92-23.92-24.85-35.68-37.07
c10.82-18.72,21.31-36.6,31.53-54.63c10.13-17.88,18.72-36.44,25.46-57.28c-4.1-0.52-6.79-1.1-9.48-1.17
c-19.98-0.48-39.99-0.43-59.95-1.38c-24.37-1.15-41.44-13.86-51.3-35.78c-9.41-20.93-7.08-40.88,7.01-59.34
c19.06-24.97,49.5-32.54,79.33-22.79c21.47,7.01,43.03,8.54,65.03,9.07c24.68,0.59,49.38,1.73,74.03,1.02
c37.08-1.07,74.08-3.17,111.05-7.28c35.35-3.93,63.98,16.8,71.28,52.84C448.69,88.4,448.42,90.05,448.42,92.12z M159.2,70.78
c0-1.99,0.18-2.66-0.04-3.16c-0.48-1.12-1.19-2.13-1.74-3.22c-6.25-12.36-16.75-18.76-29.81-22.21
c-18.28-4.83-36.2-6.22-53.53,3.12c-21.82,11.76-31.94,33.41-26.21,55.84c5.97,23.41,24.48,37.29,49.57,37.18
c17.77-0.08,24.02-8.04,17.19-24.49c-5.04-12.13-12.63-23.2-19.09-34.74c-1.22-2.18-2.46-4.34-4.73-8.33
C114.8,70.78,137.01,70.78,159.2,70.78z M125.86,137.58c1.23,0.84,1.72,1.47,2.22,1.47c10.98,0.11,21.98,0.38,32.94-0.05
c1.75-0.07,4.42-3.12,4.9-5.2c3.31-14.42,3.93-28.99,1.39-43.67c-1-5.82-3.9-8.4-9.91-8.3c-12.83,0.22-25.67,0.01-38.51,0.11
c-2.02,0.02-4.04,0.76-6.94,1.34C121.1,101.11,132.77,117.32,125.86,137.58z"/>
</g>
<g>
<path class="st2" d="M437.3,403.69c-12.05,6.13-24.1,12.27-36.16,18.4c0.06,0.71,0.11,1.41,0.17,2.12
c24.23,2.92,48.45,5.83,72.88,8.77c0.85,2.39,1.74,4.21,2.15,6.14c4.1,19.37-9.24,40.07-28.6,44.05
c-5.16,1.06-10.51,1.63-15.78,1.64c-68.14,0.11-136.27,0.08-204.41,0.06c-2.4,0-4.79-0.23-9.27-0.46
c10.87-12.42,17.06-25.54,17.43-40.56c0.37-14.77-2.14-29.17-10.26-43.31c3.8-0.56,6.28-1.23,8.77-1.24
c60.59-0.06,121.18-0.1,181.76,0.05c7,0.02,13.99,1.22,20.99,1.88C437.07,402.06,437.18,402.88,437.3,403.69z"/>
</g>
<g>
<path class="st2" d="M208.78,442.37c-2.84,0.3-5.59,0.73-8.35,0.86c-11.77,0.56-23.55,0.9-35.32,1.59
c-11.74,0.69-20.7-11.09-17.7-23.56c2.84-11.78,14.12-20.41,27.04-20.71C193.39,400.09,213.19,416.86,208.78,442.37z"/>
</g>
</g>
</g>
</g>
<g id="icon_x5F_sidebar_x5F_music" class="st0">
<g class="st1">
<g>
<g>
<path class="st2" d="M261.65,225.6c0.7,2.64,1.55,5.26,2.07,7.94c1.62,8.25,2.65,8.79,11.01,8.46c15-0.58,29.14,2.2,41.74,11.16
c14.6,10.37,19.64,25.5,21.71,42.14c2.78,22.32-10.19,36.76-25.52,49.9c-0.44,0.37-1.09,0.54-1.67,0.69
c-0.37,0.09-0.8-0.03-1.59-0.08c-3.15-4.92-2.8-9.59,0.96-14.33c6.14-7.74,11.54-15.89,12.05-26.24
c1.24-25.02-14.28-44.09-39.26-47.94c-4.59-0.71-9.31-0.53-15-0.81c0.44,4.72,0.51,7.73,1.03,10.66
c8.8,49.42,17.66,98.83,26.47,148.26c1.07,6.03,2.01,12.08,2.81,18.15c1.93,14.59-2.85,26.51-14.6,35.46
c-18.51,14.1-39.18,15.5-60.44,8.72c-16.02-5.1-25.76-22.74-22.74-38.34c3.49-18.02,17.24-29.36,35.42-29.2
c17.96,0.16,31.41,11.98,34.49,30.27c0.42,2.52,1.01,5.02,1.49,7.33c10.2,0.4,17.08-7.88,15.5-18.5
c-3.27-22-6.51-44.01-10.45-65.89c-5.72-31.73-12.04-63.35-18.15-95.01c-0.4-2.07-1.27-4.05-2.29-7.23
c-7.24,4.84-12.49,9.93-15.47,17.08c-5.54,13.32-3.63,26.35,1.74,39.25c1.25,3.01,1.98,6.23,2.95,9.35
c-0.69,0.48-1.39,0.96-2.08,1.44c-1.98-1.63-4.28-2.98-5.89-4.92c-14.99-18.11-14.14-48.78,1.75-66.18
c2.06-2.26,4.06-4.69,6.52-6.45c5.79-4.17,9.56-8.69,8.28-16.73c-0.43-2.71,3.11-6.04,4.83-9.09
C260.1,225.14,260.88,225.37,261.65,225.6z"/>
</g>
<g>
<path class="st2" d="M242.98,129.77c-0.54-2.18-1.24-3.66-1.24-5.15c0.06-27.65,5.24-53.97,20.63-77.55
c0.78-1.19,1.62-2.36,2.52-3.47c15.38-18.96,34.82-17.62,45.72,4.2c15.14,30.31,13.51,60.55-6.91,87.73
c-13.67,18.2-29.81,34.59-45.42,51.26c-18.14,19.38-36.83,38.27-50.39,61.34c-4.74,8.07-9.5,16.33-12.73,25.07
c-8.46,22.81-4.26,43.77,11.57,62.22c9.81,11.44,22.06,19.31,36.6,23.44c5.39,1.53,7.9,4.61,6.35,11.29
c-2.86,0-5.84,0.44-8.66-0.07c-31-5.57-50.06-25.12-60.87-53.46c-11.63-30.51-8.06-59.85,11.23-86
c15.34-20.81,32.18-40.57,49.3-59.97c15.92-18.03,33.27-34.79,49.64-52.44c11.16-12.03,12.87-27,10.85-42.48
c-1.06-8.1-5.98-13.73-14.13-16.01c-7.39-2.07-12.75,1.54-17.1,6.79c-2.57,3.1-5.27,6.57-6.35,10.32
c-3.64,12.7-7.02,25.51-9.61,38.46C252.62,122.04,249,126,242.98,129.77z"/>
</g>
</g>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 28 KiB

+80
View File
@@ -0,0 +1,80 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
viewBox="0 0 512 512"
style="height: 256px; width: 256px;"
version="1.1"
id="svg6"
sodipodi:docname="icon_sidebar_tables.svg"
inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)">
<metadata
id="metadata12">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs10" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1956"
inkscape:window-height="1125"
id="namedview8"
showgrid="false"
inkscape:zoom="0.71777344"
inkscape:cx="403.50636"
inkscape:cy="-55.697677"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="0"
inkscape:current-layer="svg6" />
<g
id="g838"
transform="matrix(0.52656879,-0.75618342,0.76711498,0.53418097,-33.85852,326.4134)"
style="fill:#ffffff;stroke:none">
<g
class=""
id="g4-5"
style="fill:#ffffff;stroke:none"
transform="matrix(0.76010883,0,0,0.77788021,-69.057255,5.6807692)">
<path
d="m 375.483,251.243 -109.98,51.138 0.213,183.381 211.294,-219.416 -86.993,-21.81 z m -12.736,108.626 -5.947,14.699 -48.604,-8.955 5.007,-12.832 a 141.306,141.306 0 0 0 13.51,-11.358 167.184,167.184 0 0 0 16.566,-17.517 170.478,170.478 0 0 0 12.606,-17.958 115.607,115.607 0 0 0 9.514,-17.97 l 14.068,2.51 q -9.37,22.334 -30.361,44.43 -13.296,13.64 -20.645,18.636 z M 121.603,244.334 36.893,266.097 246.474,486 V 302.38 L 136.528,251.243 Z m 19.147,50.852 a 28.72,28.72 0 0 1 24.273,6.802 53.052,53.052 0 0 1 11.226,14.188 l -13.081,2.676 a 28.542,28.542 0 0 0 -5.388,-7.374 q -5.185,-4.876 -11.262,-3.853 l -0.487,0.095 a 6.458,6.458 0 0 0 -5.162,4.448 c -0.856,2.378 -0.238,5.554 1.796,9.371 q 4.08,7.6 10.81,9.027 a 23.785,23.785 0 0 0 8.563,-0.203 l 1.867,-0.344 5.791,10.822 q -6.398,1.427 -8.23,3.282 -3.21,3.14 0.429,9.93 a 17.042,17.042 0 0 0 6.089,6.696 10.406,10.406 0 0 0 7.385,1.534 l 0.416,-0.083 q 4.757,-0.964 5.079,-4.757 c 0.261,-2.57 -0.655,-5.744 -2.748,-9.514 l 12.38,-2.545 a 49.247,49.247 0 0 1 4.103,11.226 19.956,19.956 0 0 1 -0.642,9.383 11.702,11.702 0 0 1 -3.96,5.411 19.575,19.575 0 0 1 -8.027,3.235 l -1.19,0.214 a 27.971,27.971 0 0 1 -17.494,-2.7 32.193,32.193 0 0 1 -14.128,-14.092 q -3.627,-6.79 -2.604,-12.19 a 8.396,8.396 0 0 1 2.521,-4.947 h -0.071 q -1.844,0.31 -7.04,-2.497 a 32.11,32.11 0 0 1 -12.916,-13.593 q -5.245,-9.764 -3.282,-18.398 1.962,-8.634 13.676,-11 z M 27.19,248.865 135.97,132.556 a 7.135,7.135 0 0 1 1.427,0 h 0.154 q 3.14,0.345 2.842,3.71 a 19.36,19.36 0 0 1 -3.294,8.1 39.376,39.376 0 0 1 -9.728,10.405 q -3.912,2.938 -15.044,9.514 -12.796,7.505 -19.55,14.77 a 92.535,92.535 0 0 0 -11.513,14.486 l 32.907,3.758 8.182,-12.963 -20.967,-2.378 a 36.415,36.415 0 0 1 4.757,-3.83 q 2.379,-1.605 8.444,-5.125 l 6.422,-3.747 a 92.975,92.975 0 0 0 12.903,-8.776 61.472,61.472 0 0 0 12.51,-14.414 q 6.84,-10.846 6.494,-17.957 c -0.19,-3.949 -2.105,-6.434 -5.684,-7.505 l 79.798,-85.161 -102.097,179.576 -5.708,10.06 z m 367.238,-71.974 q -3.817,-5.458 -3.758,-8.515 c 0,-2.033 1.19,-3.199 3.568,-3.448 h 0.57 a 11.892,11.892 0 0 1 6.91,2.247 29.85,29.85 0 0 1 7.837,8.051 q 3.687,5.28 3.71,8.397 c 0,2.093 -1.188,3.258 -3.496,3.567 h -0.594 a 11.75,11.75 0 0 1 -6.957,-2.378 29.79,29.79 0 0 1 -7.79,-7.885 z m -109.41,-141.52 83.948,89.634 h -1.189 c -0.38,0 -0.975,0 -1.463,0.107 q -7.825,0.892 -8.324,6.862 -0.5,5.97 5.03,13.747 a 53.778,53.778 0 0 0 6.375,7.374 37.901,37.901 0 0 0 10.144,6.897 q -2.117,2.89 -0.702,7.98 a 37.283,37.283 0 0 0 5.613,11.096 55.122,55.122 0 0 0 15.223,14.806 q 8.098,5.268 16.066,4.935 0.81,0 1.618,-0.13 8.776,-0.988 9.228,-7.873 a 16.114,16.114 0 0 0 -0.463,-4.853 l 58.689,62.686 -91.572,-22.941 -6.1,-10.703 z m 98.22,104.927 2.45,2.617 c 0.451,0.57 0.903,1.189 1.355,1.784 1.808,2.592 2.723,4.757 2.723,6.529 0,1.771 -1.034,2.782 -3.127,3.02 h -0.512 a 10.346,10.346 0 0 1 -6.077,-1.95 22.596,22.596 0 0 1 -6.184,-6.137 c -1.974,-2.83 -2.937,-5.102 -2.878,-6.814 0.06,-1.713 1.118,-2.7 3.187,-2.937 h 0.524 a 10.263,10.263 0 0 1 6.005,1.879 19.147,19.147 0 0 1 2.533,2.01 z M 255.987,26 137.456,231.026 l 118.532,55.05 118.604,-55.05 z m -1.19,208.463 q -17.529,0 -24.58,-12.273 -7.053,-12.273 -7.053,-34.988 0,-22.714 7.052,-35.047 7.052,-12.332 24.582,-12.344 17.53,0 24.582,12.332 7.052,12.333 7.052,35.047 0,22.715 -7.052,34.988 -7.053,12.273 -24.582,12.285 z m 10.538,-71.807 q 2.497,7.968 2.497,24.546 0,15.817 -2.497,24.201 -2.498,8.384 -10.537,8.325 -8.04,0 -10.632,-8.325 -2.593,-8.324 -2.593,-24.2 0,-16.579 2.593,-24.547 2.593,-7.968 10.632,-7.968 8.015,-0.012 10.513,7.956 z"
fill="#ffffff"
fill-opacity="1"
transform="matrix(0.69282032,-0.4,0.4,0.69282032,-23.762003,181.038)"
id="path2-65"
style="fill:#ffffff;stroke:none" />
</g>
<g
class=""
id="g4-4"
style="fill:#ffffff;stroke:none"
transform="matrix(0.74275157,0.16528633,-0.16151022,0.76011713,216.37438,-18.305353)">
<path
d="m 375.483,251.243 -109.98,51.138 0.213,183.381 211.294,-219.416 -86.993,-21.81 z m -12.736,108.626 -5.947,14.699 -48.604,-8.955 5.007,-12.832 a 141.306,141.306 0 0 0 13.51,-11.358 167.184,167.184 0 0 0 16.566,-17.517 170.478,170.478 0 0 0 12.606,-17.958 115.607,115.607 0 0 0 9.514,-17.97 l 14.068,2.51 q -9.37,22.334 -30.361,44.43 -13.296,13.64 -20.645,18.636 z M 121.603,244.334 36.893,266.097 246.474,486 V 302.38 L 136.528,251.243 Z m 19.147,50.852 a 28.72,28.72 0 0 1 24.273,6.802 53.052,53.052 0 0 1 11.226,14.188 l -13.081,2.676 a 28.542,28.542 0 0 0 -5.388,-7.374 q -5.185,-4.876 -11.262,-3.853 l -0.487,0.095 a 6.458,6.458 0 0 0 -5.162,4.448 c -0.856,2.378 -0.238,5.554 1.796,9.371 q 4.08,7.6 10.81,9.027 a 23.785,23.785 0 0 0 8.563,-0.203 l 1.867,-0.344 5.791,10.822 q -6.398,1.427 -8.23,3.282 -3.21,3.14 0.429,9.93 a 17.042,17.042 0 0 0 6.089,6.696 10.406,10.406 0 0 0 7.385,1.534 l 0.416,-0.083 q 4.757,-0.964 5.079,-4.757 c 0.261,-2.57 -0.655,-5.744 -2.748,-9.514 l 12.38,-2.545 a 49.247,49.247 0 0 1 4.103,11.226 19.956,19.956 0 0 1 -0.642,9.383 11.702,11.702 0 0 1 -3.96,5.411 19.575,19.575 0 0 1 -8.027,3.235 l -1.19,0.214 a 27.971,27.971 0 0 1 -17.494,-2.7 32.193,32.193 0 0 1 -14.128,-14.092 q -3.627,-6.79 -2.604,-12.19 a 8.396,8.396 0 0 1 2.521,-4.947 h -0.071 q -1.844,0.31 -7.04,-2.497 a 32.11,32.11 0 0 1 -12.916,-13.593 q -5.245,-9.764 -3.282,-18.398 1.962,-8.634 13.676,-11 z M 27.19,248.865 135.97,132.556 a 7.135,7.135 0 0 1 1.427,0 h 0.154 q 3.14,0.345 2.842,3.71 a 19.36,19.36 0 0 1 -3.294,8.1 39.376,39.376 0 0 1 -9.728,10.405 q -3.912,2.938 -15.044,9.514 -12.796,7.505 -19.55,14.77 a 92.535,92.535 0 0 0 -11.513,14.486 l 32.907,3.758 8.182,-12.963 -20.967,-2.378 a 36.415,36.415 0 0 1 4.757,-3.83 q 2.379,-1.605 8.444,-5.125 l 6.422,-3.747 a 92.975,92.975 0 0 0 12.903,-8.776 61.472,61.472 0 0 0 12.51,-14.414 q 6.84,-10.846 6.494,-17.957 c -0.19,-3.949 -2.105,-6.434 -5.684,-7.505 l 79.798,-85.161 -102.097,179.576 -5.708,10.06 z m 367.238,-71.974 q -3.817,-5.458 -3.758,-8.515 c 0,-2.033 1.19,-3.199 3.568,-3.448 h 0.57 a 11.892,11.892 0 0 1 6.91,2.247 29.85,29.85 0 0 1 7.837,8.051 q 3.687,5.28 3.71,8.397 c 0,2.093 -1.188,3.258 -3.496,3.567 h -0.594 a 11.75,11.75 0 0 1 -6.957,-2.378 29.79,29.79 0 0 1 -7.79,-7.885 z m -109.41,-141.52 83.948,89.634 h -1.189 c -0.38,0 -0.975,0 -1.463,0.107 q -7.825,0.892 -8.324,6.862 -0.5,5.97 5.03,13.747 a 53.778,53.778 0 0 0 6.375,7.374 37.901,37.901 0 0 0 10.144,6.897 q -2.117,2.89 -0.702,7.98 a 37.283,37.283 0 0 0 5.613,11.096 55.122,55.122 0 0 0 15.223,14.806 q 8.098,5.268 16.066,4.935 0.81,0 1.618,-0.13 8.776,-0.988 9.228,-7.873 a 16.114,16.114 0 0 0 -0.463,-4.853 l 58.689,62.686 -91.572,-22.941 -6.1,-10.703 z m 98.22,104.927 2.45,2.617 c 0.451,0.57 0.903,1.189 1.355,1.784 1.808,2.592 2.723,4.757 2.723,6.529 0,1.771 -1.034,2.782 -3.127,3.02 h -0.512 a 10.346,10.346 0 0 1 -6.077,-1.95 22.596,22.596 0 0 1 -6.184,-6.137 c -1.974,-2.83 -2.937,-5.102 -2.878,-6.814 0.06,-1.713 1.118,-2.7 3.187,-2.937 h 0.524 a 10.263,10.263 0 0 1 6.005,1.879 19.147,19.147 0 0 1 2.533,2.01 z M 255.987,26 137.456,231.026 l 118.532,55.05 118.604,-55.05 z m -1.19,208.463 q -17.529,0 -24.58,-12.273 -7.053,-12.273 -7.053,-34.988 0,-22.714 7.052,-35.047 7.052,-12.332 24.582,-12.344 17.53,0 24.582,12.332 7.052,12.333 7.052,35.047 0,22.715 -7.052,34.988 -7.053,12.273 -24.582,12.285 z m 10.538,-71.807 q 2.497,7.968 2.497,24.546 0,15.817 -2.497,24.201 -2.498,8.384 -10.537,8.325 -8.04,0 -10.632,-8.325 -2.593,-8.324 -2.593,-24.2 0,-16.579 2.593,-24.547 2.593,-7.968 10.632,-7.968 8.015,-0.012 10.513,7.956 z"
fill="#ffffff"
fill-opacity="1"
transform="matrix(0.69282032,-0.4,0.4,0.69282032,-23.762003,181.038)"
id="path2-6"
style="fill:#ffffff;stroke:none" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 9.3 KiB

+135 -1
View File
@@ -1,12 +1,146 @@
# 13.0
## 14.0.2 - Le grang ménage de Tétragor
### Migration Foundry V14
- Migration des classes restantes de V1 vers V2 (ApplicationV2)
- OptionsAvancees, StatusEffects, SystemCompendiums, ReglesOptionnelles,
DialogEncaissementTables
- DialogV2: formes imbriquées, boutons, styles et positionnement corrigés
- DialogV2 requiert au moins un bouton (boutons vides interdits en V14)
- templates avec wrapper à racine unique
- correction des éditeurs ProseMirror et des scrollbar sur les fiches d'acteur
- rollMode → messageMode, Token HUD, data-message-id
- champ age en StringField pour compat V14
- compat V14: _onFirstRender (HTMLElement.show) pour les jets de dés,
fermeture des dialogs TMR après lecture d'un signe draconique
- 10 fichiers .js V1 inutilisés déplacés vers _deprecated/
- scrollbar des applications V2 corrigées (LESS, plus de style inline)
- migration de toutes les directives CSS inline vers LESS
- titres des tables d'encaissement alternatives lisibles
- le dialog ne passe plus au premier plan lors du re-render (hook)
- refresh des dialogs herbes/potions/ingrédients après édition de fiche
- TODO-v14.md pour le suivi de la compatibilité V14
### Feuilles d'items
- migration des feuilles d'items vers V2 (models, apps, templates, less + common/mixins)
- ajout des sections environnement (inventaire) et temporel (blessure, maladie,
poison, rencontre, signe draconique) manquantes dans les sheets V2
### Sommeil & Château Dormant
- nouveau mode sommeil avec sélection des heures de repos
- dialogs Château Dormant intégrés, toolbar équipement
- message de statut MJ + journal de suivi stress/moral/événements par jour
- journal enrichi avec stress, perte d'enchantements, moral
- message stress journal: perte fixe de 1, reste X, conversion Y en xp
- boutons Repas externe et Rations harmonisés avec les cartouches de tchat
### Inventaire
- boutons +Ration/+Eau et cartouche de tchat compacte
- consommation des rations: assez d'unités pour remplir sustentation/eau en un
clic + alerte si vide
- ne plus afficher « rien à manger » quand les compteurs sont déjà pleins
### Règles & encaissement
- fusion des Règles customs dans Règles optionnelles (section Options alternatives)
- tables d'encaissement révisées optionnelles + dialog de consultation
### Divers
- regroupement des classes de combat
- fix assign dans les constructeurs
### Tests automatisés
- plan de test (227 cas, 33 sections) + scripts TC-01 à TC-07
- 22 scripts TC supplémentaires (TC-08 à TC-31) avec fonctions partagées
- orchestrateur run-all-tests.sh (sélection, exécution, rapport final)
- documentation du lancement des tests dans test/README.md
## 14.0.1 - Les imprécisions de Tétragor
- correction de l'indicateur de remplissage des conteneurs
- correction de l'ouverture des objets utilisant la liste des compétences
- correction de la description aléatoires
## 14.0.0 - Les rangements de Tétragor
- Amélioration de la gestion de l'équipement
- gestion des deniers
- gestion de herbes & plantes
- gestion des ingrédients
- gestion des potions
- indicateur de remplissage des conteneurs
- tri par nom / type / encombrement / quantité
- Le but des recettes alchimiques est affiché et éditable
## 13.0.48 - Les vagabondages d'Illisys
- Gestion des tâches à plusieurs
- Les tâches du monde peuvent être configurées pour être effectuées à plusieurs
- Une tâche à plusieurs ajoutée à un personnage permet au personnage de contribuer à la tâche commune
- suppression du type de TMR "Inconnu" des feuilles de création de signes draconiques (ce type sert uniquement pour le cas où une case saisie à la main est incorrecte)
- les jets de dés /rdd utilisent le mode de visibilité sélectionné
- Voies de Draconic
- Ne pas proposer les voies de Draconic à -11 pour lire un signe draconic ou lancer un sort
- Trier les voies par ordre décroissant pour le sorts à voies multiples
- Les rencontres et les maîtrises dans les TMR peuvent être vaincues sans
draconic si les voies sont négatives
- correction d'updates non affichés
- Améliorations des titres des fenêtres de jets
## 13.0.47 - Les goûts et les couleurs d'Illisys
- Correction des couleurs des tooltips d'aide foundry
## 13.0.46 - L'archétype d'Illisys
- ajout d'une génération d'archétype aléatoire
- respecte les niveaux d'archétype déjà alloués
- l'archétype alloué est supérieur au niveau actuel (si c'est possible)
- les compétences supérieures à 0 ont plus de chances d'avoir les niveaux d'archétype élevés
- si tous les niveaux d'archétype supérieurs à une compétences sont déjà alloué,
l'archétype est au niveau actuel de la compétence
- Amélioration de l'affichage de la fenêtre de jets:
- La difficultée est déplacée dans la colonne des ajustements
- les ajustements sont mieux alignés
- les ajustements sont mieux ordonnés
- Les indications d'ajustements de tir prennent moins de place
- l'icône d100 est redessinée pour être mieux centrée
## 13.0.45 - L'endépôté d'Illisys
- nouvelle correction du manifest
## 13.0.44 - Le dépôt d'Illisys
- le manifest pointe maintenant toujours vers la dernière version
- changement des liens dans le system.json
## 13.0.43 - L'urgence d'Illisys
- correction urgente des jets
## 13.0.42 - La rebellion d'Illisys
- on peut choisir la difficulté des jets de résistances
- la macro signe draconique fonctionne de nouveau (ajout et suppression)
- le Guerrier Sorde n'est pas joueur et ne cuisine pas (pas de message si compétence Jeu / Cuisine manquent)
- Corrections V14
- Les descriptions aléatoires fonctionnent de nouveau
## 13.0.41 - Le miroir d'Illisys
- les mode de visibilité des jets sont bien pris en compte
## 13.0.40 - Le miroir d'Illisys
- les mode de visibilité des jets sont bien pris en compte
- pas de stress ou de sommeil pour les personnage non liés
## 13.0.39 - La défense d'Illisys
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+5
View File
@@ -0,0 +1,5 @@
.arme-content {
.item-sheet-common();
.item-sheet-header();
.item-sheet-scrollable-body();
}
+5
View File
@@ -0,0 +1,5 @@
.armure-content {
.item-sheet-common();
.item-sheet-header();
.item-sheet-scrollable-body();
}
+5
View File
@@ -0,0 +1,5 @@
.blessure-content {
.item-sheet-common();
.item-sheet-header();
.item-sheet-scrollable-body();
}
+5
View File
@@ -0,0 +1,5 @@
.casetmr-content {
.item-sheet-common();
.item-sheet-header();
.item-sheet-scrollable-body();
}
+5
View File
@@ -0,0 +1,5 @@
.chant-content {
.item-sheet-common();
.item-sheet-header();
.item-sheet-scrollable-body();
}
+5
View File
@@ -0,0 +1,5 @@
.competence-content {
.item-sheet-common();
.item-sheet-header();
.item-sheet-scrollable-body();
}
+5
View File
@@ -0,0 +1,5 @@
.competencecreature-content {
.item-sheet-common();
.item-sheet-header();
.item-sheet-scrollable-body();
}
+5
View File
@@ -0,0 +1,5 @@
.conteneur-content {
.item-sheet-common();
.item-sheet-header();
.item-sheet-scrollable-body();
}
+5
View File
@@ -0,0 +1,5 @@
.danse-content {
.item-sheet-common();
.item-sheet-header();
.item-sheet-scrollable-body();
}
+5
View File
@@ -0,0 +1,5 @@
.empoignade-content {
.item-sheet-common();
.item-sheet-header();
.item-sheet-scrollable-body();
}
+5
View File
@@ -0,0 +1,5 @@
.extraitpoetique-content {
.item-sheet-common();
.item-sheet-header();
.item-sheet-scrollable-body();
}
+5
View File
@@ -0,0 +1,5 @@
.faune-content {
.item-sheet-common();
.item-sheet-header();
.item-sheet-scrollable-body();
}
+5
View File
@@ -0,0 +1,5 @@
.gemme-content {
.item-sheet-common();
.item-sheet-header();
.item-sheet-scrollable-body();
}
+5
View File
@@ -0,0 +1,5 @@
.herbe-content {
.item-sheet-common();
.item-sheet-header();
.item-sheet-scrollable-body();
}
+5
View File
@@ -0,0 +1,5 @@
.ingredient-content {
.item-sheet-common();
.item-sheet-header();
.item-sheet-scrollable-body();
}
+5
View File
@@ -0,0 +1,5 @@
.jeu-content {
.item-sheet-common();
.item-sheet-header();
.item-sheet-scrollable-body();
}
+5
View File
@@ -0,0 +1,5 @@
.livre-content {
.item-sheet-common();
.item-sheet-header();
.item-sheet-scrollable-body();
}
+5
View File
@@ -0,0 +1,5 @@
.maladie-content {
.item-sheet-common();
.item-sheet-header();
.item-sheet-scrollable-body();
}
+5
View File
@@ -0,0 +1,5 @@
.meditation-content {
.item-sheet-common();
.item-sheet-header();
.item-sheet-scrollable-body();
}
+1
View File
@@ -3,5 +3,6 @@
.item-sheet-common();
.item-sheet-header();
.item-sheet-scrollable-body();
}
+2 -1
View File
@@ -1,7 +1,8 @@
// Styles pour la feuille d'objet Monnaie
// Styles pour la feuille d'objet Munition
.munition-content {
.item-sheet-common();
.item-sheet-header();
.item-sheet-scrollable-body();
}
+5
View File
@@ -0,0 +1,5 @@
.musique-content {
.item-sheet-common();
.item-sheet-header();
.item-sheet-scrollable-body();
}
+5
View File
@@ -0,0 +1,5 @@
.nombreastral-content {
.item-sheet-common();
.item-sheet-header();
.item-sheet-scrollable-body();
}
+5
View File
@@ -0,0 +1,5 @@
.nourritureboisson-content {
.item-sheet-common();
.item-sheet-header();
.item-sheet-scrollable-body();
}
+5
View File
@@ -0,0 +1,5 @@
.objet-content {
.item-sheet-common();
.item-sheet-header();
.item-sheet-scrollable-body();
}
+5
View File
@@ -0,0 +1,5 @@
.oeuvre-content {
.item-sheet-common();
.item-sheet-header();
.item-sheet-scrollable-body();
}
+5
View File
@@ -0,0 +1,5 @@
.ombre-content {
.item-sheet-common();
.item-sheet-header();
.item-sheet-scrollable-body();
}
+5
View File
@@ -0,0 +1,5 @@
.plante-content {
.item-sheet-common();
.item-sheet-header();
.item-sheet-scrollable-body();
}
+5
View File
@@ -0,0 +1,5 @@
.poison-content {
.item-sheet-common();
.item-sheet-header();
.item-sheet-scrollable-body();
}
+5
View File
@@ -0,0 +1,5 @@
.possession-content {
.item-sheet-common();
.item-sheet-header();
.item-sheet-scrollable-body();
}
+5
View File
@@ -0,0 +1,5 @@
.potion-content {
.item-sheet-common();
.item-sheet-header();
.item-sheet-scrollable-body();
}
+5
View File
@@ -0,0 +1,5 @@
.queue-content {
.item-sheet-common();
.item-sheet-header();
.item-sheet-scrollable-body();
}
+5
View File
@@ -0,0 +1,5 @@
.race-content {
.item-sheet-common();
.item-sheet-header();
.item-sheet-scrollable-body();
}
+12
View File
@@ -0,0 +1,12 @@
.recettealchimique-content {
.item-sheet-common();
.item-sheet-header();
.item-sheet-scrollable-body();
.ingredient-row {
display: flex;
gap: 4px;
align-items: center;
padding: 2px 0;
}
}
+5
View File
@@ -0,0 +1,5 @@
.recettecuisine-content {
.item-sheet-common();
.item-sheet-header();
.item-sheet-scrollable-body();
}
+5
View File
@@ -0,0 +1,5 @@
.rencontre-content {
.item-sheet-common();
.item-sheet-header();
.item-sheet-scrollable-body();
}
+5
View File
@@ -0,0 +1,5 @@
.service-content {
.item-sheet-common();
.item-sheet-header();
.item-sheet-scrollable-body();
}
+5
View File
@@ -0,0 +1,5 @@
.signedraconique-content {
.item-sheet-common();
.item-sheet-header();
.item-sheet-scrollable-body();
}
+5
View File
@@ -0,0 +1,5 @@
.sort-content {
.item-sheet-common();
.item-sheet-header();
.item-sheet-scrollable-body();
}
+5
View File
@@ -0,0 +1,5 @@
.sortreserve-content {
.item-sheet-common();
.item-sheet-header();
.item-sheet-scrollable-body();
}
+5
View File
@@ -0,0 +1,5 @@
.souffle-content {
.item-sheet-common();
.item-sheet-header();
.item-sheet-scrollable-body();
}
+5
View File
@@ -0,0 +1,5 @@
.tache-content {
.item-sheet-common();
.item-sheet-header();
.item-sheet-scrollable-body();
}
+2 -1
View File
@@ -1,7 +1,8 @@
// Styles pour la feuille d'objet Monnaie
// Styles pour la feuille d'objet Tarot
.tarot-content {
.item-sheet-common();
.item-sheet-header();
.item-sheet-scrollable-body();
}
+5
View File
@@ -0,0 +1,5 @@
.tete-content {
.item-sheet-common();
.item-sheet-header();
.item-sheet-scrollable-body();
}
+20 -5
View File
@@ -32,6 +32,7 @@
display: flex;
flex-direction: column;
}
roll-conditions roll-section[name="rollmode"],
roll-type {
button[data-checked="true"] {
@@ -64,6 +65,13 @@
flex-direction: row;
align-items: anchor-center;
margin: 0 0.2rem;
label {
text-align:left;
min-width: 55%;
display: flex;
flex-direction: row;
}
}
roll-resume {
@@ -241,11 +249,18 @@
padding: 0;
filter: invert(0.8);
}
roll-conditions roll-section[name="tricher"] img {
/* image de d100 */
max-width: 2.5rem;
max-height: 2.5rem;
}
roll-conditions roll-section[name="tricher"] {
label {
display: flex;
flex-direction: row;
img {
/* image de d100 */
max-width: 2rem;
max-height: 2rem;
}
}
}
roll-buttons {
display: flex;
+26 -4
View File
@@ -74,9 +74,31 @@
}
}
.item-sheet-scrollable-body() {
max-height: 75vh;
overflow: hidden;
> section {
display: flex;
flex-direction: column;
min-height: 0;
height: 100%;
}
.sheet-header {
flex-shrink: 0;
}
.sheet-body {
overflow-y: auto;
flex: 1;
min-height: 0;
}
}
.item-sheet-header() {
background: #011d33 url(../assets/ui/bg_header.webp) no-repeat left top;
color: rgba(255, 255, 255, 1);
.sheet-header {
background: #011d33 url(../assets/ui/bg_header.webp) no-repeat left top;
}
.sheet-header-row {
display: flex;
flex-direction: row;
@@ -86,7 +108,7 @@
font-family: CaslonAntique;
font-size: 2.5rem;
font-weight: normal;
color: var(--window-header-title-color);
color: var(--window-header-title-color, #fff);
margin: 4px;
height: 3rem;
}
@@ -100,8 +122,8 @@
input[type="date"],
input[type="time"]
) {
color: rgba(255, 255, 255, 0.75);
background: rgba(255, 255, 255, 0.1);
color: #fff;
background: rgba(0, 0, 0, 0.2);
border: 0 none;
margin-bottom: 0.2rem;
}
+14
View File
@@ -0,0 +1,14 @@
// Supprimer tous les items du monde
// Coller ce code dans une macro Foundry (type script)
const count = game.items.size
if (!count) return ui.notifications.info("Aucun item dans le monde.")
const confirmed = await Dialog.confirm({
title: "Supprimer tous les items",
content: `<p>⚠️ <b>${count} items</b> vont être définitivement supprimés.</p>`,
})
if (!confirmed) return
await Item.deleteDocuments(game.items.map(i => i.id))
ui.notifications.info(`${count} items supprimés.`)
+1 -1
View File
@@ -12,7 +12,7 @@ export class ChatVente {
return undefined;
}
const nbLots = chatMessage.getFlag(SYSTEM_RDD, NB_LOTS)
const detail = foundry.utils.duplicate(chatMessage.getFlag(SYSTEM_RDD, DETAIL_VENTE))
const detail = foundry.utils.deepClone(chatMessage.getFlag(SYSTEM_RDD, DETAIL_VENTE))
if (!detail.item) {
ui.notifications.warn("Impossible d'acheter: informations sur l'objet manquantes")
return undefined;
+57 -59
View File
@@ -1,10 +1,9 @@
import { renderTemplate } from "../constants.js";
import { Misc } from "../misc.js";
import { RdDUtility } from "../rdd-utility.js";
import { ChatVente } from "./chat-vente.js";
export class DialogItemAchat extends Dialog {
import { renderTemplate } from "../constants.js"
import { Misc } from "../misc.js"
import { RdDUtility } from "../rdd-utility.js"
import { ChatVente } from "./chat-vente.js"
export class DialogItemAchat extends foundry.applications.api.DialogV2 {
static preparerAchat(chatButton) {
return ChatVente.getDetailAchatVente(RdDUtility.findChatMessageId(chatButton))
}
@@ -21,57 +20,64 @@ export class DialogItemAchat extends Dialog {
choix: { seForcer: false, supprimerSiZero: true },
prixLot,
isVente: prixLot > 0,
isConsommable: item.type == 'nourritureboisson' && acheteur?.isPersonnage(),
isConsommable: item.type == "nourritureboisson" && acheteur?.isPersonnage(),
chatMessageIdVente
}
if (venteData.vendeur?.id == venteData.acheteur?.id) {
ui.notifications.info("Inutile de se vendre à soi-même")
return
}
DialogItemAchat.changeNombreLots(venteData, 1)
const html = await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/dialog-item-achat.hbs`, venteData)
new DialogItemAchat(html, venteData).render(true)
const content = await renderTemplate("systems/foundryvtt-reve-de-dragon/templates/dialog-item-achat.hbs", venteData)
new DialogItemAchat(content, venteData).render({ force: true })
}
static changeNombreLots(venteData, nombreLots) {
venteData.choix.nombreLots = nombreLots;
venteData.prixTotal = (nombreLots * venteData.prixLot).toFixed(2);
venteData.choix.nombreLots = nombreLots
venteData.prixTotal = (nombreLots * venteData.prixLot).toFixed(2)
if (venteData.isConsommable) {
const doses = nombreLots * venteData.tailleLot;
venteData.totalSust = Misc.keepDecimals(doses * (venteData.item.system.sust ?? 0), 2);
const doses = nombreLots * venteData.tailleLot
venteData.totalSust = Misc.keepDecimals(doses * (venteData.item.system.sust ?? 0), 2)
venteData.totalDesaltere = venteData.item.system.boisson
? Misc.keepDecimals(doses * (venteData.item.system.desaltere ?? 0), 2)
: 0;
: 0
}
}
constructor(html, venteData) {
let options = { classes: ["dialogachat"], width: 400, height: 'fit-content', 'z-index': 99999 };
const actionAchat = venteData.prixLot > 0 ? "Acheter" : "Prendre";
const buttons = {};
constructor(content, venteData) {
const actionAchat = venteData.prixLot > 0 ? "Acheter" : "Prendre"
const buttons = []
if (venteData.isConsommable) {
buttons["consommer"] = { label: venteData.item.system.boisson ? "Boire" : "Manger", callback: it => this.onAchatConsommer() }
buttons.push({
label: venteData.item.system.boisson ? "Boire" : "Manger",
action: "consommer",
callback: () => this.onAchatConsommer()
})
}
buttons[actionAchat] = { label: actionAchat, callback: it => { this.onAchat(); } };
buttons["decliner"] = { label: "cliner", callback: it => { } };
const acheteur = venteData.acheteur?.name ?? 'Un acheteur';
const vendeur = venteData.vendeur?.name ?? 'Un vendeur';
let conf = {
buttons.push({ label: actionAchat, action: actionAchat, callback: () => this.onAchat() })
buttons.push({ label: "Décliner", action: "decliner", callback: () => {} })
const acheteur = venteData.acheteur?.name ?? "Un acheteur"
const vendeur = venteData.vendeur?.name ?? "Un vendeur"
super({
title: `${acheteur} - ${actionAchat} à ${vendeur}`,
content: html,
default: actionAchat,
buttons: buttons
};
content,
classes: ["dialogachat"],
position: { width: 400, height: 'fit-content' },
buttons
})
this.venteData = venteData
}
super(conf, options);
this.venteData = venteData;
_onRender(context) {
super._onRender(context)
this.element.querySelector(".nombreLots")?.addEventListener("change", event => this.setNombreLots(Number(event.currentTarget.value)))
this.element.querySelector(".se-forcer")?.addEventListener("change", event => this.setSeForcer(event))
}
async onAchat() {
await this.html.find(".nombreLots").change();
(this.venteData.vendeur ?? this.venteData.acheteur).achatVente({
const el = this.element
el.querySelector(".nombreLots")?.dispatchEvent(new Event("change"))
;(this.venteData.vendeur ?? this.venteData.acheteur).achatVente({
userId: game.user.id,
vendeurId: this.venteData.vendeur?.id,
acheteurId: this.venteData.acheteur?.id,
@@ -79,42 +85,34 @@ export class DialogItemAchat extends Dialog {
chatMessageIdVente: this.venteData.chatMessageIdVente,
choix: this.venteData.choix,
vente: this.venteData
});
})
}
async onAchatConsommer() {
this.venteData.choix.consommer = true;
await this.onAchat();
}
/* -------------------------------------------- */
activateListeners(html) {
super.activateListeners(html);
this.html = html;
this.html.find(".nombreLots").change(event => this.setNombreLots(Number(event.currentTarget.value)));
this.html.find(".se-forcer").change(event => this.setSeForcer(event));
this.venteData.choix.consommer = true
await this.onAchat()
}
setSeForcer(event) {
this.venteData.choix.seForcer = event.currentTarget.checked;
this.venteData.choix.seForcer = event.currentTarget.checked
}
setNombreLots(nbLots) {
if (!this.venteData.quantiteIllimite) {
if (!this.venteData.quantiteIllimite && nbLots > this.venteData.nbLots) {
if (nbLots > this.venteData.nbLots) {
ui.notifications.warn(`Seulement ${this.venteData.nbLots} lots disponibles, vous ne pouvez pas en prendre ${nbLots}`)
}
nbLots = Math.min(nbLots, this.venteData.nbLots);
nbLots = Math.min(nbLots, this.venteData.nbLots)
}
DialogItemAchat.changeNombreLots(this.venteData, nbLots);
this.html.find(".nombreLots").val(nbLots);
this.html.find(".prixTotal").text(this.venteData.prixTotal);
this.html.find("span.total-sust").text(this.venteData.totalSust);
this.html.find("span.total-desaltere").text(this.venteData.totalDesaltere);
DialogItemAchat.changeNombreLots(this.venteData, nbLots)
const el = this.element
const nbl = el.querySelector(".nombreLots")
if (nbl) nbl.value = nbLots
const pt = el.querySelector(".prixTotal")
if (pt) pt.textContent = this.venteData.prixTotal
const sust = el.querySelector("span.total-sust")
if (sust) sust.textContent = this.venteData.totalSust
const des = el.querySelector("span.total-desaltere")
if (des) des.textContent = this.venteData.totalDesaltere
}
}
}
+58 -53
View File
@@ -1,14 +1,13 @@
import { renderTemplate } from "../constants.js";
import { renderTemplate } from "../constants.js"
import { HtmlUtility } from "../html-utility.js";
import { RdDUtility } from "../rdd-utility.js";
import { ChatVente } from "./chat-vente.js";
export class DialogItemVente extends Dialog {
export class DialogItemVente extends foundry.applications.api.DialogV2 {
static async display({ item, quantiteMax = undefined }) {
const quantite = quantiteMax ?? item.getQuantite() ?? 1;
const quantite = quantiteMax ?? item.getQuantite() ?? 1
const venteData = {
item: item,
item,
alias: item.actor?.name ?? game.user.name,
vendeurId: item.actor?.id,
prixOrigine: item.calculerPrixCommercant(),
@@ -19,93 +18,99 @@ export class DialogItemVente extends Dialog {
maxLots: quantite,
quantiteMax: quantite,
quantiteIllimite: item.isItemCommerce() ? quantiteMax == undefined : !item.parent,
isOwned: item.parent,
isOwned: item.parent,
}
const html = await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/dialog-item-vente.hbs`, venteData);
return new DialogItemVente(venteData, html).render(true);
const content = await renderTemplate("systems/foundryvtt-reve-de-dragon/templates/dialog-item-vente.hbs", venteData)
const dialog = new DialogItemVente(venteData, content)
dialog.render({ force: true })
return dialog
}
constructor(venteData, html) {
let options = { classes: ["dialogvente"], width: 400, height: 'fit-content', 'z-index': 99999 };
let conf = {
constructor(venteData, content) {
super({
title: "Proposer",
content: html,
default: "proposer",
buttons: { "proposer": { label: "Proposer", callback: it => { this.onProposer(it); } } }
};
super(conf, options);
this.venteData = venteData;
content,
classes: ["dialogvente"],
position: { width: 400, height: 'fit-content' },
buttons: [
{ label: "Proposer", action: "proposer", callback: () => this.onProposer() }
]
})
this.venteData = venteData
}
activateListeners(html) {
super.activateListeners(html);
this.html = html;
this.html.find(".tailleLot").change(event => this.setTailleLot(Number(event.currentTarget.value)));
this.html.find(".nbLots").change(event => this.setNbLots(Number(event.currentTarget.value)));
this.html.find(".quantiteIllimite").change(event => this.setQuantiteIllimite(event.currentTarget.checked));
this.html.find(".prixLot").change(event => this.setPrixLot(Number(event.currentTarget.value)));
this.setQuantiteIllimite(this.venteData.quantiteIllimite);
_onRender(context) {
super._onRender(context)
const el = this.element
el.querySelector(".tailleLot")?.addEventListener("change", event => this.setTailleLot(Number(event.currentTarget.value)))
el.querySelector(".nbLots")?.addEventListener("change", event => this.setNbLots(Number(event.currentTarget.value)))
el.querySelector(".quantiteIllimite")?.addEventListener("change", event => this.setQuantiteIllimite(event.currentTarget.checked))
el.querySelector(".prixLot")?.addEventListener("change", event => this.setPrixLot(Number(event.currentTarget.value)))
this.setQuantiteIllimite(this.venteData.quantiteIllimite)
}
async onProposer(it) {
this.updateVente(this.getChoixVente());
this.venteData["properties"] = this.venteData.item.getProprietes();
async onProposer() {
this.updateVente(this.getChoixVente())
this.venteData["properties"] = this.venteData.item.getProprietes()
if (this.venteData.isOwned) {
if (this.venteData.nbLots * this.venteData.tailleLot > this.venteData.quantiteMax) {
ui.notifications.warn(`Vous avez ${this.venteData.quantiteMax} ${this.venteData.item.name}, ce n'est pas suffisant pour vendre ${this.venteData.nbLots} de ${this.venteData.tailleLot}`)
return;
return
}
}
await ChatVente.displayAchatVente(this.venteData)
}
updateVente(update) {
foundry.utils.mergeObject(this.venteData, update);
foundry.utils.mergeObject(this.venteData, update)
}
getChoixVente() {
const el = this.element
return {
nbLots: Number(this.html.find(".nbLots").val()),
tailleLot: Number(this.html.find(".tailleLot").val()),
quantiteIllimite: this.html.find(".quantiteIllimite").is(':checked'),
prixLot: Number(this.html.find(".prixLot").val())
};
nbLots: Number(el.querySelector(".nbLots")?.value ?? 0),
tailleLot: Number(el.querySelector(".tailleLot")?.value ?? 0),
quantiteIllimite: el.querySelector(".quantiteIllimite")?.checked ?? false,
prixLot: Number(el.querySelector(".prixLot")?.value ?? 0)
}
}
/* -------------------------------------------- */
setPrixLot(prixLot) {
this.venteData.prixLot = prixLot;
this.venteData.prixLot = prixLot
}
setTailleLot(tailleLot) {
const maxLots = Math.floor(this.venteData.quantiteMax / tailleLot);
const maxLots = Math.floor(this.venteData.quantiteMax / tailleLot)
this.updateVente({
tailleLot,
nbLots: Math.min(maxLots, this.venteData.nbLots),
maxLots: maxLots,
maxLots,
prixLot: (tailleLot * this.venteData.prixOrigine).toFixed(2)
});
this.html.find(".prixLot").val(this.venteData.prixLot);
this.html.find(".nbLots").val(this.venteData.nbLots);
this.html.find(".nbLots").attr("max", this.venteData.maxLots)
})
const el = this.element
const prix = el.querySelector(".prixLot")
if (prix) prix.value = this.venteData.prixLot
const nb = el.querySelector(".nbLots")
if (nb) {
nb.value = this.venteData.nbLots
nb.setAttribute("max", this.venteData.maxLots)
}
}
setNbLots(nbLots) {
this.updateVente({
nbLots: this.venteData.isOwned ? Math.max(0, Math.min(nbLots, this.venteData.maxLots)) : nbLots
})
this.html.find(".nbLots").val(this.venteData.nbLots);
const nb = this.element.querySelector(".nbLots")
if (nb) nb.value = this.venteData.nbLots
}
setQuantiteIllimite(checked) {
this.updateVente({ quantiteIllimite: checked })
this.html.find(".label-quantiteIllimite").text(this.venteData.quantiteIllimite ? "Illimités" : "disponibles");
HtmlUtility.showControlWhen(this.html.find(".nbLots"), !this.venteData.quantiteIllimite)
const el = this.element
const label = el.querySelector(".label-quantiteIllimite")
if (label) label.textContent = checked ? "Illimités" : "disponibles"
const nb = el.querySelector(".nbLots")
if (nb) HtmlUtility.showControlWhen(nb, !checked)
}
}
}
+254 -141
View File
@@ -18,14 +18,16 @@ import { CARACS, LIST_CARAC_PERSONNAGE, RdDCarac } from "./rdd-carac.js";
import { DialogConsommer } from "./dialog-item-consommer.js";
import { DialogFabriquerPotion } from "./dialog-fabriquer-potion.js";
import { RollDataAjustements } from "./rolldata-ajustements-v1.js";
import { RdDPossession } from "./rdd-possession.js";
import { RdDPossession } from "./combat/rdd-possession.js";
import { RdDPossessionV2 } from "./combat/rdd-possession-v2.mjs";
import { ACTOR_TYPES, renderTemplate, SHOW_DICE, SYSTEM_RDD, SYSTEM_SOCKET_ID } from "./constants.js";
import { RdDConfirm } from "./rdd-confirm.js";
import { DialogRepos } from "./sommeil/dialog-repos.js";
import { DialogNouveauRepos } from "./sommeil/dialog-nouveau-repos.js";
import { RdDBaseActor } from "./actor/base-actor.js";
import { RdDTimestamp } from "./time/rdd-timestamp.js";
import { AppAstrologie } from "./sommeil/app-astrologie.js";
import { RdDEmpoignade } from "./rdd-empoignade.js";
import { RdDEmpoignade } from "./combat/rdd-empoignade.js";
import { ExperienceLog, XP_TOPIC } from "./actor/experience-log.js";
import { ITEM_TYPES } from "./constants.js";
import { RdDBaseActorSang } from "./actor/base-actor-sang.js";
@@ -34,21 +36,20 @@ import { DialogChoixXpCarac } from "./dialog-choix-xp-carac.js";
import { ATTAQUE_TYPE, RdDItemArme } from "./item/arme.js";
import { RdDItemBlessure } from "./item/blessure.js";
import { RdDItemTete } from "./item/tete.js";
import { RdDItemTete } from "./documents/_module.mjs";
import { RdDItemSort } from "./item-sort.js";
import { RdDItemRace } from "./item/race.js";
import { RdDItemCompetence } from "./item-competence.js";
import { RdDItemSigneDraconique } from "./item/signedraconique.js";
import { RdDRencontre } from "./item/rencontre.js";
import { DialogSelect } from "./dialog-select.js";
import { CATEGORIES_COMPETENCES, PAS_DE_DRACONIC, POSSESSION_SANS_DRACONIC } from "./item/base-items.js";
import { CATEGORIES_COMPETENCES, PAS_DE_DRACONIC, SANS_DRACONIC } from "./item/base-items.js";
import { RdDRollResult } from "./rdd-roll-result.js";
import { RdDInitiative } from "./initiative.mjs";
import { RdDInitiative } from "./combat/initiative.mjs";
import RollDialog from "./roll/roll-dialog.mjs";
import { OptionsAvancees, ROLL_DIALOG_V2 } from "./settings/options-avancees.js";
import { ROLL_TYPE_COMP, ROLL_TYPE_CUISINE, ROLL_TYPE_JEU, ROLL_TYPE_MEDITATION, ROLL_TYPE_OEUVRE, ROLL_TYPE_SORT, ROLL_TYPE_APPEL_CHANCE, ROLL_TYPE_TACHE } from "./roll/roll-constants.mjs";
import { RdDPossessionV2 } from "./rdd-possession-v2.mjs";
import { Apprecier, MORAL, SITUATION_MORAL } from "./moral/apprecier.mjs";
import { Distance } from "./combat/distance.mjs";
@@ -62,36 +63,6 @@ export const MAINS_DIRECTRICES = ['Droitier', 'Gaucher', 'Ambidextre']
*/
export class RdDActor extends RdDBaseActorSang {
/* -------------------------------------------- */
/**
* Prepare Character type specific data
*/
prepareActorData() {
RdDItemRace.applyRacialLimits(this)
this.system.carac.melee.value = Math.floor((this.getForce() + parseInt(this.system.carac.agilite.value)) / 2);
this.system.carac.tir.value = Math.floor((parseInt(this.system.carac.vue.value) + parseInt(this.system.carac.dexterite.value)) / 2);
this.system.carac.lancer.value = Math.floor((parseInt(this.system.carac.tir.value) + parseInt(this.system.carac.force.value)) / 2);
this.system.carac.derobee.value = Math.floor(parseInt(((21 - this.system.carac.taille.value)) + parseInt(this.system.carac.agilite.value)) / 2);
super.prepareActorData()
this.system.attributs.sconst.value = RdDCarac.calculSConst(this.getConstitution())
this.system.attributs.sust.value = RdDCarac.getCaracDerivee(this.getTaille()).sust
this.system.sante.fatigue.max = this.getFatigueMax()
this.system.sante.fatigue.value = Math.min(this.system.sante.fatigue.value, this.system.sante.fatigue.max);
//Compteurs
this.system.reve.reve.max = 3 * this.getReve()
this.system.compteurs.chance.max = this.getChance()
this.system.attributs.hautrevant.value = this.itemTypes[ITEM_TYPES.tete].find(it => RdDItemTete.isDonDeHautReve(it))
? "Haut rêvant"
: "";
}
/* -------------------------------------------- */
canReceive(item) {
return ![ITEM_TYPES.competencecreature, ITEM_TYPES.tarot, ITEM_TYPES.service].includes(item.type)
@@ -165,10 +136,9 @@ export class RdDActor extends RdDBaseActorSang {
? this.itemTypes[ITEM_TYPES.competence].filter(it => it.system.categorie == CATEGORIES_COMPETENCES.draconic.key)
: []
}
getBestDraconic() { return foundry.utils.duplicate([...this.getDraconics(), PAS_DE_DRACONIC].sort(Misc.descending(it => it.system.niveau)).find(it => true)) }
getConjurationNaturelle() {
return new RdDItemCompetence(POSSESSION_SANS_DRACONIC)
return new RdDItemCompetence(SANS_DRACONIC)
}
isForceInsuffisante(forceRequise) {
@@ -244,7 +214,7 @@ export class RdDActor extends RdDBaseActorSang {
}
/* -------------------------------------------- */
async $perteReveEnchantementsChateauDormants() {
async $perteReveEnchantementsChateauDormants(message = undefined) {
const toUpdate = this.items.filter(it => [ITEM_TYPES.potion, ITEM_TYPES.gemme].includes(it.type))
.map(it => it.perteReveChateauDormant())
.filter(it => it != undefined)
@@ -257,6 +227,9 @@ export class RdDActor extends RdDBaseActorSang {
whisper: ChatUtility.getOwners(this),
content: messageUpdates.reduce(Misc.joining('<br>'))
})
if (message) {
message.content += messageUpdates.reduce(Misc.joining(' ')) + ' '
}
await this.updateEmbeddedDocuments('Item', toUpdate.map(it => it.update));
}
}
@@ -297,7 +270,11 @@ export class RdDActor extends RdDBaseActorSang {
}
async repos() {
await DialogRepos.create(this);
if (ReglesOptionnelles.isUsing("nouveau-mode-repos")) {
await DialogNouveauRepos.create(this);
} else {
await DialogRepos.create(this);
}
}
/* -------------------------------------------- */
@@ -361,15 +338,16 @@ export class RdDActor extends RdDBaseActorSang {
whisper: ChatUtility.getOwners(this),
content: ""
}
const stressAvant = this.system.compteurs.stress.value
await this._recuperationSante(message)
await this._recupereMoralChateauDormant(message)
await this._recupereChance()
await this.transformerStress()
await this.transformerStress(message)
await this.retourSeuilDeReve(message)
await this.setBonusPotionSoin(0)
await this.retourSust(message)
await this.$perteReveEnchantementsChateauDormants()
await this.$perteReveEnchantementsChateauDormants(message)
await this.$suppressionLancementsSort()
await RdDCoeur.applyCoeurChateauDormant(this, message)
if (message.content != "") {
@@ -377,6 +355,35 @@ export class RdDActor extends RdDBaseActorSang {
await ChatMessage.create(message)
}
await this.resetInfoSommeil()
const stressApres = this.system.compteurs.stress.value
const date = game.system.rdd.calendrier.dateCourante()
const recapMJ = `**${this.name}** — Château Dormant (${date})<br>Stress : ${stressAvant}${stressApres}`
await ChatUtility.tellToGM(message.content ? recapMJ + '<br>' + message.content : recapMJ)
const journalId = game.settings.get(SYSTEM_RDD, 'cd-suivi-journal')
if (journalId) {
const journalEntry = game.journal.get(journalId)
if (journalEntry?.canUserModify(game.user, 'update')) {
const timestamp = game.system.rdd.calendrier.getTimestamp()
const jour = timestamp.jour + 1
const mois = RdDTimestamp.definition(timestamp.mois).label
const annee = timestamp.annee
const section = `${jour} ${mois} ${annee}`
const log = `<p><b>${this.name}</b> — Stress ${stressAvant}${stressApres}</p>` + message.content
let page = journalEntry.pages.find(p => p.type == 'text' && Grammar.equalsInsensitive(p.name, section))
if (page) {
await page.update({ 'text.content': page.text.content + '\n' + log })
} else {
await journalEntry.createEmbeddedDocuments('JournalEntryPage', [new JournalEntryPage({
name: section,
type: 'text',
title: { show: true, level: 1 },
text: { content: log, format: 1 }
})])
}
}
}
}
async resetInfoSommeil() {
@@ -658,6 +665,69 @@ export class RdDActor extends RdDBaseActorSang {
return cumul;
}
/* -------------------------------------------- */
async mangerExterne() {
const besoin = this.system.attributs.sust.value
await this.update({
'system.compteurs.sust.value': besoin,
'system.compteurs.eau.value': besoin
})
ChatUtility.tellToUserAndGM(`${this.name} a mangé et bu pour la journée (repas externe)`)
}
async mangerRations() {
const besoin = this.system.attributs.sust.value
let restantSust = besoin - this.system.compteurs.sust.value
let restantEau = besoin - this.system.compteurs.eau.value
let totalSust = 0, totalEau = 0
let foundAny = false
if (restantSust <= 0 && restantEau <= 0) return
for (const item of this.items) {
if (item.type !== 'nourritureboisson') continue
const qty = item.system.quantite
if (!qty || qty <= 0) continue
const sustUnit = item.system.sust || 0
const eauUnit = item.system.desaltere || 0
if (sustUnit <= 0 && eauUnit <= 0) continue
foundAny = true
let unitNeeded = 0
if (restantSust > 0 && sustUnit > 0) {
unitNeeded = Math.max(unitNeeded, Math.ceil(restantSust / sustUnit))
}
if (restantEau > 0 && eauUnit > 0) {
unitNeeded = Math.max(unitNeeded, Math.ceil(restantEau / eauUnit))
}
const take = Math.min(unitNeeded, qty)
totalSust += Math.min(sustUnit * take, restantSust)
totalEau += Math.min(eauUnit * take, restantEau)
restantSust -= Math.min(sustUnit * take, restantSust)
restantEau -= Math.min(eauUnit * take, restantEau)
await item.diminuerQuantite(take)
}
if (!foundAny) {
ChatUtility.tellToUserAndGM(`${this.name} n'a rien à manger dans ses rations !`)
return
}
if (totalSust > 0) {
await this.update({ 'system.compteurs.sust.value': this.system.compteurs.sust.value + totalSust })
}
if (totalEau > 0) {
await this.update({ 'system.compteurs.eau.value': this.system.compteurs.eau.value + totalEau })
}
ChatUtility.tellToUserAndGM(
`${this.name} a mangé ${totalSust}/${besoin} sust, bu ${totalEau}/${besoin} eau (rations)`
)
}
/* -------------------------------------------- */
async retourSeuilDeReve(message) {
const seuil = this.system.reve.seuil.value;
@@ -694,7 +764,7 @@ export class RdDActor extends RdDBaseActorSang {
const rencontre = await game.system.rdd.rencontresTMR.getReveDeDragon(force);
let rollData = {
actor: this,
competence: this.getDraconicOuPossession().find(it => true),
competence: this.getBestDraconic(),
canClose: false,
rencontre: rencontre,
tmr: true,
@@ -777,7 +847,7 @@ export class RdDActor extends RdDBaseActorSang {
}
let carac = this.findCaracByName(caracName);
if (carac) {
carac = foundry.utils.duplicate(carac);
carac = foundry.utils.deepClone(carac);
const fromXp = Number(carac.xp);
const fromValue = Number(carac.value);
let toXp = fromXp;
@@ -917,7 +987,7 @@ export class RdDActor extends RdDBaseActorSang {
async deleteExperienceLog(from, count) {
if (from >= 0 && count > 0) {
let expLog = foundry.utils.duplicate(this.system.experiencelog)
let expLog = foundry.utils.deepClone(this.system.experiencelog)
expLog.splice(from, count)
await this.update({ [`system.experiencelog`]: expLog })
}
@@ -1047,7 +1117,7 @@ export class RdDActor extends RdDBaseActorSang {
notifyRefreshTMR() {
game.socket.emit(SYSTEM_SOCKET_ID, {
msg: "msg_tmr_move", data: {
actorId: this._id,
actorId: this.id,
tmrPos: this.system.reve.tmrpos
}
});
@@ -1257,7 +1327,7 @@ export class RdDActor extends RdDBaseActorSang {
}
async mangerNourriture(item) {
return (await DialogConsommer.create(this, item)).render(true);
return await DialogConsommer.create(this, item);
}
async actionLire(item) {
@@ -1265,6 +1335,7 @@ export class RdDActor extends RdDBaseActorSang {
if (tache) {
await this.rollTache(tache.id);
}
await this.creerCopieLue(item)
}
async fabriquerDecoctionHerbe(item) {
@@ -1383,7 +1454,7 @@ export class RdDActor extends RdDBaseActorSang {
/* -------------------------------------------- */
async saouler(forceAlcool, alcool = undefined) {
let ethylisme = foundry.utils.duplicate(this.system.compteurs.ethylisme);
let ethylisme = foundry.utils.deepClone(this.system.compteurs.ethylisme);
const etat = this.getEtatGeneral({ ethylisme: true });
const nbDoses = Number(this.system.compteurs.ethylisme.nb_doses || 0);
@@ -1457,7 +1528,7 @@ export class RdDActor extends RdDBaseActorSang {
}
/* -------------------------------------------- */
async transformerStress() {
async transformerStress(message = undefined) {
if (!ReglesOptionnelles.isUsing("transformation-stress")) { return }
const fromStress = Number(this.system.compteurs.stress.value);
if (this.system.sommeil?.insomnie || fromStress <= 0) {
@@ -1491,6 +1562,11 @@ export class RdDActor extends RdDBaseActorSang {
content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-resultat-transformer-stress.hbs`, stressRollData)
});
if (message) {
const reste = Math.max(fromStress - stressRollData.perte - 1, 0)
message.content += `Transformation de ${stressRollData.stress} points de stress : perte fixe de 1, reste ${reste}, conversion de ${stressRollData.convertis} en expérience. `
}
const toStress = Math.max(fromStress - stressRollData.perte - 1, 0);
const fromXpSress = Number(this.system.compteurs.experience.value);
const toXpStress = fromXpSress + Number(stressRollData.xp);
@@ -1543,7 +1619,7 @@ export class RdDActor extends RdDBaseActorSang {
const niveauSuivant = Number(carac.value) + 1;
let xpNeeded = RdDCarac.getCaracNextXp(niveauSuivant);
if (carac.xp >= xpNeeded) {
carac = foundry.utils.duplicate(carac);
carac = foundry.utils.deepClone(carac);
carac.value = niveauSuivant;
let checkXp = {
@@ -1570,9 +1646,10 @@ export class RdDActor extends RdDBaseActorSang {
/* -------------------------------------------- */
async ajoutExperience(rollData, hideChatMessage = 'show') {
const rollMode = rollData.current?.rollmode?.key ?? game.settings.get("core", "messageMode")
if (!rollData.rolled.isPart ||
rollData.finalLevel >= 0 ||
game.settings.get("core", "rollMode") == 'selfroll' ||
rollMode == 'self' ||
!Misc.hasConnectedGM()) {
return
}
@@ -1598,7 +1675,7 @@ export class RdDActor extends RdDBaseActorSang {
/* -------------------------------------------- */
async appliquerAppelMoral(rollData) {
if (!rollData.use.moral || game.settings.get("core", "rollMode") == 'selfroll') {
if (!rollData.use.moral || game.settings.get("core", "messageMode") == 'self') {
return
}
if (rollData.rolled.isEchec ||
@@ -1640,14 +1717,14 @@ export class RdDActor extends RdDBaseActorSang {
return await this.rollUnSortV2();
}
// Duplication car les pts de reve sont modifiés dans le sort!
let sorts = foundry.utils.duplicate(this.itemTypes[ITEM_TYPES.sort].filter(it => RdDItemSort.isSortOnCoord(it, coord)))
let sorts = foundry.utils.deepClone(this.itemTypes[ITEM_TYPES.sort].filter(it => RdDItemSort.isSortOnCoord(it, coord)))
if (sorts.length == 0) {
ui.notifications.info(`Aucun sort disponible en ${TMRUtility.getTMR(coord).label} !`);
return
}
const draconicList = this.computeDraconicAndSortIndex(sorts)
const reve = foundry.utils.duplicate(this.system.carac.reve)
const reve = foundry.utils.deepClone(this.system.carac.reve)
const dialog = await this.openRollDialog({
name: 'lancer-un-sort',
@@ -1764,7 +1841,7 @@ export class RdDActor extends RdDBaseActorSang {
console.log('lancement de sort', rollData.selectedSort)
const lancements = RdDItemSort.prepareSortAddLancement(rollData.selectedSort, rollData.selectedSort.system.ptreve_reel)
await this.updateEmbeddedDocuments('Item',
[{ _id: rollData.selectedSort._id, 'system.lancements': lancements }]
[{ _id: rollData.selectedSort.id, 'system.lancements': lancements }]
)
}
}
@@ -1795,36 +1872,6 @@ export class RdDActor extends RdDBaseActorSang {
}
}
/**
* Méthode pour faire un jet prédéterminer sans ouvrir la fenêtre de dialogue
* @param {*} caracName
* @param {*} compName
* @param {*} diff
* @param {*} options
* @returns
*/
async doRollCaracCompetence(caracName, compName, diff, options = { title: "" }) {
const carac = this.getCaracByName(caracName);
if (!carac) {
ui.notifications.warn(`${this.name} n'a pas de caractéristique correspondant à ${caracName}`)
return;
}
const competence = this.getCompetence(compName);
let rollData = {
alias: this.getAlias(),
caracValue: Number(carac.value),
selectedCarac: carac,
competence: competence,
diffLibre: diff,
show: { title: options?.title ?? '' }
};
RollDataAjustements.calcul(rollData, this);
await RdDResolutionTable.rollData(rollData);
this.ajoutExperience(rollData);
await RdDRollResult.displayRollData(rollData, this)
return rollData.rolled;
}
/* -------------------------------------------- */
async creerTacheDepuisLivre(item, options = { renderSheet: true }) {
const nomTache = "Lire " + item.name;
@@ -1868,12 +1915,12 @@ export class RdDActor extends RdDBaseActorSang {
return undefined;
}
async rollCaracCompetence(caracName, compName, diff, options = { title: "" }) {
async rollCaracCompetence(caracName, compName, diff, options = { title: undefined, verb: undefined }) {
if (OptionsAvancees.isUsing(ROLL_DIALOG_V2)) {
const rollData = {
ids: { actorId: this.id },
type: { allowed: [ROLL_TYPE_COMP], current: ROLL_TYPE_COMP },
type: { allowed: [ROLL_TYPE_COMP], current: ROLL_TYPE_COMP, label: options.verb },
selected: {
carac: { key: caracName },
comp: { key: compName, forced: options.forced },
@@ -1909,6 +1956,7 @@ export class RdDActor extends RdDBaseActorSang {
RdDEmpoignade.checkEmpoignadeEnCours(this)
const tache = this.getTache(id)
if (OptionsAvancees.isUsing(ROLL_DIALOG_V2)) {
options.title = options.title ?? 'Jet de Tâche'
const rollData = {
ids: { actorId: this.id },
selected: { tache: { key: tache.id, forced: options.forced } },
@@ -1931,7 +1979,7 @@ export class RdDActor extends RdDBaseActorSang {
diffConditions: 0,
use: { libre: false, conditions: true },
carac: {
[tache.system.carac]: foundry.utils.duplicate(this.system.carac[tache.system.carac])
[tache.system.carac]: foundry.utils.deepClone(this.system.carac[tache.system.carac])
}
},
callbacks: [{ action: r => this._tacheResult(r, options) }]
@@ -1941,22 +1989,34 @@ export class RdDActor extends RdDBaseActorSang {
/* -------------------------------------------- */
async _tacheResult(rollData, options) {
// Mise à jour de la tache
rollData.appliquerFatigue = ReglesOptionnelles.isUsing("appliquer-fatigue");
rollData.tache = foundry.utils.duplicate(rollData.tache);
rollData.tache.system.points_de_tache_courant += rollData.rolled.ptTache;
rollData.appliquerFatigue = ReglesOptionnelles.isUsing("appliquer-fatigue")
const tacheCommuneId = rollData.tache.system.tacheCommuneId;
const tache = tacheCommuneId
? game.items.get(tacheCommuneId)
: this.items.get(rollData.tache.id)
const tacheUpdates = {
system: {
points_de_tache_courant: tache.system.points_de_tache_courant + rollData.rolled.ptTache,
tentatives: tache.system.tentatives + 1
}
}
if (rollData.rolled.isETotal) {
rollData.tache.system.difficulte--;
tacheUpdates.system['difficulte'] = tache.system.difficulte - 1
}
if (rollData.rolled.isSuccess) {
rollData.tache.system.nb_jet_succes++;
tacheUpdates.system['nb_jet_succes'] = tache.system.nb_jet_succes + 1;
} else {
rollData.tache.system.nb_jet_echec++;
tacheUpdates.system['nb_jet_echec'] = tache.tache.system.nb_jet_echec + 1
}
rollData.tache.system.tentatives = rollData.tache.system.nb_jet_succes + rollData.tache.system.nb_jet_echec;
await this.updateEmbeddedDocuments('Item', [rollData.tache]);
await tache.update(tacheUpdates)
await this.santeIncDec("fatigue", rollData.tache.system.fatigue);
if (rollData.tache.system.tacheCommuneId != "") {
rollData.tache.render()
}
await RdDRollResult.displayRollData(rollData, this, 'chat-resultat-tache.hbs');
if (options?.callbacks) {
await Promise.all(callbacks.map(callback => callback(rollData)))
@@ -1981,7 +2041,7 @@ export class RdDActor extends RdDBaseActorSang {
const artData = {
art: 'jeu', verbe: 'Jeu',
use: { libre: true, conditions: true, },
competence: foundry.utils.duplicate(this.getCompetence('jeu')),
competence: foundry.utils.deepClone(this.getCompetence('jeu')),
forceCarac: {}
};
listCarac.forEach(c => artData.forceCarac[c] = this.system.carac[c]);
@@ -1993,7 +2053,7 @@ export class RdDActor extends RdDBaseActorSang {
/* -------------------------------------------- */
async rollMeditation(id) {
const meditation = foundry.utils.duplicate(this.getMeditation(id));
const meditation = foundry.utils.deepClone(this.getMeditation(id));
if (meditation && OptionsAvancees.isUsing(ROLL_DIALOG_V2)) {
const rollData = {
@@ -2004,7 +2064,7 @@ export class RdDActor extends RdDBaseActorSang {
return await RollDialog.create(rollData)
}
const competence = foundry.utils.duplicate(this.getCompetence(meditation.system.competence));
const competence = foundry.utils.deepClone(this.getCompetence(meditation.system.competence));
competence.system.defaut_carac = "intellect"; // Meditation = toujours avec intellect
let meditationData = {
competence: competence,
@@ -2034,7 +2094,7 @@ export class RdDActor extends RdDBaseActorSang {
await this.createEmbeddedDocuments("Item", [RdDItemSigneDraconique.prepareSigneDraconiqueMeditation(meditationRoll.meditation, meditationRoll.rolled)]);
}
if (meditationRoll.rolled.isEPart) {
await this.updateEmbeddedDocuments('Item', [{ _id: meditationRoll.meditation._id, 'system.malus': meditationRoll.meditation.system.malus - 1 }]);
await this.updateEmbeddedDocuments('Item', [{ _id: meditationRoll.meditation.id, 'system.malus': meditationRoll.meditation.system.malus - 1 }]);
}
await this.santeIncDec("fatigue", 2);
await RdDRollResult.displayRollData(meditationRoll, this.name, 'chat-resultat-meditation.hbs');
@@ -2054,7 +2114,7 @@ export class RdDActor extends RdDBaseActorSang {
/* -------------------------------------------- */
async rollLireSigneDraconique(coord) {
if (!this.isHautRevant()) {
ui.notifications.info("Seul un haut rêvant peut lire un signe draconique!");
ui.notifications.info("Seul un haut rêvant peut lire un signe draconique!")
return
}
let signes = this._getSignesDraconiques(coord)
@@ -2064,8 +2124,9 @@ export class RdDActor extends RdDBaseActorSang {
}
let draconicList = this.getDraconics()
.filter(it => it.system.niveau > -11)
.map(draconic => {
let draconicLecture = foundry.utils.duplicate(draconic)
let draconicLecture = foundry.utils.deepClone(draconic)
draconicLecture.system.defaut_carac = "intellect"
return draconicLecture
});
@@ -2115,12 +2176,15 @@ export class RdDActor extends RdDBaseActorSang {
if (rollData.xpSort > 0) {
const fromXp = Number(compData.system.xp_sort);
const toXp = fromXp + rollData.xpSort;
await this.updateEmbeddedDocuments("Item", [{ _id: compData._id, 'system.xp_sort': toXp }]);
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 this.deleteEmbeddedDocuments("Item", [rollData.signe.id]);
await RdDRollResult.displayRollData(rollData, this.name, 'chat-resultat-lecture-signedraconique.hbs');
this.tmrApp.close();
if (this.tmrApp) {
this.tmrApp.subdialog = undefined; // débloque $forceClose qui refuse de fermer tant qu'un subdialog est actif
await this.tmrApp.close();
}
}
/* -------------------------------------------- */
@@ -2220,7 +2284,7 @@ export class RdDActor extends RdDBaseActorSang {
if (xpData.competence) {
const from = Number(xpData.competence.system.xp);
const to = from + xpData.xpCompetence;
await this.updateEmbeddedDocuments('Item', [{ _id: xpData.competence._id, 'system.xp': to }]);
await this.updateEmbeddedDocuments('Item', [{ _id: xpData.competence.id, 'system.xp': to }]);
xpData.checkComp = await this.checkCompetenceXP(xpData.competence.name, undefined, false)
await ExperienceLog.add(this, XP_TOPIC.XP, from, to, xpData.competence.name);
return [xpData]
@@ -2231,7 +2295,7 @@ export class RdDActor extends RdDBaseActorSang {
/* -------------------------------------------- */
async _xpCarac(xpData) {
if (xpData.xpCarac > 0) {
const carac = foundry.utils.duplicate(this.system.carac)
const carac = foundry.utils.deepClone(this.system.carac)
const code = RdDBaseActor._findCaracNode(carac, xpData.caracName)
const selectedCarac = carac[code]
if (this.isCaracMax(code)) {
@@ -2284,7 +2348,7 @@ export class RdDActor extends RdDBaseActorSang {
/* -------------------------------------------- */
async deleteNombresAstraux() {
const deletions = this.itemTypes['nombreastral'].map(it => it._id);
const deletions = this.itemTypes['nombreastral'].map(it => it.id);
await this.deleteEmbeddedDocuments("Item", deletions);
}
@@ -2309,7 +2373,7 @@ export class RdDActor extends RdDBaseActorSang {
if (calendrier) {
const toDelete = this.itemTypes['nombreastral']
.filter(it => calendrier.isAfterIndexDate(it.system.jourindex))
.map(it => it._id);
.map(it => it.id);
await this.deleteEmbeddedDocuments("Item", toDelete);
}
}
@@ -2438,7 +2502,9 @@ export class RdDActor extends RdDBaseActorSang {
const tacheId = (await this.getTacheBlessure(blesse, blessure))?.id
return await this.rollTache(tacheId, {
callbacks: [async r => await blesse.callbackPremiersSoins(blessureId, r, this.id)],
title: 'Premiers soins', forced: true
verb: "soigne",
title: 'Premiers soins',
forced: true
});
}
else if (!blessure.system.soinscomplets.done) {
@@ -2446,7 +2512,9 @@ export class RdDActor extends RdDBaseActorSang {
return await this.rollCaracCompetence(CARACS.DEXTERITE, "Chirurgie", diff, {
callbacks: [async r => await blesse.onRollSoinsComplets(blessureId, r, this.id)],
onRollDone: RollDialog.onRollDoneClose,
title: "Soins complets", forced: true
verb: "applique des soins complets à",
title: "Soins complets",
forced: true
})
}
}
@@ -2524,7 +2592,7 @@ export class RdDActor extends RdDBaseActorSang {
async incDecItemUse(itemId, shouldIncrease = true) {
if (shouldIncrease) {
const currentItemUse = this.getFlag(SYSTEM_RDD, 'itemUse');
let itemUse = currentItemUse ? foundry.utils.duplicate(currentItemUse) : {};
let itemUse = currentItemUse ? foundry.utils.deepClone(currentItemUse) : {};
itemUse[itemId] = (itemUse[itemId] ?? 0) + 1;
await this.setFlag(SYSTEM_RDD, 'itemUse', itemUse);
}
@@ -2621,7 +2689,7 @@ export class RdDActor extends RdDBaseActorSang {
}
async setPointsCoeur(subActorId, coeurs, options = { immediat: false }) {
const newSuivants = foundry.utils.duplicate(this.system.subacteurs.suivants)
const newSuivants = foundry.utils.deepClone(this.system.subacteurs.suivants)
const amoureux = newSuivants.find(it => it.id == subActorId)
if (amoureux) {
amoureux[options.immediat ? 'coeur' : 'prochainCoeur'] = coeurs
@@ -2665,7 +2733,7 @@ export class RdDActor extends RdDBaseActorSang {
if (!this.isAddSubActeurAllowed(subActor)) {
return
}
const subActorOnlyId = { id: subActor._id };
const subActorOnlyId = { id: subActor.id };
if (subActor.type == 'vehicule') {
this.pushSubActeur(subActorOnlyId, this.system.subacteurs.vehicules, `system.subacteurs.vehicules`, `Le véhicule ${subActor.name}`)
} else if (subActor.type == 'creature') {
@@ -2816,7 +2884,7 @@ export class RdDActor extends RdDBaseActorSang {
}
}
await this.createEmbeddedDocuments('Item', [newPotion])
await this.diminuerQuantiteObjet(herbeData._id, herbeData.nbBrins)
await this.diminuerQuantiteObjet(herbeData.id, herbeData.nbBrins)
await ChatMessage.create({
whisper: ChatUtility.getOwners(this),
@@ -2975,24 +3043,24 @@ export class RdDActor extends RdDBaseActorSang {
}
async nouvelleIncarnation() {
let incarnation = this.toObject();
let incarnation = this.toObject()
incarnation.items = Array.from(this.items.filter(it => it.type == ITEM_TYPES.competence),
incarnation.items = Array.from(this.itemTypes[ITEM_TYPES.competence],
it => {
it = it.toObject();
it.id = undefined;
it.system.niveau = it.system.base;
it.system.niveau_archetype = Math.max(it.system.niveau + (it.system.xp > 0 ? 1 : 0), it.system.niveau_archetype);
it.system.xp = 0;
it.system.xp_sort = 0;
it.system.default_diffLibre = 0;
return it;
});
it = it.toObject()
it.id = undefined
it.system.niveau = it.system.base
it.system.niveau_archetype = Math.max(it.system.niveau + (it.system.xp > 0 ? 1 : 0), it.system.niveau_archetype)
it.system.xp = 0
it.system.xp_sort = 0
it.system.default_diffLibre = 0
return it
})
incarnation.name = 'Réincarnation de ' + incarnation.name
incarnation.system = {
carac: foundry.utils.duplicate(this.system.carac),
heure: RdDTimestamp.defHeure(await RdDDice.rollHeure({ rollMode: "selfroll", showDice: SHOW_DICE })).key,
carac: foundry.utils.deepClone(this.system.carac),
heure: RdDTimestamp.defHeure(await RdDDice.rollHeure({ rollMode: "self", showDice: SHOW_DICE })).key,
age: 18,
biographie: '',
notes: '',
@@ -3002,12 +3070,57 @@ export class RdDActor extends RdDBaseActorSang {
'reve.reve.value': this.system.carac.reve.value,
subacteurs: { suivants: [], montures: [], vehicules: [] },
}
incarnation = await RdDBaseActor.create(incarnation);
await incarnation.deleteEmbeddedDocuments('ActiveEffect', incarnation.getEmbeddedCollection("ActiveEffect").map(it => it.id));
await incarnation.remiseANeuf();
incarnation.sheet.render(true);
incarnation = await RdDBaseActor.create(incarnation)
await incarnation.deleteEmbeddedDocuments('ActiveEffect', incarnation.getEmbeddedCollection("ActiveEffect").map(it => it.id))
await incarnation.remiseANeuf()
incarnation.sheet.render(true)
}
async repartitionArchetypeAleatoire() {
const nivArchetypeDisponibles = RdDItemCompetence.computeResumeArchetype(this.itemTypes[ITEM_TYPES.competence])
.filter(it => it.reste > 0)
function proba(nivDispo, niveauActuel) {
return niveauActuel > 0 ? (nivDispo.reste + 3) : nivDispo.reste
}
async function takeNiveauArchetypeRandom(niveauMin) {
const potential = nivArchetypeDisponibles.filter(it => it.niveau >= niveauMin)
const totalChances = potential.map(it => proba(it, niveauMin)).reduce(Misc.sum(), 0)
if (totalChances > 0) {
let random = await Misc.random(totalChances)
for (const selected of potential) {
if (selected.reste > 0) {
const chances = proba(selected, niveauMin)
if (random <= chances) {
selected.nombre++
selected.reste--
return selected.niveau
}
random -= chances
}
}
}
return Math.max(0, niveauMin)
}
const compsByNiveau = Misc.classify(
this.itemTypes[ITEM_TYPES.competence].filter(it => it.system.niveau_archetype <= 0),
it => Math.max(0, it.system.niveau))
const niveaux = Object.keys(compsByNiveau).sort(Misc.descending())
const updates = []
for (let i = 0; i < niveaux.length; i++) {
const competencesDuNiveau = Misc.shuffled(compsByNiveau[niveaux[i]])
for (let j = 0; j < competencesDuNiveau.length; j++) {
const competence = competencesDuNiveau[j]
const nivArchetype = await takeNiveauArchetypeRandom(competence.system.niveau)
updates.push({ _id: competence.id, 'system.niveau_archetype': nivArchetype })
}
}
await this.updateEmbeddedDocuments('Item', updates)
}
/* -------------------------------------------- */
async _rollArtV2(oeuvreId) {
@@ -3027,7 +3140,7 @@ export class RdDActor extends RdDBaseActorSang {
}
else {
const artData = { art: 'oeuvre', verbe: 'Interpréter' }
const oeuvre = foundry.utils.duplicate(this.findItemLike(id, artData.art))
const oeuvre = foundry.utils.deepClone(this.findItemLike(id, artData.art))
await this._rollArtV1(artData, oeuvre.system.default_carac, oeuvre)
}
}
@@ -3038,7 +3151,7 @@ export class RdDActor extends RdDBaseActorSang {
}
else {
const artData = { art: 'chant', verbe: 'Chanter' }
const oeuvre = foundry.utils.duplicate(this.getChant(id))
const oeuvre = foundry.utils.deepClone(this.getChant(id))
await this._rollArtV1(artData, "ouie", oeuvre)
}
}
@@ -3049,14 +3162,14 @@ export class RdDActor extends RdDBaseActorSang {
}
else {
const artData = { art: 'danse', verbe: 'Danser', forceCarac: {} }
const oeuvre = foundry.utils.duplicate(this.findItemLike(id, artData.art))
const oeuvre = foundry.utils.deepClone(this.findItemLike(id, artData.art))
let selectedCarac = this.getCompetence(oeuvre.system.competence)?.system.defaut_carac
if (oeuvre.system.apparence) {
artData.forceCarac['apparence'] = foundry.utils.duplicate(this.system.carac.apparence)
artData.forceCarac['apparence'] = foundry.utils.deepClone(this.system.carac.apparence)
selectedCarac = "apparence"
}
if (oeuvre.system.agilite) {
artData.forceCarac['agilite'] = foundry.utils.duplicate(this.system.carac.agilite)
artData.forceCarac['agilite'] = foundry.utils.deepClone(this.system.carac.agilite)
selectedCarac = "agilite"
}
await this._rollArtV1(artData, selectedCarac, oeuvre)
@@ -3081,17 +3194,17 @@ export class RdDActor extends RdDBaseActorSang {
{
oeuvre: oeuvre,
art: oeuvre.type,
competence: foundry.utils.duplicate(this.getCompetence(artData.compName ?? oeuvre.system.competence ?? artData.art)),
competence: foundry.utils.deepClone(this.getCompetence(artData.compName ?? oeuvre.system.competence ?? artData.art)),
diffLibre: - oeuvre.system.niveau,
diffConditions: 0,
use: { libre: false, conditions: true, surenc: false },
selectedCarac: foundry.utils.duplicate(this.system.carac[selected])
selectedCarac: foundry.utils.deepClone(this.system.carac[selected])
},
{ overwrite: false });
artData.competence.system.defaut_carac = selected;
if (!artData.forceCarac) {
artData.forceCarac = {};
artData.forceCarac[selected] = foundry.utils.duplicate(this.system.carac[selected]);
artData.forceCarac[selected] = foundry.utils.deepClone(this.system.carac[selected]);
}
await this.openRollDialog({
+22 -25
View File
@@ -9,7 +9,7 @@ import { ReglesOptionnelles } from "../settings/regles-optionnelles.js";
import { RdDBaseActor } from "./base-actor.js";
import { ITEM_TYPES } from "../constants.js";
import { StatusEffects, STATUSES } from "../settings/status-effects.js";
import { Targets } from "../targets.js";
import { Targets } from "../combat/targets.js";
import { RdDConfirm } from "../rdd-confirm.js";
import { CARACS, RdDCarac } from "../rdd-carac.js";
import { RdDRollResult } from "../rdd-roll-result.js";
@@ -19,18 +19,19 @@ import { RdDItemCompetence } from "../item-competence.js";
import { ChatUtility } from "../chat-utility.js";
import { DialogValidationEncaissement } from "../dialog-validation-encaissement.js";
import { RdDCombat } from "../rdd-combat.js";
import { RdDEmpoignade } from "../rdd-empoignade.js";
import { RdDPossession } from "../rdd-possession.js";
import { BASE_CORPS_A_CORPS, BASE_ESQUIVE, CATEGORIES_COMPETENCES_CREATURES } from "../item/base-items.js";
import { PasseArme } from "../combat/passe-arme.mjs";
import { RdDEmpoignade } from "../combat/rdd-empoignade.js";
import { RdDPossession } from "../combat/rdd-possession.js";
import { RdDPossessionV2 } from "../combat/rdd-possession-v2.mjs";
import { BASE_CORPS_A_CORPS, BASE_ESQUIVE, CATEGORIES_COMPETENCES_CREATURES, SANS_DRACONIC } from "../item/base-items.js";
import { RollDataAjustements } from "../rolldata-ajustements-v1.js";
import { MappingCreatureArme } from "../item/mapping-creature-arme.mjs";
import RollDialog from "../roll/roll-dialog.mjs";
import { DEFAULT_ROLL_TYPES, DIFF, ROLL_TYPE_ATTAQUE, ROLL_TYPE_COMP, ROLL_TYPE_REVE_RESISTANCE } from "../roll/roll-constants.mjs";
import { OptionsAvancees, ROLL_DIALOG_V2 } from "../settings/options-avancees.js";
import { RdDInitiative } from "../initiative.mjs";
import { RdDInitiative } from "../combat/initiative.mjs";
import { RdDItemCompetenceCreature } from "../item-competencecreature.js";
import { RdDPossessionV2 } from "../rdd-possession-v2.mjs";
/**
* Classe de base pour les acteurs disposant de rêve (donc, pas des objets)
@@ -39,13 +40,6 @@ import { RdDPossessionV2 } from "../rdd-possession-v2.mjs";
*/
export class RdDBaseActorReve extends RdDBaseActor {
prepareActorData() {
super.prepareActorData()
this.system.attributs.plusdom.value = this.getBonusDegat()
this.system.sante.endurance.max = this.getEnduranceMax()
this.system.sante.endurance.value = Math.min(this.system.sante.endurance.value, this.system.sante.endurance.max)
}
getCarac() {
const carac = super.getCarac()
foundry.utils.mergeObject(carac, this.getCaracReveActuel())
@@ -102,17 +96,18 @@ export class RdDBaseActorReve extends RdDBaseActor {
}
getDraconics() { return [] }
getDraconicOuPossession() {
getDraconicOuNaturel(options = {possession: false}) {
return [
...this.getDraconics(),
...this.itemTypes[ITEM_TYPES.competencecreature].filter(it => it.isCompetencePossession()),
this.getConjurationNaturelle()
options.possession ? this.getConjurationNaturelle() : SANS_DRACONIC
].sort(Misc.descending(it => it.system.niveau));
}
getConjurations() {
return this.getDraconicOuPossession()
.map(it => this.toActionConjuration(it))
getBestDraconic(options = {possession: false}) {
return this.getDraconicOuNaturel(options)
.find(it => true)
}
getConjurationNaturelle() {
@@ -347,7 +342,8 @@ export class RdDBaseActorReve extends RdDBaseActor {
});
}
/**
* Méthode pour faire un jet prédéterminer sans ouvrir la fenêtre de dialogue
* Méthode pour faire un jet prédéterminé sans ouvrir la fenêtre de dialogue
*
* @param {*} caracName code ou label de la caractéristique. On peut utiliser 'intel' pour Intellect.
* @param {*} compName nom de compétence ou nom abrégé.
* @param {*} diff difficulté (0 si undefined)
@@ -367,12 +363,13 @@ export class RdDBaseActorReve extends RdDBaseActor {
selectedCarac: carac,
competence: competence,
diffLibre: diff ?? 0,
current: { rollmode: { key: game.settings.get("core", "messageMode") } },
show: { title: options?.title ?? '' }
}
RollDataAjustements.calcul(rollData, this);
await RdDResolutionTable.rollData(rollData);
this.ajoutExperience(rollData);
await RdDResolutionTable.displayRollData(rollData, this)
await RdDRollResult.displayRollData(rollData, this)
return rollData.rolled;
}
@@ -528,7 +525,7 @@ export class RdDBaseActorReve extends RdDBaseActor {
RdDPossession.onAttaquePossession(target, this, competence)
}
else {
RdDCombat.rddCombatTarget(target, this, token).attaque(competence, arme)
PasseArme.rddCombatTarget(target, this, token).attaque(competence, arme)
}
});
return
@@ -563,7 +560,7 @@ export class RdDBaseActorReve extends RdDBaseActor {
return
}
RdDCombat.rddCombatTarget(target, this, token).attaqueV2();
PasseArme.rddCombatTarget(target, this, token).attaqueV2();
})
}
else {
@@ -627,7 +624,7 @@ export class RdDBaseActorReve extends RdDBaseActor {
// TODO: vérifier si c'est possible, sinon simplifier
return RdDPossession.onAttaquePossession(target, this, comp);
}
RdDCombat.rddCombatTarget(target, this, token).attaque(comp, arme, maniement)
PasseArme.rddCombatTarget(target, this, token).attaque(comp, arme, maniement)
})
}
@@ -693,7 +690,7 @@ export class RdDBaseActorReve extends RdDBaseActor {
{ actor: this }))
if (!encaissement.hasPlayerOwner && encaissement.endurance != 0) {
encaissement = foundry.utils.duplicate(encaissement)
encaissement = foundry.utils.deepClone(encaissement)
encaissement.isGM = true
await ChatMessage.create({
whisper: ChatUtility.getGMs(),
+4 -11
View File
@@ -17,19 +17,12 @@ import { CARACS } from "../rdd-carac.js";
*/
export class RdDBaseActorSang extends RdDBaseActorReve {
async _preUpdate(changed, options, user) {
const updatedEndurance = changed?.system?.sante?.endurance
if (updatedEndurance && options.diff) {
await this.setEffect(STATUSES.StatusUnconscious, updatedEndurance.value == 0)
}
}
prepareActorData() {
this.system.sante.vie.max = Math.ceil((this.getTaille() + this.getConstitution()) / 2)
this.system.sante.vie.value = Math.min(this.system.sante.vie.value, this.system.sante.vie.max)
super.prepareActorData()
this.system.attributs.encombrement.value = this.getEncombrementMax()
return super._preUpdate(changed, options, user)
}
getCarac() {
@@ -109,7 +102,7 @@ export class RdDBaseActorSang extends RdDBaseActorReve {
/* -------------------------------------------- */
async onAppliquerJetEncaissement(encaissement, attackerToken) {
const santeOrig = foundry.utils.duplicate(this.system.sante);
const santeOrig = foundry.utils.deepClone(this.system.sante);
const blessure = this.nouvelleBlessure(encaissement.gravite, {
localisation: encaissement.dmg?.loc.label ?? '',
origine: attackerToken?.name ?? ''
@@ -124,7 +117,7 @@ export class RdDBaseActorSang extends RdDBaseActorReve {
await rollPerteEndurance.evaluate()
blessure.system.endurance = rollPerteEndurance.total
}
const isCritique = blessure.system.gravite >= 6;
const isCritique = blessure.system.gravite >= 6 || encaissement._reduireEndAZero;
if (isCritique) {
blessure.system.endurance = this.getEnduranceActuelle()
}
@@ -156,7 +149,7 @@ export class RdDBaseActorSang extends RdDBaseActorReve {
if (!this.system.sante[name]) {
return
}
const sante = foundry.utils.duplicate(this.system.sante)
const sante = foundry.utils.deepClone(this.system.sante)
const compteur = sante[name]
const result = { sonne: false }
let perteEndurance = 0
+36 -23
View File
@@ -91,7 +91,7 @@ export class RdDBaseActor extends Actor {
}
static getRealActor(actorId, tokenId) {
const actor = tokenId ? canvas.tokens.get(tokenId)?.actor : undefined
const actor = tokenId ? canvas?.tokens?.get(tokenId)?.actor : undefined
return actor ?? game.actors.get(actorId)
}
@@ -147,10 +147,8 @@ export class RdDBaseActor extends Actor {
return this.name
}
isPersonnageJoueur() { return false }
getCarac() {
return foundry.utils.duplicate(this.system.carac)
return foundry.utils.deepClone(this.system.carac)
}
findCaracByName(name) {
@@ -222,16 +220,16 @@ export class RdDBaseActor extends Actor {
await this.delayedRenderSheet('_preUpdate', changed, options)
return super._preUpdate(changed, options, user)
}
_onUpdate(changed, options, userId) {
super._onUpdate(changed, options, userId)
if (userId == game.user.id){
if (userId == game.user.id) {
this.delayedRenderSheet('_onUpdate', changed, options)
}
}
async delayedRenderSheet(caller, data, options) {
this.refreshDelayCounter = (this.refreshDelayCounter ?? 0)+1
this.refreshDelayCounter = (this.refreshDelayCounter ?? 0) + 1
if (this.refreshDelayCounter == 1) {
this.renderAfterDelay(this.refreshDelayCounter)
}
@@ -246,20 +244,17 @@ export class RdDBaseActor extends Actor {
else {
this.renderAfterDelay(this.refreshDelayCounter)
}
}, 30)
}, 50)
}
/* -------------------------------------------- */
prepareData() {
super.prepareData()
this.prepareActorData()
this.cleanupConteneurs()
this.computeEtatGeneral()
this.computeEncTotal()
}
prepareActorData() { }
async computeEtatGeneral() { }
/* -------------------------------------------- */
@@ -267,6 +262,7 @@ export class RdDBaseActor extends Actor {
return game.users.players.find(player => player.active && player.character?.id == this.id);
}
isPersonnageJoueur() { return false }
isCreatureOuEntite() { return this.isCreature() || this.isEntite() }
isCreature() { return false }
isEntite() { return false }
@@ -384,8 +380,8 @@ export class RdDBaseActor extends Actor {
}
async onTimeChanging(oldTimestamp, newTimestamp) {
this.items.filter(it => it.isFinPeriode(oldTimestamp, newTimestamp))
.forEach(async it => await it.onFinPeriodeTemporel(oldTimestamp, newTimestamp))
await Promise.all(this.items.filter(it => it.isFinPeriode(oldTimestamp, newTimestamp))
.map(async it => await it.onFinPeriodeTemporel(oldTimestamp, newTimestamp)))
}
async creerObjetParMJ(object) {
@@ -405,7 +401,7 @@ export class RdDBaseActor extends Actor {
if (Misc.isOwnerPlayer(this)) {
let updates = this.itemTypes[ITEM_TYPES.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) } });
.map(c => { return { _id: c.id, 'system.contenu': c.system.contenu.filter(id => this.getItem(id) != undefined) } });
if (updates.length > 0) {
await this.updateEmbeddedDocuments("Item", updates)
}
@@ -546,7 +542,7 @@ export class RdDBaseActor extends Actor {
if (cout > 0) {
RdDAudio.PlayContextAudio("argent");
}
const chatAchatItem = foundry.utils.duplicate(achat.vente);
const chatAchatItem = foundry.utils.deepClone(achat.vente);
chatAchatItem.quantiteTotal = quantite;
await ChatMessage.create({
user: achat.userId,
@@ -632,17 +628,20 @@ export class RdDBaseActor extends Actor {
return
}
const isItemEmpilable = "quantite" in item.system;
const baseItem = {
id: undefined,
type: item.type,
img: item.img,
name: item.name,
system: foundry.utils.mergeObject(item.system, { quantite: isItemEmpilable ? quantite : undefined }, { inplace: false })
system: foundry.utils.duplicate(item.system)
}
const createItemArray = "quantite" in item.system
? (it, qt) => { it.system.quantite = qt; return [it] }
: (it, qt) => Array.from({ length: qt }, (_, i) => it)
const newItems = isItemEmpilable ? [baseItem] : Array.from({ length: quantite }, (_, i) => baseItem);
const items = await this.createEmbeddedDocuments("Item", newItems);
return newItems.length > 0 ? items[0].id : undefined;
const newItems = createItemArray(baseItem, quantite)
const items = await this.createEmbeddedDocuments("Item", newItems)
return items.length > 0 ? items[0].id : undefined;
}
/* -------------------------------------------- */
@@ -653,6 +652,7 @@ export class RdDBaseActor extends Actor {
else {
const wasSurenc = this.isSurenc()
this.encTotal = this.items.filter(it => RdDItem.getItemTypesInventaire().includes(it.type))
.filter(it => it.type !== ITEM_TYPES.conteneur)
.map(it => it.getEncTotal()).reduce(Misc.sum(), 0)
const isSurenc = this.isSurenc()
if (isSurenc != wasSurenc) {
@@ -712,8 +712,8 @@ export class RdDBaseActor extends Actor {
}
}
}
await this.computeEncTotal()
}
await this.computeEncTotal()
return result;
}
@@ -851,7 +851,7 @@ export class RdDBaseActor extends Actor {
sourceActor.buildSubConteneurObjetList(itemId, itemsList); // Get itemId list
const itemsDataToCreate = itemsList.map(it => sourceActor.getItem(it.id))
.map(it => foundry.utils.duplicate(it))
.map(it => foundry.utils.deepClone(it))
.map(it => { it.system.contenu = []; return it; });
let newItems = await this.createEmbeddedDocuments('Item', itemsDataToCreate);
@@ -899,13 +899,26 @@ export class RdDBaseActor extends Actor {
actionImpossible(action) {
ui.notifications.info(`${this.getAlias()} ne peut pas faire cette action: ${action}`)
}
async doRollCaracCompetence(caracName, compName, diff, options = { title: "" }) {
}
ajoutExperience(rollData) { }
isAlcoolise() { return false }
async jetEthylisme() { this.actionImpossible("jet d'éthylisme") }
async rollAppelChance() { this.actionImpossible("appel à la chance") }
async jetDeMoral() { this.actionImpossible("jet de moral") }
async creerCopieLue(item) {
if (item.type !== ITEM_TYPES.livre) return
const existante = this.items.find(i => i.type === 'livre' && i.system.estCopieLue && i.name === item.name)
if (existante) return
const copie = item.toObject()
copie.system.estCopieLue = true
copie.system.lu = true
copie.system.quantite = 0
delete copie._id
await this.createEmbeddedDocuments('Item', [copie], { renderSheet: false })
}
async resetItemUse() { }
async incDecItemUse(itemId, shouldIncrease = true) { }
getItemUse(itemId) { return 0; }
+138 -131
View File
@@ -5,26 +5,98 @@ import { RdDDice } from "../../rdd-dice.js";
import { RdDNameGen } from "../../rdd-namegen.js";
import { RdDTimestamp } from "../../time/rdd-timestamp.js";
const PATHS = [
'name',
'system.sexe',
'system.age',
'system.taille',
'system.poids',
'system.main',
'system.heure',
'system.cheveux',
'system.yeux'
]
const RANDOM_VALUES = {
'system.sexe': { 'masculin': 1, 'féminin': 1 },
'system.main': { 'droitier': 51, 'gaucher': 15, 'ambidextre': 6 },
'system.cheveux': { 'noirs': 2, 'bruns': 5, 'châtains': 3, 'châtain clair': 5, 'blonds': 4, 'blond platine': 1, 'roux carotte': 1, 'roux cuivré': 3, 'chauve': 1 },
'system.yeux': { 'noirs': 2, 'noisette': 3, 'brun-vert': 4, 'verts': 3, 'bleu clair': 3, 'bleu gris': 2, 'gris': 1, 'mauves': 1, 'indigos': 1 },
async function randomFrom(values) {
const max = Object.values(values).reduce(Misc.sum(), 0)
const total = await RdDDice.rollTotal(`1d${max}`)
let sum = 0
for (let entry of Object.entries(values)) {
sum = sum + entry[1]
if (sum >= total) {
return entry[0]
}
}
return Object.keys(values)[0]
}
export class AppPersonnageAleatoire extends FormApplication {
async function randomTailleCm(taille) {
const infoTaille = RdDCarac.getCaracDerivee(taille)
const infoTailleSup = RdDCarac.getCaracDerivee(taille + 1)
const variation = (infoTailleSup.taille - infoTaille.taille) + Math.floor((infoTaille.poidsMax - infoTaille.poidsMin) / 2)
const base = infoTaille.taille
const total = await RdDDice.rollTotal(`1d${variation} -1d ${variation} + ${base}`)
const cm = total % 100
const dm = cm < 10 ? '0' : ''
const m = (total - cm) / 100
return `${m}m${dm}${cm}`
}
async function randomPoidsKg(taille) {
const infoTaille = RdDCarac.getCaracDerivee(taille)
const range = infoTaille.poidsMax - infoTaille.poidsMin + 1
const total = await RdDDice.rollTotal(`1d${range} + ${infoTaille.poidsMin}`)
return total + ' kg'
}
async function randomHeure() {
return RdDTimestamp.defHeure(await RdDDice.rollHeure({ rollMode: "self", showDice: SHOW_DICE })).key
}
const CONTROL_UNKNOWN = { name: 'unknown', path: '', getter: (act) => { undefined }, random: async act => undefined }
const TABLE_SEXES = { 'masculin': 1, 'féminin': 1 };
const TABLE_MAINS = { 'droitier': 51, 'gaucher': 15, 'ambidextre': 6 };
const TABLE_COULEURS_CHEVEUX = {
'noirs': 2,
'bruns': 5,
'châtains': 3,
'châtain clair': 5,
'blonds': 4,
'blond platine': 1,
'roux carotte': 1,
'roux cuivré': 3,
'chauve': 1
};
const TABLE_COULEURS_YEUX = {
'noirs': 2,
'noisette': 3,
'brun-vert': 4,
'verts': 3,
'bleu clair': 3,
'bleu gris': 2,
'gris': 1,
'mauves': 1,
'indigos': 1
};
const CONTROLS = [
{ name: 'name', path: 'name', getter: (act) => act.name, random: async act => await RdDNameGen.generate() },
{ name: 'sexe', path: 'system.sexe', getter: act => act.system.sexe, random: async act => await randomFrom(TABLE_SEXES) },
{ name: 'age', path: 'system.age', getter: act => act.system.age, random: async act => await RdDDice.rollTotal('(2d4kl)*10 + 1d7xo + 2d20kl') },
{ name: 'taille', path: 'system.taille', getter: act => act.system.taille, random: async act => await randomTailleCm(act.system.carac.taille.value) },
{ name: 'poids', path: 'system.poids', getter: act => act.system.poids, random: async act => await randomPoidsKg(act.system.carac.taille.value) },
{ name: 'main', path: 'system.main', getter: act => act.system.main, random: async act => await randomFrom(TABLE_MAINS) },
{ name: 'heure', path: 'system.heure', getter: act => act.system.heure, random: async act => await randomHeure() },
{ name: 'cheveux', path: 'system.cheveux', getter: act => act.system.cheveux, random: async act => await randomFrom(TABLE_COULEURS_CHEVEUX) },
{ name: 'yeux', path: 'system.yeux', getter: act => act.system.yeux, random: async act => await randomFrom(TABLE_COULEURS_YEUX) },
]
const { HandlebarsApplicationMixin } = foundry.applications.api;
export class AppPersonnageAleatoire extends HandlebarsApplicationMixin(foundry.applications.api.ApplicationV2) {
static PARTS = {
main: { template: "systems/foundryvtt-reve-de-dragon/templates/actor/random/app-personnage-aleatoire.hbs" }
}
static DEFAULT_OPTIONS = {
classes: ['app-personnage-aleatoire'],
window: {
title: "Génération aléatoire",
controls: []
},
position: {
width: 600,
height: 600
}
}
static preloadHandlebars() {
foundry.applications.handlebars.loadTemplates([
'systems/foundryvtt-reve-de-dragon/templates/actor/random/champ-aleatoire.hbs',
@@ -32,165 +104,100 @@ export class AppPersonnageAleatoire extends FormApplication {
])
}
static get defaultOptions() {
return foundry.utils.mergeObject(super.defaultOptions, {
template: "systems/foundryvtt-reve-de-dragon/templates/actor/random/app-personnage-aleatoire.hbs",
title: "Génération aléatoire",
width: 'fit-content',
height: 'fit-content',
classes: ['app-personnage-aleatoire'],
popOut: true,
resizable: true
}, { inplace: false })
}
constructor(actor) {
super({})
this.actor = actor
this.current = foundry.utils.duplicate(actor)
this.checked = {
'name': false,
'system.sexe': (this.actor.system.sexe ?? '') == '',
'system.age': this.actor.system.age == 0,
'system.taille': (this.actor.system.taille ?? '') == '',
'system.poids': (this.actor.system.poids ?? '') == '',
'system.main': (this.actor.system.main ?? '') == '',
'system.heure': (this.actor.system.heure ?? '') == '',
'system.cheveux': (this.actor.system.cheveux ?? '') == '',
'system.yeux': (this.actor.system.yeux ?? '') == '',
}
this.current = Object.fromEntries(CONTROLS.map(it => [it.name, it.getter(this.actor)]));
this.checked = Object.fromEntries(CONTROLS.map(it => [it.name, [0, '', undefined].includes(this.current[it.name])]))
}
async getData(options) {
return foundry.utils.mergeObject(await super.getData(options), {
_prepareContext() {
return {
actor: this.actor,
current: this.current,
checked: this.checked,
options: { isGM: game.user.isGM }
})
}
}
activateListeners(html) {
super.activateListeners(html)
this.html = html
this.html.find("button.button-cancel").click(async event => await this.close())
this.html.find("button.button-apply").click(async event => await this.onApply())
_onRender(context, options) {
super._onRender(context, options)
this.html = $(this.element)
this.html.find("input.current-value").change(async event => await this.onChange(event))
this.html.find("div.random-field[data-path='system.heure'] select.current-value").change(async event => await this.onChange(event))
this.html.find('a[data-action="sexe-masculin"]').click(async event => await this.onSexe('masculin'))
this.html.find('a[data-action="sexe-feminin"]').click(async event => await this.onSexe('féminin'))
this.html.find("a.random").click(async event => await this.onRandom(event))
this.html.find("a.reset").click(async event => await this.onReset(event))
this.html.find("a.randomize-selected").click(async event => await this.onRandomizeSelected())
this.html.find("input.check-for-random").click(async event => await this.onCheckForRandom(event))
this.html.find("div.random-field[data-field-name='heure'] select.current-value").change(async event => await this.onChange(event))
this.html.find('a[data-action="sexe-masculin"]').click(async event => await this.onSexe('masculin'))
this.html.find('a[data-action="sexe-feminin"]').click(async event => await this.onSexe('féminin'))
this.html.find("button.button-cancel").click(async event => await this.close())
this.html.find("button.button-apply").click(async event => await this.onApply())
}
async _updateObject(event, formData) { }
async onApply() {
const updates = Object.fromEntries(
PATHS.filter(path => game.user.isGM || path != 'name')
.map(path => [path, this.current[path]])
CONTROLS.filter(control => game.user.isGM || control.name != 'name')
.map(control => [control.path, this.current[control.name]])
)
await this.actor.update(updates)
await this.close()
}
getPath(selector) {
getName(selector) {
const fields = this.html.find(selector).parents("div.random-field:first")
return fields[0].attributes['data-path'].value
return fields[0].attributes['data-field-name'].value
}
getControl(name) {
return CONTROLS.find(it => it.name == name) ?? CONTROL_UNKNOWN
}
async onSexe(sexe) {
this.current['system.sexe'] = sexe
this.render()
this.current['sexe'] = sexe
this.render({ force: true })
}
async onChange(event) {
const path = this.getPath(event.currentTarget)
this.current[path] = event.currentTarget.value
const name = this.getName(event.currentTarget)
const control = this.getControl(name)
this.current[control.name] = event.currentTarget.value
this.render({ force: true })
}
async onRandom(event) {
const path = this.getPath(event.currentTarget)
await this.setRandom(path);
this.render()
const name = this.getName(event.currentTarget)
const control = this.getControl(name)
await this.randomControl(control)
this.render({ force: true })
}
async onReset(event) {
const path = this.getPath(event.currentTarget)
this.current[path] = this.actor[path]
await this.render()
const name = this.getName(event.currentTarget)
const control = this.getControl(name)
this.current[control.name] = control.getter(this.actor)
this.render({ force: true })
}
async onCheckForRandom(event) {
const path = this.getPath(event.currentTarget)
this.checked[path] = event.currentTarget.checked
this.render()
const name = this.getName(event.currentTarget)
this.checked[name] = event.currentTarget.checked
this.render({ force: true })
}
async onRandomizeSelected() {
const paths = this.html.find("input.check-for-random:checked")
const controls = this.html.find("input.check-for-random:checked")
.parents("div.random-field")
.toArray()
.map(it => it.attributes['data-path'].value)
await Promise.all(paths.map(path => this.setRandom(path)))
this.render()
.map(it => this.getControl(it.attributes['data-field-name'].value))
await Promise.all(controls.map(it => this.randomControl(it)))
this.render({ force: true })
}
async setRandom(path) {
this.current[path] = await this.random(path);
async randomControl(control) {
this.current[control.name] = await control.random(this.actor)
}
async random(path) {
switch (path) {
case 'name':
return await RdDNameGen.generate()
case 'system.sexe':
case 'system.main':
case 'system.cheveux':
case 'system.yeux':
return await this.randomFromMap(RANDOM_VALUES[path])
case 'system.poids':
return await this.randomPoids()
case 'system.taille':
return await this.randomTaille()
case 'system.age':
return await RdDDice.rollTotal('(2d4kl)*10 + 1d7xo + 2d20kl')
case 'system.heure':
return RdDTimestamp.defHeure(await RdDDice.rollHeure({ rollMode: "selfroll", showDice: SHOW_DICE })).key
}
return 'unknown'
}
async randomFromMap(valuesMap) {
const max = Object.values(valuesMap).reduce(Misc.sum(), 0)
const total = await RdDDice.rollTotal(`1d${max}`)
let sum = 0
for (let entry of Object.entries(valuesMap)) {
sum = sum + entry[1]
if (sum >= total) {
return entry[0]
}
}
return Object.keys(valuesMap)[0]
}
async randomPoids() {
const caracTaille = RdDCarac.getCaracDerivee(this.current.system.carac.taille.value)
const range = caracTaille.poidsMax - caracTaille.poidsMin + 1
const total = await RdDDice.rollTotal(`1d${range} + ${caracTaille.poidsMin}`)
return total + ' kg'
}
async randomTaille() {
const caracTaille = RdDCarac.getCaracDerivee(this.current.system.carac.taille.value)
const base = this.current.system.carac.taille.value * 2 + 60 + caracTaille.poidsMin
const variation = Math.floor((caracTaille.poidsMax - caracTaille.poidsMin + base / 5) / 2)
const total = await RdDDice.rollTotal(`2d${variation} + ${base}`)
const cm = total % 100
const dm = cm < 10 ? '0' : ''
const m = (total - cm) / 100
return `${m}m${dm}${cm}`
}
}
+52 -5
View File
@@ -1,5 +1,52 @@
export { default as RdDItemBaseSheet} from "./common-item-sheet.mjs"
export { default as RdDMonnaieSheet } from "./monnaie-sheet.mjs"
export { default as RdDMunitionSheet } from "./munition-sheet.mjs"
export { default as RdDTarotSheet } from "./tarot-sheet.mjs"
export { RdDBaseActorSheetV2 } from "./base-actor-sheet.mjs"
export { RdDCreatureSheetV2 } from "./creature-sheet.mjs"
export { RdDActorVehiculeSheetV2 } from "./vehicule-sheet.mjs"
export { RdDCommerceSheetV2 } from "./commerce-sheet.mjs"
export { RdDActorEntiteSheetV2 } from "./entite-sheet.mjs"
export { RdDActorSheetV2 } from "./personnage-sheet.mjs"
export { RdDActorExportSheetV2 } from "./export-encart-sheet.mjs"
export { default as RdDItemBaseSheet} from "./common-item-sheet.mjs"
export { default as RdDMonnaieSheet } from "./monnaie-sheet.mjs"
export { default as RdDMunitionSheet } from "./munition-sheet.mjs"
export { default as RdDTarotSheet } from "./tarot-sheet.mjs"
export { default as RdDTeteSheet } from "./tete-sheet.mjs"
export { default as RdDQueueSheet } from "./queue-sheet.mjs"
export { default as RdDSouffleSheet } from "./souffle-sheet.mjs"
export { default as RdDOmbreSheet } from "./ombre-sheet.mjs"
export { default as RdDChantSheet } from "./chant-sheet.mjs"
export { default as RdDMusiqueSheet } from "./musique-sheet.mjs"
export { default as RdDDanseSheet } from "./danse-sheet.mjs"
export { default as RdDJeuSheet } from "./jeu-sheet.mjs"
export { default as RdDRecetteAlchimiqueSheet } from "./recettealchimique-sheet.mjs"
export { default as RdDRecetteCuisineSheet } from "./recettecuisine-sheet.mjs"
export { default as RdDArmeSheet } from "./arme-sheet.mjs"
export { default as RdDArmureSheet } from "./armure-sheet.mjs"
export { default as RdDObjetSheet } from "./objet-sheet.mjs"
export { default as RdDConteneurSheet } from "./conteneur-sheet.mjs"
export { default as RdDNourritureBoissonSheet } from "./nourritureboisson-sheet.mjs"
export { default as RdDGemmeSheet } from "./gemme-sheet.mjs"
export { default as RdDServiceSheet } from "./service-sheet.mjs"
export { default as RdDTacheSheet } from "./tache-sheet.mjs"
export { default as RdDBlessureSheet } from "./blessure-sheet.mjs"
export { default as RdDMaladieSheet } from "./maladie-sheet.mjs"
export { default as RdDPoisonSheet } from "./poison-sheet.mjs"
export { default as RdDCompetenceSheet } from "./competence-sheet.mjs"
export { default as RdDCompetenceCreatureSheet } from "./competencecreature-sheet.mjs"
export { default as RdDPotionSheet } from "./potion-sheet.mjs"
export { default as RdDSigneDraconiqueSheet } from "./signedraconique-sheet.mjs"
export { default as RdDSortSheet } from "./sort-sheet.mjs"
export { default as RdDRaceSheet } from "./race-sheet.mjs"
export { default as RdDRencontreSheet } from "./rencontre-sheet.mjs"
export { default as RdDEmpoignadeSheet } from "./empoignade-sheet.mjs"
export { default as RdDPossessionSheet } from "./possession-sheet.mjs"
export { default as RdDLivreSheet } from "./livre-sheet.mjs"
export { default as RdDFauneSheet } from "./faune-sheet.mjs"
export { default as RdDHerbeSheet } from "./herbe-sheet.mjs"
export { default as RdDPlanteSheet } from "./plante-sheet.mjs"
export { default as RdDIngredientSheet } from "./ingredient-sheet.mjs"
export { default as RdDExtraitPoetiqueSheet } from "./extraitpoetique-sheet.mjs"
export { default as RdDNombreAstralSheet } from "./nombreastral-sheet.mjs"
export { default as RdDCaseTMRSheet } from "./casetmr-sheet.mjs"
export { default as RdDSortReserveSheet } from "./sortreserve-sheet.mjs"
export { default as RdDMeditationSheet } from "./meditation-sheet.mjs"
export { default as RdDOeuvreSheet } from "./oeuvre-sheet.mjs"
+92
View File
@@ -0,0 +1,92 @@
import { TEMPLATE_DESCRIPTION, TEMPLATE_INVENTAIRE } from "../../common/_module.mjs";
import { ITEM_TYPES, ACTOR_TYPES } from "../../constants.js";
import { SystemCompendiums } from "../../settings/system-compendiums.js";
import RdDItemBaseSheet from "./common-item-sheet.mjs";
export default class RdDArmeSheet extends RdDItemBaseSheet {
static get ITEM_TYPE() { return ITEM_TYPES.arme; }
static get TEMPLATES() { return [TEMPLATE_DESCRIPTION, TEMPLATE_INVENTAIRE]; }
static MORTALITE_CHOICES = {
mortel: "Mortel",
"non-mortel": "Non mortel",
empoignade: "Empoignade",
}
static CATEGORIE_PARADE_CHOICES = {
"sans-armes": "Sans arme",
"armes-naturelles": "Armes naturelles",
hast: "Armes d'hast",
batons: "Bâtons",
boucliers: "Boucliers",
dagues: "Dagues",
"epees-courtes": "Epées courtes",
"epees-longues": "Epées longues",
"epees-lourdes": "Epées lourdes",
haches: "Haches",
lances: "Lances",
masses: "Masses",
}
static INIT_CHOICES = {
hast: "Armes Hast",
lance: "Lance",
baton: "Bâton",
doubledragonne: "Double Dragonne",
esparlongue: "Esparlongue",
epeedragonne: "Epée Dragonne",
epeebatarde: "Epée Bâtarde",
epeecyane: "Epée Cyane",
epeesorde: "Epée Sorde",
grandehache: "Grande Hache",
hachebataille: "Hache de Bataille",
epeegnome: "Epée Gnome",
masse: "Masse",
gourdin: "Gourdin",
fleau: "Fléaux",
dague: "Dague",
armenaturelle: "Armes Naturelles",
autre: "Autres",
}
static DEFAULT_OPTIONS = Object.assign({},
RdDItemBaseSheet.DEFAULT_OPTIONS,
{
classes: ["fvtt-rdd", "item", "arme"],
position: { width: 448 },
window: { contentClasses: ["arme-content"] },
});
static PARTS = {
main: {
template: "systems/foundryvtt-reve-de-dragon/templates/sheets/item/arme.hbs",
},
};
async _prepareContext() {
const competences = (await SystemCompendiums.getCompetences(ACTOR_TYPES.personnage))
.filter(it => it.isCompetenceArme())
const competenceMeleeChoices = {}
const competenceLancerChoices = {}
const competenceTirChoices = {}
competences.forEach(c => {
const label = c.name
switch (c.system.categorie) {
case 'melee': competenceMeleeChoices[label] = label; break
case 'lancer': competenceLancerChoices[label] = label; break
case 'tir': competenceTirChoices[label] = label; break
}
})
return Object.assign(
await super._prepareContext(),
{
competenceMeleeChoices,
competenceLancerChoices,
competenceTirChoices,
mortaliteChoices: RdDArmeSheet.MORTALITE_CHOICES,
categorieParadeChoices: RdDArmeSheet.CATEGORIE_PARADE_CHOICES,
initChoices: RdDArmeSheet.INIT_CHOICES,
}
);
}
}
@@ -0,0 +1,23 @@
import { TEMPLATE_DESCRIPTION, TEMPLATE_INVENTAIRE } from "../../common/_module.mjs";
import { ITEM_TYPES } from "../../constants.js";
import RdDItemBaseSheet from "./common-item-sheet.mjs";
export default class RdDArmureSheet extends RdDItemBaseSheet {
static get ITEM_TYPE() { return ITEM_TYPES.armure; }
static get TEMPLATES() { return [TEMPLATE_DESCRIPTION, TEMPLATE_INVENTAIRE]; }
static DEFAULT_OPTIONS = Object.assign({},
RdDItemBaseSheet.DEFAULT_OPTIONS,
{
classes: ["fvtt-rdd", "item", "armure"],
position: { width: 448 },
window: { contentClasses: ["armure-content"] },
});
static PARTS = {
main: {
template: "systems/foundryvtt-reve-de-dragon/templates/sheets/item/armure.hbs",
},
};
}
@@ -0,0 +1,460 @@
const { HandlebarsApplicationMixin } = foundry.applications.api
import { RdDUtility } from "../../rdd-utility.js"
import { Misc } from "../../misc.js"
import { DialogSplitItem } from "../../dialog-split-item.js"
import { RdDSheetUtility } from "../../rdd-sheet-utility.js"
import { Monnaie } from "../../item-monnaie.js"
import { ITEM_TYPES } from "../../constants.js"
import { RdDItem } from "../../item.js"
import { RdDTextEditor } from "../../apps/rdd-text-roll-editor.js"
import { ItemAction } from "../../item/item-actions.js"
import { DialogVerifierIngredients } from "../../dialog-verifier-ingredients.js"
import { DialogLancerRecette } from "../../dialog-lancer-recette.js"
import { ChatUtility } from "../../chat-utility.js"
import { RdDItemBlessure } from "../../item/blessure.js"
import { Grammar } from "../../grammar.js"
import { SYSTEM_RDD } from "../../constants.js"
export class RdDBaseActorSheetV2 extends HandlebarsApplicationMixin(foundry.applications.sheets.ActorSheetV2) {
get actor() { return this.document }
// Was this.options.* — custom state
vueDetaillee = false
triEquipement = "name"
recherche = undefined
static TYPE = undefined
static DEFAULT_OPTIONS = {
classes: ["rdd", "sheet", "actor"],
position: { width: 640 },
form: { submitOnChange: true, closeOnSubmit: false },
window: { resizable: true, controls: [] },
actions: {
postToChat: RdDBaseActorSheetV2._onPostToChat,
},
}
//#region Registration
static register() {
foundry.documents.collections.Actors.registerSheet(SYSTEM_RDD, this, {
types: [this.TYPE],
makeDefault: true,
})
}
static async registerAll(...sheetClasses) {
const handlebars = []
sheetClasses.forEach(sheetClass => {
if (sheetClass.PARTS) {
Object.values(sheetClass.PARTS).forEach(part => {
if (part.template) handlebars.push(part.template)
})
}
sheetClass.register()
})
await foundry.applications.handlebars.loadTemplates(Misc.distinct(handlebars))
}
//#endregion
//#region Data
async _prepareContext() {
Monnaie.validerMonnaies(this.actor)
this.actor.computeEtatGeneral()
this._sheetOptions = foundry.utils.mergeObject(
RdDSheetUtility.mergeDocumentRights({ ...this.options }, this.actor, this.isEditable),
{ vueDetaillee: this.vueDetaillee, triEquipement: this.triEquipement, recherche: this.recherche },
{ inplace: false }
)
const ctx = {
title: this.title,
id: this.actor.id,
type: this.actor.type,
img: this.actor.img,
name: this.actor.name,
system: this.actor.system,
systemFields: this.actor.system.schema.fields,
description: await RdDTextEditor.enrichHTML(this.actor.system.description, this.actor),
notesmj: await RdDTextEditor.enrichHTML(this.actor.system.notesmj, this.actor),
options: this._sheetOptions,
effects: this.actor.effects,
editable: this.isEditable,
cssClass: this.isEditable ? "editable" : "locked",
limited: this.actor.limited,
owner: this.actor.isOwner,
}
RdDUtility.filterItemsPerTypeForSheet(ctx, this.actor.itemTypes, this.triEquipement)
ctx.calc = {
fortune: Monnaie.toSolsDeniers(this.actor.getFortune()),
prixTotalEquipement: this.actor.computePrixTotalEquipement(),
encTotal: this.actor.getEncTotal(),
}
this.objetVersConteneur = RdDUtility.buildArbreDeConteneurs(ctx.conteneurs, ctx.inventaires)
this._appliquerRechercheObjets(ctx.conteneurs, ctx.inventaires)
ctx.conteneurs = RdDUtility.conteneursRacine(ctx.conteneurs)
ctx.competences.filter(it => it.type == ITEM_TYPES.competencecreature)
.forEach(it => it.isdommages = it.isDommages())
return ctx
}
_appliquerRechercheObjets(conteneurs, inventaires) {
if (this.recherche?.text) {
const recherche = this.recherche
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)
const parentsIds = conteneurs.filter(it => it.system.contenu.find(id => allVisible.includes(id))).map(it => it.id)
addVisible = parentsIds.filter(id => !allVisible.includes(id))
}
while (addVisible.length > 0)
inventaires.forEach(it => it.system.isHidden = !allVisible.includes(it.id))
conteneurs.forEach(it => it.system.isHidden = !allVisible.includes(it.id))
}
else {
inventaires.forEach(it => it.system.isHidden = false)
conteneurs.forEach(it => it.system.isHidden = false)
}
}
//#endregion
//#region Rendering
async _renderFrame(options) {
const frame = await super._renderFrame(options)
return frame
}
async _onRender(context, options) {
await super._onRender(context, options)
this.html = $(this.element)
const nav = this.element.querySelector(".sheet-tabs")
if (nav) {
const tab = this.tabGroups?.primary || nav.querySelector("[data-tab]")?.dataset.tab
if (tab) this.changeTab(tab, "primary", { force: true })
}
this.html.find(".actionItem").click(async event => await ItemAction.onActionItem(event, this.actor, this._sheetOptions))
this.html.find(".item-edit").click(async event => await this._onItemEdit(event))
this.html.find(".item-verify-ingredients").click(async event => await this._onVerifyIngredients(event))
this.html.find(".item-lancer-recette").click(async event => await this._onLancerRecette(event))
this.html.find(".conteneur-name a").click(async event => {
RdDUtility.toggleAfficheContenu(this._getItemId(event))
this.render({ force: true })
})
this.html.find(".actor-montrer").click(async event => await 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)
this.html.find(".item-list .item").dblclick(async event => {
const item = this._getItem(event)
if (item) item.sheet.render({ force: true })
})
this.html.find(".tri-equipement").change(event => {
this.triEquipement = event.currentTarget.value
this.render({ force: true })
})
if (!this.isEditable) return
this.html.find(".item-equip-armure").click(async event => await this.actor.equiperObjet(this._getItem(event)))
this.html.find(".item-delete").click(async event => await RdDUtility.confirmActorItemDelete(this._getItem(event), this.actor))
this.html.find(".item-quantite-plus").click(async event => await this.actor.itemQuantiteIncDec(this._getItemId(event), 1))
this.html.find(".item-quantite-moins").click(async event => await this.actor.itemQuantiteIncDec(this._getItemId(event), -1))
this.html.find(".item-quantite").change(async event => {
const input = event.currentTarget
const item = this.actor.items.get(input.dataset.itemId)
if (item) {
const newQty = Math.max(0, parseInt(input.value) || 0)
await item.update({ "system.quantite": newQty })
if (newQty === 0) this.render({ force: true })
}
})
this.html.find(".item-quantite").on("contextmenu", async event => {
event.preventDefault()
const item = this._getItem(event)
if (!item?.isInventaire()) return
new foundry.applications.api.DialogV2({
title: `Quantité — ${item.name}`,
content: `<p>Réduire la quantité de :</p>
<select class="qty-amount">
<option value="1">1</option>
<option value="5">5</option>
<option value="10">10</option>
<option value="all">Tout jeter</option>
</select>`,
buttons: [
{ action: "reduce", label: "Retirer", icon: "fa-solid fa-minus", callback: (event, button, dialog) => {
const amount = dialog.element.querySelector(".qty-amount").value
if (amount === "all") {
item.delete()
this.render({ force: true })
} else {
item.update({ "system.quantite": Math.max(0, item.system.quantite - parseInt(amount)) })
}
}},
],
}).render({ force: true })
})
this.html.find(".creer-un-objet").click(async event => await this._selectObjetTypeToCreate())
this.html.find(".nettoyer-conteneurs").click(async event => await this.actor.nettoyerConteneurs())
this.html.find(".quick-add-ration").click(async event => {
const existante = this.actor.items.find(it => it.type === "nourritureboisson" && it.name === "Ration")
if (existante) {
await existante.update({ "system.quantite": Math.max(0, Number(existante.system.quantite) + 1) })
} else {
await this.actor.createEmbeddedDocuments("Item", [{
name: "Ration", type: "nourritureboisson",
img: "systems/foundryvtt-reve-de-dragon/icons/objets/provision_crue.webp",
system: { sust: 1, encombrement: 0.1, quantite: 1, cout: 0.1, boisson: false },
}], { renderSheet: false })
}
this.render({ force: true })
})
this.html.find(".quick-add-eau").click(async event => {
const existante = this.actor.items.find(it => it.type === "nourritureboisson" && it.name === "Eau")
if (existante) {
await existante.update({ "system.quantite": Math.max(0, Number(existante.system.quantite) + 1) })
} else {
await this.actor.createEmbeddedDocuments("Item", [{
name: "Eau", type: "nourritureboisson",
img: "systems/foundryvtt-reve-de-dragon/icons/objets/outre.webp",
system: { desaltere: 1, encombrement: 0.1, quantite: 1, cout: 0.05, boisson: true },
}], { renderSheet: false })
}
this.render({ force: true })
})
this.html.find(".vue-detaillee").click(async event => {
this.vueDetaillee = !this.vueDetaillee
this.render({ force: true })
})
// Revel listeners (was base-actor-reve-sheet.js)
this.html.find(".button-encaissement").click(async event => await this.actor.encaisser())
this.html.find(".roll-carac").click(async event => {
await this.actor.rollCarac(Grammar.toLowerCaseNoAccent(event.currentTarget.attributes["data-carac-name"].value))
})
this.html.find(".roll-competence").click(async event => await this.actor.rollCompetence(this._getItemId(event)))
this.html.find(".endurance-plus").click(async event => await this.actor.santeIncDec("endurance", 1))
this.html.find(".endurance-moins").click(async event => await this.actor.santeIncDec("endurance", -1))
if (game.user.isGM) {
this.html.find(".button-remise-a-neuf").click(async event => await this.actor.remiseANeuf())
this.html.find(".delete-active-effect").click(async event => await this.actor.removeEffect(this.html.find(event.currentTarget).parents(".active-effect").data("effect")))
this.html.find(".enlever-tous-effets").click(async event => await this.actor.removeEffects())
}
this.html.find(".competence-add").click(async event =>
await this.actor.createEmbeddedDocuments("Item", [{
type: ITEM_TYPES.competencecreature,
name: "Nouvelle competence",
img: "systems/foundryvtt-reve-de-dragon/icons/compcreature-serres.webp",
system: { carac_value: this.actor.getForce() },
}], { renderSheet: true })
)
this.html.find(".roll-text").click(async event => await RdDTextEditor.rollText(event, this.actor))
this.html.find(".chat-roll-text").click(async event => await RdDTextEditor.chatRollText(event))
if (this.vueDetaillee) {
this.html.find(".carac-value").change(async event => {
if (event.currentTarget.name.includes("carac.")) {
const caracName = event.currentTarget.name.replace("carac.", "")
await this.actor.updateCarac(caracName, parseInt(event.currentTarget.value))
}
})
this.html.find(".competence-value").change(async event => {
const compName = event.currentTarget.attributes.compname.value
await this.actor.updateCompetence(compName, parseInt(event.currentTarget.value))
})
}
// Sang listeners (was base-actor-sang-sheet.js)
this.html.find(".creer-blessure-legere").click(async event => await RdDItemBlessure.createBlessure(this.actor, 2))
this.html.find(".creer-blessure-grave").click(async event => await RdDItemBlessure.createBlessure(this.actor, 4))
this.html.find(".creer-blessure-critique").click(async event => await RdDItemBlessure.createBlessure(this.actor, 6))
this.html.find(".subir-blessure-contusion").click(async event => await RdDItemBlessure.applyFullBlessure(this.actor, 0))
this.html.find(".subir-blessure-legere").click(async event => await RdDItemBlessure.applyFullBlessure(this.actor, 2))
this.html.find(".subir-blessure-grave").click(async event => await RdDItemBlessure.applyFullBlessure(this.actor, 4))
this.html.find(".subir-blessure-critique").click(async event => await RdDItemBlessure.applyFullBlessure(this.actor, 6))
this.html.find(".jet-vie").click(async event => await this.actor.jetDeVie())
this.html.find(".jet-endurance").click(async event => await this._jetEndurance())
this.html.find(".vie-plus").click(async event => await this.actor.santeIncDec("vie", 1))
this.html.find(".vie-moins").click(async event => await this.actor.santeIncDec("vie", -1))
}
async _jetEndurance() {
const endurance = this.actor.getEnduranceActuelle()
const result = await this.actor.jetEndurance(endurance)
await ChatMessage.create({
content: `Jet d'Endurance : ${result.jetEndurance} / ${endurance}
<br>${this.actor.name} a ${result.sonne ? "échoué" : "réussi"} son Jet d'Endurance ${result.sonne ? "et devient Sonné" : ""}`,
whisper: ChatUtility.getOwners(this.actor),
})
}
_rechercherKeyup(event) {
const currentTarget = event.currentTarget
const nouvelleRecherche = this._optionRecherche(currentTarget)
if (this.recherche?.text != nouvelleRecherche?.text) {
this.recherche = nouvelleRecherche
if (this._timerRecherche) clearTimeout(this._timerRecherche)
this._timerRecherche = setTimeout(() => {
this._timerRecherche = undefined
this.render({ force: true })
}, 500)
}
}
_rechercheSelectArea(field) {
if (this.recherche) {
field.focus()
field.setSelectionRange(this.recherche.start, this.recherche.end)
}
}
_optionRecherche(target) {
if (!target.value?.length) return undefined
return {
text: target.value,
start: target.selectionStart,
end: target.selectionEnd,
}
}
//#endregion
//#region Drop
async _onDropItem(event, item) {
const destItemId = this.html.find(event.target)?.closest(".item").attr("data-item-id")
const previousItemIds = new Set(this.actor.items.keys())
const dropParams = await RdDSheetUtility.prepareItemDropParameters(destItemId, this.actor, { uuid: item.uuid }, this.objetVersConteneur)
if (dropParams) {
const callSuper = await this.actor.processDropItem(dropParams)
if (callSuper) {
await super._onDropItem(event, item)
}
if (destItemId && dropParams.sourceActorId !== this.actor.id) {
const container = this.actor.items.get(destItemId)
if (container?.isConteneur()) {
const dropped = [...this.actor.items].find(i => !previousItemIds.has(i.id))
if (dropped && !this.actor.findConteneur(dropped)) {
await this.actor.ajouterDansConteneur(dropped, container, () => {})
}
}
}
}
}
async _onDropActor(event, actor) {
this.actor.addSubActeur(actor)
await super._onDropActor(event, actor)
}
//#endregion
//#region Helpers
_getItemId(event) {
return RdDSheetUtility.getItemId(event)
}
_getItem(event) {
return RdDSheetUtility.getItem(event, this.actor)
}
async _onItemEdit(event) {
const item = this._getItem(event)
if (item) item.sheet.render({ force: true })
}
async _onVerifyIngredients(event) {
event.preventDefault()
const item = this._getItem(event)
if (!item || item.type !== ITEM_TYPES.recettealchimique) return
DialogVerifierIngredients.create(item, this.actor)
}
async _onLancerRecette(event) {
event.preventDefault()
const item = this._getItem(event)
if (!item || item.type !== ITEM_TYPES.recettealchimique) return
const ingredients = Misc.safeJsonParse(item.system.ingredients, [])
if (!ingredients.length) {
ui.notifications.warn("Cette recette n'a pas d'ingrédients définis.")
return
}
DialogLancerRecette.create(item, this.actor)
}
//#endregion
//#region Actions
static async _onPostToChat(event, target) {
await this.actor.postActorToChat()
}
//#endregion
//#region Item operations
async _selectObjetTypeToCreate() {
const types = this._getTypesInventaire().sort(Misc.ascending(type => Misc.typeName("Item", type)))
let content = `<span class="generic-label">Selectionnez le type d'équipement</span><select class="item-type">`
for (const typeName of types) {
content += `<option value="${typeName}">${Misc.typeName("Item", typeName)}</option>`
}
content += "</select>"
new foundry.applications.api.DialogV2({
title: "Créer un équipement",
content,
buttons: [
{ action: "create", label: "Créer l'objet", icon: "fa-solid fa-check", callback: () => this.actor.createItem($(".item-type").val()) },
],
}).render({ force: true })
}
_getTypesInventaire() {
return RdDItem.getItemTypesInventaire()
}
async splitItem(item) {
const dialog = await DialogSplitItem.create(item, (it, split) => this._onSplitItem(it, split))
dialog.render({ force: true })
}
async _onSplitItem(item, split) {
if (split >= 1 && split < item.system.quantite) {
await item.diminuerQuantite(split)
const splitItem = foundry.utils.deepClone(item)
splitItem.system.quantite = split
await this.actor.createEmbeddedDocuments("Item", [splitItem])
}
}
vendre(item) {
item?.proposerVente(this.actor.getQuantiteDisponible(item))
}
//#endregion
}
@@ -0,0 +1,17 @@
import { TEMPLATE_DESCRIPTION } from "../../common/_module.mjs";
import { ITEM_TYPES } from "../../constants.js";
import RdDItemBaseSheet from "./common-item-sheet.mjs";
export default class RdDBlessureSheet extends RdDItemBaseSheet {
static get ITEM_TYPE() { return ITEM_TYPES.blessure; }
static get TEMPLATES() { return [TEMPLATE_DESCRIPTION]; }
static DEFAULT_OPTIONS = Object.assign({},
RdDItemBaseSheet.DEFAULT_OPTIONS,
{ classes: ["fvtt-rdd", "item", "blessure"], position: { width: 448 }, window: { contentClasses: ["blessure-content"] } });
static PARTS = {
main: { template: "systems/foundryvtt-reve-de-dragon/templates/sheets/item/blessure.hbs" },
};
}
@@ -0,0 +1,23 @@
import { TEMPLATE_DESCRIPTION } from "../../common/_module.mjs";
import { ITEM_TYPES } from "../../constants.js";
import RdDItemBaseSheet from "./common-item-sheet.mjs";
export default class RdDCaseTMRSheet extends RdDItemBaseSheet {
static get ITEM_TYPE() { return ITEM_TYPES.casetmr; }
static get TEMPLATES() { return [TEMPLATE_DESCRIPTION]; }
static DEFAULT_OPTIONS = Object.assign({},
RdDItemBaseSheet.DEFAULT_OPTIONS,
{
classes: ["fvtt-rdd", "item", "casetmr"],
position: { width: 448 },
window: { contentClasses: ["casetmr-content"] },
});
static PARTS = {
main: {
template: "systems/foundryvtt-reve-de-dragon/templates/sheets/item/casetmr.hbs",
},
};
}
@@ -0,0 +1,26 @@
import { TEMPLATE_DESCRIPTION } from "../../common/_module.mjs";
import { ITEM_TYPES } from "../../constants.js";
import RdDItemBaseSheet from "./common-item-sheet.mjs";
import { CommonAppreciable } from "../../common/appreciable.mjs";
const TEMPLATE_APPRECIABLE = new CommonAppreciable();
export default class RdDChantSheet extends RdDItemBaseSheet {
static get ITEM_TYPE() { return ITEM_TYPES.chant; }
static get TEMPLATES() { return [TEMPLATE_DESCRIPTION, TEMPLATE_APPRECIABLE]; }
static DEFAULT_OPTIONS = Object.assign({},
RdDItemBaseSheet.DEFAULT_OPTIONS,
{
classes: ["fvtt-rdd", "item", "chant"],
position: { width: 448 },
window: { contentClasses: ["chant-content"] },
});
static PARTS = {
main: {
template: "systems/foundryvtt-reve-de-dragon/templates/sheets/item/chant.hbs",
},
};
}
@@ -0,0 +1,52 @@
import { RdDBaseActorSheetV2 } from "./base-actor-sheet.mjs"
import { RdDItem } from "../../item.js"
import { ACTOR_TYPES } from "../../constants.js"
export class RdDCommerceSheetV2 extends RdDBaseActorSheetV2 {
static TYPE = ACTOR_TYPES.commerce
static DEFAULT_OPTIONS = Object.assign({}, RdDBaseActorSheetV2.DEFAULT_OPTIONS, {
position: { width: 600, height: 720 },
})
static PARTS = {
form: { template: "systems/foundryvtt-reve-de-dragon/templates/actor/commerce-actor-sheet.hbs" },
}
get title() {
if (this.actor.token && this.actor.token !== this.actor.prototypeToken) {
return this.actor.token.name
}
return super.title
}
async _prepareContext() {
const ctx = await super._prepareContext()
if (this.actor.token && this.actor.token !== this.actor.prototypeToken) {
foundry.utils.mergeObject(ctx, {
title: this.actor.token.name,
token: { img: this.actor.token.texture.src },
}, { overwrite: true })
}
return ctx
}
async _onRender(context, options) {
await super._onRender(context, options)
if (!this.isEditable) return
this.html.find("input.item-quantite").change(async event => {
const newQuantite = Math.max(0, Number.parseInt(this.html.find(event.currentTarget).val()))
await this._getItem(event)?.update({ "system.quantite": newQuantite })
})
this.html.find("input.item-cout").change(async event => {
const newCout = Math.max(0, Number(this.html.find(event.currentTarget).val()))
await this._getItem(event)?.update({ "system.cout": newCout })
})
}
_getTypesInventaire() {
return RdDItem.getItemTypesInventaire("all")
}
}
@@ -18,7 +18,7 @@ export default class RdDItemBaseSheet extends HandlebarsApplicationMixin(foundry
static register(sheetClass) {
const itemType = sheetClass.ITEM_TYPE
Items.registerSheet(SYSTEM_RDD, sheetClass, {
foundry.documents.collections.Items.registerSheet(SYSTEM_RDD, sheetClass, {
label: Misc.typeName('Item', itemType),
types: [itemType],
makeDefault: true
@@ -63,13 +63,15 @@ export default class RdDItemBaseSheet extends HandlebarsApplicationMixin(foundry
resizable: true,
},
actions: {
editImage: RdDItemBaseSheet.#onEditImage,
editImage: RdDItemBaseSheet._onEditImage,
postToChat: RdDItemBaseSheet._onPostToChat,
proposerVente: RdDItemBaseSheet._onProposerVente,
}
}
/** @override */
async _prepareContext() {
return {
const ctx = {
item: this.document,
options: RdDSheetUtility.getOptions(this.document, this.isEditable),
fields: this.document.schema.fields,
@@ -77,7 +79,12 @@ export default class RdDItemBaseSheet extends HandlebarsApplicationMixin(foundry
system: this.document.system,
source: this.document.toObject(),
isEditable: this.isEditable,
canVendre: this.document.isInventaire?.() && this.document.isVideOuNonConteneur?.(),
}
for (const tpl of this.constructor.TEMPLATES) {
Object.assign(ctx, await tpl.prepareContext(this.document))
}
return ctx
}
// #region Actions
@@ -91,7 +98,7 @@ export default class RdDItemBaseSheet extends HandlebarsApplicationMixin(foundry
* @returns {Promise}
* @private
*/
static async #onEditImage(event, target) {
static async _onEditImage(event, target) {
const attr = target.dataset.edit
const current = foundry.utils.getProperty(this.document, attr)
const { img } = this.document.constructor.getDefaultArtwork?.(this.document.toObject()) ?? {}
@@ -107,5 +114,40 @@ export default class RdDItemBaseSheet extends HandlebarsApplicationMixin(foundry
})
return fp.browse()
}
static async _onPostToChat(event, target) {
await this.document.postItemToChat()
}
static async _onProposerVente(event, target) {
await this.document.proposerVente(1)
}
/** @override */
async _renderFrame(options) {
const frame = await super._renderFrame(options)
const header = frame.querySelector(".window-header")
if (header) {
const closeBtn = header.querySelector("button[data-action=close]")
const chatBtn = document.createElement("button")
chatBtn.type = "button"
chatBtn.className = "header-control icon fa-solid fa-comment"
chatBtn.dataset.action = "postToChat"
chatBtn.dataset.tooltip = "Poster dans le chat"
chatBtn.ariaLabel = "Poster dans le chat"
header.insertBefore(chatBtn, closeBtn)
if (this.document.isInventaire?.() && this.document.isVideOuNonConteneur?.()) {
const sellBtn = document.createElement("button")
sellBtn.type = "button"
sellBtn.className = "header-control icon fa-solid fa-comments-dollar"
sellBtn.dataset.action = "proposerVente"
sellBtn.dataset.tooltip = "Proposer à la vente"
sellBtn.ariaLabel = "Proposer à la vente"
header.insertBefore(sellBtn, chatBtn)
}
}
return frame
}
// #endregion
}
@@ -0,0 +1,17 @@
import { TEMPLATE_DESCRIPTION } from "../../common/_module.mjs";
import { ITEM_TYPES } from "../../constants.js";
import RdDItemBaseSheet from "./common-item-sheet.mjs";
export default class RdDCompetenceSheet extends RdDItemBaseSheet {
static get ITEM_TYPE() { return ITEM_TYPES.competence; }
static get TEMPLATES() { return [TEMPLATE_DESCRIPTION]; }
static DEFAULT_OPTIONS = Object.assign({},
RdDItemBaseSheet.DEFAULT_OPTIONS,
{ classes: ["fvtt-rdd", "item", "competence"], position: { width: 448 }, window: { contentClasses: ["competence-content"] } });
static PARTS = {
main: { template: "systems/foundryvtt-reve-de-dragon/templates/sheets/item/competence.hbs" },
};
}
@@ -0,0 +1,17 @@
import { TEMPLATE_DESCRIPTION } from "../../common/_module.mjs";
import { ITEM_TYPES } from "../../constants.js";
import RdDItemBaseSheet from "./common-item-sheet.mjs";
export default class RdDCompetenceCreatureSheet extends RdDItemBaseSheet {
static get ITEM_TYPE() { return ITEM_TYPES.competencecreature; }
static get TEMPLATES() { return [TEMPLATE_DESCRIPTION]; }
static DEFAULT_OPTIONS = Object.assign({},
RdDItemBaseSheet.DEFAULT_OPTIONS,
{ classes: ["fvtt-rdd", "item", "competencecreature"], position: { width: 448 }, window: { contentClasses: ["competencecreature-content"] } });
static PARTS = {
main: { template: "systems/foundryvtt-reve-de-dragon/templates/sheets/item/competencecreature.hbs" },
};
}
@@ -0,0 +1,31 @@
import { TEMPLATE_DESCRIPTION, TEMPLATE_INVENTAIRE } from "../../common/_module.mjs";
import { ITEM_TYPES } from "../../constants.js";
import RdDItemBaseSheet from "./common-item-sheet.mjs";
export default class RdDConteneurSheet extends RdDItemBaseSheet {
static get ITEM_TYPE() { return ITEM_TYPES.conteneur; }
static get TEMPLATES() { return [TEMPLATE_DESCRIPTION, TEMPLATE_INVENTAIRE]; }
static DEFAULT_OPTIONS = Object.assign({},
RdDItemBaseSheet.DEFAULT_OPTIONS,
{
classes: ["fvtt-rdd", "item", "conteneur"],
position: { width: 448 },
window: { contentClasses: ["conteneur-content"] },
});
static PARTS = {
main: {
template: "systems/foundryvtt-reve-de-dragon/templates/sheets/item/conteneur.hbs",
},
};
async _prepareContext() {
return Object.assign(
await super._prepareContext(),
{
actorId: this.document.parent?.id,
}
);
}
}
@@ -0,0 +1,33 @@
import { RdDBaseActorSheetV2 } from "./base-actor-sheet.mjs"
import { ACTOR_TYPES } from "../../constants.js"
export class RdDCreatureSheetV2 extends RdDBaseActorSheetV2 {
static TYPE = ACTOR_TYPES.creature
static DEFAULT_OPTIONS = Object.assign({}, RdDBaseActorSheetV2.DEFAULT_OPTIONS, {
position: { width: 640, height: 720 },
})
static PARTS = {
form: { template: "systems/foundryvtt-reve-de-dragon/templates/actor-creature-sheet.hbs" },
}
async _onRender(context, options) {
await super._onRender(context, options)
if (!this.isEditable) return
this.html.find(".creature-carac").change(async event => {
const compName = event.currentTarget.attributes.compname.value
await this.actor.updateCreatureCompetence(compName, "carac_value", parseInt(event.target.value))
})
this.html.find(".creature-niveau").change(async event => {
const compName = event.currentTarget.attributes.compname.value
await this.actor.updateCreatureCompetence(compName, "niveau", parseInt(event.target.value))
})
this.html.find(".creature-dommages").change(async event => {
const compName = event.currentTarget.attributes.compname.value
await this.actor.updateCreatureCompetence(compName, "dommages", parseInt(event.target.value))
})
}
}
@@ -0,0 +1,34 @@
import { TEMPLATE_DESCRIPTION } from "../../common/_module.mjs";
import { ITEM_TYPES } from "../../constants.js";
import RdDItemBaseSheet from "./common-item-sheet.mjs";
import { CommonAppreciable } from "../../common/appreciable.mjs";
const TEMPLATE_APPRECIABLE = new CommonAppreciable();
export default class RdDDanseSheet extends RdDItemBaseSheet {
static get ITEM_TYPE() { return ITEM_TYPES.danse; }
static get TEMPLATES() { return [TEMPLATE_DESCRIPTION, TEMPLATE_APPRECIABLE]; }
static DEFAULT_OPTIONS = Object.assign({},
RdDItemBaseSheet.DEFAULT_OPTIONS,
{
classes: ["fvtt-rdd", "item", "danse"],
position: { width: 448 },
window: { contentClasses: ["danse-content"] },
});
static PARTS = {
main: {
template: "systems/foundryvtt-reve-de-dragon/templates/sheets/item/danse.hbs",
},
};
async _prepareContext() {
return Object.assign(
await super._prepareContext(),
{
typeChoices: { recreative: "Récreative", soliste: "Soliste" },
}
);
}
}
@@ -0,0 +1,17 @@
import { TEMPLATE_DESCRIPTION } from "../../common/_module.mjs";
import { ITEM_TYPES } from "../../constants.js";
import RdDItemBaseSheet from "./common-item-sheet.mjs";
export default class RdDEmpoignadeSheet extends RdDItemBaseSheet {
static get ITEM_TYPE() { return ITEM_TYPES.empoignade; }
static get TEMPLATES() { return [TEMPLATE_DESCRIPTION]; }
static DEFAULT_OPTIONS = Object.assign({},
RdDItemBaseSheet.DEFAULT_OPTIONS,
{ classes: ["fvtt-rdd", "item", "empoignade"], position: { width: 448 }, window: { contentClasses: ["empoignade-content"] } });
static PARTS = {
main: { template: "systems/foundryvtt-reve-de-dragon/templates/sheets/item/empoignade.hbs" },
};
}
@@ -0,0 +1,81 @@
import { RdDBaseActorSheetV2 } from "./base-actor-sheet.mjs"
import { RdDSheetUtility } from "../../rdd-sheet-utility.js"
import { RdDUtility } from "../../rdd-utility.js"
import { DialogSelect } from "../../dialog-select.js"
import { ACTOR_TYPES } from "../../constants.js"
export class RdDActorEntiteSheetV2 extends RdDBaseActorSheetV2 {
static TYPE = ACTOR_TYPES.entite
static DEFAULT_OPTIONS = Object.assign({}, RdDBaseActorSheetV2.DEFAULT_OPTIONS, {
position: { width: 640, height: 720 },
})
static PARTS = {
form: { template: "systems/foundryvtt-reve-de-dragon/templates/actor-entite-sheet.hbs" },
}
async _prepareContext() {
const ctx = await super._prepareContext()
ctx.niveau = this.actor.getNiveau()
const { niveau: _, ...caracRest } = ctx.system.carac
ctx.system = { ...ctx.system, carac: caracRest }
ctx.resonances = this.actor.system.sante.resonnance.actors
.map(actorId => game.actors.get(actorId))
.filter(actor => actor != undefined)
.map(actor => ({ id: actor.id, name: actor.name, img: actor.img }))
return ctx
}
async _onRender(context, options) {
await super._onRender(context, options)
if (!this.isEditable) return
this.html.find(".creature-carac").change(async event => {
const compName = event.currentTarget.attributes.compname.value
await this.actor.updateCreatureCompetence(compName, "carac_value", parseInt(event.target.value))
})
this.html.find(".creature-dommages").change(async event => {
const compName = event.currentTarget.attributes.compname.value
await this.actor.updateCreatureCompetence(compName, "dommages", parseInt(event.target.value))
})
this.html.find(".resonance-add").click(async event =>
await DialogSelect.select({
label: "Choisir un acteur à accorder",
list: game.actors.filter(it => true),
},
it => this._resonanceAdd(it.id))
)
this.html.find(".resonance-delete").click(async event => {
const li = RdDSheetUtility.getEventElement(event)
const actorId = li.data("actor-id")
if (actorId) {
const actorResonance = game.actors.get(actorId)
RdDUtility.confirmSubActeurDelete(this, actorResonance, li, () => {
this._resonanceDelete(actorId)
RdDUtility.slideOnDelete(this, li)
})
}
})
}
async _onDropActor(event, dragData) {
const dropActor = fromUuidSync(dragData.uuid)
await this.actor.setEntiteReveAccordee(dropActor)
await super._onDropActor(event, dragData)
}
async _resonanceAdd(actorId) {
const newResonances = [...this.actor.system.sante.resonnance.actors, actorId]
await this.actor.update({ "system.sante.resonnance.actors": newResonances })
}
async _resonanceDelete(actorId) {
console.log("Delete : ", actorId)
const newResonances = this.actor.system.sante.resonnance.actors.filter(id => id !== actorId)
await this.actor.update({ "system.sante.resonnance.actors": newResonances }, { render: false })
}
}
@@ -0,0 +1,118 @@
import { RdDActorSheetV2 } from "./personnage-sheet.mjs"
import { SYSTEM_RDD } from "../../constants.js"
import { Misc } from "../../misc.js"
import { EXPORT_CSV_SCRIPTARIUM, OptionsAvancees } from "../../settings/options-avancees.js"
import { ExportScriptarium } from "../../actor/export-scriptarium/export-scriptarium.js"
import { CATEGORIES_COMPETENCES_BASE, CATEGORIES_DRACONIC, Mapping } from "../../actor/export-scriptarium/mapping.js"
export class RdDActorExportSheetV2 extends RdDActorSheetV2 {
static TYPE = "personnage"
static DEFAULT_OPTIONS = Object.assign({}, RdDActorSheetV2.DEFAULT_OPTIONS, {
position: { width: 550 },
})
static PARTS = {
form: { template: "systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/actor-encart-sheet.hbs" },
}
showCompNiveauBase = false
vueArchetype = false
static async init() {
await foundry.applications.handlebars.loadTemplates([
"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/arme.hbs",
"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/arme-titre.hbs",
"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/blessure.hbs",
"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/blessures.hbs",
"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/carac.hbs",
"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/carac-compteur.hbs",
"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/carac-derivee.hbs",
"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/carac-derivee-compteur.hbs",
"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/competences.hbs",
"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/esquive.hbs",
"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/fatigue.hbs",
"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/protection.hbs",
"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/sort.hbs",
])
}
static register() {
foundry.documents.collections.Actors.registerSheet(SYSTEM_RDD, this, {
types: ["personnage"],
makeDefault: false,
label: "Feuille simplifiée",
})
}
async _prepareContext() {
const ctx = await super._prepareContext()
ctx.context = Mapping.prepareContext(this.actor)
ctx.attaques = this.actor.listActionsAttaque()
ctx.export = this._getMappingValues(ctx.context, this.actor)
ctx.competences = this._getCompetences(CATEGORIES_COMPETENCES_BASE)
ctx.draconic = this._getCompetences(CATEGORIES_DRACONIC)
const legeres = this.actor.countBlessures(it => it.isLegere())
const graves = this.actor.countBlessures(it => it.isGrave())
const critiques = this.actor.countBlessures(it => it.isCritique())
ctx.etat = {
surenc: this.actor.computeMalusSurEncombrement(),
fatigue: {
value: this.actor.getFatigueActuelle(),
max: this.actor.getFatigueMax(),
malus: this.actor.malusFatigue(),
},
blessures: legeres + graves + critiques,
blessure: [legeres > 0, legeres > 1, legeres > 2, legeres > 3, legeres > 4, graves > 0, graves > 1, critiques > 0],
}
ctx.options.exportScriptarium = OptionsAvancees.isUsing(EXPORT_CSV_SCRIPTARIUM)
return ctx
}
_getMappingValues(context, actor) {
return Object.fromEntries(Mapping.getMapping().map(it => [it.column, {
colName: it.colName ?? it.column,
column: it.column,
rollClass: it.rollClass,
value: String(it.getter(actor, context)),
}]))
}
_getCompetences(categories) {
const competences = Mapping.getCompetencesCategorie(this.actor, categories)
if (competences.length == 0) return ""
const byCategories = Mapping.competencesByCategoriesByNiveau(competences, categories)
const listByCategories = Object.values(byCategories)
.map(it => it.competencesParNiveau)
.map(byNiveau => {
const niveaux = Object.keys(byNiveau).map(it => Number(it)).sort(Misc.ascending())
if (niveaux.length == 0) return undefined
const listCategorieByNiveau = niveaux.map(niveau => {
const list = byNiveau[niveau].sort(Misc.ascending(it => it.name))
return { niveau, list }
})
return Misc.concat(listCategorieByNiveau)
}).filter(it => it != undefined)
return Misc.concat(listByCategories)
}
async _onRender(context, options) {
await super._onRender(context, options)
this.html.find(".click-blessure-remove").click(async event =>
await this.actor.supprimerBlessure({
gravite: this.html.find(event.currentTarget).data("gravite"),
})
)
this.html.find(".click-blessure-add").click(async event => {
const blessure = this.actor.nouvelleBlessure(this.html.find(event.currentTarget).data("gravite"))
await this.actor.createEmbeddedDocuments("Item", [blessure])
})
this.html.find(".button-export").click(async event => await
ExportScriptarium.INSTANCE.exportActors([this.actor],
`${this.actor.uuid}-${this.actor.name}`
)
)
}
}
@@ -0,0 +1,21 @@
import { ITEM_TYPES } from "../../constants.js";
import RdDItemBaseSheet from "./common-item-sheet.mjs";
export default class RdDExtraitPoetiqueSheet extends RdDItemBaseSheet {
static get ITEM_TYPE() { return ITEM_TYPES.extraitpoetique; }
static get TEMPLATES() { return []; }
static DEFAULT_OPTIONS = Object.assign({},
RdDItemBaseSheet.DEFAULT_OPTIONS,
{
classes: ["fvtt-rdd", "item", "extraitpoetique"],
position: { width: 448 },
window: { contentClasses: ["extraitpoetique-content"] },
});
static PARTS = {
main: {
template: "systems/foundryvtt-reve-de-dragon/templates/sheets/item/extraitpoetique.hbs",
},
};
}
@@ -0,0 +1,23 @@
import { TEMPLATE_DESCRIPTION, TEMPLATE_INVENTAIRE, TEMPLATE_COMESTIBLE } from "../../common/_module.mjs";
import { ITEM_TYPES } from "../../constants.js";
import RdDItemBaseSheet from "./common-item-sheet.mjs";
export default class RdDFauneSheet extends RdDItemBaseSheet {
static get ITEM_TYPE() { return ITEM_TYPES.faune; }
static get TEMPLATES() { return [TEMPLATE_DESCRIPTION, TEMPLATE_INVENTAIRE, TEMPLATE_COMESTIBLE]; }
static DEFAULT_OPTIONS = Object.assign({},
RdDItemBaseSheet.DEFAULT_OPTIONS,
{
classes: ["fvtt-rdd", "item", "faune"],
position: { width: 448 },
window: { contentClasses: ["faune-content"] },
});
static PARTS = {
main: {
template: "systems/foundryvtt-reve-de-dragon/templates/sheets/item/faune.hbs",
},
};
}
@@ -0,0 +1,64 @@
import { TEMPLATE_DESCRIPTION, TEMPLATE_INVENTAIRE } from "../../common/_module.mjs";
import { ITEM_TYPES } from "../../constants.js";
import { RdDItemGemme } from "../../item/gemme.js";
import { RdDTimestamp } from "../../time/rdd-timestamp.js";
import RdDItemBaseSheet from "./common-item-sheet.mjs";
export default class RdDGemmeSheet extends RdDItemBaseSheet {
static get ITEM_TYPE() { return ITEM_TYPES.gemme; }
static get TEMPLATES() { return [TEMPLATE_DESCRIPTION, TEMPLATE_INVENTAIRE]; }
static DEFAULT_OPTIONS = Object.assign({},
RdDItemBaseSheet.DEFAULT_OPTIONS,
{
classes: ["fvtt-rdd", "item", "gemme"],
position: { width: 448 },
window: { contentClasses: ["gemme-content"] },
actions: {
enchanter: RdDGemmeSheet.#onEnchanter,
},
});
static PARTS = {
main: {
template: "systems/foundryvtt-reve-de-dragon/templates/sheets/item/gemme.hbs",
},
};
async _prepareContext() {
const item = this.document
const enchantement = RdDTimestamp.splitIndexDate(item.system.prdate)
return Object.assign(
await super._prepareContext(),
{
gemmeTypeList: RdDItemGemme.getGemmeTypeOptionList(),
isEnchantementPossible: item.isEnchantementPossible,
dateActuelle: game.system.rdd.calendrier.dateCourante(),
enchantement,
}
);
}
_onChangeForm(event, formData) {
const obj = formData?.object
if (!obj) return super._onChangeForm(event, formData)
if (event.target?.classList?.contains('date-enchantement')) {
const jour = Number(this.element?.querySelector('input.date-enchantement[name="enchantement.jour"]')?.value)
const moisEl = this.element?.querySelector('select.date-enchantement[name="enchantement.mois"]')
if (moisEl) {
const mois = RdDTimestamp.definition(moisEl.value)
const indexDate = game.system.rdd.calendrier.getIndexFromDate(jour, mois.heure)
obj['system.prdate'] = indexDate
delete obj['enchantement.jour']
delete obj['enchantement.mois']
}
}
return super._onChangeForm(event, formData)
}
static async #onEnchanter(event, target) {
const { DialogEnchanter } = await import("../../enchantement/dialog-enchanter.js")
DialogEnchanter.enchanter(this.document)
}
}
@@ -0,0 +1,42 @@
import { TEMPLATE_DESCRIPTION, TEMPLATE_INVENTAIRE, TEMPLATE_COMESTIBLE } from "../../common/_module.mjs";
import { ITEM_TYPES } from "../../constants.js";
import RdDItemBaseSheet from "./common-item-sheet.mjs";
export default class RdDHerbeSheet extends RdDItemBaseSheet {
static get ITEM_TYPE() { return ITEM_TYPES.herbe; }
static get TEMPLATES() { return [TEMPLATE_DESCRIPTION, TEMPLATE_INVENTAIRE, TEMPLATE_COMESTIBLE]; }
static DEFAULT_OPTIONS = Object.assign({},
RdDItemBaseSheet.DEFAULT_OPTIONS,
{
classes: ["fvtt-rdd", "item", "herbe"],
position: { width: 448 },
window: { contentClasses: ["herbe-content"] },
});
static PARTS = {
main: {
template: "systems/foundryvtt-reve-de-dragon/templates/sheets/item/herbe.hbs",
},
};
async _prepareContext() {
const ctx = await super._prepareContext()
ctx.isBrut = this.document.getUtilisationCuisine() === 'brut'
return ctx
}
async _onRender(context, options) {
await super._onRender(context, options)
this.element.querySelector('.preparer-nourriture')?.addEventListener('click', async () => {
const actor = this.document.parent
if (actor) await actor.preparerNourriture(this.document)
})
this.element.querySelector('.manger-nourriture')?.addEventListener('click', async () => {
const actor = this.document.parent
if (actor) await actor.mangerNourriture(this.document)
})
}
}
@@ -0,0 +1,42 @@
import { TEMPLATE_DESCRIPTION, TEMPLATE_INVENTAIRE, TEMPLATE_COMESTIBLE } from "../../common/_module.mjs";
import { ITEM_TYPES } from "../../constants.js";
import RdDItemBaseSheet from "./common-item-sheet.mjs";
export default class RdDIngredientSheet extends RdDItemBaseSheet {
static get ITEM_TYPE() { return ITEM_TYPES.ingredient; }
static get TEMPLATES() { return [TEMPLATE_DESCRIPTION, TEMPLATE_INVENTAIRE, TEMPLATE_COMESTIBLE]; }
static DEFAULT_OPTIONS = Object.assign({},
RdDItemBaseSheet.DEFAULT_OPTIONS,
{
classes: ["fvtt-rdd", "item", "ingredient"],
position: { width: 448 },
window: { contentClasses: ["ingredient-content"] },
});
static PARTS = {
main: {
template: "systems/foundryvtt-reve-de-dragon/templates/sheets/item/ingredient.hbs",
},
};
async _prepareContext() {
const ctx = await super._prepareContext()
ctx.isBrut = this.document.getUtilisationCuisine() === 'brut'
return ctx
}
async _onRender(context, options) {
await super._onRender(context, options)
this.element.querySelector('.preparer-nourriture')?.addEventListener('click', async () => {
const actor = this.document.parent
if (actor) await actor.preparerNourriture(this.document)
})
this.element.querySelector('.manger-nourriture')?.addEventListener('click', async () => {
const actor = this.document.parent
if (actor) await actor.mangerNourriture(this.document)
})
}
}
+34
View File
@@ -0,0 +1,34 @@
import { TEMPLATE_DESCRIPTION } from "../../common/_module.mjs";
import { ITEM_TYPES } from "../../constants.js";
import RdDItemBaseSheet from "./common-item-sheet.mjs";
import { CommonAppreciable } from "../../common/appreciable.mjs";
const TEMPLATE_APPRECIABLE = new CommonAppreciable();
export default class RdDJeuSheet extends RdDItemBaseSheet {
static get ITEM_TYPE() { return ITEM_TYPES.jeu; }
static get TEMPLATES() { return [TEMPLATE_DESCRIPTION, TEMPLATE_APPRECIABLE]; }
static DEFAULT_OPTIONS = Object.assign({},
RdDItemBaseSheet.DEFAULT_OPTIONS,
{
classes: ["fvtt-rdd", "item", "jeu"],
position: { width: 448 },
window: { contentClasses: ["jeu-content"] },
});
static PARTS = {
main: {
template: "systems/foundryvtt-reve-de-dragon/templates/sheets/item/jeu.hbs",
},
};
async _prepareContext() {
return Object.assign(
await super._prepareContext(),
{
typeChoices: { adressehasard: "Adresse/Hasard", de: "Dés", carte: "Cartes", reflexion: "Réflexion" },
}
);
}
}

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