diff --git a/.eslintrc.js b/.eslintrc.js index 6ec7574..73e50f3 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -144,7 +144,7 @@ module.exports = { 'no-lone-blocks': 'warn', 'no-lonely-if': 'warn', 'no-loop-func': 'warn', - 'no-magic-numbers': ['warn', { ignore: [0, 1, 2], ignoreEnums: true, ignoreNumericLiteralTypes: true, ignoreArrayIndexes: true }], + '@typescript-eslint/no-magic-numbers': 'off', 'no-multi-assign': 'warn', 'no-multi-str': 'warn', 'no-negated-condition': 'warn', @@ -208,7 +208,7 @@ module.exports = { 'one-var': ['warn', 'never'], 'one-var-declaration-per-line': ['warn', 'initializations'], 'operator-assignment': ['warn', 'always'], - 'prefer-arrow-callback': ['warn', { classPropertiesAllowed: true, disallowTLSClassFields: true }], + 'prefer-arrow-callback': 'warn', 'prefer-const': ['error', { destructuring: 'all', ignoreReadBeforeAssign: false }], 'prefer-destructuring': ['warn', { array: false, object: true }], 'prefer-exponentiation-operator': 'warn', @@ -221,7 +221,7 @@ module.exports = { 'prefer-rest-params': 'warn', 'prefer-spread': 'warn', 'prefer-template': 'warn', - 'quote-props': ['warn', 'as-needed', { keywords: true, unnecessaryQuote: false, numbers: true }], + 'quote-props': ['warn', 'as-needed'], 'radix': ['error', 'always'], 'require-await': 'warn', 'require-unicode-regexp': 'off', @@ -313,7 +313,7 @@ module.exports = { 'padded-blocks': ['warn', 'never'], 'padding-line-between-statements': 'off', 'prefer-exponentiation-operator': 'warn', - 'quote-props': ['warn', 'as-needed', { keywords: true, unnecessaryQuote: false, numbers: true }], + 'quote-props': ['warn', 'as-needed'], 'quotes': ['warn', 'single', { avoidEscape: true, allowTemplateLiterals: true }], 'rest-spread-spacing': ['warn', 'never'], 'semi': ['warn', 'always'], diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 0463e6e..16e226d 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -2,6 +2,8 @@ ## Build & Development +Requires Node.js v16.15.1 (see `.nvmrc`). + ```bash npm run watch # Watch SCSS + templates, proxy Foundry at localhost:30000 (requires Foundry running) npm run buildStyle # Compile SCSS once to css/vermine2047.css @@ -10,7 +12,7 @@ npm run pushLDBtoYAML # Extract LevelDB packs to editable YAML in src/packs/ npx eslint module/ # Lint JavaScript (ESLint configured in .eslintrc.js) ``` -There are no automated tests. Use `npm run watch` during development to live-reload SCSS and Handlebars templates via browser-sync. +There are no automated tests. Use `npm run watch` during development — browser-sync proxies Foundry over HTTPS and live-reloads SCSS, `.hbs`, and `.html` templates on change. `system.json` declares `hotReload` for `.css`, `.scss`, `.hbs`, and `.json` extensions, so Foundry auto-refreshes those assets client-side when the dev server is running. ## Architecture @@ -27,6 +29,7 @@ This is a **FoundryVTT game system** (`system.json` → system ID `vermine2047`) |---|---| | `config.mjs` | All game constants (`CONFIG.VERMINE`) — abilities, skills, totems, threat/role/pattern levels, traits, damage types | | `roll.mjs` | `VermineUtils` class — d10 dice pool system with success counting, totem mechanics, rerolls, Dice So Nice integration | +| `dice3d.mjs` | Dice So Nice 3D dice configuration (appearance, colors, themes for totem/standard dice) | | `fight.mjs` | Confrontation system (`VermineFight`), plus `VermineCombat`, `VermineCombatant`, `VermineCombatTracker` | | `group-link.mjs` | `GroupLink` — bidirectional sync of members/encounters between group actors and character/NPC actors via Foundry hooks | | `hooks.mjs` | All Foundry hook registrations (chat messages, hotbar drop, combat, preCreate, Dice So Nice) | @@ -34,21 +37,27 @@ This is a **FoundryVTT game system** (`system.json` → system ID `vermine2047`) | `handlebars-manager.mjs` | Template preloading paths + all Handlebars helpers (level config lookups, math, conditionals) | | `effects.mjs` | Active effect management | | `dialogs/rollDialog.mjs` | Advanced roll dialog (ability/skill selection, difficulty, totems, specialties, assist/pool bonuses) | -| `applications.mjs` | `TotemPicker` and `TraitSelector` applications | +| `applications.mjs` | `TotemPicker` and `TraitSelector` applications (still AppV1) | +| `applications/sheets/` | ApplicationV2 sheet classes: `base-actor-sheet.mjs`, `base-item-sheet.mjs` + 4 actor + 12 item sheets | -**Data model**: `template.json` defines the Actor/Item schemas (Foundry's template system). Derived data is computed in `prepareDerivedData()` in `module/documents/actor.mjs` and `module/documents/item.mjs`. +**Data model**: Defined via Foundry DataModels (`module/models/`) extending `foundry.abstract.TypeDataModel`. Type-specific derived data is computed in each DataModel's `prepareDerivedData()`. The legacy `template.json` has been removed in favor of `system.json` → `documentTypes`. -**Sheet inheritance**: `VermineActorSheet` (base) → `VermineCharacterSheet`, `VermineNpcSheet`, `VermineGroupSheet`, `VermineCreatureSheet`. Sheets expose `CONFIG.VERMINE` as `context.config` in template data. +**Sheet inheritance**: ApplicationV2 (`HandlebarsApplicationMixin(ActorSheetV2)`/`ItemSheetV2`) in `module/applications/sheets/`. `VermineBaseActorSheet` → `VermineCharacterSheetV2`, etc. Sheets expose `CONFIG.VERMINE` as `context.config` in template data. Each sheet is split into parts via `static PARTS`; tab navigation uses Core's `templates/generic/tab-navigation.hbs`. + +**Data preparation**: `VermineActor.prepareDerivedData()` delegates to the type-specific DataModel. Each DataModel implements its own `prepareDerivedData()` with type-specific computation logic. + +**Global access**: On `init`, `game.vermine2047` is populated with `{ VermineActor, VermineItem, VermineUtils, VermineCombat, GroupLink }` for easy access in macros and scripts. **Compendium packs**: Stored in `packs/` as LevelDB databases. Edit source data in `src/packs/` as YAML, then `npm run pullYAMLtoLDB` to build. The CI release workflow runs this automatically. ## Key Conventions -- **All `.mjs` files**: ES module syntax only. Foundry globals (`game`, `Hooks`, `CONFIG`, `Actor`, `Item`, `ChatMessage`, `Roll`, `Handlebars`, `renderTemplate`, `foundry`) are available but declared as readonly globals in `.eslintrc.js`. +- **All `.mjs` files**: ES module syntax only. Foundry globals (`game`, `Hooks`, `CONFIG`, `Actor`, `Item`, `ChatMessage`, `Roll`, `Handlebars`, `renderTemplate`, `foundry`, `ui`, `Canvas`, `Dialog`) are available but declared as readonly globals in `.eslintrc.js`. +- **ESLint conventions**: 2-space indent, single quotes, semicolons required, `===` equality (except `== null`). Constants named with `VERMINE_` prefix are exempt from camelCase. Max 1 class per file, 500 lines per file, 100 lines per function, 5 levels of nesting max. No `console.log` calls — use `ui.notifications`. - **Code language**: Source code and comments are in French. UI strings in `lang/fr.json` and `lang/en.json`. Use `game.i18n.localize()` for all user-visible text. -- **Template naming**: Actor sheets at `templates/actor/actor-{type}-sheet.hbs`, item sheets at `templates/item/item-{type}-sheet.html` (note: item sheets use `.html`, everything else uses `.hbs`). Chat card templates at `templates/item/chatCards/{type}.hbs`. +- **Template naming**: Actor sheets use ApplicationV2 part templates in `templates/actor/appv2/{type}-{part}.hbs` (e.g. `character-main.hbs`, `npc-characteristics.hbs`). Item sheets at `templates/item/item-{type}-sheet.html`. Chat card templates at `templates/item/chatCards/{type}.hbs`. Legacy templates in `templates/actor/` subdirectories are preserved for dialog/chat use. - **Dice system**: d10 pools with success counting (result ≥ difficulty). Totem dice (human/adapted) count double on success. Formula syntax: `{N}d10cs>={threshold}[label]`. Totem dice: `(1d10cs>={threshold}[totem_label]*2)`. -- **CSS**: SCSS sources in `scss/` compile to `css/vermine2047.css`. Organized by concern: `_app.scss`, `item-sheet.scss`, `roll.scss`, `dialog.scss`, etc. +- **CSS**: SCSS sources in `scss/` compile to `css/vermine2047.css`. Entry point: `vermine2047.scss` which imports partials: `_app.scss`, `_flex.scss`, `dialog.scss`, `item-sheet.scss`, `itemCards.scss`, `roll.scss`, `special-applications.scss`, `special-inputs.scss`, `style.scss`, `base_work.scss`. Add new SCSS partials as `_component.scss`, import in `vermine2047.scss`. - **Data tools**: The `pushLDBtoYAML` / `pullYAMLtoLDB` scripts use `@foundryvtt/foundryvtt-cli` to convert between LevelDB packs and editable YAML. When adding pack content, edit YAML in `src/packs/` then rebuild. - **Actor updates**: Use `actor.update({...})` with dot-notation paths (e.g., `'system.adaptation.totems.human.value'`). The `GroupLink` hooks system automatically syncs group memberships on actor changes. - **New template partials**: Must be listed in `preloadHandlebarsTemplates()` in `handlebars-manager.mjs` for pre-compilation. diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 430eb12..54dc6be 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -31,12 +31,16 @@ jobs: - name: Install Dependencies run: npm ci + # Build CSS from LESS + - name: Build CSS + run: npm run build:less + # Pull YAML to LDB packs - name: Build Packs run: npm run pullYAMLtoLDB # Create a zip file with all files required by the module to add to the release - - run: zip -r ./system.zip system.json template.json assets/ css/ lang/ module/ templates/ packs/ + - run: zip -r ./system.zip system.json assets/ css/ lang/ module/ templates/ packs/ # Create a release for this specific version - name: Update Release with Files diff --git a/.lesshintrc b/.lesshintrc new file mode 100644 index 0000000..6bb8fe6 --- /dev/null +++ b/.lesshintrc @@ -0,0 +1,48 @@ +{ + "atom": false, + "borderZero": { + "style": "none" + }, + "colorVariables": true, + "comment": false, + "depthLevel": 10, + "duplicateProperty": true, + "emptyRule": true, + "finalNewline": true, + "hexLength": "long", + "hexNotation": "lowercase", + "hexValidation": true, + "idSelector": false, + "important": true, + "importPath": [ + "./less" + ], + "maxCharPerLine": 120, + "newlineAfterBlock": true, + "propertyOrdering": false, + "propertyUnits": true, + "qualifyingElement": [ + "button", + "input", + "select", + "textarea" + ], + "selectorNaming": false, + "singleLinePerProperty": true, + "singleLinePerSelector": false, + "spaceAfterComma": true, + "spaceAfterComment": true, + "spaceAfterPropertyColon": "one", + "spaceAfterPropertyValue": true, + "spaceAroundCombinator": true, + "spaceAroundOperator": true, + "spaceBeforeBrace": "one", + "spaceBetweenParens": false, + "stringQuotes": "double", + "trailingSemicolon": true, + "trailingWhitespace": true, + "urlFormat": "relative", + "urlQuotes": true, + "variableNaming": false, + "zeroUnit": false +} diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..5c183c7 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,63 @@ +# AGENTS.md — Vermine2047 FoundryVTT system + +## Project + +FoundryVTT v14 game system for the French post-apocalyptic TTRPG "Vermine 2047". Bilingual FR/EN. + +- **Entrypoint**: `module/vermine2047.mjs` (declared in `system.json` esmodules) +- **CSS**: `css/vermine2047.min.css` (compiled from LESS, **not** SCSS) +- **System ID**: `vermine2047` + +## Architecture + +| Layer | Location | Notes | +|-------|----------|-------| +| Entry/init | `module/vermine2047.mjs` | `Hooks.once('init',...)` — register DataModels before Document classes | +| DataModels | `module/models/*.mjs` | FoundryV2 `TypeDataModel` — 4 Actor types, 12 Item types | +| Documents | `module/documents/*.mjs` | `VermineActor`, `VermineItem` (thin wrappers) | +| Sheets (AppV2) | `module/applications/sheets/*.mjs` | ApplicationV2 sheets per type | +| System | `module/system/*.mjs` | config, roll, fight, dialogs, hooks, settings, dice3d, group-link | +| Templates (HBS) | `templates/actor/appv2/*.hbs` | ApplicationV2 templates | +| Legacy templates | `templates/actor/*.hbs`, `templates/actor/{character,group,npc,creature}/*.hbs` | Coexisting legacy templates | + +### Actor types: character, npc, group, creature +### Item types: item, weapon, defense, vehicle, ability, specialty, background, trauma, evolution, rumor, target, rite + +Key objects at runtime: +- `game.vermine2047` → `{ VermineUtils, VermineCombat, GroupLink }` +- `CONFIG.VERMINE` → game configuration (totems, traits, skills, etc.) +- `CONFIG.ui.combat` → custom `VermineCombatTracker` + +Dice system: d10-based, success-counting (`Xd10cs>=N`). Totems give domain bonuses. Initiative formula: +`(@abilities.reflexes.value + @skills.alertness.value)d10cs>=@combatStatus.difficulty` + +## Commands + +```sh +npm run build:less # LESS → vermine2047.min.css +npm run build:less:dev # LESS → vermine2047.dev.css (unminified) +npm run build:all-css # both +npm run watch # gulp watch + browser-sync proxy to localhost:30000 +npm run lint:less # lesshint +npm run pushLDBtoYAML # extract Foundry packs → src/packs/*.yml +npm run pullYAMLtoLDB # compile src/packs/*.yml → packs/ LevelDB +make build / watch / lint # Makefile wrappers for above +``` + +- Node version required: `v16.15.1` (per `.nvmrc`) + +## Gotchas + +- **DataModels before Document classes**: In `init` hook, register `CONFIG.Actor.dataModels.*` and `CONFIG.Item.dataModels.*` **before** setting `CONFIG.Actor.documentClass` / `CONFIG.Item.documentClass`. +- **`no-console: 'error'`**: ESLint blocks `console.log/warn/info`. Use `console.error` sparingly or disable the rule inline. +- **ESLint is very verbose**: ~350 rules. Common failures: missing semicolons, trailing commas, single quotes, 2-space indent, `max-len: 120`. Run `npx eslint module/` before committing. +- **Two template systems**: Both legacy (`templates/actor/*.hbs`) and ApplicationV2 (`templates/actor/appv2/*.hbs`) are preloaded. Don't confuse them. +- **Packs in two places**: `src/packs/*.yml` (YAML source, tracked) ↔ `packs/*` (LevelDB binary, gitignored). Edit YAML source, then run `pullYAMLtoLDB` to compile. +- **CSS auto-loaded**: `system.json` declares styles; **do not** inject `` manually (causes MIME type errors). +- **`game-mode` setting**: Default in code is `'e'` (likely a typo for `'1'`). Values: `1`=Survie, `2`=Cauchemar, `3`=Apocalypse. +- **editMode flag disabled**: No auto-set on actor creation (causes ActiveEffect errors). Enable manually via sheet checkbox. +- **GroupLink auto-syncs**: `GroupLink.registerHooks()` runs on init. Actor updates propagate to groups and vice versa. +- **Custom dice**: Dice So Nice integration uses user color (regular/human/adapted color sets) with custom d10 face images. +- **No tests**: `npm test` is a stub (exits 1). No test framework installed. +- **No CI**: `.github/` is gitignored; no workflows configured. +- **HotReload**: `system.json` flags hotReload for css, scss, hbs, json extensions. diff --git a/REVISION_COMPLETE.md b/REVISION_COMPLETE.md deleted file mode 100644 index aa0f206..0000000 --- a/REVISION_COMPLETE.md +++ /dev/null @@ -1,203 +0,0 @@ -# Révision Complète des Templates Acteurs Vermine2047 - -## 📅 Date: 2026-06-04 - -## 🎯 Objectif -Réviser fichiers par fichier les templates des acteurs pour identifier et corriger les duplications et incohérences, comme demandé par l'utilisateur. - ---- - -## ✅ Corrections Effectuées - -### 1. **Corrections de Structure CSS** -- ✅ `templates/actor/parts/actor-items.hbs:77` - `grid grid-2` → `grid grid-2col` - -### 2. **Corrections des Balises HTML** -Toutes les balises `

` mal utilisées dans les listes d'items ont été remplacées par `

` : - -- ✅ `templates/actor/parts/actor-weapons.hbs:25-36` - 6 balises `

` corrigées -- ✅ `templates/actor/parts/actor-defenses.hbs:38-41` - 4 balises `

` corrigées -- ✅ `templates/actor/group/group-items.hbs:20-21` - 2 balises `

` corrigées -- ✅ `templates/actor/group/group-vehicles.hbs:22-27` - 3 balises `

` corrigées - -**Impact**: Meilleure sémantique HTML et cohérence avec le reste du codebase. - -### 3. **Corrections de Fautes de Frappe** -- ✅ `templates/actor/character/character-totem.hbs:12-16,19-23,26-30` - `smarttlk` → `smarttl` (3 occurrences) -- ✅ `templates/actor/character/character-totem.hbs:98` - `{{compétence}}` → `"Compétence"` (tooltip) - -### 4. **Corrections de Classes CSS Dupliquées** -- ✅ `templates/actor/character/character-totem.hbs:59` - `class="item-name" class="flexrow"` → `class="item-name flexrow"` - -### 5. **Corrections de Commentaires HTML** -Tous les commentaires HTML standard `` ont été convertis en commentaires Handlebars `{{!-- --}}` : - -- ✅ `templates/actor/character/character-features.hbs:1` -- ✅ `templates/actor/character/character-header.hbs:1` -- ✅ `templates/actor/group/group-header.hbs:1` -- ✅ `templates/actor/character/character-totem.hbs:30-34` - Commentaire multi-lignes simplifié -- ✅ `templates/actor/character/character-id.hbs:5` - Ajout de commentaire - -### 6. **Uniformisation des Localisations** -- ✅ `templates/actor/character/character-features.hbs:2` - `Caractéristiques` → `{{ localize 'VERMINE.abilities' }}` -- ✅ `templates/actor/character/character-features.hbs:32` - `Compétences` → `{{ localize 'VERMINE.skills' }}` - -### 7. **Suppression des Balises Orphelines** -- ✅ `templates/actor/character/character-id.hbs:112` - Suppression de `{{/if}}` orphelin - -### 8. **Optimisation des Structures Dupliquées** - -#### a) Création de Partial pour les Catégories de Compétences NPC -- ✅ **Nouveau fichier**: `templates/actor/parts/npc-skill-category.hbs` - - Partial réutilisable pour afficher une catégorie de compétences - - Accepte `categoryKey` et `categoryLabel` comme paramètres -- ✅ **Modification**: `templates/actor/actor-npc-sheet.hbs:227-297` - - Remplacement de ~150 lignes de code dupliqué par une boucle Handlebars - - Utilisation du nouveau partial pour les 6 catégories (Homme, Animal, Outil, Arme, Survie, Monde) - - **Réduction**: ~145 lignes de code - -#### b) Création de Partial Générique pour les Listes d'Items -- ✅ **Nouveau fichier**: `templates/actor/parts/item-list.hbs` - - Partial générique et réutilisable pour afficher des listes d'items - - Prend en charge: itemType, items, createType, showSkill - - Peut être utilisé pour standardiser l'affichage des listes dans character-totem.hbs et group-info.hbs - -### 9. **Correction d'Erreur JavaScript** -- ✅ `module/system/roll.mjs:365-424` - Correction de l'erreur `html.find(...).forEach is not a function` - - Problème: La fonction `chatListenners` recevait un objet jQuery ou un élément DOM, et `html.find()` échouait si `html` était un élément DOM natif - - Solution: Ajout de `const $html = $(html);` au début de la fonction - - Remplacement de toutes les occurrences de `html.` par `$html.` dans la fonction - - **Impact**: La fonction gère maintenant correctement les deux types d'entrée (jQuery object ou DOM element) - ---- - -## 📁 Fichiers Modifiés - -### Templates Principaux (4) -1. `templates/actor/actor-character-sheet.hbs` - OK -2. `templates/actor/actor-npc-sheet.hbs` - ✅ Optimisé -3. `templates/actor/actor-creature-sheet.hbs` - OK -4. `templates/actor/actor-group-sheet.hbs` - OK - -### Partials Character (6) -1. `templates/actor/character/character-features.hbs` - ✅ Corrigé -2. `templates/actor/character/character-header.hbs` - ✅ Corrigé -3. `templates/actor/character/character-id.hbs` - ✅ Corrigé -4. `templates/actor/character/character-stories.hbs` - OK -5. `templates/actor/character/character-totem.hbs` - ✅ Corrigé (multiples corrections) -6. `templates/actor/character/character-combat.hbs` - OK (à optimiser) - -### Partials Parts (7) -1. `templates/actor/parts/actor-items.hbs` - ✅ Corrigé -2. `templates/actor/parts/actor-weapons.hbs` - ✅ Corrigé -3. `templates/actor/parts/actor-defenses.hbs` - ✅ Corrigé -4. `templates/actor/parts/actor-effects.hbs` - OK -5. `templates/actor/parts/npc-skill-item.hbs` - OK -6. `templates/actor/parts/npc-skill-category.hbs` - ✅ **NOUVEAU** -7. `templates/actor/parts/item-list.hbs` - ✅ **NOUVEAU** - -### Partials Group (5) -1. `templates/actor/group/group-header.hbs` - ✅ Corrigé -2. `templates/actor/group/group-info.hbs` - ✅ Corrigé -3. `templates/actor/group/group-items.hbs` - ✅ Corrigé -4. `templates/actor/group/group-vehicles.hbs` - ✅ Corrigé -5. `templates/actor/group/group-experience.hbs` - OK - -### JavaScript (2) -1. `module/system/roll.mjs` - ✅ Correction de l'erreur html.find().forEach -2. `module/system/hooks.mjs` - OK (pas de modification nécessaire) - -### Nouveaux Fichiers Créés (2) -1. `templates/actor/parts/npc-skill-category.hbs` -2. `templates/actor/parts/item-list.hbs` - ---- - -## 📊 Statistiques - -- **Fichiers analysés**: 24 templates + 2 fichiers JS -- **Fichiers modifiés**: 16 fichiers -- **Nouveaux fichiers créés**: 3 (2 partials + 1 rapport) -- **Duplications supprimées**: 1 majeure (catégories de compétences NPC) -- **Lignes de code réduites**: ~150+ lignes -- **Problèmes corrigés**: 20+ -- **Partials créés**: 2 - ---- - -## 🔍 Problèmes Restants à Résoudre - -### 1. **Duplication des Sections de Blessures** -Les templates suivants ont des implémentations similaires pour les blessures : -- `templates/actor/character/character-combat.hbs` (lignes 108-199) -- `templates/actor/npc/npc-combat.hbs` (lignes 23-47) -- `templates/actor/creature/creature-combat.hbs` (lignes 34-66) - -**Solution recommandée**: Créer un partial `templates/actor/parts/wounds-section.hbs` pour standardiser l'affichage des blessures (minor, major, deadly). - -### 2. **Utilisation du Partial item-list.hbs** -Le partial `item-list.hbs` a été créé mais n'est pas encore utilisé. Il pourrait remplacer les duplications dans : -- `templates/actor/character/character-totem.hbs` (5 listes: abilities, specialties, backgrounds, traumas, evolutions) -- `templates/actor/group/group-info.hbs` (5 listes identiques) -- `templates/actor/group/group-experience.hbs` (1 liste) - -**Impact potentiel**: Réduction de ~200+ lignes de code dupliqué. - -### 3. **Erreurs JavaScript Restantes** -Les erreurs suivantes n'ont pas encore été investiguées : -- `vermine2047.mjs:83` - `Cannot read properties of undefined (reading 'Actor')` - Problème de timing avec `game.system.template.Actor` -- `actor.mjs:89` - `Cannot read properties of undefined (reading 'difficulty')` - Problème dans `prepareCombatStatus` - ---- - -## 📝 Rapport Complet - -Un rapport détaillé a été créé : `REVISION_TEMPLATES_RAPPORT.md` - ---- - -## 🎯 Résumé des Actions - -### ✅ Terminées -1. Correction de toutes les incohérences de syntaxe HTML/CSS -2. Suppression des duplications évidentes (catégories de compétences NPC) -3. Correction des fautes de frappe et erreurs de syntaxe -4. Uniformisation des commentaires et localisations -5. Correction de l'erreur JavaScript `html.find(...).forEach` -6. Création de 2 nouveaux partials réutilisables - -### ⏳ Recommandations pour la Suite -1. Créer un partial pour les blessures (`wounds-section.hbs`) -2. Appliquer le partial `item-list.hbs` dans les templates existants -3. Investiguer et corriger les erreurs JavaScript restantes -4. Tester tous les templates dans FoundryVTT - ---- - -## 💡 Améliorations Apportées - -### Maintenabilité -- **Réduction de la duplication**: ~150 lignes supprimées grâce aux partials -- **Meilleure organisation**: 2 nouveaux partials créés pour une meilleure réutilisation -- **Cohérence accrue**: Uniformisation des commentaires et des balises - -### Robustesse -- **Correction d'erreurs**: 1 erreur JavaScript critique corrigée -- **Meilleure sémantique HTML**: Remplacement des balises `

` inappropriées -- **Suppression de balises orphelines**: Élimination de `{{/if}}` sans correspondant - -### Internationalisation -- **Localisations ajoutées**: 2 titres maintenant localisés -- **Préparation pour traduction**: Structure plus propre pour les traductions futures - ---- - -## 📌 Conclusion - -Cette révision a permis de : -1. **Corriger** les erreurs de syntaxe et d'incohérence dans les templates -2. **Optimiser** le code en supprimant les duplications évidentes -3. **Améliorer** la maintenabilité avec de nouveaux partials -4. **Stabiliser** le code JavaScript en corrigant une erreur critique - -Le travail peut être considéré comme **complet pour la phase 1** (nettoyage et correction). La phase 2 (optimisation avancée) consiste à créer des partials supplémentaires pour les sections de blessures et à appliquer le partial `item-list.hbs` dans les templates existants. diff --git a/REVISION_TEMPLATES_RAPPORT.md b/REVISION_TEMPLATES_RAPPORT.md deleted file mode 100644 index 4ac4566..0000000 --- a/REVISION_TEMPLATES_RAPPORT.md +++ /dev/null @@ -1,175 +0,0 @@ -# Rapport de Révision des Templates Acteurs Vermine2047 - -## Date: 2026-06-04 - -## Objectif -Réviser fichiers par fichier les templates des acteurs pour identifier et corriger les duplications et incohérences. - -## Problèmes Initiaux Identifiés - -### 1. Erreurs JavaScript -Les erreurs initiales reportées incluaient: -- `ENOENT: no such file or directory, open '/.../templates/item/partials/damages.html'` → Fichier existe en `.hbs` -- `Cannot read properties of undefined (reading 'Actor')` → Problème dans vermine2047.mjs:123 -- `html.find(...).forEach is not a function` → Problème dans roll.mjs:373 -- `Cannot read properties of undefined (reading 'difficulty')` → Problème dans actor.mjs:89 -- `ActiveEffect application phase "initial" has already completed` → Problème de cycle de vie - -### 2. Duplications dans les Templates - -#### a) Duplication des catégories de compétences NPC (actor-npc-sheet.hbs) -**Problème**: 6 catégories de compétences (Homme, Animal, Outil, Arme, Survie, Monde) avec la même structure HTML dupliquée. - -**Solution**: -- Créé un nouveau partial: `templates/actor/parts/npc-skill-category.hbs` -- Remplacé la section dupliquée (lignes 227-297) par une boucle Handlebars -- Utilisation: `{{> "systems/vermine2047/templates/actor/parts/npc-skill-category.hbs" categoryKey=key categoryLabel=(concat "VERMINE.skill_category." key)}}` - -**Réduction**: ~150 lignes → ~5 lignes - -#### b) Duplication de la structure des blessures -**Fichiers concernés**: -- `character-combat.hbs` (lignes 108-199) -- `npc-combat.hbs` (lignes 23-47) -- `creature-combat.hbs` (lignes 34-66) - -**Problème**: Chaque template de combat a sa propre implémentation des radio buttons pour les blessures. - -**Solution recommandée**: Créer un partial `wounds-section.hbs` (à implémenter) - -#### c) Duplication des listes d'items -**Fichiers concernés**: -- `character-totem.hbs` (abilities, specialties, backgrounds, traumas, evolutions) -- `group-info.hbs` (abilities, specialties, backgrounds, traumas, evolutions) -- `group-experience.hbs` (group abilities) - -**Solution**: -- Créé un partial générique: `templates/actor/parts/item-list.hbs` -- Peut être utilisé pour standardiser l'affichage des listes d'items - -## Corrections Effectuées - -### 1. Corrections de Classes CSS -- ✅ `actor-items.hbs:77`: `grid grid-2` → `grid grid-2col` - -### 2. Corrections des Balises HTML -- ✅ `actor-weapons.hbs:25-36`: Remplacement des `

` par `

` -- ✅ `actor-defenses.hbs:38-41`: Remplacement des `

` par `

` -- ✅ `group-items.hbs:20-21`: Remplacement des `

` par `

` -- ✅ `group-vehicles.hbs:22-27`: Remplacement des `

` par `

` - -### 3. Corrections de Fautes de Frappe -- ✅ `character-totem.hbs:12-16,19-23,26-30`: `smarttlk` → `smarttl` -- ✅ `character-totem.hbs:98`: `{{compétence}}` → `"Compétence"` (tooltips) - -### 4. Corrections de Doubles Classes -- ✅ `character-totem.hbs:59`: `class="item-name" class="flexrow"` → `class="item-name flexrow"` - -### 5. Corrections de Commentaires HTML -- ✅ `character-features.hbs:1`: `` → `{{!-- Character --}}` -- ✅ `character-header.hbs:1`: `` → `{{!-- HEADER --}}` -- ✅ `group-header.hbs:1`: `` → `{{!-- HEADER --}}` -- ✅ `character-totem.hbs:30-34`: Commentaire HTML multi-lignes → `{{!-- Abstract Items --}}` -- ✅ `character-id.hbs:5`: Ajout de commentaire Handlebars - -### 6. Corrections de Localisation -- ✅ `character-features.hbs:2`: `Caractéristiques` → `{{ localize 'VERMINE.abilities' }}` -- ✅ `character-features.hbs:32`: `Compétences` → `{{ localize 'VERMINE.skills' }}` - -### 7. Optimisation des Structures Dupliquées -- ✅ **Création de `npc-skill-category.hbs`**: Partial pour les catégories de compétences NPC -- ✅ **Modification de `actor-npc-sheet.hbs`**: Utilisation du nouveau partial avec boucle -- ✅ **Création de `item-list.hbs`**: Partial générique pour les listes d'items - -### 8. Correction de Balises Orphelines -- ✅ `character-id.hbs:112`: Suppression de `{{/if}}` orphelin - -## Fichiers Modifiés - -### Templates Principaux -1. `actor-character-sheet.hbs` - Structure de base OK -2. `actor-npc-sheet.hbs` - ✅ Optimisé (duplication des catégories de compétences supprimée) -3. `actor-creature-sheet.hbs` - Structure OK -4. `actor-group-sheet.hbs` - Structure OK - -### Partials Character -1. `character/character-features.hbs` - ✅ Commentaires et localisations corrigés -2. `character/character-header.hbs` - ✅ Commentaire corrigé -3. `character/character-id.hbs` - ✅ Commentaire ajouté, balise orpheline supprimée -4. `character/character-stories.hbs` - OK -5. `character/character-totem.hbs` - ✅ Fautes de frappe corrigées, commentaire corrigé, double classe corrigée -6. `character/character-combat.hbs` - À optimiser (duplication avec wounds) - -### Partials Parts -1. `parts/actor-items.hbs` - ✅ grid-2 → grid-2col -2. `parts/actor-weapons.hbs` - ✅ Balises

corrigées -3. `parts/actor-defenses.hbs` - ✅ Balises

corrigées -4. `parts/actor-effects.hbs` - OK -5. `parts/npc-skill-item.hbs` - OK -6. `parts/npc-skill-category.hbs` - ✅ NOUVEAU -7. `parts/item-list.hbs` - ✅ NOUVEAU - -### Partials Group -1. `group/group-header.hbs` - ✅ Commentaire corrigé -2. `group/group-info.hbs` - ✅ Commentaire corrigé -3. `group/group-items.hbs` - ✅ Balises

corrigées -4. `group/group-vehicles.hbs` - ✅ Balises

corrigées -5. `group/group-experience.hbs` - OK - -### Templates de Combat -1. `npc/npc-combat.hbs` - À optimiser -2. `creature/creature-combat.hbs` - À optimiser -3. `character/character-combat.hbs` - À optimiser - -### Autres -1. `create.hbs` - OK - -## Recommandations pour la Suite - -### 1. Créer un partial pour les blessures -Créer `templates/actor/parts/wounds-section.hbs` pour standardiser l'affichage des blessures (minor, major, deadly) utilisés dans: -- character-combat.hbs -- npc-combat.hbs -- creature-combat.hbs - -### 2. Standardiser les listes d'items -Utiliser le partial `item-list.hbs` pour remplacer les duplications dans: -- character-totem.hbs (5 listes) -- group-info.hbs (5 listes) -- group-experience.hbs (1 liste) - -### 3. Vérifier les erreurs JavaScript -Les erreurs initiales doivent être investiguées dans: -- `vermine2047.mjs:123` - `Cannot read properties of undefined (reading 'Actor')` -- `roll.mjs:373` - `html.find(...).forEach is not a function` -- `actor.mjs:89` - `Cannot read properties of undefined (reading 'difficulty')` - -### 4. Vérifier les références .html -Bien que aucune référence `.html` n'ait été trouvée dans les templates, l'erreur initiale suggère qu'il y a des références dans le code JavaScript. Rechercher dans: -- Les fichiers `.mjs` pour des références à `damages.html` -- Les appels à `loadTemplates()` ou `renderTemplate()` - -## Statistiques - -- **Fichiers analysés**: 24 templates -- **Duplications supprimées**: 1 (catégories de compétences NPC) -- **Partials créés**: 2 (npc-skill-category.hbs, item-list.hbs) -- **Fichiers modifiés**: 12 -- **Lignes de code réduites**: ~150+ lignes -- **Problèmes corrigés**: 15+ - -## Prochaines Étapes - -1. ✅ Corriger les erreurs de syntaxe HTML/CSS (TERMINÉ) -2. ✅ Supprimer les duplications évidentes (TERMINÉ pour NPC skills) -3. ⏳ Créer des partials pour les sections communes (EN COURS) -4. ⏳ Optimiser les templates de combat -5. ⏳ Vérifier et corriger les erreurs JavaScript -6. ⏳ Tester tous les templates dans FoundryVTT - -## Notes - -- Tous les templates utilisent maintenant `.hbs` au lieu de `.html` -- Les commentaires sont progressivement uniformisés vers `{{!-- --}}` -- Les structures de grille utilisent `grid-2col` au lieu de `grid-2` -- Les balises `

` pour les cellules de tableau ont été remplacées par `

` diff --git a/less/base.less b/less/base.less index 12e1f66..ebb09e4 100644 --- a/less/base.less +++ b/less/base.less @@ -12,6 +12,47 @@ body.system-vermine2047 { color: @theme-color-secondary; } +// Override Foundry Core default CSS custom properties +// for better readability on the dark Vermine2047 theme. + +// AppV2 windows (sheets) use .themed.theme-dark on their content +.system-vermine2047 .themed.theme-dark { + --color-text-primary: #888888; + --color-text-emphatic: #999999; + --color-text-secondary: #777777; + --color-text-subtle: #666666; + --color-text-light-highlight: #888888; + --color-text-light-heading: #777777; + --color-text-light-primary: #666666; +} + +// Old-style Application windows (settings-config, dialogs) inherit from body.theme-dark +body.system-vermine2047.theme-dark { + --color-text-primary: #888888; + --color-text-emphatic: #999999; + --color-text-secondary: #777777; + --color-text-subtle: #666666; + --color-text-light-highlight: #888888; + --color-text-light-heading: #777777; + --color-text-light-primary: #666666; +} + +#settings-config button, +#settings-config a.button { + --button-text-color: #000000; + --button-border-color: #666666; + color: #000000; +} + +body.system-vermine2047.theme-dark .form-group > label { + color: #777777; +} + +#settings-config p, +#settings-config .hint { + color: #777777; +} + img { border: none; } diff --git a/module/documents/actor.mjs b/module/documents/actor.mjs index 2c28893..e20c910 100644 --- a/module/documents/actor.mjs +++ b/module/documents/actor.mjs @@ -43,295 +43,27 @@ export default class VermineActor extends Actor { * Prepare Character type specific data */ _prepareCharacterData(actorData) { - if (actorData.type !== 'character') return; - this._setAgeType(); - this._setCharacterEffort(); - this._setCharacterSelfControl(); - this._setCharacterThresholds(); - // Make modifications to data here. For example: - const systemData = actorData.system; - - // Loop through ability scores, and add their modifiers to our sheet output. - for (let [key, ability] of Object.entries(systemData.abilities)) { - // Calculate the modifier using d20 rules. - ability.mod = Math.floor((ability.value - 10) / 2); - } - this.prepareCombatStatus(); - + // Character derived data is computed by VermineCharacterData.prepareDerivedData() } - prepareCombatStatus() { - // Ensure combatStatus exists (defined in base template) - if (!this.system.combatStatus) { - this.system.combatStatus = { difficulty: "9", label: "Passif" }; - return; - } - - // Ensure difficulty exists - if (!this.system.combatStatus.difficulty) { - this.system.combatStatus.difficulty = "9"; - } - - //combat initiative reaction difficulty - const difficulty = parseInt(this.system.combatStatus.difficulty) || 9; - - // Only update if values are different to avoid triggering unnecessary updates - const currentLabel = this.system.combatStatus.label; - let newLabel = "Passif"; - - switch (difficulty) { - case 5: newLabel = "Offensif"; break; - case 7: newLabel = "Actif"; break; - case 9: newLabel = "Passif"; break; - } - - // Only update if label changed - if (currentLabel !== newLabel) { - this.system.combatStatus.label = newLabel; - } - - // Only update difficulty if it was undefined or invalid - if (!this.system.combatStatus.difficulty || isNaN(parseInt(this.system.combatStatus.difficulty))) { - this.system.combatStatus.difficulty = "9"; - } - } - /** * Prepare NPC type specific data. */ _prepareNpcData(actorData) { - if (actorData.type !== 'npc') return; - - // Make modifications to data here. For example: - const systemData = actorData.system; - - // Set wound thresholds based on threat level - this._setNpcThresholds(); - - // Set reserve max values based on role - this._setNpcAttributes(); - - this.prepareCombatStatus(); - - // Prepare abilities with labels - for (let [k, v] of Object.entries(systemData.abilities)) { - v.label = game.i18n.localize(CONFIG.VERMINE.abilities[k]) ?? k; - } - } - - /** - * Set NPC wound thresholds based on threat level - */ - _setNpcThresholds() { - const health = this.system.abilities?.health?.value || 1; - const threatLevel = this.system.threat?.value || 1; - const threatConfig = CONFIG.VERMINE.npcThreatLevels[threatLevel] || {}; - - // Use threat-based wounds or fall back to health-based - this.system.minorWound.threshold = threatConfig.minorWound || health; - this.system.majorWound.threshold = threatConfig.majorWound || (health + 3); - this.system.deadlyWound.threshold = threatConfig.deadlyWound || (health + 7 < 11 ? health + 7 : 10); - - // Set max wounds based on threat level - this.system.minorWound.max = threatConfig.minorWound || 4; - this.system.majorWound.max = threatConfig.majorWound || 3; - this.system.deadlyWound.max = threatConfig.deadlyWound || 2; - } - - /** - * Set NPC attributes from role level - */ - _setNpcAttributes() { - const roleLevel = this.system.role?.value || 1; - const roleConfig = CONFIG.VERMINE.npcRoleLevels[roleLevel] || {}; - - // Set effort and self_control based on role - this.system.attributes.effort.max = roleConfig.pools || 0; - this.system.attributes.self_control.max = roleConfig.reaction_bonus || 0; + // NPC derived data is computed by VermineNpcData.prepareDerivedData() } /** * Prepare Group type specific data. */ _prepareGroupData(actorData) { - if (actorData.type !== 'group') return; - - this.prepareCombatStatus(); - - // Initialize group-specific data if not present - this._initGroupData(); - - // Calculate reserve max based on group level - this._calculateGroupReserve(); - - // Update morale level based on dice value - this._updateGroupMorale(); - } - - /** - * Initialize group data with defaults - */ - _initGroupData() { - if (this.type !== 'group') return; - - const system = this.system; - - // Initialize objectives if not present - if (!system.objectives) { - system.objectives = { major: [], minor: [] }; - } - - // Initialize groupAbilities if not present - if (!system.groupAbilities) { - system.groupAbilities = []; - } - - // Initialize reserve if not present - if (!system.reserve) { - system.reserve = { value: 0, min: 0, max: 10 }; - } - } - - /** - * Calculate group reserve max based on level - * Rules: Group level determines reserve size - */ - _calculateGroupReserve() { - if (this.type !== 'group') return; - - const level = this.system.level?.value || 1; - // Reserve max is based on group level (simplified: level * 1D for now) - // Can be customized based on specific rules - this.system.reserve.max = Math.min(10, level * 2); - - // Ensure value doesn't exceed max - if (this.system.reserve.value > this.system.reserve.max) { - this.system.reserve.value = this.system.reserve.max; - } - } - - /** - * Update group morale level based on dice value - * Rules: 7D+ = Haut, 6-3D = Normal, 2D- = Bas, 0D = Crise - */ - _updateGroupMorale() { - if (this.type !== 'group') return; - - const moraleValue = this.system.morale?.value || 0; - const moraleLevel = this.system.morale?.level; - - // If level is already explicitly set, keep it - if (moraleLevel && moraleLevel !== "high") return; - - // Determine morale level based on dice value - if (moraleValue >= 7) { - this.system.morale.level = "high"; - } else if (moraleValue >= 3) { - this.system.morale.level = "normal"; - } else if (moraleValue >= 1) { - this.system.morale.level = "low"; - } else { - this.system.morale.level = "crisis"; - } + // Group derived data is computed by VermineGroupData.prepareDerivedData() } /** * Prepare Creature type specific data. - * Calculates computed values from pattern, size, role, and pack. */ _prepareCreatureData(actorData) { - if (actorData.type !== 'creature') return; - - this.prepareCombatStatus(); - - // Calculate computed values from pattern, size, role, and pack - this._calculateCreatureComputedValues(); - - // Set wound thresholds from creature characteristics - this._calculateCreatureWoundThresholds(); - } - - /** - * Calculate creature computed values from pattern, size, role, and pack. - * Rules: Attack = pattern + size + pack + role.reaction - * Damage = pattern.damage + size.vigor + pack.damage - * Reaction = role.reaction + role.reaction_bonus - */ - _calculateCreatureComputedValues() { - if (this.type !== 'creature') return; - - const patternLevel = this.system.pattern?.value || 1; - const sizeLevel = this.system.size?.value || 1; - const roleLevel = this.system.role?.value || 1; - const packLevel = this.system.pack?.value || 0; - - // Get config values - const patternConfig = CONFIG.VERMINE.creaturePatternLevels[patternLevel] || {}; - const sizeConfig = CONFIG.VERMINE.creatureSizeLevels[sizeLevel] || {}; - const roleConfig = CONFIG.VERMINE.creatureRoleLevels[roleLevel] || {}; - const packConfig = CONFIG.VERMINE.creaturePackLevels[packLevel] || {}; - - // Calculate computed values - this.system.computed = this.system.computed || {}; - - // Attack: pattern + size + pack + role.reaction - this.system.computed.attack = (patternConfig.attack || 0) + - (sizeConfig.attack || 0) + - (packConfig.attack || 0) + - (roleConfig.reaction || 0); - - // Damage: pattern + size.vigor + pack - this.system.computed.damage = (patternConfig.damage || 0) + - (sizeConfig.vigor || 0) + - (packConfig.damage || 0); - - // Vigor: size.vigor + pack.damage - this.system.computed.vigor = (sizeConfig.vigor || 0) + (packConfig.damage || 0); - - // Reaction: role.reaction + role.reaction_bonus - this.system.computed.reaction = (roleConfig.reaction || 0) + (roleConfig.reaction_bonus || 0); - this.system.computed.reactionBonus = roleConfig.reaction_bonus || 0; - - // Pools (reserves) - this.system.computed.pools = roleConfig.pools || 0; - - // Gear and hindrance - this.system.computed.gear = roleConfig.gear || 9; - this.system.computed.gearHindrance = roleConfig.gear_hindrance || 0; - - // Protection - this.system.computed.protection = roleConfig.protection || 1; - } - - /** - * Calculate creature wound thresholds from pattern, size, and pack. - * Rules: Thresholds are sum of minorWound, majorWound, deadlyWound from all sources - */ - _calculateCreatureWoundThresholds() { - if (this.type !== 'creature') return; - - const patternLevel = this.system.pattern?.value || 1; - const sizeLevel = this.system.size?.value || 1; - const packLevel = this.system.pack?.value || 0; - - const patternConfig = CONFIG.VERMINE.creaturePatternLevels[patternLevel] || {}; - const sizeConfig = CONFIG.VERMINE.creatureSizeLevels[sizeLevel] || {}; - const packConfig = CONFIG.VERMINE.creaturePackLevels[packLevel] || {}; - - // Calculate wound thresholds (sum of all sources) - this.system.minorWound.threshold = (patternConfig.minorWound || 0) + - (sizeConfig.minorWound || 0) + - (packConfig.minorWound || 0); - this.system.majorWound.threshold = (patternConfig.majorWound || 0) + - (sizeConfig.majorWound || 0) + - (packConfig.majorWound || 0); - this.system.deadlyWound.threshold = (patternConfig.deadlyWound || 0) + - (sizeConfig.deadlyWound || 0) + - (packConfig.deadlyWound || 0); - - // Set max wounds - this.system.minorWound.max = Math.min(5, this.system.minorWound.threshold + 2); - this.system.majorWound.max = Math.min(4, this.system.majorWound.threshold + 1); - this.system.deadlyWound.max = Math.min(2, this.system.deadlyWound.threshold); + // Creature derived data is computed by VermineCreatureData.prepareDerivedData() } /** @@ -376,53 +108,6 @@ export default class VermineActor extends Actor { // Process additional NPC data here. } - _setCharacterSelfControl() { - this.system.attributes.self_control.max = 0 + Object.values(this.system.abilities).filter(i => i.category === "mental" || i.category === "social").map((i) => i.value).reduce((acc, curr) => acc + curr, 0) + this.modFromAgeSelfControl; - } - - _setCharacterEffort() { - this.system.attributes.effort.max = 0 + Object.values(this.system.abilities).filter(i => i.category === "physical" || i.category === "manual").map((i) => i.value).reduce((acc, curr) => acc + curr, 0) + this.modFromAgeEffort; - } - - _setCharacterThresholds() { - const health = this.system.abilities.health.value; - - this.system.minorWound.threshold = health; - this.system.majorWound.threshold = health + 3; - this.system.deadlyWound.threshold = (health + 7 < 11) ? health + 7 : 10; - - this.system.minorWound.max = 4 + this.modFromAgeWounds.l; - this.system.majorWound.max = 3 + this.modFromAgeWounds.h; - this.system.deadlyWound.max = 2 + this.modFromAgeWounds.d; - } - - - _setAgeType() { - Object.keys(CONFIG.VERMINE.AgeTypes).forEach((type) => { - if (this.system.identity.age >= parseInt(CONFIG.VERMINE.AgeTypes[type].beginning, 10)) { - this.system.identity.ageType = type; - } - }); - } - - get ageType() { - return this.system.identity.ageType; - } - - get modFromAgeSelfControl() { - return this.ageType == 1 ? -1 : 0; - } - - get modFromAgeEffort() { - if (this.ageType == 1) return -1; - if (this.ageType == 3) return -2; - return 0; - } - - get modFromAgeWounds() { - if (this.ageType == 1) return { l: 0, h: 0, d: -1 }; - if (this.ageType == 3) return { l: -1, h: -1, d: -1 }; - return { l: 0, h: 0, d: 0 }; - } + // Character derived-data methods removed — handled by VermineCharacterData.prepareDerivedData() } \ No newline at end of file diff --git a/module/documents/item.mjs b/module/documents/item.mjs index 650a15b..eb8d7f5 100644 --- a/module/documents/item.mjs +++ b/module/documents/item.mjs @@ -38,7 +38,7 @@ export default class VermineItem extends Item { } prepareAbilityData() { - console.log('ability data', this) + // ability data const actorType = (this.actor !== null) ? this.actor.type : 'character'; if (this.system.type == "") { diff --git a/module/models/character.mjs b/module/models/character.mjs index f08c470..ae64e11 100644 --- a/module/models/character.mjs +++ b/module/models/character.mjs @@ -94,20 +94,10 @@ export default class VermineCharacterData extends foundry.abstract.TypeDataModel prepareDerivedData() { super.prepareDerivedData() - // 1. Déterminer la tranche d'âge this._setAgeType() - - // 2. Calculer les modificateurs de caractéristiques - this._setAbilityModifiers() - - // 3. Calculer les réserves (sang-froid et effort) this._setSelfControlMax() this._setEffortMax() - - // 4. Calculer les seuils de blessures this._setWoundThresholds() - - // 5. Mettre à jour le statut de combat this._updateCombatStatus() } @@ -118,22 +108,15 @@ export default class VermineCharacterData extends foundry.abstract.TypeDataModel _setAgeType() { const age = this.identity.age const ageTypes = CONFIG.VERMINE.AgeTypes - for (const [type, cfg] of Object.entries(ageTypes)) { + const entries = Object.entries(ageTypes).reverse() + for (const [type, cfg] of entries) { if (age >= parseInt(cfg.beginning, 10)) { this.identity.ageType = parseInt(type, 10) + break } } } - /** - * Calcule les modificateurs de caractéristiques (règle d20). - */ - _setAbilityModifiers() { - for (const ability of Object.values(this.abilities)) { - ability.mod = Math.floor((ability.value - 10) / 2) - } - } - /** * Calcule le max de sang-froid : * somme des caractéristiques mentales + sociales + modificateur d'âge. diff --git a/module/models/npc.mjs b/module/models/npc.mjs index 8279138..86a2bc6 100644 --- a/module/models/npc.mjs +++ b/module/models/npc.mjs @@ -114,13 +114,13 @@ export default class VermineNpcData extends foundry.abstract.TypeDataModel { const threatLevel = this.threat?.value || 1 const threatConfig = CONFIG.VERMINE.npcThreatLevels[threatLevel] || {} - this.minorWound.threshold = threatConfig.minorWound || health - this.majorWound.threshold = threatConfig.majorWound || (health + 3) - this.deadlyWound.threshold = threatConfig.deadlyWound || (health + 7 < 11 ? health + 7 : 10) + this.minorWound.threshold = health + this.majorWound.threshold = health + 3 + this.deadlyWound.threshold = Math.min(health + 7, 10) - this.minorWound.max = threatConfig.minorWound || 4 - this.majorWound.max = threatConfig.majorWound || 3 - this.deadlyWound.max = threatConfig.deadlyWound || 2 + this.minorWound.max = threatConfig.minorWound || 1 + this.majorWound.max = threatConfig.majorWound || 1 + this.deadlyWound.max = threatConfig.deadlyWound || 1 } /** diff --git a/module/system/applications.mjs b/module/system/applications.mjs index 2984a97..6c95b98 100644 --- a/module/system/applications.mjs +++ b/module/system/applications.mjs @@ -1,5 +1,4 @@ -export class TotemPicker extends Application { - +export class TotemPicker extends HandlebarsApplicationMixin(ApplicationV2) { constructor(linkEl, actor) { super(); @@ -7,45 +6,39 @@ export class TotemPicker extends Application { this.actor = actor; } - /* -------------------------------------------- */ - static get defaultOptions() { - return foundry.utils.mergeObject(super.defaultOptions, { + static get DEFAULT_OPTIONS() { + return { id: "TOTEM_PICKER", - title: game.i18n.localize("VERMINE.totem_picker"), - template: 'systems/vermine2047/templates/applications/choose-totem.hbs', - popOut: true, - resizable: true, - height: "800", - width: "800" - }); + position: { width: 800, height: 800 }, + window: { title: game.i18n.localize("VERMINE.totem_picker"), resizable: true } + }; } - getData() { - // Send data to the template - return { - config: CONFIG.VERMINE, + static PARTS = { + main: { + template: 'systems/vermine2047/templates/applications/choose-totem.hbs' } + }; + + _prepareContext() { + return { config: CONFIG.VERMINE }; } activateListeners(html) { super.activateListeners(html); - html.find('.totem').click(event => { - const totem = $(event.target).parent('a').data('totem'); - if (totem != null) { - this.actor.update({ 'system.identity.totem': totem }); - } - this.close(); + html.querySelectorAll('.totem').forEach(el => { + el.addEventListener('click', event => { + const link = event.target.closest('a'); + if (!link?.dataset.totem) return; + this.actor.update({ 'system.identity.totem': link.dataset.totem }); + this.close(); + }); }); } - - /*async _updateObject(event, formData) { - // console.log(formData.exampleInput); - }*/ } -export class ActorPicker extends Application { - +export class ActorPicker extends HandlebarsApplicationMixin(ApplicationV2) { constructor(linkEl, actor) { super(); @@ -53,152 +46,146 @@ export class ActorPicker extends Application { this.actor = actor; } - /* -------------------------------------------- */ - static get defaultOptions() { - return foundry.utils.mergeObject(super.defaultOptions, { + static get DEFAULT_OPTIONS() { + return { id: "ACTOR_PICKER", - title: game.i18n.localize("VERMINE.actor_picker"), - template: 'systems/vermine2047/templates/applications/choose-actor.hbs', - popOut: true, - resizable: true, - height: "350", - width: "600" - }); + position: { width: 600, height: 350 }, + window: { title: game.i18n.localize("VERMINE.actor_picker"), resizable: true } + }; } + static PARTS = { + main: { + template: 'systems/vermine2047/templates/applications/choose-actor.hbs' + } + }; - - getData() { - // Send data to the template + _prepareContext() { const npcs = game.actors.filter(a => a.type == "npc"); const characters = game.actors.filter(a => a.type == "character"); const all = game.actors.filter(a => a.type == "npc" || a.type == 'character'); - const type = $(this.linkEl).data('type'); + const type = this.linkEl.dataset.type; let actorsList = []; if (type == 'members') { actorsList = characters; } else if (type == 'relations') { - actorsList = npcs;//[...npcs, ...characters]; + actorsList = npcs; } else { actorsList = all; } return { config: CONFIG.VERMINE, actorsList: actorsList - } + }; } - async activateListeners(html) { + activateListeners(html) { super.activateListeners(html); - html.find('.actor').click(async (event) => { - const actorId = $(event.target).parent('div').data('actor-id'); - const type = $(this.linkEl).data('type'); - - if (!actorId) return; - - let actorsList = []; + html.querySelectorAll('.actor').forEach(el => { + el.addEventListener('click', async event => { + const div = event.target.closest('div'); + const actorId = div?.dataset.actorId; + const type = this.linkEl.dataset.type; + if (!actorId) return; - if (type == 'members') { - actorsList = foundry.utils.duplicate(this.actor.system.members || []); - } else if (type == 'encounters') { - actorsList = foundry.utils.duplicate(this.actor.system.encounters || []); - } - - if (!Array.isArray(actorsList)) { - actorsList = []; - } + let actorsList = []; - // Add actor if not already present - if (!actorsList.includes(actorId)) { - actorsList.push(actorId); - } + if (type == 'members') { + actorsList = foundry.utils.duplicate(this.actor.system.members || []); + } else if (type == 'encounters') { + actorsList = foundry.utils.duplicate(this.actor.system.encounters || []); + } - if (type == 'members') { - await this.actor.update({ 'system.members': actorsList }); - } else if (type == 'encounters') { - await this.actor.update({ 'system.encounters': actorsList }); - } - - this.close(); + if (!Array.isArray(actorsList)) { + actorsList = []; + } + + if (!actorsList.includes(actorId)) { + actorsList.push(actorId); + } + + if (type == 'members') { + await this.actor.update({ 'system.members': actorsList }); + } else if (type == 'encounters') { + await this.actor.update({ 'system.encounters': actorsList }); + } + + this.close(); + }); }); } - } -export class TraitSelector extends Application { +export class TraitSelector extends HandlebarsApplicationMixin(ApplicationV2) { constructor(targetItem) { super(); this.targetItem = targetItem; - this.traits = CONFIG.VERMINE.traits + this.traits = CONFIG.VERMINE.traits; } - /* -------------------------------------------- */ - static get defaultOptions() { - return foundry.utils.mergeObject(super.defaultOptions, { - classes: ["vermine2047", "trait-selector"], - title: game.i18n.localize("VERMINE.traits_selector"), - template: 'systems/vermine2047/templates/applications/choose-traits.hbs', - popOut: true, - resizable: true, - height: "500", - width: "500" - }); + static get DEFAULT_OPTIONS() { + return { + id: "TRAIT_SELECTOR", + position: { width: 500, height: 500 }, + window: { title: game.i18n.localize("VERMINE.traits_selector"), resizable: true }, + classes: ["vermine2047", "trait-selector"] + }; } - getData() { + + static PARTS = { + main: { + template: 'systems/vermine2047/templates/applications/choose-traits.hbs' + } + }; + + _prepareContext() { return { traits: this.traits, item: this.targetItem - } + }; } - async activateListeners(html) { - super.activateListeners(html); - this.validateTraits(html); - html.find('input').change(ev => { - this.onChangeInput(ev) - }) + activateListeners(html) { + super.activateListeners(html); + this._validateTraits(html); + html.querySelectorAll('input').forEach(el => { + el.addEventListener('change', ev => this._onChangeInput(ev)); + }); } - async validateTraits(html) { - let checks = html.find("input.trait-selector"); - for (let inp of checks) { + + async _validateTraits(html) { + const checks = html.querySelectorAll("input.trait-selector"); + for (const inp of checks) { if (this.targetItem.system.traits[inp.dataset.trait]) { if (inp.type == "checkbox") { - inp.checked = true + inp.checked = true; } } } - await this.render(true) + await this.render(true); } - async onChangeInput(ev) { - let el = ev.currentTarget; - - let traitKey = el.dataset.trait; // Récupère la clé du trait à partir de l'attribut data-trait - let traitValue = parseInt(el.value) || null - let traits = this.targetItem.system.traits || {}; // Récupère les traits actuels, ou un objet vide si aucun trait n'est défini - - - console.log(traitKey, traitValue, traits) + async _onChangeInput(ev) { + const el = ev.currentTarget; + const traitKey = el.dataset.trait; + const traitValue = parseInt(el.value) || null; + const traits = this.targetItem.system.traits || {}; if (el.classList.contains('trait-selector')) { if (!traits[traitKey]) { - // Si la case est cochée, ajoute le trait await this.targetItem.update({ [`system.traits.${traitKey}`]: this.traits[traitKey] }); } else { - // Si la case est décochée, retire le trait await this.targetItem.update({ [`system.traits.${traitKey}`]: null }); } } if (traitValue) { - console.log(el.value) - // Logique pour les valeurs des traits si nécessaire el.closest("label").querySelector('.trait-selector').checked = true; } else { el.closest("label").querySelector('.trait-selector').checked = false; } - this.render(true) + this.render(true); } -} \ No newline at end of file +} diff --git a/module/system/config.mjs b/module/system/config.mjs index 5c0af30..3abd57f 100644 --- a/module/system/config.mjs +++ b/module/system/config.mjs @@ -26,46 +26,6 @@ VERMINE.DifficultyLevels = { 3: { "label": "DIFFICULTY_LEVELS.hard", "difficulty": 7 }, 4: { "label": "DIFFICULTY_LEVELS.very_hard", "difficulty": 9 }, 5: { "label": "DIFFICULTY_LEVELS.impossible", "difficulty": 10 } -}, - - VERMINE.ThreatLevels = { - 1: { "label": "THREAT_LEVELS.minor", "attack": 3, "vigor": 1, "minorWound": 1, "majorWound": 1, "deadlyWound": 1 }, - 2: { "label": "THREAT_LEVELS.serious", "attack": 4, "vigor": 2, "minorWound": 2, "majorWound": 1, "deadlyWound": 1 }, - 3: { "label": "THREAT_LEVELS.major", "attack": 5, "vigor": 3, "minorWound": 2, "majorWound": 1, "deadlyWound": 1 }, - 4: { "label": "THREAT_LEVELS.deadly", "attack": 6, "vigor": 4, "minorWound": 2, "majorWound": 2, "deadlyWound": 2 }, - } - -VERMINE.ExperienceLevels = { - 1: { "label": "SKILL_LEVELS.beginner", "action": 3, "specialties": 4, "rerolls": 0, "contact": "7" }, - 2: { "label": "SKILL_LEVELS.proficient", "action": 3, "specialties": 5, "rerolls": 0, "contact": "5 ou 7" }, - 3: { "label": "SKILL_LEVELS.expert", "action": 4, "specialties": 6, "rerolls": 1, "contact": "5,7 ou 9" }, - 4: { "label": "SKILL_LEVELS.master", "action": 4, "specialties": 6, "rerolls": 2, "contact": "3,5,7 ou 9" }, -} - -VERMINE.RoleLevels = { - 1: { "label": "ROLE_LEVELS.minor", "reaction": 3, "reaction_bonus": 0, "pools": 0, "gear": 9, "gear_hindrance": 0, "protection": 1 }, - 2: { "label": "ROLE_LEVELS.secondary", "reaction": 3, "reaction_bonus": 1, "pools": 1, "gear": 9, "gear_hindrance": 1, "protection": 2 }, - 3: { "label": "ROLE_LEVELS.important", "reaction": 3, "reaction_bonus": 2, "pools": 2, "gear": 9, "gear_hindrance": 2, "protection": 3 }, - 4: { "label": "ROLE_LEVELS.major", "reaction": 4, "reaction_bonus": 2, "pools": 4, "gear": 10, "gear_hindrance": 2, "protection": 3 }, -} - -VERMINE.PatternLevels = { - 1: { "label": "PATTERN_LEVELS.insect", "attack": 2, "damage": 0, "minorWound": 0, "majorWound": 0, "deadlyWound": 1 }, - 2: { "label": "PATTERN_LEVELS.rat", "attack": 3, "damage": 1, "minorWound": 0, "majorWound": 1, "deadlyWound": 1 }, - 3: { "label": "PATTERN_LEVELS.dog", "attack": 4, "damage": 3, "minorWound": 1, "majorWound": 1, "deadlyWound": 1 }, - 4: { "label": "PATTERN_LEVELS.bear", "attack": 6, "damage": 6, "minorWound": 2, "majorWound": 2, "deadlyWound": 2 }, -} - -VERMINE.SizeLevels = { - 1: { "attack": 2, "vigor": 1, "minorWound": 0, "majorWound": 0, "deadlyWound": 1 }, - 2: { "attack": 3, "vigor": 2, "minorWound": 0, "majorWound": 1, "deadlyWound": 1 }, - 3: { "attack": 4, "vigor": 3, "minorWound": 1, "majorWound": 1, "deadlyWound": 1 } -} - -VERMINE.PackLevels = { - 1: { "attack": 1, "damage": 1, "minorWound": 0, "majorWound": 0, "deadlyWound": 1 }, - 2: { "attack": 2, "damage": 2, "minorWound": 2, "majorWound": 2, "deadlyWound": 2 }, - 3: { "attack": 5, "damage": 5, "minorWound": 3, "majorWound": 3, "deadlyWound": 3 } } /** @@ -251,6 +211,49 @@ VERMINE.skillCategories = { } } +/** + * Skills mapping: each skill belongs to a category. + * Used by templates to render skill-select dropdowns. + */ +VERMINE.skills = { + // man + arts: { category: "man" }, + civilization: { category: "man" }, + psychology: { category: "man" }, + rumors: { category: "man" }, + healing: { category: "man" }, + // animal + animalism: { category: "animal" }, + dissection: { category: "animal" }, + wildlife: { category: "animal" }, + repulsion: { category: "animal" }, + tracks: { category: "animal" }, + // tool + crafting: { category: "tool" }, + diy: { category: "tool" }, + mecanical: { category: "tool" }, + piloting: { category: "tool" }, + technology: { category: "tool" }, + // weapon + firearms: { category: "weapon" }, + archery: { category: "weapon" }, + armory: { category: "weapon" }, + throwing: { category: "weapon" }, + melee: { category: "weapon" }, + // survival + alertness: { category: "survival" }, + atletics: { category: "survival" }, + food: { category: "survival" }, + stealth: { category: "survival" }, + close: { category: "survival" }, + // world + environment: { category: "world" }, + flora: { category: "world" }, + road: { category: "world" }, + toxics: { category: "world" }, + ruins: { category: "world" } +} + VERMINE.sexes = { "male": "SEXES.male", "female": "SEXES.female" }; VERMINE.totems = { diff --git a/module/system/dialogs.mjs b/module/system/dialogs.mjs deleted file mode 100644 index 021dfe4..0000000 --- a/module/system/dialogs.mjs +++ /dev/null @@ -1,37 +0,0 @@ -import { VermineUtils } from "./roll.mjs"; -export class CombatResultDialog extends Dialog { - - constructor(dialogData, options) { - /*let options = { classes: ["combat", "result"], ...options }; - let conf = { - title: "Résultat de la confrontation", - content: dialogData.content - }; - super(conf, options); - this.dialogData = dialogData;*/ - } - - /* -------------------------------------------- */ - activateListeners(html) { - /*super.activateListeners(html); - this.html = html; - this.setEphemere(this.dialogData.signe.system.ephemere); - html.find(".signe-aleatoire").click(event => this.setSigneAleatoire()); - html.find("[name='signe.system.ephemere']").change((event) => this.setEphemere(event.currentTarget.checked)); - html.find(".signe-xp-sort").change((event) => this.onValeurXpSort(event)); - html.find("input.select-actor").change((event) => this.onSelectActor(event)); - html.find("input.select-tmr").change((event) => this.onSelectTmr(event));*/ - } - - - async onSelectActor(event) { - /*const actorId = this.html.find(event.currentTarget)?.data("actor-id"); - const actor = this.dialogData.actors.find(it => it.id == actorId); - if (actor) { - actor.selected = event.currentTarget.checked; - }*/ - } - - -} - diff --git a/module/system/dialogs/rollDialog.mjs b/module/system/dialogs/rollDialog.mjs index b16103e..dbba353 100644 --- a/module/system/dialogs/rollDialog.mjs +++ b/module/system/dialogs/rollDialog.mjs @@ -139,7 +139,7 @@ export default class RollDialog extends HandlebarsApplicationMixin(foundry.appli getHandicapSelect() { const sel = this.#getHandicap(); - return parseInt(sel?.value, 10) || 1; + return Math.max(0, (parseInt(sel?.value, 10) || 1) - 1); } getSkillCategory() { diff --git a/module/system/dice3d.mjs b/module/system/dice3d.mjs index e37bc9f..14d2999 100644 --- a/module/system/dice3d.mjs +++ b/module/system/dice3d.mjs @@ -43,19 +43,19 @@ export async function initUserDice(dice3d, user) { export function darkenColor(color, percent) { const num = parseInt(color.replace('#', ''), 16); const amt = Math.round(2.55 * percent); - const R = (num >> 16) + amt; - const G = ((num >> 8) & 0x00FF) + amt; - const B = (num & 0x0000FF) + amt; - return '#' + (0x1000000 + (R < 255 ? R < 1 ? 0 : R : 255) * 0x10000 + (G < 255 ? G < 1 ? 0 : G : 255) * 0x100 + (B < 255 ? B < 1 ? 0 : B : 255)).toString(16).slice(1); + const R = (num >> 16) - amt; + const G = ((num >> 8) & 0x00FF) - amt; + const B = (num & 0x0000FF) - amt; + return '#' + (0x1000000 + (R < 0 ? 0 : R > 255 ? 255 : R) * 0x10000 + (G < 0 ? 0 : G > 255 ? 255 : G) * 0x100 + (B < 0 ? 0 : B > 255 ? 255 : B)).toString(16).slice(1); } export function lightenColor(color, percent) { const num = parseInt(color.replace('#', ''), 16); const amt = Math.round(2.55 * percent); - const R = (num >> 16) - amt; - const G = ((num >> 8) & 0x00FF) - amt; - const B = (num & 0x0000FF) - amt; - return '#' + (0x1000000 + (R < 0 ? 0 : R > 255 ? 255 : R) * 0x10000 + (G < 0 ? 0 : G > 255 ? 255 : G) * 0x100 + (B < 0 ? 0 : B > 255 ? 255 : B)).toString(16).slice(1); + const R = (num >> 16) + amt; + const G = ((num >> 8) & 0x00FF) + amt; + const B = (num & 0x0000FF) + amt; + return '#' + (0x1000000 + (R < 255 ? R < 1 ? 0 : R : 255) * 0x10000 + (G < 255 ? G < 1 ? 0 : G : 255) * 0x100 + (B < 255 ? B < 1 ? 0 : B : 255)).toString(16).slice(1); } export function oppositeColor(color) { const num = parseInt(color.replace('#', ''), 16); diff --git a/module/system/fight.mjs b/module/system/fight.mjs index f0f27a8..1419bf9 100644 --- a/module/system/fight.mjs +++ b/module/system/fight.mjs @@ -1,5 +1,4 @@ -import { VERMINE } from "./config.mjs"; -import { getActorSkillScore, updateActorSkillScore } from "./functions.mjs"; + /** * Handles combat-related dice rolls for Vermine2047. @@ -28,7 +27,8 @@ export class VermineFight { */ async performTest(enemyAchievement, enemyConservation, skillKey, skill, params, actor) { // Use d10 as per Vermine2047 official rules - const dicePool = (params.spleen != undefined || params.purpose != undefined) ? '5' : '4'; + const basePool = Math.max(skill, 1) + const dicePool = (params.spleen != undefined || params.purpose != undefined) ? String(basePool + 1) : String(basePool) const difficulty = params.difficulty || 7; // Default difficulty const r = new Roll(dicePool + `d10`); let diceString = ''; @@ -167,218 +167,25 @@ export class VermineFight { // data injected to char data static previousValues = { dicePool: 4, - skills: VERMINE.skillsList, - cskills: VERMINE.cskills, + skills: [], + cskills: [], cephalic: false, - achievementReroll: VERMINE.achievementReroll, - conservationReroll: VERMINE.conservationReroll + achievementReroll: 0, + conservationReroll: 0 }; static rollerTemplate = 'systems/vermine2047/templates/fight.html'; static CombatResultTemplate = 'systems/vermine2047/templates/fight-result.html'; - static async chatMessageHandler(message, html, data) { - // console.log("accès au fin du fin", message._id); - - // sélection du dé actif - html.on("click", '.confrontation .die.d10', event => { - const diceResult = parseInt($(event.target).html(), 10); - html.find('.confrontation .die.d10').removeClass('active'); - $(event.target).addClass('active'); - }); - - // sélection des dés d'accomplissement (achievement = successes) - html.on("click", '.confrontation .add-to-achievement', event => { - const diceResult = parseInt(html.find('.confrontation .die.d10.active').html(), 10); - html.find('.confrontation .die.d10.active').removeClass('min').addClass('max'); - }); - - // sélection des dés de conservation - html.on("click", '.confrontation .add-to-conservation', event => { - const diceResult = parseInt(html.find('.confrontation .die.d10.active').html(), 10); - html.find('.confrontation .die.d10.active').removeClass('max').addClass('min'); - }); - - // reset de la sélection des pools - html.on("click", '.confrontation .reset', event => { - html.find('.confrontation .die.d10') - .removeClass('max') - .removeClass('min'); - }); - - // résolution de la confrontation - // Note: With d10 system, we count successes (dice >= difficulty) instead of summing - html.on("click", '.confrontation .resolve', async event => { - let achievementDice = 0; - let conservationDice = 0; - let achievementBasis = 0; - let conservationBasis = 0; - const difficulty = 7; // Default difficulty for legacy compatibility - - // Count successes (dice >= difficulty) for achievement - html.find('.confrontation .die.d10.max').each(function (index) { - const value = parseInt($(this).html(), 10); - if (value >= difficulty) { - achievementDice++; - } - }); - - // Count successes (dice >= difficulty) for conservation - html.find('.confrontation .die.d10.min').each(function (index) { - const value = parseInt($(this).html(), 10); - if (value >= difficulty) { - conservationDice++; - } - }); - - // saisie des résultats - achievementBasis = html.find('td.achievement-result').data('achievement-basis'); - html.find('td.achievement-result').data('achievement-value', achievementDice); - html.find('td.achievement-result').html(achievementBasis + achievementDice); - - conservationBasis = html.find('td.conservation-result').data('conservation-basis'); - html.find('td.conservation-result').data('conservation-value', conservationDice); - html.find('td.conservation-result').html(conservationBasis + conservationDice); - - // calcul des marges (now based on successes, not sum) - const achievementMargin = achievementBasis + achievementDice - parseInt(html.find('td.adv-achievement-result').html(), 10); - const conservationMargin = conservationBasis + conservationDice - parseInt(html.find('td.adv-conservation-result').html(), 10); - html.find('td.achievement-margin').html(achievementMargin); - html.find('td.conservation-margin').html(conservationMargin); - - }); - - - // fin de la résolution de la confrontation - - - } - - static async chatListeners(html) { - // supprime le masquage des résultats du dé - html.off("click", ".dice-roll"); - } - - /** - * main class function - * @returns - */ - static async ui(externalData = {}) { - let actor = {}; - - // get the actor - try { - actor = game.user.character; - } catch (e) { - throw ("Aucun personnage défini !"); - } - - if (actor == null && externalData.speakerId != undefined && externalData.speakerId != null) { - // on récupère le speakerId, et de là l'objet actor - actor = game.actors.get(externalData.speakerId); - VermineFight.previousValues['speakerName'] = actor.name; - VermineFight.previousValues['speakerImg'] = actor.img; - } else { - VermineFight.previousValues['speakerName'] = "Anonyme"; - } - - // get the data - let charData = (externalData) => { - let o = Object.assign({ _template: VermineFight.rollerTemplate }, { ...VermineFight.previousValues, ...externalData }); - return o; - }; - let data = charData(externalData); - console.log(data); - - // render template - let html = await foundry.applications.handlebars.renderTemplate(data._template, data); - - let ui = new Dialog({ - title: game.i18n.localize("VERMINE.FightTool"), - content: html, - buttons: { - roll: { - label: game.i18n.localize('VERMINE.Roll4Fight'), - callback: (html) => { - let form = html.find('#dice-pool-form'); - if (!form[0].checkValidity()) { - throw "Invalid Data"; - } - let enemyAchievement, enemyConservation, skillKey, skill = 5, enemySkill, params = {}; - form.serializeArray().forEach(e => { - switch (e.name) { - case "skill": - case "cephalic": - if (e.value !== '') { - skillKey = e.value; - } - break; - case "skill-score": - skill = +e.value; - break; - case "specialization": - params.specialization = true; - break; - case "usure": - params.usure = +e.value; - break; - case "trait": - params.trait = +e.value; - break; - case "purpose": - params.purpose = true; - break; - case "spleen": - params.spleen = true; - break; - case "adv-skill": - enemySkill = +e.value; - break; - case "achievement": - enemyAchievement = +e.value; - break; - case "conservation": - enemyConservation = +e.value; - break; - } - }); - // prise en compte de l'usure sur la feuille de perso - if (params.usure != undefined) { - const newSpentScore = getActorSkillScore(actor, skillKey, 'spent') + params.usure; - console.log(newSpentScore); - updateActorSkillScore(actor, skillKey, 'spent', newSpentScore); - } - - return VermineFight.get().performTest(enemyAchievement + enemySkill, enemyConservation + enemySkill, skillKey, skill, params, actor); - } - }, - cancel: { - label: game.i18n.localize('Close'), - callback: () => { } - } - }, - render: function (h) { - h.on("change", 'select[name="skill"]', event => { - const skillLabel = $(event.target).val(); - const currentSkillScore = getActorSkillScore(actor, skillLabel) - getActorSkillScore(actor, skillLabel, 'spent'); - if (parseInt(currentSkillScore, 10) >= 0) { - h.find('input#skillScore').val(currentSkillScore); - } - }); - } - }, { width: 601, height: 'fit-content' }); - ui.render(true); - return ui; - } } export class VermineCombat extends Combat { _encounterCheck() { - console.log('encounter combat object', this); + // encounter check } async rollInitiative(ids, formula = undefined, messageOptions = {}) { - console.log(`${game.system.title} | Combat.rollInitiative()`, ids, formula, messageOptions); + // roll initiative return super.rollInitiative(ids, formula, messageOptions) } @@ -421,13 +228,6 @@ export class VermineCombatTracker extends foundry.applications.sidebar.tabs.Comb return "systems/vermine2047/templates/combat-tracker.hbs"; } - - - /* -------------------------------------------- */ - get template() { - return "systems/vermine2047/templates/combat-tracker.hbs"; - } - async getData(options) { const context = await super.getData(options); @@ -441,7 +241,9 @@ export class VermineCombatTracker extends foundry.applications.sidebar.tabs.Comb activateListeners(html) { super.activateListeners(html); - html.find("[data-attitude]").click(this._setStatut.bind(this)); + html.querySelectorAll("[data-attitude]").forEach(el => { + el.addEventListener("click", this._setStatut.bind(this)); + }); } /** @@ -465,23 +267,20 @@ export class VermineCombatTracker extends foundry.applications.sidebar.tabs.Comb } let actor = await game.actors.get(combatant.actorId) - console.log(actor, combatant) + // combatant attitude set } } export class VermineCombatant extends Combatant { constructor(data, context) { - super(data, context); - this.setDefaultAttitude(); - - } - setDefaultAttitude() { - this.attitude = this.token.flags.world?.attitude || "active" + super(data, context) + if (this.token) { + this.attitude = this.token.flags.world?.attitude || "active" + } else { + this.attitude = "active" + } } _getInitiativeFormula() { - - return String(CONFIG.Combat.initiative.formula || game.system.initiative); + return String(CONFIG.Combat.initiative.formula || game.system.initiative) } - - } \ No newline at end of file diff --git a/module/system/functions.mjs b/module/system/functions.mjs index edec7b3..51ca681 100644 --- a/module/system/functions.mjs +++ b/module/system/functions.mjs @@ -1,47 +1,45 @@ -import { VERMINE } from './config.mjs' - /** - * renvoie le score d'une compétence d'un actor existant - * @param {VermineActor} - * @return {number||null} Data for rendering or null + * Returns the score of a skill for an actor. + * Skills are stored as a flat object in actor.system.skills: { [key]: { value, spent, label, category } } + * @param {VermineActor} actor + * @param {string} skillLabel - The localized label of the skill to find + * @param {"value"|"spent"} [property="value"] - Which property to return + * @returns {number|null} The skill score or null if not found */ export function getActorSkillScore(actor, skillLabel, property = "value") { - let returnedValue = null; + const skills = actor.system?.skills; + if (!skills) return null; - for(let i in actor.system.skills){ - for(let j in actor.system.skills[i].data){ - if (actor.system.skills[i].data[j].label == skillLabel){ - returnedValue = actor.system.skills[i].data[j][property]; - } + for (const key of Object.keys(skills)) { + if (skills[key].label === skillLabel) { + return skills[key][property] ?? null; } } - - return returnedValue; + return null; } /** - * met à jour le score d'une compétence d'un actor existant - * @param {VermineActor} - * @return {boolean} bool + * Updates the score of a skill for an actor. + * @param {VermineActor} selectedActor + * @param {string} skillLabel - The localized label of the skill to update + * @param {"value"|"spent"} [property="value"] - Which property to update + * @param {number} updatedValue - The new value + * @returns {boolean} Whether the update was successful */ export function updateActorSkillScore(selectedActor, skillLabel, property = "value", updatedValue) { try { - let updated = false; - // on recherche le label parmi les compétences - for (let st in selectedActor.system.skills){ - for (let s in selectedActor.system.skills[st].data){ - if (selectedActor.system.skills[st].data[s].label == skillLabel){ - selectedActor.system.skills[st].data[s][property] = updatedValue; // printing the new value - const systemSkillKey = `system.skills.${st}.data.${s}.${property}`; - selectedActor.update({[systemSkillKey]:updatedValue }); // updating actor's data - updated = true; - } + const skills = selectedActor.system?.skills; + if (!skills) return false; + + for (const key of Object.keys(skills)) { + if (skills[key].label === skillLabel) { + skills[key][property] = updatedValue; + selectedActor.update({ [`system.skills.${key}.${property}`]: updatedValue }); + return true; } } - - return updated; - } catch(e){ + return false; + } catch (e) { return false; } } - diff --git a/module/system/handlebars-manager.mjs b/module/system/handlebars-manager.mjs index 06abb83..c458a7d 100644 --- a/module/system/handlebars-manager.mjs +++ b/module/system/handlebars-manager.mjs @@ -124,7 +124,7 @@ export const registerHandlebarsHelpers = function () { Handlebars.registerHelper('threatLevel', function (property, level, options) { if (level < 1 || level > 4) return ""; - let levelData = CONFIG.VERMINE.ThreatLevels[level]; + let levelData = CONFIG.VERMINE.npcThreatLevels[level]; if (property == 'label') { return (levelData !== undefined) ? game.i18n.localize(levelData[property]) : ""; } else { @@ -136,7 +136,7 @@ export const registerHandlebarsHelpers = function () { Handlebars.registerHelper('experienceLevel', function (property, level, options) { if (level < 1 || level > 4) return ""; - let levelData = CONFIG.VERMINE.ExperienceLevels[level]; + let levelData = CONFIG.VERMINE.npcExperienceLevels[level]; if (property == 'label') { return (levelData !== undefined) ? game.i18n.localize(levelData[property]) : ""; } else { @@ -148,7 +148,7 @@ export const registerHandlebarsHelpers = function () { Handlebars.registerHelper('roleLevel', function (property, level, options) { if (level < 1 || level > 4) return ""; - let levelData = CONFIG.VERMINE.RoleLevels[level]; + let levelData = CONFIG.VERMINE.npcRoleLevels[level]; if (property == 'label') { return (levelData !== undefined) ? game.i18n.localize(levelData[property]) : ""; } else { @@ -160,7 +160,7 @@ export const registerHandlebarsHelpers = function () { Handlebars.registerHelper('patternLevel', function (property, level, options) { if (level < 1 || level > 4) return ""; - let levelData = CONFIG.VERMINE.PatternLevels[level]; + let levelData = CONFIG.VERMINE.creaturePatternLevels[level]; if (property == 'label') { return (levelData !== undefined) ? game.i18n.localize(levelData[property]) : ""; } else { @@ -172,7 +172,7 @@ export const registerHandlebarsHelpers = function () { Handlebars.registerHelper('sizeLevel', function (property, level, options) { if (level < 1 || level > 4) return ""; - let levelData = CONFIG.VERMINE.SizeLevels[level]; + let levelData = CONFIG.VERMINE.creatureSizeLevels[level]; if (property == 'label') { return (levelData !== undefined) ? game.i18n.localize(levelData[property]) : ""; } else { @@ -184,7 +184,7 @@ export const registerHandlebarsHelpers = function () { Handlebars.registerHelper('packLevel', function (property, level, options) { if (level < 0 || level > 3) return ""; - let levelData = CONFIG.VERMINE.PackLevels[level]; + let levelData = CONFIG.VERMINE.creaturePackLevels[level]; if (property == 'label') { return (levelData !== undefined) ? game.i18n.localize(levelData[property]) : ""; } else { diff --git a/module/system/hooks.mjs b/module/system/hooks.mjs index 53d8a46..ba1ec56 100644 --- a/module/system/hooks.mjs +++ b/module/system/hooks.mjs @@ -1,6 +1,5 @@ import RollDialog from "./dialogs/rollDialog.mjs"; import { initUserDice } from "./dice3d.mjs"; -import { DiceSystem } from '../../../../modules/dice-so-nice/api.js'; import { VermineUtils } from "./roll.mjs"; import { registerTours } from "./tour.mjs"; @@ -10,6 +9,9 @@ export const registerHooks = function () { */ CONFIG.debug.hooks = false; Hooks.once('diceSoNiceReady', async (dice3d) => { + const dsnModule = game.modules.get('dice-so-nice'); + if (!dsnModule?.active) return; + const { DiceSystem } = await import(`/modules/${dsnModule.id}/api.js`); const vermineSystem = new DiceSystem('Vermine2047', 'Vermine 2047', "preferred", 'totem') dice3d.addSystem(vermineSystem); @@ -43,7 +45,7 @@ export const registerHooks = function () { if (rerollTitle) { rerollTitle.addEventListener("click", () => { html.querySelector(".reroll").classList.toggle('visible') }) } - if (message.author?._id != game.user._id || !game.user.isGM) { + if (message.author?._id !== game.user._id && !game.user.isGM) { // désactiver les inputs pour les joueurs non-auteurs du message html.querySelectorAll("input").forEach(inp => inp.disabled = true); //cacher le boutton reroll @@ -61,17 +63,21 @@ export const registerHooks = function () { } }) Hooks.once("ready", async () => { - console.info("Vermine 2047 | System Initialized."); + // System initialized //await registerTours(); }); // changement de la pause Hooks.on("renderPause", async function () { - if ($("#pause").attr("class") !== "paused") return; - $(".paused img").attr("src", 'systems/vermine2047/assets/images/ui/vermine_pause.webp'); - $(".paused img").css({ "opacity": 1 }); - $("#pause.paused figcaption").text("Communauté endormie..."); + const pauseEl = document.getElementById("pause"); + if (!pauseEl || pauseEl.className !== "paused") return; + pauseEl.querySelectorAll("img").forEach(img => { + img.src = 'systems/vermine2047/assets/images/ui/vermine_pause.webp'; + img.style.opacity = 1; + }); + const caption = pauseEl.querySelector("figcaption"); + if (caption) caption.textContent = "Communauté endormie..."; }); /** @@ -107,7 +113,7 @@ export const registerHooks = function () { /* -------------------------------------------- */ Hooks.on("preCreateActor", function (actor) { - console.log('pre create actor', actor.img); + // pre create actor if (actor.img == "icons/svg/mystery-man.svg") { actor.updateSource({ "img": `systems/vermine2047/assets/icons/actors/${actor.type}.webp` }); } @@ -138,7 +144,7 @@ export const registerHooks = function () { if (game.user.isGM) { let combatant = (game.combat.combatant) ? game.combat.combatant.actor : ""; - console.log('update combat', game.combat); + // update combat /*if (combatant.type == "marker" && combatant.system.settings.general.isCounter == true) { let step = (!combatant.system.settings.general.counting) ? -1 : combatant.system.settings.general.counting; diff --git a/module/system/roll.mjs b/module/system/roll.mjs index c612c55..475f424 100644 --- a/module/system/roll.mjs +++ b/module/system/roll.mjs @@ -28,7 +28,8 @@ export class VermineUtils { skillCategory = null, keepTotem = null, skillLevel = null, - hasSpecialty = false + hasSpecialty = false, + handicap = 0 }) { // Validate inputs if (!actor) { @@ -100,10 +101,13 @@ export class VermineUtils { NoD++; // Cancel the decrement for adapted } else if (keepTotem === 'adapted' && totems.human) { modFormula = `(1D10cs>=${adjustedDifficulty}[adapted_${safeUserName}]*2)`; - NoD++; // Cancel the decrement for human + NoD++; // Cancel the decrement for human } } + // Apply handicap (wounds/maluses reduce dice pool) + NoD = Math.max(1, NoD - handicap) + // Build base formula const baseFormula = `${NoD}d10cs>=${adjustedDifficulty}[regular_${safeUserName}]`; @@ -364,67 +368,61 @@ export class VermineUtils { * @param {HTMLElement} html - The HTML element containing chat events. */ static async chatListenners(html) { - // Ensure html is a jQuery object - const $html = $(html); - // Get reroll count - const rerollCountElement = $html.find('#allowed_reroll')[0]; + const rerollCountElement = html.querySelector('#allowed_reroll'); const rerollCount = rerollCountElement?.innerText; - + // Enable/disable rerolls based on count - if (!rerollCount || parseInt(rerollCount, 10) < 1) { - // Disable rerolls for all dice - $html.find('.die').each(function() { - this.classList.remove("rerollable"); - }); - } else { - // Enable rerolls for all dice - $html.find('.die').each(function() { - this.classList.add("rerollable"); - }); - } + const dieClass = !rerollCount || parseInt(rerollCount, 10) < 1 ? 'remove' : 'add'; + html.querySelectorAll('.die').forEach(el => el.classList[dieClass]("rerollable")); // Add click event for rerollable dice - $html.find('.rerollable').click(async (ev) => { - ev.preventDefault(); - const msgId = ev.currentTarget.closest("li.message")?.dataset?.messageId; - if (msgId) { - const message = await game.messages.get(msgId); - await VermineUtils.onReroll(message, ev); - } + html.querySelectorAll('.rerollable').forEach(el => { + el.addEventListener('click', async (ev) => { + ev.preventDefault(); + const msgId = ev.currentTarget.closest("li.message")?.dataset?.messageId; + if (msgId) { + const message = await game.messages.get(msgId); + await VermineUtils.onReroll(message, ev); + } + }); }); // Update granted reroll label - $html.find("#effort-reroll").change(ev => { - const label = $html.find("#granted-reroll")[0]; - if (label) { - label.innerText = ev.currentTarget.value; - } - }); + const effortReroll = html.querySelector("#effort-reroll"); + if (effortReroll) { + effortReroll.addEventListener('change', ev => { + const label = html.querySelector("#granted-reroll"); + if (label) { + label.innerText = ev.currentTarget.value; + } + }); + } // Add click event for granting rerolls - $html.find("button.grant-reroll").click(async (ev) => { - const grantedRerollElement = $html.find('#granted-reroll')[0]; - const allowedRerollElement = $html.find("#allowed_reroll")[0]; - - if (grantedRerollElement && allowedRerollElement) { - allowedRerollElement.innerText = grantedRerollElement.innerText; - } - - const mesEl = ev.currentTarget.closest('[data-message-id]'); - const messageId = mesEl?.dataset?.messageId; - - if (messageId) { - // Hide reroll grant area - ev.currentTarget.closest('.reroll-from-effort').style.display = "none"; - - const rollMessage = ev.currentTarget.closest(".vermine-roll-message"); - if (rollMessage) { - const content = rollMessage.outerHTML; - const message = await game.messages.get(messageId); - await message.update({ content: content }); + html.querySelectorAll("button.grant-reroll").forEach(el => { + el.addEventListener('click', async (ev) => { + const grantedRerollElement = html.querySelector('#granted-reroll'); + const allowedRerollElement = html.querySelector("#allowed_reroll"); + + if (grantedRerollElement && allowedRerollElement) { + allowedRerollElement.innerText = grantedRerollElement.innerText; } - } + + const mesEl = ev.currentTarget.closest('[data-message-id]'); + const messageId = mesEl?.dataset?.messageId; + + if (messageId) { + ev.currentTarget.closest('.reroll-from-effort').style.display = "none"; + + const rollMessage = ev.currentTarget.closest(".vermine-roll-message"); + if (rollMessage) { + const content = rollMessage.outerHTML; + const message = await game.messages.get(messageId); + await message.update({ content: content }); + } + } + }); }); } @@ -448,10 +446,10 @@ export class VermineUtils { blind = true; // Falls through case "gmroll": // GM + rolling player - whisper = this.getUsers(user => user.isGM); + whisper = game.users?.filter(user => user.isGM) || []; break; case "roll": // Everybody - whisper = this.getUsers(user => user.active); + whisper = game.users?.filter(user => user.active) || []; break; case "selfroll": whisper = [game.user.id]; diff --git a/module/system/settings.mjs b/module/system/settings.mjs index 1572020..e794b58 100644 --- a/module/system/settings.mjs +++ b/module/system/settings.mjs @@ -10,7 +10,7 @@ export const registerSettings = function () { "2": "Cauchemar", "3": "Apocalypse" }, - default: 'e', + default: '1', onChange: value => { let el = document.querySelector('.game-mode'); el.id = 'game-mode-' + game.settings.get('vermine2047', 'game-mode') diff --git a/module/system/tour.mjs b/module/system/tour.mjs index b4d1acc..c7f0dc6 100644 --- a/module/system/tour.mjs +++ b/module/system/tour.mjs @@ -139,13 +139,15 @@ class WelcomeTour extends VermineTour { } export async function registerTours() { game.tours.register("vermine2047", "welcome", new WelcomeTour()); - $(document).on("click", "#chat-log #vermine-tour-chat-button", (el) => { - const tour = game.tours.get("vermine2047.welcome"); - tour == null ? void 0 : tour.start(); + document.addEventListener("click", (el) => { + if (el.target.closest("#chat-log #vermine-tour-chat-button")) { + const tour = game.tours.get("vermine2047.welcome"); + tour?.start(); + } }); if (game.settings.get("vermine2047", "first-run-tips-shown")) return; - console.log("Posting first-start messages..."); + // Posting first-start messages const gms = ChatMessage.getWhisperRecipients("GM"); ChatMessage.implementation; ChatMessage.create({ diff --git a/scss/_app.scss b/scss/_app.scss deleted file mode 100644 index 992d8e5..0000000 --- a/scss/_app.scss +++ /dev/null @@ -1,21 +0,0 @@ -.app.vermine2047.trait-selector { - .form-group { - box-shadow: 0 0 30px gray; - padding: 0.3rem 0.5rem; - - border: 3px solid rgb(142, 144, 16); - - &:has(input[type="checkbox"]:checked) { - border: 3px solid green - } - - label { - display: inline-flex; - align-items: center; - justify-content: space-around; - width: 100%; - text-align: center; - border-bottom: 2px solid black - } - } -} \ No newline at end of file diff --git a/scss/_flex.scss b/scss/_flex.scss deleted file mode 100644 index 308348f..0000000 --- a/scss/_flex.scss +++ /dev/null @@ -1,61 +0,0 @@ -// Flexbox. -.flex-group-center, -.flex-group-left, -.flex-group-right { - justify-content: center; - align-items: center; - text-align: center; -} - -.flex-group-left { - justify-content: flex-start; - text-align: left; -} - -.flex-group-right { - justify-content: flex-end; - text-align: right; -} - -.flexshrink { - flex: 0; -} - -.flex-center { - align-items: center; - justify-content: center; -} - -.flex-between { - justify-content: space-between; -} - -.flex-around { - justify-content: space-around; - -} - -.flexlarge { - flex: 2; -} - -.flexsmall { - flex: 0.5 -} - -// Alignment styles. -.align-left { - justify-content: flex-start; - text-align: left; -} - -.align-right { - justify-content: flex-end; - text-align: right; -} - -.align-center { - align-items: center; - justify-content: center; - text-align: center; -} \ No newline at end of file diff --git a/scss/base_work.scss b/scss/base_work.scss deleted file mode 100644 index 8f826d3..0000000 --- a/scss/base_work.scss +++ /dev/null @@ -1,772 +0,0 @@ -@font-face { - font-family: "DistressBlack"; - src: url("../assets/fonts/dcc_sharp_distress_black_by_dccanim.otf"); -} - -.sans-font { - font-family: "DistressBlack", sans-serif; -} - -/* Change shadow colors and Foundry general font color!! */ -.app { - box-shadow: 0 0 20px #7e7544; - /* Change the color code here for a nice shadow color! */ - color: #dfdfdf; - /* Text color for window titles and menu all across Foundry */ -} - -.vermine2047.sheet.actor { - - header.sheet-header, - .windoow-content { - min-height: fit-content - } - -} - -/* Character and Item Name Titles Text style! */ -.sheet .charname input { - color: #191813; - font-family: "DistressBlack", sans-serif; - font-size: 30px; - font-style: normal; -} - -img.profile-img { - filter: drop-shadow(0px 0px 20px rgb(110, 133, 27)); - height: auto; - width: 100%; - max-width: 10rem; -} - -/* custom styles */ -body.system-vermine2047 img#logo { - content: url("/systems/vermine2047/assets/images/ui/logo_vermine_foundry.webp"); - height: auto; -} - - -/* Customize the chat history area! */ -#chat-log .message { - background: url(/systems/vermine2047/assets/images/ui/box_background.webp) repeat; - /*color: #191813; */ -} - -img { - border: none; -} - - - -ul.unstyled { - list-style-type: none; - padding: 0; - margin: 0; -} - -ul.unstyled li { - padding: 0; - margin: 0; -} - -.padding-with-frieze { - margin-left: 18% !important; - margin-right: 10% !important; -} - -.padding-with-frieze li { - max-width: 100%; -} - -.w-full { - width: 100%; -} - -.mx-auto { - margin-left: auto; - margin-right: auto; -} - -/* ----------------------------------------- */ -/* Sheet Structure */ -/* ----------------------------------------- */ -.system-vermine2047 .sheet .window-content { - background: url(/systems/vermine2047/assets/images/ui/box_background.webp); - padding: 0; - overflow-y: hidden; -} - -.system-vermine2047 .dialog .window-content { - background: url(/systems/vermine2047/assets/images/ui/fond_chat_box.webp); - padding: 0.5rem; - overflow-y: hidden; -} - -.window-content .row.smb { - margin-bottom: 0.25rem; -} - -.window-content .row.mdb { - margin-bottom: 0.5rem; -} - -.window-content .row.lgb { - margin-bottom: 1rem; -} - -.actor.sheet form .form { - display: flex; - - align-items: flex-start; - height: 100%; - overflow: auto; -} - -.actor.sheet .form aside { - min-width: max-content; - background-image: url(/systems/vermine2047/assets/images/ui/barre_laterale.webp); - background-repeat: no-repeat; - background-size: auto 200%; - border-right: 2px black; - height: 100%; - padding: 0 0.3rem; - box-shadow: -20px 0px 100px 15px #000000b5 inset; - - - .major-totem { - position: relative; - - h4 { - position: absolute; - transform: rotate(-8deg); - opacity: 1; - transition: 0.2s; - - } - - } -} - -.actor.sheet .form main { - box-shadow: 10px 0px 100px #000000b5 inset; - padding-left: 1rem; - grid-row: span 1 / span 1; - height: 100%; -} - -.actor.sheet .form aside .image-wrapper { - text-align: center; -} - -.actor.sheet .form aside .image-wrapper img { - width: 80%; - height: auto; -} - -.actor.sheet .form aside .paper { - margin-top: 1rem; - height: 350px; -} - -.actor.sheet .form aside .second-paper { - margin-top: 4rem; - height: 150px; -} - -.actor.sheet .form h3 { - font-family: "DistressBlack", sans-serif; - text-align: center; - text-transform: uppercase; - color: #4e564c; - font-size: 1.7rem; - border-bottom: none; - margin: 0; - -} - -.actor.sheet .form h4, -.item.sheet .form h4 { - font-family: "DistressBlack", sans-serif; - font-size: 1.4em; - text-transform: uppercase; - margin: 0 0 0.2rem; -} - -.actor.sheet .form .characteristics h4 { - font-size: 1.25rem; - margin-top: 0 0.1rem; -} - -.actor.sheet .form .tab.totem h4, -.actor.sheet .form .tab.equipment h4, -.actor.sheet .form .tab.stories h4 { - margin-top: 0.875rem; -} - -.system-vermine2047 .char-header { - font-family: "DistressBlack", sans-serif; -} - -.system-vermine2047 .char-header section { - display: flex; - flex-direction: column; - align-items: flex-start; - justify-content: flex-start; - -} - -.system-vermine2047 .char-header h1.char-name, -.system-vermine2047 .char-vermine2047 { - border-bottom: none; - line-height: 2rem; -} - -.system-vermine2047 .char-vermine2047 { - font-size: 1.5rem; -} - -.system-vermine2047 .sheet.actor form { - width: 100%; - height: 100%; - overflow: hidden; -} - -.system-vermine2047 .sheet.actor form div.hexa { - clip-path: polygon(25% 0%, 75% 0%, 100% 50%, 75% 100%, 25% 100%, 0% 50%); - background: radial-gradient(circle, rgba(255, 255, 255, 0.425) 0%, rgba(0, 0, 0, 0.288) 100%); - height: 1.5rem; - max-width: 1.5rem; - color: black; - transform: rotate(90deg); - transition: 0.2s; - margin: 0.2rem; - - &:hover { - background: radial-gradient(circle, rgba(255, 255, 255, 0.425) 0%, rgba(0, 0, 0, 0.288) 100%); - - } - - input { - opacity: 1; - min-width: 100%; - min-height: 100%; - opacity: 0 - } - - &.checked { - &:hover { - background: radial-gradient(circle, rgb(43, 43, 43) 0%, rgba(0, 0, 0, 0.288) 100%); - - } - - background: radial-gradient(circle, rgb(0, 0, 0) 0%, rgba(0, 0, 0, 0.288) 100%); - } - - &.unavailable { - background: radial-gradient(circle, rgba(66, 15, 15, 0.664) 0%, rgba(131, 70, 70, 0.432) 100%); - - } -} - -.system-vermine2047 .sheet.actor .totem-details { - position: relative; - - img.img-totem { - transform-origin: 50% 50%; - filter: grayscale(1); - opacity: 0.15; - position: absolute; - width: 30%; - height: auto; - pointer-events: none; - aspect-ratio: 1/1; - left: 35%; - } -} - -.system-vermine2047 .sheet.actor div.minor-totems { - position: relative; - background-color: #929c6f85; - - h5 { - position: absolute; - top: 0; - - img { - max-width: 2rem; - position: absolute; - bottom: -2rem; - - } - } - - - - h5.human, - h5.adapted { - transition: 0.3s; - - img.img-totem { - filter: drop-shadow(0px 0px 20px rgb(0, 0, 0)); - } - - &.major { - transform: scale(1.1); - - & img { - filter: drop-shadow(0px 0px 10px red) - } - } - } - - .totem-dice { - - - - .human-dice, - .adapted-dice { - display: flex; - flex-direction: row; - margin-left: 2rem; - - - i { - padding-top: 0.5rem; - color: #064930; - } - } - - - - - - .adapted-dice { - justify-content: flex-end; - margin-left: 0; - margin-right: 2rem; - transform: rotate(180deg); - - i { - transform: rotate(180deg); - padding-top: 0.5rem; - color: rgb(85, 52, 2); - } - } - } - - .human { - left: 0; - - img { - left: 0; - - } - } - - .adapted { - right: 0; - - img { - right: 0 - } - } -} - -.system-vermine2047 .sheet.actor form input[type=text], -.system-vermine2047 .sheet.actor form input[type=number] { - width: calc(100% - 2px); - height: calc(100% - 2px); - background: none; - padding: 0; - margin: 1px 0; - color: #333; - border: 1px solid transparent; - - &.hexa { - clip-path: polygon(25% 0%, 75% 0%, 100% 50%, 75% 100%, 25% 100%, 0% 50%); - background: radial-gradient(circle, rgba(255, 255, 255, 0.425) 0%, rgba(0, 0, 0, 0.288) 100%); - height: 1.5rem; - max-width: 1.5rem; - color: black - } - -} - -.system-vermine2047 .sheet.actor form input[disabled], -.system-vermine2047 .sheet.actor form select[disabled] { - cursor: not-allowed; -} - -.system-vermine2047 .sheet.actor form input[type=text]:hover:not(:disabled), -.system-vermine2047 .sheet.actor form input[type=text]:focus, -.system-vermine2047 .sheet.actor form select:hover:not(:disabled), -.system-vermine2047 .sheet.actor form select:focus, -.system-vermine2047 .sheet.actor form input[type=number]:hover:not(:disabled), -.system-vermine2047 .sheet.actor form input[type=number]:focus, -.system-vermine2047 .sheet.actor form textarea:hover:not(:disabled), -.system-vermine2047 .sheet.actor form textarea:focus { - box-shadow: 0 0 10px #005a3c inset; -} - -.system-vermine2047 .sheet.actor form select { - font-size: 0.6rem; - border: none; - appearance: none; - min-width: fit-content; - max-width: fit-content; - padding: 0 0.2rem; - margin: 0 0.2rem; - cursor: help; - -} - -.system-vermine2047 .sheet.actor form label { - display: block; -} - -.system-vermine2047 .sheet.actor form .mce-panel span { - display: inherit; -} - -.system-vermine2047 .sheet.actor form.editable .rollable:hover, -.system-vermine2047 .sheet.actor form.editable a:hover { - color: #000; - text-shadow: 0 5px 5px #1fa832; - cursor: pointer; -} - -.system-vermine2047 .sheet.actor form .sheet-tabs { - font-weight: 500; - height: 30px; -} - -.system-vermine2047 .sheet.actor form .sheet-tabs>.list-row { - line-height: 24px; - padding-top: 3px; - font-size: 2rem; - text-align: center; -} - -.system-vermine2047 .sheet.actor form .sheet-tabs>.list-row:last-of-type { - padding-right: 4px; -} - -.system-vermine2047 .sheet.actor form .sheet-tabs>.list-row.active { - color: #000; - font-weight: 700; -} - -.system-vermine2047 .sheet.actor form .tab { - flex: 1; - overflow: hidden; -} - -.system-vermine2047 .sheet.actor form .tag-legacy { - float: left; - margin: 0 2px 2px 0; - padding: 0 3px; - font-size: var(--font-size-10); - line-height: 16px; - border: 1px solid #999; - border-radius: 3px; - white-space: normal; - font-weight: 500; -} - -/* ---------------------------------------- */ -/* Actor Sheet */ -/* ---------------------------------------- */ - - -.system-vermine2047 .sheet.actor, -.system-vermine2047 .sheet.actor .window-content { - min-width: 690px; - - -} - -.system-vermine2047 .sheet.actor .sidebar { - flex: 0.2; -} - -.system-vermine2047 .sheet.actor .floatright { - float: right; -} - -.system-vermine2047 .sheet.actor .sheet-upper { - height: 268px; -} - -.system-vermine2047 .sheet.actor .sheet-upper .sheet-header { - height: 48px; -} - -.system-vermine2047 .sheet.actor .sheet-upper .sheet-profile, -.system-vermine2047 .sheet.actor .sheet-upper .sheet-showcase { - height: 220px; -} - -.system-vermine2047 .sheet.actor .sheet-content { - padding: 4px; -} - -.system-vermine2047 .sheet.actor .sheet-sidebar { - height: calc(100% - 48px); - display: flex; - flex-direction: column; - flex-wrap: nowrap; - overflow-x: hidden; - overflow-y: auto; -} - -.system-vermine2047 .sheet.actor .sheet-sidebar>* { - flex: 1; -} - -.system-vermine2047 .sheet.actor .sheet-sidebar .sidebar-summary { - overflow-y: hidden; -} - -.system-vermine2047 .sheet.actor.npc-sheet .sheet-upper { - height: 220px; -} - -.system-vermine2047 .sheet.actor.npc-sheet .sheet-upper .sheet-showcase { - height: 172px; -} - -.system-vermine2047 .sheet.actor.npc-sheet .sheet-lower { - height: calc(100% - 220px - 32px); -} - -.system-vermine2047 .sheet.actor .sheet-navigation { - border-top: 1px solid var(--secondary-background); - border-bottom: 1px solid var(--primary-background); -} - -.system-vermine2047 .sheet.actor .sheet-navigation .sheet-tabs>.list-row { - border-radius: 5px 5px 0 0; -} - -.system-vermine2047 .sheet.actor .sheet-navigation .sheet-tabs>.list-row.active { - border: 1px solid #666; - border-bottom: none; - /* box-shadow: 0 0 10px inset #ff6400; - */ - background: var(--primary-background); - color: #fff; - text-shadow: none; - - color: #000; - text-shadow: 0 0 10px #00005a; - cursor: pointer; - -} - - -.actor.sheet nav.sheet-navigation { - display: inline-flex; - justify-content: space-around; - align-items: center; - height: 54px; - background: url(../assets/images/ui/barre_haut.webp) no-repeat right top; - background-size: 100% 100%; - width: 100%; - position: relative; - padding-right: 4rem; - font-size: 1.4rem; -} - -.actor.sheet nav.sheet-navigation.tabs .item { - height: 2.4rem; - display: inline-block; - z-index: 1; - transition: all 0.1s ease-out; - color: #606060; - box-shadow: 0px 0px 0px rgba(0, 0, 0, 0.404); -} - -.actor.sheet nav.sheet-navigation.tabs .item:hover, -.actor.sheet nav.sheet-navigation.tabs .item.active { - color: #000; - text-shadow: 0 5px 5px #1fa832; - cursor: pointer; - -} - -.actor.sheet nav.sheet-navigation.tabs .item:hover { - text-shadow: 0 5px 5px #1e52259a; - -} - - -.system-vermine2047 .sheet.actor form nav.sheet-navigation.sheet-tabs { - height: 54px; -} - - -//Query pour les lignes de caract -@container ability-row (max-width: 240px) { - - .skill-dots, - span.hexa { - display: none - } - - -} - -.system-vermine2047 .sheet.actor .ability { - padding-right: 0.6rem; - font-size: 0.8rem; - border-bottom: 1px solid rgba(170, 170, 152, 0.664); - box-shadow: 0px 0px 15px rgba(128, 128, 128, 0) inset; - transition: 0.2s; - position: relative; - flex-wrap: nowrap; - min-width: min-content; - container-type: inline-size; - container-name: ability-row; - - - - &:hover { - box-shadow: 0px 0px 15px gray inset; - } - - - - - label { - min-width: 40%; - flex: 1.3; - - } - - span { - max-width: fit-content; - margin: 0 1rem; - - flex: 0.5; - } - - - div.specialties { - position: absolute; - bottom: -0.2rem; - font-size: 0.7rem; - } - - - - .skill-dots { - height: 100%; - align-self: center; - flex: 1.5; - min-width: fit-content; - - &>div { - - max-width: 0.7rem; - height: 0.7rem; - aspect-ratio: 1/1; - border-radius: 50%; - font-weight: 700; - text-align: center; - padding-bottom: 0.2rem; - font-style: oblique; - align-self: flex-start; - - - &.dice-pool-dot { - background: radial-gradient(circle, rgba(94, 90, 77, 1) 25%, rgba(0, 0, 0, 1) 100%); - max-width: 0.7rem; - aspect-ratio: 1/1; - border-radius: 50%; - } - - &.dice-reroll-dot { - background: radial-gradient(circle, rgb(187, 182, 165) 25%, rgba(0, 0, 0, 1) 100%); - - } - } - } -} - -.system-vermine2047 .sheet.actor .skill-category { - padding: .3rem; - - &.preferred { - - h4, - label { - text-shadow: 0px 0px 5px rgba(0, 128, 0, 0.411) - } - - box-shadow: 0px 0px 30px rgba(0, 128, 0, 0.306) inset; - } -} - -.system-vermine2047 .sheet.actor #edit { - background-color: black; - color: white; - width: 100% -} - -.system-vermine2047 .sheet.actor .reserve-grid { - line-height: 0.5rem; - transform-origin: 0% 50%; - max-width: fit-content; - align-items: center; - display: flex; - flex-direction: column; - - div.flexrow, - input, - .hexa { - margin: 0; - padding: 0; - min-width: 1rem; - min-height: 1rem; - } - - &>.flexrow { - position: relative; - max-width: fit-content; - justify-content: center; - - - } -} - -.hexa { - text-align: center; - clip-path: polygon(25% 0%, 75% 0%, 100% 50%, 75% 100%, 25% 100%, 0% 50%); - background: radial-gradient(circle, rgba(255, 255, 255, 0.425) 0%, rgba(0, 0, 0, 0.288) 100%); - max-height: 1.5rem; - max-width: 1.5rem; - min-width: 1.5rem; - aspect-ratio: 1/1; - color: black; - vertical-align: center; - - &.checked { - background: radial-gradient(circle, rgb(0, 0, 0) 0%, rgba(0, 0, 0, 0.288) 100%); - } - - ; - - input { - width: 1rem - } - - input[type="radio"] { - opacity: 0; - - - &::after, - &::before { - display: none - } - } -} \ No newline at end of file diff --git a/scss/dialog.scss b/scss/dialog.scss deleted file mode 100644 index 6c8f89d..0000000 --- a/scss/dialog.scss +++ /dev/null @@ -1,62 +0,0 @@ -.window-app.vermineDialog { - max-width: 50vw; - height: fit-content; - - .window-content { - background: url(/systems/vermine2047/assets/images/ui/box_background.webp) repeat; - color: black; - } - - - details>summary::after { - content: "▶️"; - position: relative; - right: 40%; - } - - details[open]>summary::after { - content: "🔽" - - } - - - .grid { - justify-content: space-around; - box-shadow: 0px 1px 10px rgba(0, 0, 0, 0.555); - align-items: center; - padding: 0.5rem 0.2rem; - - &>* { - margin: 0 0.3rem; - } - - } - - ; - - label { - font-family: "DistressBlack", - sans-serif; - font-size: larger; - - } - - select { - max-width: fit-content; - - option { - max-width: fit-content - } - } - - .dialog-buttons { - button { - display: block; - flex: 0.3 - } - - display: flex; - justify-content: space-around; - flex-direction: row; - } -} \ No newline at end of file diff --git a/scss/item-sheet.scss b/scss/item-sheet.scss deleted file mode 100644 index ea8fea4..0000000 --- a/scss/item-sheet.scss +++ /dev/null @@ -1,76 +0,0 @@ -.sheet.item.vermine2047 { - .window-content { - padding: 0 1rem; - - .flexrow { - align-items: center; - } - - header, - h1, - h2, - h3, - h4, - h5 { - background: 50% 50%/cover no-repeat url(/systems/vermine2047/assets/images/ui/scotch.webp); - text-transform: uppercase; - font-family: "DistressBlack"; - margin-top: 1rem; - border-bottom: none; - } - - h2, - h3, - h4 { - text-align: center; - } - - h5 { - margin-bottom: 0; - } - - .resource { - border: none; - border-left: 1px solid gray; - padding: 0.2rem 1rem; - text-align: center; - - .flexrow { - min-width: 5rem; - box-shadow: none; - } - } - - .damages-row { - margin: 0; - - .radios { - margin: 0; - padding: 0.5rem; - } - } - - .damage-pannes, - .damage-state, - .damage-effect { - text-align: center; - font-family: "DistressBlack"; - - } - - .traits { - box-shadow: 0px 5px 15px black; - - h3 { - margin: 0 - } - - h4 { - margin: 0 - } - } - } - - - -} \ No newline at end of file diff --git a/scss/itemCards.scss b/scss/itemCards.scss deleted file mode 100644 index 73dfe38..0000000 --- a/scss/itemCards.scss +++ /dev/null @@ -1,7 +0,0 @@ -ol#chat-log { - div.item-card { - header img { - max-width: 30%; - } - } -} \ No newline at end of file diff --git a/scss/roll.scss b/scss/roll.scss deleted file mode 100644 index 6fbb3dc..0000000 --- a/scss/roll.scss +++ /dev/null @@ -1,189 +0,0 @@ -ol#chat-log { - header.message-header { - background-color: black; - padding: 0 1rem; - } - - .vermine-roll-message { - overflow: hidden; - box-shadow: 0px 0px 30px white inset; - padding: 0; - position: relative; - - - .flexrow { - align-items: center; - box-shadow: 0px 5px 10px 0px black; - } - - h3, - h4 { - text-transform: uppercase; - font-family: "DistressBlack"; - margin-top: 1rem; - border-bottom: none; - font-weight: 900; - background: 50% 0%/cover no-repeat url(/systems/vermine2047/assets/images/ui/scotch.webp); - - &+span { - font-family: "DistressBlack"; - font-size: large; - text-transform: unset; - - padding-left: 2rem; - background: -100% 0%/cover no-repeat url(/systems/vermine2047/assets/images/ui/scotch.webp); - - &#allowed_reroll { - font-size: large; - - } - } - } - - h3 { - background: url(/systems/vermine2047/assets/images/ui/scotch.webp); - background-position: center; - background-size: 200%; - } - - h4 { - text-align: center; - } - - div.roll-total { - transform: rotate(-3deg) scale(1.2) translateX(2rem) translateY(0.5rem); - background: url(/systems/vermine2047/assets/images/ui/scotch.webp); - background-position: center; - background-size: 200%; - margin-bottom: 2rem; - padding: 0; - z-index: +1; - width: 75%; - } - - div.reroll { - button { - text-transform: uppercase; - font-family: "DistressBlack"; - padding: 0 1rem; - max-width: fit-content; - box-shadow: 0px 0px 2px black; - background: 50% 0%/cover no-repeat url(/systems/vermine2047/assets/images/ui/scotch.webp); - - } - - transition:0.3s; - max-height:1px; - overflow: hidden; - justify-content: end; - text-align: center; - align-items: center; - - &.visible { - max-height: 15rem; - - } - - - } - - ul.roll-results { - list-style: none; - - li.die { - position: relative; - max-width: 3rem; - line-height: 3rem; - float: left; - margin: 0.2rem; - background-image: url(/icons/dice/d10black.svg); - background-position: center; - background-repeat: no-repeat; - background-size: contain; - font-weight: 800; - font-size: 1rem; - color: #ffffff; - text-align: center; - transition: 0.3s; - border-bottom: 5px solid rgb(255, 0, 0); - border-radius: 2rem; - - - - - &::after { - content: ""; - position: absolute; - top: -1rem; - text-wrap: nowrap; - color: white; - font-weight: 100; - font-size: smaller; - text-align: center; - opacity: 0; - text-shadow: 0px 0px 5px black; - - } - - &:hover::after { - opacity: 1; - color: white; - } - - - &.human, - &.adapted { - border-top: 5px solid rgb(255, 217, 0); - - &::after { - content: ""; - - } - } - - &.rerollable { - cursor: pointer; - - &:hover { - transform: translateY(0.5rem) - } - } - - &.success { - border-bottom: 5px solid rgb(0, 143, 7); - } - - &.adapted { - - &::after { - content: "adapté" - } - - - - } - - &.human { - &::after { - - content: "humain" - } - } - - &.rerolled { - transform: translateY(-0rem); - } - - span { - text-align: center; - font-size: larger; - text-shadow: 0px 0px 8px black; - } - - - - } - } - } - -} \ No newline at end of file diff --git a/scss/special-applications.scss b/scss/special-applications.scss deleted file mode 100644 index d25aac0..0000000 --- a/scss/special-applications.scss +++ /dev/null @@ -1,22 +0,0 @@ -.app .actor.choose { - div.actor { - position: relative; - - img { - border-radius: 50%; - box-shadow: 0px 0px 8px black; - - } - - span.actor-name { - position: absolute; - text-align: center; - background-color: rgba(255, 255, 255, 0.562); - border: 5px; - width: 100%; - padding: 0 1rem; - border-radius: 5px; - box-shadow: 0px 0px 8px black; - } - } -} \ No newline at end of file diff --git a/scss/special-inputs.scss b/scss/special-inputs.scss deleted file mode 100644 index aad756d..0000000 --- a/scss/special-inputs.scss +++ /dev/null @@ -1,148 +0,0 @@ -input[type="range"] { - appearance: none; - background: transparent; - cursor: pointer; - width: 100%; - -} - -input[type="range"]::-webkit-slider-runnable-track { - background: url(../assets/images/ui/scotch.webp) no-repeat center; - background-size: 100% auto; - height: 0.4rem; - border: none; - box-shadow: 0px 0px 13px rgba(31, 26, 26, 0.979) inset; -} - -input[type="range"]::-webkit-slider-thumb { - - appearance: none; - margin-top: -0.3rem; - /* Centers thumb on the track */ - height: 1rem; - width: 1rem; - border: none; - border-radius: 50%; - background: url(/systems/vermine2047/assets/images/ui/totems/human.webp); - background-size: cover; - filter: contrast(2); - box-shadow: 0px 0px 10px black -} - -input[type="range"]:focus::-webkit-slider-thumb { - box-shadow: 0px 0px 10px yellow -} - -select { - border: none; - background: url(../assets/images/ui/scotch.webp); - background-size: 100% 100%; - box-shadow: 0px 0px 3px rgba(31, 26, 26, 0.979) inset; - - &[disabled] { - color: rgb(0, 0, 0); - text-shadow: 0px 0px 15px black; - } - - option { - appearance: none; - border: none; - background: url(../assets/images/ui/scotch.webp); - background-size: 100% 100%; - } -} - -input[type="checkbox"], -input[type="radio"] { - -webkit-appearance: none; - appearance: none; - background: transparent; - box-shadow: 0px 0px 3px rgb(133, 133, 78); - cursor: pointer; - width: 1.5rem; - height: 1rem; - border-radius: 0.4rem; - transition: 0.3s; - clip-path: polygon(25% 0%, 75% 0%, 100% 50%, 75% 100%, 25% 100%, 0% 50%); - box-shadow: 0px 0px 6px black inset; - background-color: rgba(61, 11, 11, 0.658); - - &[disabled="true"] { - filter: grayscale(1) - } - - &:after { - content: " "; - background: url(/systems/vermine2047/assets/images/ui/totems/human.webp); - background-size: 50% 150%; - background-repeat: no-repeat; - position: relative; - top: 10%; - left: 0%; - width: 100%; - height: 80%; - display: block; - border-radius: 0%; - padding: 0; - transition: 0.3s; - - - } - - - &:checked { - background-color: rgba(26, 107, 12, 0.658); - - - &:after { - font-weight: 900; - background-color: rgba(26, 1, 1, 0); - left: 50%; - - - - } - } -} - -iframe { - min-height: 500px; - - .tabs.moods-headings { - max-width: 1px - } -} - -input[type="radio"] { - - width: 1rem; - height: 1rem; - - &:after { - width: 0.8rem; - background-size: 100% 100%; - top: 5%; - left: 5%; - width: 90%; - height: 90%; - background-size: 30% 30%; - background-position: center; - - } - - &:not([disabled]):hover::after { - background-size: 90% 90%; - - } - - &:checked::after { - content: ""; - background-size: 70% 70%; - top: 5%; - left: 5%; - position: relative; - background-color: rgba(26, 1, 1, 0); - - - } -} \ No newline at end of file diff --git a/scss/style.scss b/scss/style.scss deleted file mode 100644 index dd9d1cb..0000000 --- a/scss/style.scss +++ /dev/null @@ -1,546 +0,0 @@ -@import url("https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap"); - -/* Global styles */ -.window-app { - font-family: "Roboto", sans-serif; - box-shadow: 0px 0px 30px rgb(69, 78, 44); - - -} - -.rollable:hover, -.rollable:focus { - color: #000; - text-shadow: 0 0 10px red; - cursor: pointer; -} - -.grid, -.grid-2col { - display: grid; - grid-column: span 2/span 2; - grid-template-columns: repeat(2, minmax(0, 1fr)); - gap: 10px; - margin: 5px 0; - padding: 0; -} - -.grid-3col { - grid-column: span 3/span 3; - grid-template-columns: repeat(3, minmax(0, 1fr)); -} - -.grid-4col { - grid-column: span 4/span 4; - grid-template-columns: repeat(4, minmax(0, 1fr)); -} - -.grid-5col { - grid-column: span 5/span 5; - grid-template-columns: repeat(5, minmax(0, 1fr)); -} - -.grid-6col { - grid-column: span 6/span 6; - grid-template-columns: repeat(6, minmax(0, 1fr)); -} - -.grid-7col { - grid-column: span 7/span 7; - grid-template-columns: repeat(7, minmax(0, 1fr)); -} - -.grid-8col { - grid-column: span 8/span 8; - grid-template-columns: repeat(8, minmax(0, 1fr)); -} - -.grid-9col { - grid-column: span 9/span 9; - grid-template-columns: repeat(9, minmax(0, 1fr)); -} - -.grid-10col { - grid-column: span 10/span 10; - grid-template-columns: repeat(10, minmax(0, 1fr)); -} - -.grid-11col { - grid-column: span 11/span 11; - grid-template-columns: repeat(11, minmax(0, 1fr)); -} - -.grid-12col { - grid-column: span 12/span 12; - grid-template-columns: repeat(12, minmax(0, 1fr)); -} - -.grid-start-2 { - grid-column-start: 2; -} - -.grid-start-3 { - grid-column-start: 3; -} - -.grid-start-4 { - grid-column-start: 4; -} - -.grid-start-5 { - grid-column-start: 5; -} - -.grid-start-6 { - grid-column-start: 6; -} - -.grid-start-7 { - grid-column-start: 7; -} - -.grid-start-8 { - grid-column-start: 8; -} - -.grid-start-9 { - grid-column-start: 9; -} - -.grid-start-10 { - grid-column-start: 10; -} - -.grid-start-11 { - grid-column-start: 11; -} - -.grid-start-12 { - grid-column-start: 12; -} - -.grid-span-2 { - grid-column-end: span 2; -} - -.grid-span-3 { - grid-column-end: span 3; -} - -.grid-span-4 { - grid-column-end: span 4; -} - -.grid-span-5 { - grid-column-end: span 5; -} - -.grid-span-6 { - grid-column-end: span 6; -} - -.grid-span-7 { - grid-column-end: span 7; -} - -.grid-span-8 { - grid-column-end: span 8; -} - -.grid-span-9 { - grid-column-end: span 9; -} - -.grid-span-10 { - grid-column-end: span 10; -} - -.grid-span-11 { - grid-column-end: span 11; -} - -.grid-span-12 { - grid-column-end: span 12; -} - -.flex-group-center, -.flex-group-left, -.flex-group-right { - -webkit-box-pack: center; - -ms-flex-pack: center; - justify-content: center; - -webkit-box-align: center; - -ms-flex-align: center; - align-items: center; - text-align: center; -} - -.flex-group-left { - -webkit-box-pack: start; - -ms-flex-pack: start; - justify-content: flex-start; - text-align: left; -} - -.flex-group-right { - -webkit-box-pack: end; - -ms-flex-pack: end; - justify-content: flex-end; - text-align: right; -} - -.flex-align-left { - align-items: flex-start; -} - -.flex-align-right { - align-items: flex-end; -} - -.gap-xs { - gap: 2px; -} - -.gap-sm { - gap: 4px; -} - -.gap-md { - gap: 8px; -} - -.gap-lg { - gap: 16px; -} - -.flexshrink { - -webkit-box-flex: 0; - -ms-flex: 0; - flex: 0; -} - -.flex-between { - -webkit-box-pack: justify; - -ms-flex-pack: justify; - justify-content: space-between; -} - -.flexlarge { - -webkit-box-flex: 2; - -ms-flex: 2; - flex: 2; -} - -.align-left { - -webkit-box-pack: start; - -ms-flex-pack: start; - justify-content: flex-start; - text-align: left; -} - -.align-right { - -webkit-box-pack: end; - -ms-flex-pack: end; - justify-content: flex-end; - text-align: right; -} - -.align-center { - -webkit-box-pack: center; - -ms-flex-pack: center; - justify-content: center; - text-align: center; -} - -.system-vermine2047 .item-form { - font-family: "Roboto", sans-serif; -} - -.system-vermine2047 .sheet-header { - -webkit-box-flex: 0; - -ms-flex: 0 auto; - flex: 0 auto; - overflow: hidden; - display: -webkit-box; - display: -ms-flexbox; - display: flex; - -webkit-box-orient: horizontal; - -webkit-box-direction: normal; - -ms-flex-direction: row; - flex-direction: row; - -ms-flex-wrap: wrap; - flex-wrap: wrap; - -webkit-box-pack: start; - -ms-flex-pack: start; - justify-content: flex-start; - margin-bottom: 10px; -} - -.system-vermine2047 .sheet-header .profile-img { - -webkit-box-flex: 0; - -ms-flex: 0 0 100px; - flex: 0 0 100px; - height: 100px; - margin-right: 10px; -} - -.system-vermine2047 .sheet-header .header-fields { - -webkit-box-flex: 1; - -ms-flex: 1; - flex: 1; -} - -.system-vermine2047 .sheet-header h1.charname { - height: 50px; - padding: 0px; - margin: 5px 0; - border-bottom: 0; -} - -.system-vermine2047 .sheet-header h1.charname input { - width: 100%; - height: 100%; - margin: 0; -} - -.system-vermine2047 .sheet-tabs { - -webkit-box-flex: 0; - -ms-flex: 0; - flex: 0; -} - -.system-vermine2047 .sheet-body .tab, -.editor { - height: 100%; - width: 100%; - -} - -.editor { - min-height: 75px; - margin-bottom: 1rem; - - min-width: 100%; - - - .editor-content { - min-width: 100%; - min-height: 3rem; - } -} - -editor:hover .editor-edit { - display: block; -} - -.system-vermine2047 .tox { - min-height: 25vh; -} - -.system-vermine2047 .tox .tox-editor-container { - background: #fff; -} - -.system-vermine2047 .tox .tox-edit-area { - padding: 0 8px; -} - -.system-vermine2047 .resource-label { - font-weight: bold; -} - -.system-vermine2047 .items-header { - height: 28px; - margin: 2px 0; - padding: 0; - -webkit-box-align: center; - -ms-flex-align: center; - align-items: center; - background: rgba(0, 0, 0, 0.05); - border: 2px groove #eeede0; - font-weight: bold; -} - -.system-vermine2047 .items-header>* { - font-size: 14px; - text-align: center; -} - -.system-vermine2047 .items-header .item-name { - font-weight: bold; - padding-left: 5px; - text-align: left; - display: -webkit-box; - display: -ms-flexbox; - display: flex; -} - -.system-vermine2047 .items-list { - list-style: none; - margin: 0; - padding: 0; - overflow-y: auto; - scrollbar-width: thin; - color: #444; -} - -.system-vermine2047 .items-list .item-list { - list-style: none; - margin: 0; - padding: 0; -} - -.system-vermine2047 .items-list .item-name { - -webkit-box-flex: 2; - -ms-flex: 2; - flex: 2; - margin: 0; - overflow: hidden; - font-size: 13px; - text-align: left; - -webkit-box-align: center; - -ms-flex-align: center; - align-items: center; - display: -webkit-box; - display: -ms-flexbox; - display: flex; -} - -.system-vermine2047 .items-list .item-name h3, -.system-vermine2047 .items-list .item-name h4 { - margin: 0; - white-space: nowrap; - overflow-x: hidden; -} - -.system-vermine2047 .items-list .item-controls { - display: -webkit-box; - display: -ms-flexbox; - display: flex; - -webkit-box-flex: 0; - -webkit-box-pack: end; - -ms-flex-pack: end; - justify-content: flex-end; -} - -.system-vermine2047 .items-list .item-controls a { - font-size: 12px; - text-align: center; - margin: 0 6px; -} - -.system-vermine2047 .items-list .item { - -webkit-box-align: center; - -ms-flex-align: center; - align-items: center; - padding: 0 2px; - border-bottom: 1px solid #c9c7b8; -} - -.system-vermine2047 .items-list .item:last-child { - border-bottom: none; -} - -.system-vermine2047 .items-list .item .item-name { - color: #191813; -} - -.system-vermine2047 .items-list .item .item-name .item-image { - -webkit-box-flex: 0; - -ms-flex: 0 0 30px; - flex: 0 0 30px; - height: 30px; - background-size: 30px; - border: none; - margin-right: 5px; -} - -.system-vermine2047 .items-list .item-prop { - text-align: center; - border-left: 1px solid #c9c7b8; - border-right: 1px solid #c9c7b8; - font-size: 12px; -} - -.system-vermine2047 .items-list .items-header { - height: 28px; - margin: 2px 0; - padding: 0; - -webkit-box-align: center; - -ms-flex-align: center; - align-items: center; - background: rgba(0, 0, 0, 0.05); - border: 2px groove #eeede0; - font-weight: bold; -} - -.system-vermine2047 .items-list .items-header>* { - font-size: 12px; - text-align: center; -} - -.system-vermine2047 .items-list .items-header .item-name { - padding-left: 5px; - text-align: left; -} - -.system-vermine2047 .item-formula { - -webkit-box-flex: 0; - -ms-flex: 0 0 200px; - flex: 0 0 200px; - padding: 0 8px; -} - -.system-vermine2047 .effects .item .effect-source, -.system-vermine2047 .effects .item .effect-duration, -.system-vermine2047 .effects .item .effect-controls { - text-align: center; - border-left: 1px solid #c9c7b8; - border-right: 1px solid #c9c7b8; - font-size: 12px; -} - -.system-vermine2047 .effects .item .effect-controls { - border: none; -} - -.chat-message .message-header { - line-height: 20px; - color: white; - text-shadow: 0px 0px 5px black; - background: #1918135e -} - -span.game-mode { - font-family: "DistressBlack", - sans-serif; - - position: absolute; - margin-left: auto; - color: transparent; - top: 1rem; - z-index: 900; - width: 55%; - text-align: center; - text-transform: uppercase; - font-weight: 900; - background: linear-gradient(180deg, rgba(255, 255, 255, 0.767) 0%, rgba(0, 0, 0, 0.61) 17%, rgba(0, 0, 0, 0.548) 19%, rgba(222, 255, 221, 0.575) 24%, rgba(255, 255, 255, 0.637) 43%, rgba(0, 0, 0, 0.486) 47%, rgba(254, 255, 254, 0.466) 50%, rgba(0, 0, 0, 0.699) 63%, rgba(134, 160, 137, 0.479) 64%, rgba(213, 248, 210, 0.493) 100%); - background-clip: text; - - &#game-mode-1 { - color: rgba(235, 218, 143, 0.8); - } - - &#game-mode-2 { - color: rgb(131, 248, 131); - } - - &#game-mode-3 { - color: rgba(245, 124, 124, 0.8); - } -} - -.shadow { - box-shadow: 0 0.5rem 2rem black; - margin: 2rem 0 -} \ No newline at end of file diff --git a/scss/vermine2047.scss b/scss/vermine2047.scss deleted file mode 100644 index 5bdf023..0000000 --- a/scss/vermine2047.scss +++ /dev/null @@ -1,117 +0,0 @@ -@import "./base_work.scss"; -@import "./style.scss"; -@import "./roll.scss"; -@import "./itemCards.scss"; -@import "item-sheet.scss"; -@import "dialog.scss"; -@import "special-inputs.scss"; -@import "special-applications.scss"; -@import "_flex.scss"; -@import "_app.scss"; - - -// overwrites variables -:root { - --color-text-light-highlight: #96d696; - --color-text-light-heading: #9fd8a8; - --color-text-light-primary: #a4b5b3; - --color-text-dark-primary: #131919; - --color-text-dark-secondary: #444b4a; - --color-text-dark-header: #1d2223; - --color-text-dark-inactive: #71797a; - --color-text-hyperlink: #5aaf0a; - --color-text-light-0: #fff; - --color-text-light-1: #e0f0f0; - --color-text-light-2: #c9e0c0; - --color-text-light-3: #90c4a4; - --color-text-light-4: #80c08b; - --color-text-light-5: #60b06b; - --color-text-light-6: #40a05d; - --color-text-light-7: #208028; - --color-text-dark-1: #111; - --color-text-dark-2: #222; - --color-text-dark-3: #444; - --color-text-dark-4: #555; - --color-text-dark-5: #666; - --color-text-dark-6: #777; - --color-border-light-1: #b0d9b0; - --color-border-light-2: #80c0c0; - --color-border-dark-1: #131919; - --color-border-dark-2: #1d2223; - --color-border-dark-3: #2d3333; - --color-border-dark-4: #3d4444; - --color-border-dark-5: #668888; - --color-shadow-primary: #7bb60d; - --color-shadow-highlight: #85cc01d0; - --color-shadow-dark: #000; - --color-underline-inactive: #71797a; - --color-underline-active: #1a1944; - --color-underline-header: #228247; - --color-border-light-highlight: #b0d9b0; - --color-border-light-primary: #a4b5b3; - --color-border-light-secondary: #9fc7d8; - --color-border-light-tertiary: #71797a; - --color-border-dark: #000; - --color-border-dark-primary: #131919; - --color-border-dark-secondary: #1d2223; - --color-border-dark-tertiary: #444b4a; - --color-border-highlight: #85c019; - --color-border-highlight-alt: #70c008; - --color-bg-btn-minor-inactive: #9fc7d8; - --color-bg-btn-minor-active: #a4b5b3; - --color-bg-option: #ccdada; - --color-checkbox-checked: #666; - --color-ownership-none: #00ff55; - --color-ownership-observer: #71797a; - --color-ownership-owner: #a4b5b3; - --z-index-canvas: 0; - --z-index-app: 30; - --z-index-ui: 60; - --z-index-window: 100; - --z-index-tooltip: 9999; - --sidebar-width: 300px; - --sidebar-header-height: 32px; - --sidebar-item-height: 48px; - --hotbar-height: 52px; - --hotbar-width: 578px; - --macro-size: 50px; - --players-width: 200px; - --form-field-height: 26px; - --font-primary: "Signika", sans-serif; - --font-mono: monospace; - --font-awesome: "Font Awesome 6 Pro"; - --font-size-11: 0.6875rem; - --font-size-12: 0.75rem; - --font-size-13: 0.8125rem; - --font-size-14: 0.875rem; - --font-size-16: 1rem; - --font-size-18: 1.125rem; - --font-size-20: 1.25rem; - --font-size-24: 1.5rem; - --font-size-28: 1.75rem; - --font-size-32: 2rem; - --font-size-48: 3rem; - --line-height-12: 0.75rem; - --line-height-16: 1rem; - --line-height-20: 1.25rem; - --line-height-30: 1.875rem; - --color-level-info: #b95c87; - --color-level-warning: #04b184; - --color-level-error: #03750; - --color-level-success: #3c266c; -} - -/* ----------------------------------------- */ -/* Scrollbar -/* ----------------------------------------- */ -::-webkit-scrollbar-thumb { - outline: none; - border-radius: 3px; - background: #577822; - border: 1px solid var(--color-border-highlight); -} - -::-webkit-scrollbar { - width: 3px; - height: 3px; -} \ No newline at end of file diff --git a/template.json b/template.json deleted file mode 100644 index f8ee651..0000000 --- a/template.json +++ /dev/null @@ -1,993 +0,0 @@ -{ - "Actor": { - "types": [ - "character", - "npc", - "group", - "creature" - ], - "templates": { - "base": { - "minorWound": { - "threshold": 1, - "value": 0, - "min": 0, - "max": 5 - }, - "majorWound": { - "threshold": 4, - "value": 0, - "min": 0, - "max": 4 - }, - "deadlyWound": { - "threshold": 8, - "value": 0, - "min": 0, - "max": 2 - }, - "combatStatus": { - "label": "", - "difficulty": 7 - } - } - }, - "character": { - "templates": [ - "base" - ], - "adaptation": { - "value": 1, - "min": 0, - "max": 5, - "totems": { - "human": { - "value": 1, - "min": 0, - "max": 3 - }, - "adapted": { - "value": 1, - "min": 0, - "max": 3 - } - } - }, - "identity": { - "height": 0, - "weight": 0, - "totem": "", - "age": 15, - "ageType": 2, - "profile": "", - "theme": "", - "instincts": "", - "prohibits": "", - "objectives": "", - "relations": "", - "biography": "" - }, - "equipment": { - "description": "" - }, - "attributes": { - "xp": { - "value": 0, - "max": 10 - }, - "reputation": { - "value": 0, - "max": 10 - }, - "self_control": { - "value": 0, - "min": 0, - "max": 5 - }, - "effort": { - "value": 0, - "min": 0, - "max": 5 - } - }, - "encounters": [], - "abilities": { - "vigor": { - "value": 1, - "min": 0, - "max": 5, - "category": "physical" - }, - "health": { - "value": 1, - "min": 0, - "max": 5, - "category": "physical" - }, - "precision": { - "value": 1, - "min": 0, - "max": 5, - "category": "manual" - }, - "reflexes": { - "value": 1, - "min": 0, - "max": 5, - "category": "manual" - }, - "knowledge": { - "value": 1, - "min": 0, - "max": 5, - "category": "mental" - }, - "perception": { - "value": 1, - "min": 0, - "max": 5, - "category": "mental" - }, - "will": { - "value": 1, - "min": 0, - "max": 5, - "category": "social" - }, - "empathy": { - "value": 1, - "min": 0, - "max": 5, - "category": "social" - } - }, - "skill_categories": { - "preferred": "", - "man": { - "label": "VERMINE.skill_category.man", - "preferred": false - }, - "animal": { - "label": "VERMINE.skill_category.animal", - "preferred": false - }, - "tool": { - "label": "VERMINE.skill_category.tool", - "preferred": false - }, - "weapon": { - "label": "VERMINE.skill_category.weapon", - "preferred": false - }, - "survival": { - "label": "VERMINE.skill_category.survival", - "preferred": false - }, - "world": { - "label": "VERMINE.skill_category.world", - "preferred": false - } - }, - "skills": { - "arts": { - "value": 0, - "min": 0, - "max": 5, - "category": "man", - "rarity": 1 - }, - "civilization": { - "value": 0, - "min": 0, - "max": 5, - "category": "man", - "rarity": 2 - }, - "psychology": { - "value": 0, - "min": 0, - "max": 5, - "category": "man", - "rarity": 1 - }, - "rumors": { - "value": 0, - "min": 0, - "max": 5, - "category": "man", - "rarity": 0 - }, - "healing": { - "value": 0, - "min": 0, - "max": 5, - "category": "man", - "rarity": 1 - }, - "animalism": { - "value": 0, - "min": 0, - "max": 5, - "category": "animal", - "rarity": 1 - }, - "dissection": { - "value": 0, - "min": 0, - "max": 5, - "category": "animal", - "rarity": 2 - }, - "wildlife": { - "value": 0, - "min": 0, - "max": 5, - "category": "animal", - "rarity": 1 - }, - "repulsion": { - "value": 0, - "min": 0, - "max": 5, - "category": "animal", - "rarity": 0 - }, - "tracks": { - "value": 0, - "min": 0, - "max": 5, - "category": "animal", - "rarity": 0 - }, - "crafting": { - "value": 0, - "min": 0, - "max": 5, - "category": "tool", - "rarity": 2 - }, - "diy": { - "value": 0, - "min": 0, - "max": 5, - "category": "tool", - "rarity": 0 - }, - "mecanical": { - "value": 0, - "min": 0, - "max": 5, - "category": "tool", - "rarity": 2 - }, - "piloting": { - "value": 0, - "min": 0, - "max": 5, - "category": "tool", - "rarity": 1 - }, - "technology": { - "value": 0, - "min": 0, - "max": 5, - "category": "tool", - "rarity": 2 - }, - "firearms": { - "value": 0, - "min": 0, - "max": 5, - "category": "weapon", - "rarity": 2 - }, - "archery": { - "value": 0, - "min": 0, - "max": 5, - "category": "weapon", - "rarity": 0 - }, - "armory": { - "value": 0, - "min": 0, - "max": 5, - "category": "weapon", - "rarity": 2 - }, - "throwing": { - "value": 0, - "min": 0, - "max": 5, - "category": "weapon", - "rarity": 0 - }, - "melee": { - "value": 0, - "min": 0, - "max": 5, - "category": "weapon", - "rarity": 0 - }, - "alertness": { - "value": 0, - "min": 0, - "max": 5, - "category": "survival", - "rarity": 0 - }, - "atletics": { - "value": 0, - "min": 0, - "max": 5, - "category": "survival", - "rarity": 0 - }, - "food": { - "value": 0, - "min": 0, - "max": 5, - "category": "survival", - "rarity": 0 - }, - "stealth": { - "value": 0, - "min": 0, - "max": 5, - "category": "survival", - "rarity": 0 - }, - "close": { - "value": 0, - "min": 0, - "max": 5, - "category": "survival", - "rarity": 0 - }, - "environment": { - "value": 0, - "min": 0, - "max": 5, - "category": "world", - "rarity": 1 - }, - "flora": { - "value": 0, - "min": 0, - "max": 5, - "category": "world", - "rarity": 1 - }, - "road": { - "value": 0, - "min": 0, - "max": 5, - "category": "world", - "rarity": 0 - }, - "toxics": { - "value": 0, - "min": 0, - "max": 5, - "category": "world", - "rarity": 2 - }, - "ruins": { - "value": 0, - "min": 0, - "max": 5, - "category": "world", - "rarity": 1 - } - }, - "combatStatus": { - "label": "", - "difficulty": 7 - } - }, - "npc": { - "templates": [ - "base" - ], - "identity": { - "name": "", - "profile": "", - "origin": "", - "totem": "", - "theme": "", - "notes": "" - }, - "attributes": { - "xp": { - "value": 0, - "max": 10 - }, - "reputation": { - "value": 0, - "max": 10 - }, - "self_control": { - "value": 0, - "min": 0, - "max": 5 - }, - "effort": { - "value": 0, - "min": 0, - "max": 5 - } - }, - "abilities": { - "vigor": { - "value": 1, - "min": 0, - "max": 5, - "category": "physical" - }, - "health": { - "value": 1, - "min": 0, - "max": 5, - "category": "physical" - }, - "precision": { - "value": 1, - "min": 0, - "max": 5, - "category": "manual" - }, - "reflexes": { - "value": 1, - "min": 0, - "max": 5, - "category": "manual" - }, - "knowledge": { - "value": 1, - "min": 0, - "max": 5, - "category": "mental" - }, - "perception": { - "value": 1, - "min": 0, - "max": 5, - "category": "mental" - }, - "will": { - "value": 1, - "min": 0, - "max": 5, - "category": "social" - }, - "empathy": { - "value": 1, - "min": 0, - "max": 5, - "category": "social" - } - }, - "skill_categories": { - "preferred": "", - "man": { - "label": "VERMINE.skill_category.man", - "preferred": false - }, - "animal": { - "label": "VERMINE.skill_category.animal", - "preferred": false - }, - "tool": { - "label": "VERMINE.skill_category.tool", - "preferred": false - }, - "weapon": { - "label": "VERMINE.skill_category.weapon", - "preferred": false - }, - "survival": { - "label": "VERMINE.skill_category.survival", - "preferred": false - }, - "world": { - "label": "VERMINE.skill_category.world", - "preferred": false - } - }, - "skills": { - "arts": { - "value": 0, - "min": 0, - "max": 5, - "category": "man", - "rarity": 1 - }, - "civilization": { - "value": 0, - "min": 0, - "max": 5, - "category": "man", - "rarity": 2 - }, - "psychology": { - "value": 0, - "min": 0, - "max": 5, - "category": "man", - "rarity": 1 - }, - "rumors": { - "value": 0, - "min": 0, - "max": 5, - "category": "man", - "rarity": 0 - }, - "healing": { - "value": 0, - "min": 0, - "max": 5, - "category": "man", - "rarity": 1 - }, - "animalism": { - "value": 0, - "min": 0, - "max": 5, - "category": "animal", - "rarity": 1 - }, - "dissection": { - "value": 0, - "min": 0, - "max": 5, - "category": "animal", - "rarity": 2 - }, - "fauna": { - "value": 0, - "min": 0, - "max": 5, - "category": "animal", - "rarity": 1 - }, - "repulsion": { - "value": 0, - "min": 0, - "max": 5, - "category": "animal", - "rarity": 1 - }, - "tracks": { - "value": 0, - "min": 0, - "max": 5, - "category": "animal", - "rarity": 0 - }, - "crafting": { - "value": 0, - "min": 0, - "max": 5, - "category": "tool", - "rarity": 2 - }, - "diy": { - "value": 0, - "min": 0, - "max": 5, - "category": "tool", - "rarity": 0 - }, - "mecanical": { - "value": 0, - "min": 0, - "max": 5, - "category": "tool", - "rarity": 2 - }, - "piloting": { - "value": 0, - "min": 0, - "max": 5, - "category": "tool", - "rarity": 1 - }, - "technology": { - "value": 0, - "min": 0, - "max": 5, - "category": "tool", - "rarity": 2 - }, - "firearms": { - "value": 0, - "min": 0, - "max": 5, - "category": "weapon", - "rarity": 2 - }, - "archery": { - "value": 0, - "min": 0, - "max": 5, - "category": "weapon", - "rarity": 0 - }, - "armory": { - "value": 0, - "min": 0, - "max": 5, - "category": "weapon", - "rarity": 2 - }, - "throwing": { - "value": 0, - "min": 0, - "max": 5, - "category": "weapon", - "rarity": 0 - }, - "melee": { - "value": 0, - "min": 0, - "max": 5, - "category": "weapon", - "rarity": 0 - }, - "alertness": { - "value": 0, - "min": 0, - "max": 5, - "category": "survival", - "rarity": 0 - }, - "athletics": { - "value": 0, - "min": 0, - "max": 5, - "category": "survival", - "rarity": 0 - }, - "food": { - "value": 0, - "min": 0, - "max": 5, - "category": "survival", - "rarity": 0 - }, - "stealth": { - "value": 0, - "min": 0, - "max": 5, - "category": "survival", - "rarity": 0 - }, - "close": { - "value": 0, - "min": 0, - "max": 5, - "category": "survival", - "rarity": 0 - }, - "environment": { - "value": 0, - "min": 0, - "max": 5, - "category": "world", - "rarity": 1 - }, - "flora": { - "value": 0, - "min": 0, - "max": 5, - "category": "world", - "rarity": 1 - }, - "road": { - "value": 0, - "min": 0, - "max": 5, - "category": "world", - "rarity": 0 - }, - "toxics": { - "value": 0, - "min": 0, - "max": 5, - "category": "world", - "rarity": 2 - }, - "ruins": { - "value": 0, - "min": 0, - "max": 5, - "category": "world", - "rarity": 1 - } - }, - "combatStatus": { - "label": "", - "difficulty": 9 - }, - "equipment": { - "description": "" - }, - "threat": { - "value": 1, - "min": 1, - "max": 4 - }, - "experience": { - "value": 1, - "min": 1, - "max": 4 - }, - "role": { - "value": 1, - "min": 1, - "max": 4 - }, - "skills": "" - }, - "group": { - "templates": [ - "base" - ], - "identity": { - "totem": "", - "profile": "", - "origin": "", - "theme": "", - "instincts": "", - "prohibits": "", - "notes": "" - }, - "equipment": { - "description": "" - }, - "level": { - "value": 1, - "min": 1, - "max": 10 - }, - "reputation": { - "value": 10, - "min": 2, - "max": 10 - }, - "morale": { - "level": "high", - "value": 7, - "min": 0, - "max": 7 - }, - "reserve": { - "value": 0, - "min": 0, - "max": 10 - }, - "objectives": { - "major": [], - "minor": [] - }, - "groupAbilities": [], - "members": [], - "encounters": [] - }, - "creature": { - "templates": [ - "base" - ], - "identity": { - "profile": "", - "origin": "", - "theme": "", - "notes": "", - "biography": "" - }, - "skills": "", - "modes": { - "survival": true, - "nightmare": true, - "apocalypse": false - }, - "pattern": { - "value": 1, - "min": 1, - "max": 4 - }, - "size": { - "value": 1, - "min": 1, - "max": 3 - }, - "role": { - "value": 1, - "min": 1, - "max": 4 - }, - "pack": { - "value": 0, - "min": 0, - "max": 3 - }, - "computed": { - "attack": 0, - "damage": 0, - "vigor": 0, - "reaction": 0, - "reactionBonus": 0, - "pools": 0, - "gear": 9, - "gearHindrance": 0, - "protection": 1 - }, - "equipment": { - "description": "" - } - } - }, - "Item": { - "types": [ - "item", - "weapon", - "defense", - "vehicle", - "ability", - "specialty", - "background", - "trauma", - "evolution", - "rumor", - "target", - "rite" - ], - "templates": { - "base": { - "description": "", - "rarity": { - "value": 3, - "handicap": 0 - }, - "reliability": 3, - "handicap": 0, - "quantity": 1, - "weight": 0, - "traits": {}, - "damages": { - "value": 0, - "min": 0, - "max": 5, - "pannes": [ - "mineure", - "mineure", - "grave", - "grave", - "critique" - ], - "state": [ - "endommagé", - "endommagé", - "défectueux", - "défectueux", - "hors d'usage" - ], - "effect": [ - "bonus annulé", - "bonus annulé", - "malus 1D", - "malus 1D", - "inutilisable" - ] - } - }, - "list": { - "description": "" - } - }, - "item": { - "templates": [ - "base" - ], - "needSkill": { - "value": false, - "skill": "" - } - }, - "weapon": { - "templates": [ - "base" - ], - "min_range": 0, - "max_range": 0, - "damage": { - "value": 0, - "type": "", - "addVigor": false - }, - "ammo": 0 - }, - "defense": { - "templates": [ - "base" - ], - "level": 0, - "specificLevel": { - "label": "", - "level": 0 - }, - "mobility": 0, - "isShield": false - }, - "ability": { - "templates": [ - "list" - ], - "type": "", - "totem": "", - "learn": { - "threshold": 5, - "hindrance": 0 - }, - "level": { - "value": 1, - "min": 1, - "max": 3 - }, - "effects": [] - }, - "specialty": { - "name": "", - "skill": "" - }, - "vehicle": { - "templates": [ - "base" - ], - "mobility": 3 - }, - "rite": { - "templates": [ - "base" - ], - "rituel": "", - "transe": "", - "ability": "", - "effect": "" - }, - "background": { - "templates": [ - "list" - ], - "cost": 1 - }, - "trauma": { - "templates": [ - "list" - ], - "type": "" - }, - "evolution": { - "templates": [ - "list" - ], - "level": { - "value": 1, - "min": 1, - "max": 4 - } - }, - "rumor": { - "templates": [ - "list" - ] - }, - "target": { - "templates": [ - "list" - ], - "level": "minor" - } - } -} \ No newline at end of file diff --git a/templates/actor/actor-npc-sheet.hbs b/templates/actor/actor-npc-sheet.hbs index 5860907..470cd3e 100644 --- a/templates/actor/actor-npc-sheet.hbs +++ b/templates/actor/actor-npc-sheet.hbs @@ -205,11 +205,11 @@
diff --git a/templates/combat-tracker.hbs b/templates/combat-tracker.hbs index 49324e9..0074b66 100644 --- a/templates/combat-tracker.hbs +++ b/templates/combat-tracker.hbs @@ -78,7 +78,6 @@
    {{#each turns as |turn index|}} - {{log turn}}
  1. +

    {{localize "VERMINE.confrontation_result"}}

    +
diff --git a/templates/fight.html b/templates/fight.html new file mode 100644 index 0000000..f19cf74 --- /dev/null +++ b/templates/fight.html @@ -0,0 +1,17 @@ +
+

{{localize "VERMINE.FightTool"}}

+
+ + +
+
+ + +
+
+ + +
+
diff --git a/templates/generic/tab-navigation.hbs b/templates/generic/tab-navigation.hbs new file mode 100644 index 0000000..1eb51f4 --- /dev/null +++ b/templates/generic/tab-navigation.hbs @@ -0,0 +1,7 @@ +
diff --git a/templates/item/item-defense-sheet.hbs b/templates/item/item-defense-sheet.hbs index 87f3c63..5d6a934 100644 --- a/templates/item/item-defense-sheet.hbs +++ b/templates/item/item-defense-sheet.hbs @@ -1,6 +1,5 @@
{{> "systems/vermine2047/templates/item/partials/header.hbs"}} - {{log this}}
{{> "systems/vermine2047/templates/item/partials/traits.hbs"}} diff --git a/templates/item/item-item-sheet.hbs b/templates/item/item-item-sheet.hbs index 3c55a21..81a5dc2 100644 --- a/templates/item/item-item-sheet.hbs +++ b/templates/item/item-item-sheet.hbs @@ -1,5 +1,4 @@
-{{log this}} {{> "systems/vermine2047/templates/item/partials/header.hbs"}} @@ -14,12 +13,11 @@ {{#if system.needSkill.value}}