Compare commits
33 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 779b4c60f5 | |||
| 84608ffbf7 | |||
| 2fbcfa52aa | |||
| 9e9d2c4f3e | |||
| abe35cb537 | |||
| f72230dd39 | |||
|
|
36a66d3eac | ||
|
|
317411ce60 | ||
|
|
3c6529bc99 | ||
|
|
061390df80 | ||
|
|
b4fd1c738f | ||
|
|
c7d6c6c5e5 | ||
|
|
31f094818e | ||
|
|
40afa53337 | ||
|
|
cb98d721c5 | ||
|
|
6ba5137ea1 | ||
|
|
5377674a30 | ||
|
|
f6ed462bce | ||
|
|
890223021a | ||
|
|
b1f874b3c8 | ||
|
|
2dd9ee19e9 | ||
|
|
aa203c546c | ||
|
|
8f31031244 | ||
|
|
84e367b79f | ||
|
|
0854e25a66 | ||
|
|
0c299db26f | ||
|
|
f267d06536 | ||
|
|
494b027513 | ||
|
|
35c58ff631 | ||
|
|
e87cd6d73e | ||
|
|
05b7a1181c | ||
|
|
2e91fe7ae4 | ||
|
|
9c3de358b3 |
91
.gitea/workflows/release.yaml
Normal file
91
.gitea/workflows/release.yaml
Normal file
@@ -0,0 +1,91 @@
|
||||
name: Release Creation
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- run: echo "💡 The ${{ gitea.repository }} repository will be cloned to the runner."
|
||||
|
||||
- uses: https://github.com/RouxAntoine/checkout@v3.5.4
|
||||
|
||||
# get part of the tag after the `v`
|
||||
- name: Extract tag version number
|
||||
id: get_version
|
||||
uses: https://github.com/battila7/get-version-action@v2
|
||||
|
||||
# Compile SCSS → CSS before packaging
|
||||
- name: Setup Node.js
|
||||
uses: https://github.com/actions/setup-node@v3
|
||||
with:
|
||||
node-version: '18'
|
||||
|
||||
- name: Install dependencies and compile styles
|
||||
run: npm ci && npm run compile
|
||||
|
||||
# Substitute the Manifest and Download URLs in system.json
|
||||
- name: Substitute Manifest and Download Links For Versioned Ones
|
||||
id: sub_manifest_link_version
|
||||
uses: https://github.com/microsoft/variable-substitution@v1
|
||||
with:
|
||||
files: "system/system.json"
|
||||
env:
|
||||
version: ${{steps.get_version.outputs.version-without-v}}
|
||||
url: https://www.uberwald.me/gitea/uberwald/l5rx-chiaroscuro
|
||||
manifest: https://www.uberwald.me/gitea/uberwald/l5rx-chiaroscuro/releases/download/latest/system.json
|
||||
download: https://www.uberwald.me/gitea/uberwald/l5rx-chiaroscuro/releases/download/${{github.event.release.tag_name}}/l5rx-chiaroscuro.zip
|
||||
|
||||
# Copy versioned system.json to root so it can be uploaded as-is
|
||||
- name: Copy system.json to root
|
||||
run: cp system/system.json system.json
|
||||
|
||||
# Create a zip file with all files required by the system
|
||||
- run: |
|
||||
apt update -y
|
||||
apt install -y zip
|
||||
|
||||
- run: |
|
||||
cd system
|
||||
zip -r ../l5rx-chiaroscuro.zip \
|
||||
assets/ \
|
||||
babele/ \
|
||||
fonts/ \
|
||||
lang/ \
|
||||
lib/ \
|
||||
macros/ \
|
||||
packs/ \
|
||||
scripts/ \
|
||||
styles/ \
|
||||
templates/ \
|
||||
system.json \
|
||||
template.json
|
||||
cd ..
|
||||
zip -j ./l5rx-chiaroscuro.zip README.md CHANGELOG.md LICENSE.md
|
||||
|
||||
- name: Setup Go
|
||||
uses: https://github.com/actions/setup-go@v4
|
||||
with:
|
||||
go-version: ">=1.20.1"
|
||||
|
||||
- name: Upload release assets to Gitea
|
||||
id: use-go-action
|
||||
uses: https://gitea.com/actions/release-action@main
|
||||
with:
|
||||
files: |-
|
||||
./l5rx-chiaroscuro.zip
|
||||
system.json
|
||||
api_key: "${{secrets.ALLOW_PUSH_RELEASE}}"
|
||||
|
||||
- name: Publish to Foundry server
|
||||
uses: https://github.com/djlechuck/foundryvtt-publish-package-action@v1
|
||||
with:
|
||||
token: ${{ secrets.FOUNDRYVTT_RELEASE_TOKEN }}
|
||||
id: 'l5rx-chiaroscuro'
|
||||
version: ${{github.event.release.tag_name}}
|
||||
manifest: 'https://www.uberwald.me/gitea/uberwald/l5rx-chiaroscuro/releases/download/latest/system.json'
|
||||
notes: 'https://www.uberwald.me/gitea/uberwald/l5rx-chiaroscuro/releases/tag/${{github.event.release.tag_name}}'
|
||||
compatibility-minimum: '13'
|
||||
compatibility-verified: '14'
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -13,3 +13,5 @@ system/l5r5e.lock
|
||||
|
||||
# v11 db files (will be added later)
|
||||
system/packs/*/**
|
||||
.github/
|
||||
.history/
|
||||
|
||||
14
CHANGELOG.md
14
CHANGELOG.md
@@ -6,6 +6,20 @@ Date format : day/month/year
|
||||
> - `foundry-version`: Stick to the major version of FoundryVTT.
|
||||
> - `system-version`: System functionalities and Fixes.
|
||||
|
||||
## 1.13.4 - 01/03/2026 - UI Polish, Compendium Upgrades
|
||||
Welcoming Litasa as a maintainer for the system!
|
||||
|
||||
- Fixing type in Courts of Stone title, thanks to SagaTympana (!51).
|
||||
- Update to the [development wiki](https://gitlab.com/teaml5r/l5r5e/-/wikis/home), thanks to Norman Briggs (!52)
|
||||
- Updating the sidebar icons to show L5r5e specific ones (#72)(!53) (Litasa)
|
||||
- Adding incremental buttons for honor, glory, and status (#69)(!54) (Litasa)
|
||||
- New rank is now shown directly when completing a school rank (#64)(!57) (Litasa)
|
||||
- Adding Starting items to Compendiums that was missing. Split Poison and Omamori into individual items(!58) (Litasa)
|
||||
- Some combinations of light and dark theme made the GM Toolbox and GM Monitor hard/impossible to use. Fixed now (#75)(!59) (Litasa)
|
||||
- Conditions now show in the top of dice-picker and roll-n-keep (related to #74)(!60) (Litasa)
|
||||
- Compendium filter is now a lot "snappier". New search box and now able to multi select elements/ranks/rarity. (!61) (Litasa)
|
||||
- Adding selection circle to Combat encounter (!62) (Litasa)
|
||||
|
||||
## 1.13.3 - 01/02/2026 - Tactical Grid & Fixes
|
||||
- Updated demeanors from books up to Imperfect Land (included), thanks to Olivier Brencklé (!48).
|
||||
- Added Tactical Grid Range Band, thanks to Litasa (!49).
|
||||
|
||||
@@ -18,13 +18,14 @@ See the [Wiki page - Installation](https://gitlab.com/teaml5r/l5r5e/-/wikis/user
|
||||
|
||||
|
||||
## Current L5R team (alphabetical order)
|
||||
- Carter (compendiums, adventure adaptation)
|
||||
- Litasa (development)
|
||||
- Vlyan (development)
|
||||
|
||||
|
||||
## Historical L5R team (alphabetical order)
|
||||
- Carter (compendiums, adventure adaptation)
|
||||
- Hrunh (compendiums, pre-gen characters adaptation)
|
||||
- Litasa (development)
|
||||
- Mandar (development)
|
||||
- Sasmira (contributor)
|
||||
- Vlyan (development)
|
||||
|
||||
BIN
modif/L5RxChiaroscuro _ Dev Foundry VTT.docx
Normal file
BIN
modif/L5RxChiaroscuro _ Dev Foundry VTT.docx
Normal file
Binary file not shown.
4
package-lock.json
generated
4
package-lock.json
generated
@@ -1,11 +1,11 @@
|
||||
{
|
||||
"name": "l5r5e",
|
||||
"name": "l5rx-chiaroscuro",
|
||||
"version": "1.0.0",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "l5r5e",
|
||||
"name": "l5rx-chiaroscuro",
|
||||
"version": "1.0.0",
|
||||
"license": "ISC",
|
||||
"devDependencies": {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "l5r5e",
|
||||
"name": "l5rx-chiaroscuro",
|
||||
"version": "1.0.0",
|
||||
"description": "This is a game system for Legend of the Five Rings (5th edition) by Edge Studio",
|
||||
"main": "index.js",
|
||||
|
||||
393
system/.history/system_20260423143038.json
Normal file
393
system/.history/system_20260423143038.json
Normal file
@@ -0,0 +1,393 @@
|
||||
{
|
||||
"id": "l5rx-chiaroscuro",
|
||||
"title": "Legend of the Five Rings (5th Edition)",
|
||||
"description": "This is an authorised multilingual game system En|Fr|Es, for Legend of the Five Rings (5th Edition) by <a href='https://edge-studio.net/'>Edge Studio</a> <p> - Join the official Discord server: <a href='https://discord.gg/foundryvtt'> Official Discord</a></p><p> - Rejoignez la communauté Francophone: <a href='https://discord.gg/pPSDNJk'>Francophone Discord</a></p>",
|
||||
"url": "https://gitlab.com/teaml5r/l5r5e",
|
||||
"readme": "https://gitlab.com/teaml5r/l5r5e/-/blob/master/README.md",
|
||||
"changelog": "https://gitlab.com/teaml5r/l5r5e/-/blob/master/CHANGELOG.md",
|
||||
"license": "https://gitlab.com/teaml5r/l5r5e/-/blob/master/LICENSE.md",
|
||||
"manifest": "https://gitlab.com/teaml5r/l5r5e/-/raw/master/system/system.json",
|
||||
"download": "https://gitlab.com/teaml5r/l5r5e/-/jobs/artifacts/v1.13.4/raw/l5r5e.zip?job=build",
|
||||
"version": "1.13.4",
|
||||
"compatibility": {
|
||||
"minimum": "13",
|
||||
"verified": "14"
|
||||
},
|
||||
"socket": true,
|
||||
"authors": [
|
||||
{
|
||||
"name": "Vlyan",
|
||||
"discord": "Vlyan#6771",
|
||||
"url": "https://ko-fi.com/vlyan"
|
||||
},
|
||||
{
|
||||
"name": "Mandar",
|
||||
"discord": "Mandar#3440"
|
||||
},
|
||||
{
|
||||
"name": "Carter",
|
||||
"discord": "Carter#2703",
|
||||
"url": "https://fr.tipeee.com/carter-foundryvtt"
|
||||
},
|
||||
{
|
||||
"name": "Litasa",
|
||||
"discord": "Litasa#3139"
|
||||
}
|
||||
],
|
||||
"background": "systems/l5r5e/assets/l5r-header.webp",
|
||||
"scripts": [],
|
||||
"esmodules": [
|
||||
"./scripts/main-l5r5e.js"
|
||||
],
|
||||
"styles": [
|
||||
"./styles/l5r5e.css"
|
||||
],
|
||||
"packFolders": [
|
||||
{
|
||||
"name": "L5R5e System",
|
||||
"color": "#9a0909",
|
||||
"sorting": "m",
|
||||
"folders": [
|
||||
{
|
||||
"name": "Character related",
|
||||
"color": "#019806",
|
||||
"sorting": "m",
|
||||
"packs": [
|
||||
"core-peculiarities-distinctions",
|
||||
"core-peculiarities-passions",
|
||||
"core-peculiarities-adversities",
|
||||
"core-peculiarities-anxieties",
|
||||
"core-bonds",
|
||||
"core-titles",
|
||||
"core-journal-school-curriculum",
|
||||
"core-journal-great-clans-presentation"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Techniques",
|
||||
"color": "#4b1eb3",
|
||||
"sorting": "m",
|
||||
"packs": [
|
||||
"core-techniques-kata",
|
||||
"core-techniques-kiho",
|
||||
"core-techniques-inversions",
|
||||
"core-techniques-invocations",
|
||||
"core-techniques-rituals",
|
||||
"core-techniques-shuji",
|
||||
"core-techniques-maho",
|
||||
"core-techniques-ninjutsu",
|
||||
"core-techniques-mantra",
|
||||
"core-techniques-school",
|
||||
"core-techniques-mastery"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Objects related",
|
||||
"color": "#0985ae",
|
||||
"sorting": "m",
|
||||
"packs": [
|
||||
"core-properties",
|
||||
"core-item-patterns",
|
||||
"core-items",
|
||||
"core-armors",
|
||||
"core-weapons",
|
||||
"core-signature-scrolls",
|
||||
"core-celestial-implement-boons"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Helpers",
|
||||
"color": "#6b3d1f",
|
||||
"sorting": "m",
|
||||
"packs": [
|
||||
"core-journal-conditions",
|
||||
"core-journal-terrain-qualities",
|
||||
"core-journal-opportunities"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Tools",
|
||||
"color": "#834949",
|
||||
"sorting": "m",
|
||||
"packs": [
|
||||
"core-name-tables",
|
||||
"core-macros"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"packs": [
|
||||
{
|
||||
"name": "core-properties",
|
||||
"label": "Properties",
|
||||
"path": "packs/core-properties.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-techniques-kata",
|
||||
"label": "Techniques Kata",
|
||||
"path": "packs/core-techniques-kata.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-techniques-kiho",
|
||||
"label": "Techniques Kihõ",
|
||||
"path": "packs/core-techniques-kiho.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-techniques-inversions",
|
||||
"label": "Techniques Inversions",
|
||||
"path": "packs/core-techniques-inversions.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-techniques-invocations",
|
||||
"label": "Techniques Invocations",
|
||||
"path": "packs/core-techniques-invocations.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-techniques-rituals",
|
||||
"label": "Techniques Rituals",
|
||||
"path": "packs/core-techniques-rituals.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-techniques-shuji",
|
||||
"label": "Techniques Shuji",
|
||||
"path": "packs/core-techniques-shuji.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-techniques-maho",
|
||||
"label": "Techniques Mahõ",
|
||||
"path": "packs/core-techniques-maho.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-techniques-ninjutsu",
|
||||
"label": "Techniques Ninjutsu",
|
||||
"path": "packs/core-techniques-ninjutsu.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-techniques-mantra",
|
||||
"label": "Techniques Mantra",
|
||||
"path": "packs/core-techniques-mantra.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-techniques-school",
|
||||
"label": "School Abilities",
|
||||
"path": "packs/core-techniques-school.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-techniques-mastery",
|
||||
"label": "Mastery Abilities",
|
||||
"path": "packs/core-techniques-mastery.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-items",
|
||||
"label": "Items",
|
||||
"path": "packs/core-items.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-armors",
|
||||
"label": "Armors",
|
||||
"path": "packs/core-armors.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-weapons",
|
||||
"label": "Weapons",
|
||||
"path": "packs/core-weapons.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-peculiarities-distinctions",
|
||||
"label": "Distinctions",
|
||||
"path": "packs/core-peculiarities-distinctions.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-peculiarities-passions",
|
||||
"label": "Passions",
|
||||
"path": "packs/core-peculiarities-passions.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-peculiarities-adversities",
|
||||
"label": "Adversities",
|
||||
"path": "packs/core-peculiarities-adversities.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-peculiarities-anxieties",
|
||||
"label": "Anxieties",
|
||||
"path": "packs/core-peculiarities-anxieties.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-bonds",
|
||||
"label": "Bonds",
|
||||
"path": "packs/core-bonds.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-titles",
|
||||
"label": "Titles",
|
||||
"path": "packs/core-titles.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-item-patterns",
|
||||
"label": "Item Patterns",
|
||||
"path": "packs/core-item-patterns.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-signature-scrolls",
|
||||
"label": "Signature Scrolls",
|
||||
"path": "packs/core-signature-scrolls.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-celestial-implement-boons",
|
||||
"label": "Celestial Implement Boons",
|
||||
"path": "packs/core-celestial-implement-boons.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-journal-school-curriculum",
|
||||
"label": "School Curriculum",
|
||||
"path": "packs/core-journal-school-curriculum.db",
|
||||
"type": "JournalEntry",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-journal-conditions",
|
||||
"label": "Conditions",
|
||||
"path": "packs/core-journal-conditions.db",
|
||||
"type": "JournalEntry",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-journal-terrain-qualities",
|
||||
"label": "Terrain Qualities",
|
||||
"path": "packs/core-journal-terrain-qualities.db",
|
||||
"type": "JournalEntry",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-journal-great-clans-presentation",
|
||||
"label": "Great Clans Presentation",
|
||||
"path": "packs/core-journal-great-clans-presentation.db",
|
||||
"type": "JournalEntry",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-journal-opportunities",
|
||||
"label": "Opportunities",
|
||||
"path": "packs/core-journal-opportunities.db",
|
||||
"type": "JournalEntry",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-name-tables",
|
||||
"label": "Name Tables",
|
||||
"path": "packs/core-name-tables.db",
|
||||
"type": "RollTable",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-macros",
|
||||
"label": "L5R5E Macros",
|
||||
"path": "packs/core-macros.db",
|
||||
"type": "Macro",
|
||||
"system": "l5r5e"
|
||||
}
|
||||
],
|
||||
"languages": [
|
||||
{
|
||||
"lang": "en",
|
||||
"name": "English",
|
||||
"path": "lang/en-en.json"
|
||||
},
|
||||
{
|
||||
"lang": "fr",
|
||||
"name": "French (France)",
|
||||
"path": "lang/fr-fr.json"
|
||||
},
|
||||
{
|
||||
"lang": "es",
|
||||
"name": "Spanish (Spain)",
|
||||
"path": "lang/es-es.json"
|
||||
},
|
||||
{
|
||||
"lang": "it",
|
||||
"name": "Italian (Italy)",
|
||||
"path": "lang/it-it.json"
|
||||
}
|
||||
],
|
||||
"media": [
|
||||
{
|
||||
"type": "screenshot",
|
||||
"url": "https://gitlab.com/teaml5r/l5r5e/-/raw/master/screenshoots/login.jpg?raw=true",
|
||||
"caption": "Login screen"
|
||||
},
|
||||
{
|
||||
"type": "screenshot",
|
||||
"url": "https://gitlab.com/teaml5r/l5r5e/-/raw/master/screenshoots/roll.jpg?raw=true",
|
||||
"caption": "DicePicker and Roll and Keep"
|
||||
},
|
||||
{
|
||||
"type": "screenshot",
|
||||
"url": "https://gitlab.com/teaml5r/l5r5e/-/raw/master/screenshoots/school.jpg?raw=true",
|
||||
"caption": "Experience and School"
|
||||
},
|
||||
{
|
||||
"type": "screenshot",
|
||||
"url": "https://gitlab.com/teaml5r/l5r5e/-/raw/master/screenshoots/sheet_pc.jpg?raw=true",
|
||||
"caption": "PC sheet"
|
||||
},
|
||||
{
|
||||
"type": "screenshot",
|
||||
"url": "https://gitlab.com/teaml5r/l5r5e/-/raw/master/screenshoots/sheet_npc_army.jpg?raw=true",
|
||||
"caption": "NPC and Army sheets"
|
||||
},
|
||||
{
|
||||
"type": "screenshot",
|
||||
"url": "https://gitlab.com/teaml5r/l5r5e/-/raw/master/screenshoots/compendiums.jpg?raw=true",
|
||||
"caption": "Compendiums"
|
||||
}
|
||||
]
|
||||
}
|
||||
393
system/.history/system_20260423143040.json
Normal file
393
system/.history/system_20260423143040.json
Normal file
@@ -0,0 +1,393 @@
|
||||
{
|
||||
"id": "l5rx-chiaroscuro",
|
||||
"title": "Legend of the Five Rings (5th Edition)",
|
||||
"description": "This is an authorised multilingual game system En|Fr|Es, for Legend of the Five Rings (5th Edition) by <a href='https://edge-studio.net/'>Edge Studio</a> <p> - Join the official Discord server: <a href='https://discord.gg/foundryvtt'> Official Discord</a></p><p> - Rejoignez la communauté Francophone: <a href='https://discord.gg/pPSDNJk'>Francophone Discord</a></p>",
|
||||
"url": "https://gitlab.com/teaml5r/l5r5e",
|
||||
"readme": "https://gitlab.com/teaml5r/l5r5e/-/blob/master/README.md",
|
||||
"changelog": "https://gitlab.com/teaml5r/l5r5e/-/blob/master/CHANGELOG.md",
|
||||
"license": "https://gitlab.com/teaml5r/l5r5e/-/blob/master/LICENSE.md",
|
||||
"manifest": "https://gitlab.com/teaml5r/l5r5e/-/raw/master/system/system.json",
|
||||
"download": "https://gitlab.com/teaml5r/l5r5e/-/jobs/artifacts/v1.13.4/raw/l5r5e.zip?job=build",
|
||||
"version": "1.13.4",
|
||||
"compatibility": {
|
||||
"minimum": "13",
|
||||
"verified": "14"
|
||||
},
|
||||
"socket": true,
|
||||
"authors": [
|
||||
{
|
||||
"name": "Vlyan",
|
||||
"discord": "Vlyan#6771",
|
||||
"url": "https://ko-fi.com/vlyan"
|
||||
},
|
||||
{
|
||||
"name": "Mandar",
|
||||
"discord": "Mandar#3440"
|
||||
},
|
||||
{
|
||||
"name": "Carter",
|
||||
"discord": "Carter#2703",
|
||||
"url": "https://fr.tipeee.com/carter-foundryvtt"
|
||||
},
|
||||
{
|
||||
"name": "Litasa",
|
||||
"discord": "Litasa#3139"
|
||||
}
|
||||
],
|
||||
"background": "systems/l5r5e/assets/l5r-header.webp",
|
||||
"scripts": [],
|
||||
"esmodules": [
|
||||
"./scripts/main-l5r5e.js"
|
||||
],
|
||||
"styles": [
|
||||
"./styles/l5r5e.css"
|
||||
],
|
||||
"packFolders": [
|
||||
{
|
||||
"name": "L5R5e System",
|
||||
"color": "#9a0909",
|
||||
"sorting": "m",
|
||||
"folders": [
|
||||
{
|
||||
"name": "Character related",
|
||||
"color": "#019806",
|
||||
"sorting": "m",
|
||||
"packs": [
|
||||
"core-peculiarities-distinctions",
|
||||
"core-peculiarities-passions",
|
||||
"core-peculiarities-adversities",
|
||||
"core-peculiarities-anxieties",
|
||||
"core-bonds",
|
||||
"core-titles",
|
||||
"core-journal-school-curriculum",
|
||||
"core-journal-great-clans-presentation"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Techniques",
|
||||
"color": "#4b1eb3",
|
||||
"sorting": "m",
|
||||
"packs": [
|
||||
"core-techniques-kata",
|
||||
"core-techniques-kiho",
|
||||
"core-techniques-inversions",
|
||||
"core-techniques-invocations",
|
||||
"core-techniques-rituals",
|
||||
"core-techniques-shuji",
|
||||
"core-techniques-maho",
|
||||
"core-techniques-ninjutsu",
|
||||
"core-techniques-mantra",
|
||||
"core-techniques-school",
|
||||
"core-techniques-mastery"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Objects related",
|
||||
"color": "#0985ae",
|
||||
"sorting": "m",
|
||||
"packs": [
|
||||
"core-properties",
|
||||
"core-item-patterns",
|
||||
"core-items",
|
||||
"core-armors",
|
||||
"core-weapons",
|
||||
"core-signature-scrolls",
|
||||
"core-celestial-implement-boons"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Helpers",
|
||||
"color": "#6b3d1f",
|
||||
"sorting": "m",
|
||||
"packs": [
|
||||
"core-journal-conditions",
|
||||
"core-journal-terrain-qualities",
|
||||
"core-journal-opportunities"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Tools",
|
||||
"color": "#834949",
|
||||
"sorting": "m",
|
||||
"packs": [
|
||||
"core-name-tables",
|
||||
"core-macros"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"packs": [
|
||||
{
|
||||
"name": "core-properties",
|
||||
"label": "Properties",
|
||||
"path": "packs/core-properties.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-techniques-kata",
|
||||
"label": "Techniques Kata",
|
||||
"path": "packs/core-techniques-kata.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-techniques-kiho",
|
||||
"label": "Techniques Kihõ",
|
||||
"path": "packs/core-techniques-kiho.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-techniques-inversions",
|
||||
"label": "Techniques Inversions",
|
||||
"path": "packs/core-techniques-inversions.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-techniques-invocations",
|
||||
"label": "Techniques Invocations",
|
||||
"path": "packs/core-techniques-invocations.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-techniques-rituals",
|
||||
"label": "Techniques Rituals",
|
||||
"path": "packs/core-techniques-rituals.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-techniques-shuji",
|
||||
"label": "Techniques Shuji",
|
||||
"path": "packs/core-techniques-shuji.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-techniques-maho",
|
||||
"label": "Techniques Mahõ",
|
||||
"path": "packs/core-techniques-maho.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-techniques-ninjutsu",
|
||||
"label": "Techniques Ninjutsu",
|
||||
"path": "packs/core-techniques-ninjutsu.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-techniques-mantra",
|
||||
"label": "Techniques Mantra",
|
||||
"path": "packs/core-techniques-mantra.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-techniques-school",
|
||||
"label": "School Abilities",
|
||||
"path": "packs/core-techniques-school.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-techniques-mastery",
|
||||
"label": "Mastery Abilities",
|
||||
"path": "packs/core-techniques-mastery.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-items",
|
||||
"label": "Items",
|
||||
"path": "packs/core-items.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-armors",
|
||||
"label": "Armors",
|
||||
"path": "packs/core-armors.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-weapons",
|
||||
"label": "Weapons",
|
||||
"path": "packs/core-weapons.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-peculiarities-distinctions",
|
||||
"label": "Distinctions",
|
||||
"path": "packs/core-peculiarities-distinctions.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-peculiarities-passions",
|
||||
"label": "Passions",
|
||||
"path": "packs/core-peculiarities-passions.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-peculiarities-adversities",
|
||||
"label": "Adversities",
|
||||
"path": "packs/core-peculiarities-adversities.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-peculiarities-anxieties",
|
||||
"label": "Anxieties",
|
||||
"path": "packs/core-peculiarities-anxieties.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-bonds",
|
||||
"label": "Bonds",
|
||||
"path": "packs/core-bonds.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-titles",
|
||||
"label": "Titles",
|
||||
"path": "packs/core-titles.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-item-patterns",
|
||||
"label": "Item Patterns",
|
||||
"path": "packs/core-item-patterns.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-signature-scrolls",
|
||||
"label": "Signature Scrolls",
|
||||
"path": "packs/core-signature-scrolls.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-celestial-implement-boons",
|
||||
"label": "Celestial Implement Boons",
|
||||
"path": "packs/core-celestial-implement-boons.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-journal-school-curriculum",
|
||||
"label": "School Curriculum",
|
||||
"path": "packs/core-journal-school-curriculum.db",
|
||||
"type": "JournalEntry",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-journal-conditions",
|
||||
"label": "Conditions",
|
||||
"path": "packs/core-journal-conditions.db",
|
||||
"type": "JournalEntry",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-journal-terrain-qualities",
|
||||
"label": "Terrain Qualities",
|
||||
"path": "packs/core-journal-terrain-qualities.db",
|
||||
"type": "JournalEntry",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-journal-great-clans-presentation",
|
||||
"label": "Great Clans Presentation",
|
||||
"path": "packs/core-journal-great-clans-presentation.db",
|
||||
"type": "JournalEntry",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-journal-opportunities",
|
||||
"label": "Opportunities",
|
||||
"path": "packs/core-journal-opportunities.db",
|
||||
"type": "JournalEntry",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-name-tables",
|
||||
"label": "Name Tables",
|
||||
"path": "packs/core-name-tables.db",
|
||||
"type": "RollTable",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-macros",
|
||||
"label": "L5R5E Macros",
|
||||
"path": "packs/core-macros.db",
|
||||
"type": "Macro",
|
||||
"system": "l5r5e"
|
||||
}
|
||||
],
|
||||
"languages": [
|
||||
{
|
||||
"lang": "en",
|
||||
"name": "English",
|
||||
"path": "lang/en-en.json"
|
||||
},
|
||||
{
|
||||
"lang": "fr",
|
||||
"name": "French (France)",
|
||||
"path": "lang/fr-fr.json"
|
||||
},
|
||||
{
|
||||
"lang": "es",
|
||||
"name": "Spanish (Spain)",
|
||||
"path": "lang/es-es.json"
|
||||
},
|
||||
{
|
||||
"lang": "it",
|
||||
"name": "Italian (Italy)",
|
||||
"path": "lang/it-it.json"
|
||||
}
|
||||
],
|
||||
"media": [
|
||||
{
|
||||
"type": "screenshot",
|
||||
"url": "https://gitlab.com/teaml5r/l5r5e/-/raw/master/screenshoots/login.jpg?raw=true",
|
||||
"caption": "Login screen"
|
||||
},
|
||||
{
|
||||
"type": "screenshot",
|
||||
"url": "https://gitlab.com/teaml5r/l5r5e/-/raw/master/screenshoots/roll.jpg?raw=true",
|
||||
"caption": "DicePicker and Roll and Keep"
|
||||
},
|
||||
{
|
||||
"type": "screenshot",
|
||||
"url": "https://gitlab.com/teaml5r/l5r5e/-/raw/master/screenshoots/school.jpg?raw=true",
|
||||
"caption": "Experience and School"
|
||||
},
|
||||
{
|
||||
"type": "screenshot",
|
||||
"url": "https://gitlab.com/teaml5r/l5r5e/-/raw/master/screenshoots/sheet_pc.jpg?raw=true",
|
||||
"caption": "PC sheet"
|
||||
},
|
||||
{
|
||||
"type": "screenshot",
|
||||
"url": "https://gitlab.com/teaml5r/l5r5e/-/raw/master/screenshoots/sheet_npc_army.jpg?raw=true",
|
||||
"caption": "NPC and Army sheets"
|
||||
},
|
||||
{
|
||||
"type": "screenshot",
|
||||
"url": "https://gitlab.com/teaml5r/l5r5e/-/raw/master/screenshoots/compendiums.jpg?raw=true",
|
||||
"caption": "Compendiums"
|
||||
}
|
||||
]
|
||||
}
|
||||
393
system/.history/system_20260423143043.json
Normal file
393
system/.history/system_20260423143043.json
Normal file
@@ -0,0 +1,393 @@
|
||||
{
|
||||
"id": "l5rx-chiaroscuro",
|
||||
"title": "Legend of the Five Rings (5th Edition)",
|
||||
"description": "This is an authorised multilingual game system En|Fr|Es, for Legend of the Five Rings (5th Edition) by <a href='https://edge-studio.net/'>Edge Studio</a> <p> - Join the official Discord server: <a href='https://discord.gg/foundryvtt'> Official Discord</a></p><p> - Rejoignez la communauté Francophone: <a href='https://discord.gg/pPSDNJk'>Francophone Discord</a></p>",
|
||||
"url": "https://gitlab.com/teaml5r/l5r5e",
|
||||
"readme": "https://gitlab.com/teaml5r/l5r5e/-/blob/master/README.md",
|
||||
"changelog": "https://gitlab.com/teaml5r/l5r5e/-/blob/master/CHANGELOG.md",
|
||||
"license": "https://gitlab.com/teaml5r/l5r5e/-/blob/master/LICENSE.md",
|
||||
"manifest": "https://gitlab.com/teaml5r/l5r5e/-/raw/master/system/system.json",
|
||||
"download": "https://gitlab.com/teaml5r/l5r5e/-/jobs/artifacts/v1.13.4/raw/l5r5e.zip?job=build",
|
||||
"version": "14.0.0",
|
||||
"compatibility": {
|
||||
"minimum": "13",
|
||||
"verified": "14"
|
||||
},
|
||||
"socket": true,
|
||||
"authors": [
|
||||
{
|
||||
"name": "Vlyan",
|
||||
"discord": "Vlyan#6771",
|
||||
"url": "https://ko-fi.com/vlyan"
|
||||
},
|
||||
{
|
||||
"name": "Mandar",
|
||||
"discord": "Mandar#3440"
|
||||
},
|
||||
{
|
||||
"name": "Carter",
|
||||
"discord": "Carter#2703",
|
||||
"url": "https://fr.tipeee.com/carter-foundryvtt"
|
||||
},
|
||||
{
|
||||
"name": "Litasa",
|
||||
"discord": "Litasa#3139"
|
||||
}
|
||||
],
|
||||
"background": "systems/l5r5e/assets/l5r-header.webp",
|
||||
"scripts": [],
|
||||
"esmodules": [
|
||||
"./scripts/main-l5r5e.js"
|
||||
],
|
||||
"styles": [
|
||||
"./styles/l5r5e.css"
|
||||
],
|
||||
"packFolders": [
|
||||
{
|
||||
"name": "L5R5e System",
|
||||
"color": "#9a0909",
|
||||
"sorting": "m",
|
||||
"folders": [
|
||||
{
|
||||
"name": "Character related",
|
||||
"color": "#019806",
|
||||
"sorting": "m",
|
||||
"packs": [
|
||||
"core-peculiarities-distinctions",
|
||||
"core-peculiarities-passions",
|
||||
"core-peculiarities-adversities",
|
||||
"core-peculiarities-anxieties",
|
||||
"core-bonds",
|
||||
"core-titles",
|
||||
"core-journal-school-curriculum",
|
||||
"core-journal-great-clans-presentation"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Techniques",
|
||||
"color": "#4b1eb3",
|
||||
"sorting": "m",
|
||||
"packs": [
|
||||
"core-techniques-kata",
|
||||
"core-techniques-kiho",
|
||||
"core-techniques-inversions",
|
||||
"core-techniques-invocations",
|
||||
"core-techniques-rituals",
|
||||
"core-techniques-shuji",
|
||||
"core-techniques-maho",
|
||||
"core-techniques-ninjutsu",
|
||||
"core-techniques-mantra",
|
||||
"core-techniques-school",
|
||||
"core-techniques-mastery"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Objects related",
|
||||
"color": "#0985ae",
|
||||
"sorting": "m",
|
||||
"packs": [
|
||||
"core-properties",
|
||||
"core-item-patterns",
|
||||
"core-items",
|
||||
"core-armors",
|
||||
"core-weapons",
|
||||
"core-signature-scrolls",
|
||||
"core-celestial-implement-boons"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Helpers",
|
||||
"color": "#6b3d1f",
|
||||
"sorting": "m",
|
||||
"packs": [
|
||||
"core-journal-conditions",
|
||||
"core-journal-terrain-qualities",
|
||||
"core-journal-opportunities"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Tools",
|
||||
"color": "#834949",
|
||||
"sorting": "m",
|
||||
"packs": [
|
||||
"core-name-tables",
|
||||
"core-macros"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"packs": [
|
||||
{
|
||||
"name": "core-properties",
|
||||
"label": "Properties",
|
||||
"path": "packs/core-properties.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-techniques-kata",
|
||||
"label": "Techniques Kata",
|
||||
"path": "packs/core-techniques-kata.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-techniques-kiho",
|
||||
"label": "Techniques Kihõ",
|
||||
"path": "packs/core-techniques-kiho.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-techniques-inversions",
|
||||
"label": "Techniques Inversions",
|
||||
"path": "packs/core-techniques-inversions.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-techniques-invocations",
|
||||
"label": "Techniques Invocations",
|
||||
"path": "packs/core-techniques-invocations.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-techniques-rituals",
|
||||
"label": "Techniques Rituals",
|
||||
"path": "packs/core-techniques-rituals.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-techniques-shuji",
|
||||
"label": "Techniques Shuji",
|
||||
"path": "packs/core-techniques-shuji.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-techniques-maho",
|
||||
"label": "Techniques Mahõ",
|
||||
"path": "packs/core-techniques-maho.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-techniques-ninjutsu",
|
||||
"label": "Techniques Ninjutsu",
|
||||
"path": "packs/core-techniques-ninjutsu.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-techniques-mantra",
|
||||
"label": "Techniques Mantra",
|
||||
"path": "packs/core-techniques-mantra.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-techniques-school",
|
||||
"label": "School Abilities",
|
||||
"path": "packs/core-techniques-school.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-techniques-mastery",
|
||||
"label": "Mastery Abilities",
|
||||
"path": "packs/core-techniques-mastery.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-items",
|
||||
"label": "Items",
|
||||
"path": "packs/core-items.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-armors",
|
||||
"label": "Armors",
|
||||
"path": "packs/core-armors.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-weapons",
|
||||
"label": "Weapons",
|
||||
"path": "packs/core-weapons.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-peculiarities-distinctions",
|
||||
"label": "Distinctions",
|
||||
"path": "packs/core-peculiarities-distinctions.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-peculiarities-passions",
|
||||
"label": "Passions",
|
||||
"path": "packs/core-peculiarities-passions.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-peculiarities-adversities",
|
||||
"label": "Adversities",
|
||||
"path": "packs/core-peculiarities-adversities.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-peculiarities-anxieties",
|
||||
"label": "Anxieties",
|
||||
"path": "packs/core-peculiarities-anxieties.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-bonds",
|
||||
"label": "Bonds",
|
||||
"path": "packs/core-bonds.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-titles",
|
||||
"label": "Titles",
|
||||
"path": "packs/core-titles.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-item-patterns",
|
||||
"label": "Item Patterns",
|
||||
"path": "packs/core-item-patterns.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-signature-scrolls",
|
||||
"label": "Signature Scrolls",
|
||||
"path": "packs/core-signature-scrolls.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-celestial-implement-boons",
|
||||
"label": "Celestial Implement Boons",
|
||||
"path": "packs/core-celestial-implement-boons.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-journal-school-curriculum",
|
||||
"label": "School Curriculum",
|
||||
"path": "packs/core-journal-school-curriculum.db",
|
||||
"type": "JournalEntry",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-journal-conditions",
|
||||
"label": "Conditions",
|
||||
"path": "packs/core-journal-conditions.db",
|
||||
"type": "JournalEntry",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-journal-terrain-qualities",
|
||||
"label": "Terrain Qualities",
|
||||
"path": "packs/core-journal-terrain-qualities.db",
|
||||
"type": "JournalEntry",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-journal-great-clans-presentation",
|
||||
"label": "Great Clans Presentation",
|
||||
"path": "packs/core-journal-great-clans-presentation.db",
|
||||
"type": "JournalEntry",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-journal-opportunities",
|
||||
"label": "Opportunities",
|
||||
"path": "packs/core-journal-opportunities.db",
|
||||
"type": "JournalEntry",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-name-tables",
|
||||
"label": "Name Tables",
|
||||
"path": "packs/core-name-tables.db",
|
||||
"type": "RollTable",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-macros",
|
||||
"label": "L5R5E Macros",
|
||||
"path": "packs/core-macros.db",
|
||||
"type": "Macro",
|
||||
"system": "l5r5e"
|
||||
}
|
||||
],
|
||||
"languages": [
|
||||
{
|
||||
"lang": "en",
|
||||
"name": "English",
|
||||
"path": "lang/en-en.json"
|
||||
},
|
||||
{
|
||||
"lang": "fr",
|
||||
"name": "French (France)",
|
||||
"path": "lang/fr-fr.json"
|
||||
},
|
||||
{
|
||||
"lang": "es",
|
||||
"name": "Spanish (Spain)",
|
||||
"path": "lang/es-es.json"
|
||||
},
|
||||
{
|
||||
"lang": "it",
|
||||
"name": "Italian (Italy)",
|
||||
"path": "lang/it-it.json"
|
||||
}
|
||||
],
|
||||
"media": [
|
||||
{
|
||||
"type": "screenshot",
|
||||
"url": "https://gitlab.com/teaml5r/l5r5e/-/raw/master/screenshoots/login.jpg?raw=true",
|
||||
"caption": "Login screen"
|
||||
},
|
||||
{
|
||||
"type": "screenshot",
|
||||
"url": "https://gitlab.com/teaml5r/l5r5e/-/raw/master/screenshoots/roll.jpg?raw=true",
|
||||
"caption": "DicePicker and Roll and Keep"
|
||||
},
|
||||
{
|
||||
"type": "screenshot",
|
||||
"url": "https://gitlab.com/teaml5r/l5r5e/-/raw/master/screenshoots/school.jpg?raw=true",
|
||||
"caption": "Experience and School"
|
||||
},
|
||||
{
|
||||
"type": "screenshot",
|
||||
"url": "https://gitlab.com/teaml5r/l5r5e/-/raw/master/screenshoots/sheet_pc.jpg?raw=true",
|
||||
"caption": "PC sheet"
|
||||
},
|
||||
{
|
||||
"type": "screenshot",
|
||||
"url": "https://gitlab.com/teaml5r/l5r5e/-/raw/master/screenshoots/sheet_npc_army.jpg?raw=true",
|
||||
"caption": "NPC and Army sheets"
|
||||
},
|
||||
{
|
||||
"type": "screenshot",
|
||||
"url": "https://gitlab.com/teaml5r/l5r5e/-/raw/master/screenshoots/compendiums.jpg?raw=true",
|
||||
"caption": "Compendiums"
|
||||
}
|
||||
]
|
||||
}
|
||||
393
system/.history/system_20260423143048.json
Normal file
393
system/.history/system_20260423143048.json
Normal file
@@ -0,0 +1,393 @@
|
||||
{
|
||||
"id": "l5rx-chiaroscuro",
|
||||
"title": "chiaroscuro - Legend of the Five Rings (5th Edition)",
|
||||
"description": "This is an authorised multilingual game system En|Fr|Es, for Legend of the Five Rings (5th Edition) by <a href='https://edge-studio.net/'>Edge Studio</a> <p> - Join the official Discord server: <a href='https://discord.gg/foundryvtt'> Official Discord</a></p><p> - Rejoignez la communauté Francophone: <a href='https://discord.gg/pPSDNJk'>Francophone Discord</a></p>",
|
||||
"url": "https://gitlab.com/teaml5r/l5r5e",
|
||||
"readme": "https://gitlab.com/teaml5r/l5r5e/-/blob/master/README.md",
|
||||
"changelog": "https://gitlab.com/teaml5r/l5r5e/-/blob/master/CHANGELOG.md",
|
||||
"license": "https://gitlab.com/teaml5r/l5r5e/-/blob/master/LICENSE.md",
|
||||
"manifest": "https://gitlab.com/teaml5r/l5r5e/-/raw/master/system/system.json",
|
||||
"download": "https://gitlab.com/teaml5r/l5r5e/-/jobs/artifacts/v1.13.4/raw/l5r5e.zip?job=build",
|
||||
"version": "14.0.0",
|
||||
"compatibility": {
|
||||
"minimum": "13",
|
||||
"verified": "14"
|
||||
},
|
||||
"socket": true,
|
||||
"authors": [
|
||||
{
|
||||
"name": "Vlyan",
|
||||
"discord": "Vlyan#6771",
|
||||
"url": "https://ko-fi.com/vlyan"
|
||||
},
|
||||
{
|
||||
"name": "Mandar",
|
||||
"discord": "Mandar#3440"
|
||||
},
|
||||
{
|
||||
"name": "Carter",
|
||||
"discord": "Carter#2703",
|
||||
"url": "https://fr.tipeee.com/carter-foundryvtt"
|
||||
},
|
||||
{
|
||||
"name": "Litasa",
|
||||
"discord": "Litasa#3139"
|
||||
}
|
||||
],
|
||||
"background": "systems/l5r5e/assets/l5r-header.webp",
|
||||
"scripts": [],
|
||||
"esmodules": [
|
||||
"./scripts/main-l5r5e.js"
|
||||
],
|
||||
"styles": [
|
||||
"./styles/l5r5e.css"
|
||||
],
|
||||
"packFolders": [
|
||||
{
|
||||
"name": "L5R5e System",
|
||||
"color": "#9a0909",
|
||||
"sorting": "m",
|
||||
"folders": [
|
||||
{
|
||||
"name": "Character related",
|
||||
"color": "#019806",
|
||||
"sorting": "m",
|
||||
"packs": [
|
||||
"core-peculiarities-distinctions",
|
||||
"core-peculiarities-passions",
|
||||
"core-peculiarities-adversities",
|
||||
"core-peculiarities-anxieties",
|
||||
"core-bonds",
|
||||
"core-titles",
|
||||
"core-journal-school-curriculum",
|
||||
"core-journal-great-clans-presentation"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Techniques",
|
||||
"color": "#4b1eb3",
|
||||
"sorting": "m",
|
||||
"packs": [
|
||||
"core-techniques-kata",
|
||||
"core-techniques-kiho",
|
||||
"core-techniques-inversions",
|
||||
"core-techniques-invocations",
|
||||
"core-techniques-rituals",
|
||||
"core-techniques-shuji",
|
||||
"core-techniques-maho",
|
||||
"core-techniques-ninjutsu",
|
||||
"core-techniques-mantra",
|
||||
"core-techniques-school",
|
||||
"core-techniques-mastery"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Objects related",
|
||||
"color": "#0985ae",
|
||||
"sorting": "m",
|
||||
"packs": [
|
||||
"core-properties",
|
||||
"core-item-patterns",
|
||||
"core-items",
|
||||
"core-armors",
|
||||
"core-weapons",
|
||||
"core-signature-scrolls",
|
||||
"core-celestial-implement-boons"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Helpers",
|
||||
"color": "#6b3d1f",
|
||||
"sorting": "m",
|
||||
"packs": [
|
||||
"core-journal-conditions",
|
||||
"core-journal-terrain-qualities",
|
||||
"core-journal-opportunities"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Tools",
|
||||
"color": "#834949",
|
||||
"sorting": "m",
|
||||
"packs": [
|
||||
"core-name-tables",
|
||||
"core-macros"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"packs": [
|
||||
{
|
||||
"name": "core-properties",
|
||||
"label": "Properties",
|
||||
"path": "packs/core-properties.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-techniques-kata",
|
||||
"label": "Techniques Kata",
|
||||
"path": "packs/core-techniques-kata.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-techniques-kiho",
|
||||
"label": "Techniques Kihõ",
|
||||
"path": "packs/core-techniques-kiho.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-techniques-inversions",
|
||||
"label": "Techniques Inversions",
|
||||
"path": "packs/core-techniques-inversions.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-techniques-invocations",
|
||||
"label": "Techniques Invocations",
|
||||
"path": "packs/core-techniques-invocations.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-techniques-rituals",
|
||||
"label": "Techniques Rituals",
|
||||
"path": "packs/core-techniques-rituals.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-techniques-shuji",
|
||||
"label": "Techniques Shuji",
|
||||
"path": "packs/core-techniques-shuji.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-techniques-maho",
|
||||
"label": "Techniques Mahõ",
|
||||
"path": "packs/core-techniques-maho.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-techniques-ninjutsu",
|
||||
"label": "Techniques Ninjutsu",
|
||||
"path": "packs/core-techniques-ninjutsu.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-techniques-mantra",
|
||||
"label": "Techniques Mantra",
|
||||
"path": "packs/core-techniques-mantra.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-techniques-school",
|
||||
"label": "School Abilities",
|
||||
"path": "packs/core-techniques-school.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-techniques-mastery",
|
||||
"label": "Mastery Abilities",
|
||||
"path": "packs/core-techniques-mastery.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-items",
|
||||
"label": "Items",
|
||||
"path": "packs/core-items.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-armors",
|
||||
"label": "Armors",
|
||||
"path": "packs/core-armors.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-weapons",
|
||||
"label": "Weapons",
|
||||
"path": "packs/core-weapons.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-peculiarities-distinctions",
|
||||
"label": "Distinctions",
|
||||
"path": "packs/core-peculiarities-distinctions.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-peculiarities-passions",
|
||||
"label": "Passions",
|
||||
"path": "packs/core-peculiarities-passions.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-peculiarities-adversities",
|
||||
"label": "Adversities",
|
||||
"path": "packs/core-peculiarities-adversities.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-peculiarities-anxieties",
|
||||
"label": "Anxieties",
|
||||
"path": "packs/core-peculiarities-anxieties.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-bonds",
|
||||
"label": "Bonds",
|
||||
"path": "packs/core-bonds.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-titles",
|
||||
"label": "Titles",
|
||||
"path": "packs/core-titles.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-item-patterns",
|
||||
"label": "Item Patterns",
|
||||
"path": "packs/core-item-patterns.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-signature-scrolls",
|
||||
"label": "Signature Scrolls",
|
||||
"path": "packs/core-signature-scrolls.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-celestial-implement-boons",
|
||||
"label": "Celestial Implement Boons",
|
||||
"path": "packs/core-celestial-implement-boons.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-journal-school-curriculum",
|
||||
"label": "School Curriculum",
|
||||
"path": "packs/core-journal-school-curriculum.db",
|
||||
"type": "JournalEntry",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-journal-conditions",
|
||||
"label": "Conditions",
|
||||
"path": "packs/core-journal-conditions.db",
|
||||
"type": "JournalEntry",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-journal-terrain-qualities",
|
||||
"label": "Terrain Qualities",
|
||||
"path": "packs/core-journal-terrain-qualities.db",
|
||||
"type": "JournalEntry",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-journal-great-clans-presentation",
|
||||
"label": "Great Clans Presentation",
|
||||
"path": "packs/core-journal-great-clans-presentation.db",
|
||||
"type": "JournalEntry",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-journal-opportunities",
|
||||
"label": "Opportunities",
|
||||
"path": "packs/core-journal-opportunities.db",
|
||||
"type": "JournalEntry",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-name-tables",
|
||||
"label": "Name Tables",
|
||||
"path": "packs/core-name-tables.db",
|
||||
"type": "RollTable",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-macros",
|
||||
"label": "L5R5E Macros",
|
||||
"path": "packs/core-macros.db",
|
||||
"type": "Macro",
|
||||
"system": "l5r5e"
|
||||
}
|
||||
],
|
||||
"languages": [
|
||||
{
|
||||
"lang": "en",
|
||||
"name": "English",
|
||||
"path": "lang/en-en.json"
|
||||
},
|
||||
{
|
||||
"lang": "fr",
|
||||
"name": "French (France)",
|
||||
"path": "lang/fr-fr.json"
|
||||
},
|
||||
{
|
||||
"lang": "es",
|
||||
"name": "Spanish (Spain)",
|
||||
"path": "lang/es-es.json"
|
||||
},
|
||||
{
|
||||
"lang": "it",
|
||||
"name": "Italian (Italy)",
|
||||
"path": "lang/it-it.json"
|
||||
}
|
||||
],
|
||||
"media": [
|
||||
{
|
||||
"type": "screenshot",
|
||||
"url": "https://gitlab.com/teaml5r/l5r5e/-/raw/master/screenshoots/login.jpg?raw=true",
|
||||
"caption": "Login screen"
|
||||
},
|
||||
{
|
||||
"type": "screenshot",
|
||||
"url": "https://gitlab.com/teaml5r/l5r5e/-/raw/master/screenshoots/roll.jpg?raw=true",
|
||||
"caption": "DicePicker and Roll and Keep"
|
||||
},
|
||||
{
|
||||
"type": "screenshot",
|
||||
"url": "https://gitlab.com/teaml5r/l5r5e/-/raw/master/screenshoots/school.jpg?raw=true",
|
||||
"caption": "Experience and School"
|
||||
},
|
||||
{
|
||||
"type": "screenshot",
|
||||
"url": "https://gitlab.com/teaml5r/l5r5e/-/raw/master/screenshoots/sheet_pc.jpg?raw=true",
|
||||
"caption": "PC sheet"
|
||||
},
|
||||
{
|
||||
"type": "screenshot",
|
||||
"url": "https://gitlab.com/teaml5r/l5r5e/-/raw/master/screenshoots/sheet_npc_army.jpg?raw=true",
|
||||
"caption": "NPC and Army sheets"
|
||||
},
|
||||
{
|
||||
"type": "screenshot",
|
||||
"url": "https://gitlab.com/teaml5r/l5r5e/-/raw/master/screenshoots/compendiums.jpg?raw=true",
|
||||
"caption": "Compendiums"
|
||||
}
|
||||
]
|
||||
}
|
||||
393
system/.history/system_20260423143050.json
Normal file
393
system/.history/system_20260423143050.json
Normal file
@@ -0,0 +1,393 @@
|
||||
{
|
||||
"id": "l5rx-chiaroscuro",
|
||||
"title": "Chiaroscuro - Legend of the Five Rings (5th Edition)",
|
||||
"description": "This is an authorised multilingual game system En|Fr|Es, for Legend of the Five Rings (5th Edition) by <a href='https://edge-studio.net/'>Edge Studio</a> <p> - Join the official Discord server: <a href='https://discord.gg/foundryvtt'> Official Discord</a></p><p> - Rejoignez la communauté Francophone: <a href='https://discord.gg/pPSDNJk'>Francophone Discord</a></p>",
|
||||
"url": "https://gitlab.com/teaml5r/l5r5e",
|
||||
"readme": "https://gitlab.com/teaml5r/l5r5e/-/blob/master/README.md",
|
||||
"changelog": "https://gitlab.com/teaml5r/l5r5e/-/blob/master/CHANGELOG.md",
|
||||
"license": "https://gitlab.com/teaml5r/l5r5e/-/blob/master/LICENSE.md",
|
||||
"manifest": "https://gitlab.com/teaml5r/l5r5e/-/raw/master/system/system.json",
|
||||
"download": "https://gitlab.com/teaml5r/l5r5e/-/jobs/artifacts/v1.13.4/raw/l5r5e.zip?job=build",
|
||||
"version": "14.0.0",
|
||||
"compatibility": {
|
||||
"minimum": "13",
|
||||
"verified": "14"
|
||||
},
|
||||
"socket": true,
|
||||
"authors": [
|
||||
{
|
||||
"name": "Vlyan",
|
||||
"discord": "Vlyan#6771",
|
||||
"url": "https://ko-fi.com/vlyan"
|
||||
},
|
||||
{
|
||||
"name": "Mandar",
|
||||
"discord": "Mandar#3440"
|
||||
},
|
||||
{
|
||||
"name": "Carter",
|
||||
"discord": "Carter#2703",
|
||||
"url": "https://fr.tipeee.com/carter-foundryvtt"
|
||||
},
|
||||
{
|
||||
"name": "Litasa",
|
||||
"discord": "Litasa#3139"
|
||||
}
|
||||
],
|
||||
"background": "systems/l5r5e/assets/l5r-header.webp",
|
||||
"scripts": [],
|
||||
"esmodules": [
|
||||
"./scripts/main-l5r5e.js"
|
||||
],
|
||||
"styles": [
|
||||
"./styles/l5r5e.css"
|
||||
],
|
||||
"packFolders": [
|
||||
{
|
||||
"name": "L5R5e System",
|
||||
"color": "#9a0909",
|
||||
"sorting": "m",
|
||||
"folders": [
|
||||
{
|
||||
"name": "Character related",
|
||||
"color": "#019806",
|
||||
"sorting": "m",
|
||||
"packs": [
|
||||
"core-peculiarities-distinctions",
|
||||
"core-peculiarities-passions",
|
||||
"core-peculiarities-adversities",
|
||||
"core-peculiarities-anxieties",
|
||||
"core-bonds",
|
||||
"core-titles",
|
||||
"core-journal-school-curriculum",
|
||||
"core-journal-great-clans-presentation"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Techniques",
|
||||
"color": "#4b1eb3",
|
||||
"sorting": "m",
|
||||
"packs": [
|
||||
"core-techniques-kata",
|
||||
"core-techniques-kiho",
|
||||
"core-techniques-inversions",
|
||||
"core-techniques-invocations",
|
||||
"core-techniques-rituals",
|
||||
"core-techniques-shuji",
|
||||
"core-techniques-maho",
|
||||
"core-techniques-ninjutsu",
|
||||
"core-techniques-mantra",
|
||||
"core-techniques-school",
|
||||
"core-techniques-mastery"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Objects related",
|
||||
"color": "#0985ae",
|
||||
"sorting": "m",
|
||||
"packs": [
|
||||
"core-properties",
|
||||
"core-item-patterns",
|
||||
"core-items",
|
||||
"core-armors",
|
||||
"core-weapons",
|
||||
"core-signature-scrolls",
|
||||
"core-celestial-implement-boons"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Helpers",
|
||||
"color": "#6b3d1f",
|
||||
"sorting": "m",
|
||||
"packs": [
|
||||
"core-journal-conditions",
|
||||
"core-journal-terrain-qualities",
|
||||
"core-journal-opportunities"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Tools",
|
||||
"color": "#834949",
|
||||
"sorting": "m",
|
||||
"packs": [
|
||||
"core-name-tables",
|
||||
"core-macros"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"packs": [
|
||||
{
|
||||
"name": "core-properties",
|
||||
"label": "Properties",
|
||||
"path": "packs/core-properties.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-techniques-kata",
|
||||
"label": "Techniques Kata",
|
||||
"path": "packs/core-techniques-kata.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-techniques-kiho",
|
||||
"label": "Techniques Kihõ",
|
||||
"path": "packs/core-techniques-kiho.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-techniques-inversions",
|
||||
"label": "Techniques Inversions",
|
||||
"path": "packs/core-techniques-inversions.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-techniques-invocations",
|
||||
"label": "Techniques Invocations",
|
||||
"path": "packs/core-techniques-invocations.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-techniques-rituals",
|
||||
"label": "Techniques Rituals",
|
||||
"path": "packs/core-techniques-rituals.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-techniques-shuji",
|
||||
"label": "Techniques Shuji",
|
||||
"path": "packs/core-techniques-shuji.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-techniques-maho",
|
||||
"label": "Techniques Mahõ",
|
||||
"path": "packs/core-techniques-maho.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-techniques-ninjutsu",
|
||||
"label": "Techniques Ninjutsu",
|
||||
"path": "packs/core-techniques-ninjutsu.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-techniques-mantra",
|
||||
"label": "Techniques Mantra",
|
||||
"path": "packs/core-techniques-mantra.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-techniques-school",
|
||||
"label": "School Abilities",
|
||||
"path": "packs/core-techniques-school.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-techniques-mastery",
|
||||
"label": "Mastery Abilities",
|
||||
"path": "packs/core-techniques-mastery.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-items",
|
||||
"label": "Items",
|
||||
"path": "packs/core-items.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-armors",
|
||||
"label": "Armors",
|
||||
"path": "packs/core-armors.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-weapons",
|
||||
"label": "Weapons",
|
||||
"path": "packs/core-weapons.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-peculiarities-distinctions",
|
||||
"label": "Distinctions",
|
||||
"path": "packs/core-peculiarities-distinctions.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-peculiarities-passions",
|
||||
"label": "Passions",
|
||||
"path": "packs/core-peculiarities-passions.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-peculiarities-adversities",
|
||||
"label": "Adversities",
|
||||
"path": "packs/core-peculiarities-adversities.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-peculiarities-anxieties",
|
||||
"label": "Anxieties",
|
||||
"path": "packs/core-peculiarities-anxieties.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-bonds",
|
||||
"label": "Bonds",
|
||||
"path": "packs/core-bonds.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-titles",
|
||||
"label": "Titles",
|
||||
"path": "packs/core-titles.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-item-patterns",
|
||||
"label": "Item Patterns",
|
||||
"path": "packs/core-item-patterns.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-signature-scrolls",
|
||||
"label": "Signature Scrolls",
|
||||
"path": "packs/core-signature-scrolls.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-celestial-implement-boons",
|
||||
"label": "Celestial Implement Boons",
|
||||
"path": "packs/core-celestial-implement-boons.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-journal-school-curriculum",
|
||||
"label": "School Curriculum",
|
||||
"path": "packs/core-journal-school-curriculum.db",
|
||||
"type": "JournalEntry",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-journal-conditions",
|
||||
"label": "Conditions",
|
||||
"path": "packs/core-journal-conditions.db",
|
||||
"type": "JournalEntry",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-journal-terrain-qualities",
|
||||
"label": "Terrain Qualities",
|
||||
"path": "packs/core-journal-terrain-qualities.db",
|
||||
"type": "JournalEntry",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-journal-great-clans-presentation",
|
||||
"label": "Great Clans Presentation",
|
||||
"path": "packs/core-journal-great-clans-presentation.db",
|
||||
"type": "JournalEntry",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-journal-opportunities",
|
||||
"label": "Opportunities",
|
||||
"path": "packs/core-journal-opportunities.db",
|
||||
"type": "JournalEntry",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-name-tables",
|
||||
"label": "Name Tables",
|
||||
"path": "packs/core-name-tables.db",
|
||||
"type": "RollTable",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-macros",
|
||||
"label": "L5R5E Macros",
|
||||
"path": "packs/core-macros.db",
|
||||
"type": "Macro",
|
||||
"system": "l5r5e"
|
||||
}
|
||||
],
|
||||
"languages": [
|
||||
{
|
||||
"lang": "en",
|
||||
"name": "English",
|
||||
"path": "lang/en-en.json"
|
||||
},
|
||||
{
|
||||
"lang": "fr",
|
||||
"name": "French (France)",
|
||||
"path": "lang/fr-fr.json"
|
||||
},
|
||||
{
|
||||
"lang": "es",
|
||||
"name": "Spanish (Spain)",
|
||||
"path": "lang/es-es.json"
|
||||
},
|
||||
{
|
||||
"lang": "it",
|
||||
"name": "Italian (Italy)",
|
||||
"path": "lang/it-it.json"
|
||||
}
|
||||
],
|
||||
"media": [
|
||||
{
|
||||
"type": "screenshot",
|
||||
"url": "https://gitlab.com/teaml5r/l5r5e/-/raw/master/screenshoots/login.jpg?raw=true",
|
||||
"caption": "Login screen"
|
||||
},
|
||||
{
|
||||
"type": "screenshot",
|
||||
"url": "https://gitlab.com/teaml5r/l5r5e/-/raw/master/screenshoots/roll.jpg?raw=true",
|
||||
"caption": "DicePicker and Roll and Keep"
|
||||
},
|
||||
{
|
||||
"type": "screenshot",
|
||||
"url": "https://gitlab.com/teaml5r/l5r5e/-/raw/master/screenshoots/school.jpg?raw=true",
|
||||
"caption": "Experience and School"
|
||||
},
|
||||
{
|
||||
"type": "screenshot",
|
||||
"url": "https://gitlab.com/teaml5r/l5r5e/-/raw/master/screenshoots/sheet_pc.jpg?raw=true",
|
||||
"caption": "PC sheet"
|
||||
},
|
||||
{
|
||||
"type": "screenshot",
|
||||
"url": "https://gitlab.com/teaml5r/l5r5e/-/raw/master/screenshoots/sheet_npc_army.jpg?raw=true",
|
||||
"caption": "NPC and Army sheets"
|
||||
},
|
||||
{
|
||||
"type": "screenshot",
|
||||
"url": "https://gitlab.com/teaml5r/l5r5e/-/raw/master/screenshoots/compendiums.jpg?raw=true",
|
||||
"caption": "Compendiums"
|
||||
}
|
||||
]
|
||||
}
|
||||
393
system/.history/system_20260423143055.json
Normal file
393
system/.history/system_20260423143055.json
Normal file
@@ -0,0 +1,393 @@
|
||||
{
|
||||
"id": "l5rx-chiaroscuro",
|
||||
"title": "Chiaroscuro - L5R",
|
||||
"description": "This is an authorised multilingual game system En|Fr|Es, for Legend of the Five Rings (5th Edition) by <a href='https://edge-studio.net/'>Edge Studio</a> <p> - Join the official Discord server: <a href='https://discord.gg/foundryvtt'> Official Discord</a></p><p> - Rejoignez la communauté Francophone: <a href='https://discord.gg/pPSDNJk'>Francophone Discord</a></p>",
|
||||
"url": "https://gitlab.com/teaml5r/l5r5e",
|
||||
"readme": "https://gitlab.com/teaml5r/l5r5e/-/blob/master/README.md",
|
||||
"changelog": "https://gitlab.com/teaml5r/l5r5e/-/blob/master/CHANGELOG.md",
|
||||
"license": "https://gitlab.com/teaml5r/l5r5e/-/blob/master/LICENSE.md",
|
||||
"manifest": "https://gitlab.com/teaml5r/l5r5e/-/raw/master/system/system.json",
|
||||
"download": "https://gitlab.com/teaml5r/l5r5e/-/jobs/artifacts/v1.13.4/raw/l5r5e.zip?job=build",
|
||||
"version": "14.0.0",
|
||||
"compatibility": {
|
||||
"minimum": "13",
|
||||
"verified": "14"
|
||||
},
|
||||
"socket": true,
|
||||
"authors": [
|
||||
{
|
||||
"name": "Vlyan",
|
||||
"discord": "Vlyan#6771",
|
||||
"url": "https://ko-fi.com/vlyan"
|
||||
},
|
||||
{
|
||||
"name": "Mandar",
|
||||
"discord": "Mandar#3440"
|
||||
},
|
||||
{
|
||||
"name": "Carter",
|
||||
"discord": "Carter#2703",
|
||||
"url": "https://fr.tipeee.com/carter-foundryvtt"
|
||||
},
|
||||
{
|
||||
"name": "Litasa",
|
||||
"discord": "Litasa#3139"
|
||||
}
|
||||
],
|
||||
"background": "systems/l5r5e/assets/l5r-header.webp",
|
||||
"scripts": [],
|
||||
"esmodules": [
|
||||
"./scripts/main-l5r5e.js"
|
||||
],
|
||||
"styles": [
|
||||
"./styles/l5r5e.css"
|
||||
],
|
||||
"packFolders": [
|
||||
{
|
||||
"name": "L5R5e System",
|
||||
"color": "#9a0909",
|
||||
"sorting": "m",
|
||||
"folders": [
|
||||
{
|
||||
"name": "Character related",
|
||||
"color": "#019806",
|
||||
"sorting": "m",
|
||||
"packs": [
|
||||
"core-peculiarities-distinctions",
|
||||
"core-peculiarities-passions",
|
||||
"core-peculiarities-adversities",
|
||||
"core-peculiarities-anxieties",
|
||||
"core-bonds",
|
||||
"core-titles",
|
||||
"core-journal-school-curriculum",
|
||||
"core-journal-great-clans-presentation"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Techniques",
|
||||
"color": "#4b1eb3",
|
||||
"sorting": "m",
|
||||
"packs": [
|
||||
"core-techniques-kata",
|
||||
"core-techniques-kiho",
|
||||
"core-techniques-inversions",
|
||||
"core-techniques-invocations",
|
||||
"core-techniques-rituals",
|
||||
"core-techniques-shuji",
|
||||
"core-techniques-maho",
|
||||
"core-techniques-ninjutsu",
|
||||
"core-techniques-mantra",
|
||||
"core-techniques-school",
|
||||
"core-techniques-mastery"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Objects related",
|
||||
"color": "#0985ae",
|
||||
"sorting": "m",
|
||||
"packs": [
|
||||
"core-properties",
|
||||
"core-item-patterns",
|
||||
"core-items",
|
||||
"core-armors",
|
||||
"core-weapons",
|
||||
"core-signature-scrolls",
|
||||
"core-celestial-implement-boons"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Helpers",
|
||||
"color": "#6b3d1f",
|
||||
"sorting": "m",
|
||||
"packs": [
|
||||
"core-journal-conditions",
|
||||
"core-journal-terrain-qualities",
|
||||
"core-journal-opportunities"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Tools",
|
||||
"color": "#834949",
|
||||
"sorting": "m",
|
||||
"packs": [
|
||||
"core-name-tables",
|
||||
"core-macros"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"packs": [
|
||||
{
|
||||
"name": "core-properties",
|
||||
"label": "Properties",
|
||||
"path": "packs/core-properties.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-techniques-kata",
|
||||
"label": "Techniques Kata",
|
||||
"path": "packs/core-techniques-kata.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-techniques-kiho",
|
||||
"label": "Techniques Kihõ",
|
||||
"path": "packs/core-techniques-kiho.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-techniques-inversions",
|
||||
"label": "Techniques Inversions",
|
||||
"path": "packs/core-techniques-inversions.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-techniques-invocations",
|
||||
"label": "Techniques Invocations",
|
||||
"path": "packs/core-techniques-invocations.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-techniques-rituals",
|
||||
"label": "Techniques Rituals",
|
||||
"path": "packs/core-techniques-rituals.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-techniques-shuji",
|
||||
"label": "Techniques Shuji",
|
||||
"path": "packs/core-techniques-shuji.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-techniques-maho",
|
||||
"label": "Techniques Mahõ",
|
||||
"path": "packs/core-techniques-maho.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-techniques-ninjutsu",
|
||||
"label": "Techniques Ninjutsu",
|
||||
"path": "packs/core-techniques-ninjutsu.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-techniques-mantra",
|
||||
"label": "Techniques Mantra",
|
||||
"path": "packs/core-techniques-mantra.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-techniques-school",
|
||||
"label": "School Abilities",
|
||||
"path": "packs/core-techniques-school.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-techniques-mastery",
|
||||
"label": "Mastery Abilities",
|
||||
"path": "packs/core-techniques-mastery.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-items",
|
||||
"label": "Items",
|
||||
"path": "packs/core-items.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-armors",
|
||||
"label": "Armors",
|
||||
"path": "packs/core-armors.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-weapons",
|
||||
"label": "Weapons",
|
||||
"path": "packs/core-weapons.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-peculiarities-distinctions",
|
||||
"label": "Distinctions",
|
||||
"path": "packs/core-peculiarities-distinctions.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-peculiarities-passions",
|
||||
"label": "Passions",
|
||||
"path": "packs/core-peculiarities-passions.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-peculiarities-adversities",
|
||||
"label": "Adversities",
|
||||
"path": "packs/core-peculiarities-adversities.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-peculiarities-anxieties",
|
||||
"label": "Anxieties",
|
||||
"path": "packs/core-peculiarities-anxieties.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-bonds",
|
||||
"label": "Bonds",
|
||||
"path": "packs/core-bonds.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-titles",
|
||||
"label": "Titles",
|
||||
"path": "packs/core-titles.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-item-patterns",
|
||||
"label": "Item Patterns",
|
||||
"path": "packs/core-item-patterns.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-signature-scrolls",
|
||||
"label": "Signature Scrolls",
|
||||
"path": "packs/core-signature-scrolls.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-celestial-implement-boons",
|
||||
"label": "Celestial Implement Boons",
|
||||
"path": "packs/core-celestial-implement-boons.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-journal-school-curriculum",
|
||||
"label": "School Curriculum",
|
||||
"path": "packs/core-journal-school-curriculum.db",
|
||||
"type": "JournalEntry",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-journal-conditions",
|
||||
"label": "Conditions",
|
||||
"path": "packs/core-journal-conditions.db",
|
||||
"type": "JournalEntry",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-journal-terrain-qualities",
|
||||
"label": "Terrain Qualities",
|
||||
"path": "packs/core-journal-terrain-qualities.db",
|
||||
"type": "JournalEntry",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-journal-great-clans-presentation",
|
||||
"label": "Great Clans Presentation",
|
||||
"path": "packs/core-journal-great-clans-presentation.db",
|
||||
"type": "JournalEntry",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-journal-opportunities",
|
||||
"label": "Opportunities",
|
||||
"path": "packs/core-journal-opportunities.db",
|
||||
"type": "JournalEntry",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-name-tables",
|
||||
"label": "Name Tables",
|
||||
"path": "packs/core-name-tables.db",
|
||||
"type": "RollTable",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-macros",
|
||||
"label": "L5R5E Macros",
|
||||
"path": "packs/core-macros.db",
|
||||
"type": "Macro",
|
||||
"system": "l5r5e"
|
||||
}
|
||||
],
|
||||
"languages": [
|
||||
{
|
||||
"lang": "en",
|
||||
"name": "English",
|
||||
"path": "lang/en-en.json"
|
||||
},
|
||||
{
|
||||
"lang": "fr",
|
||||
"name": "French (France)",
|
||||
"path": "lang/fr-fr.json"
|
||||
},
|
||||
{
|
||||
"lang": "es",
|
||||
"name": "Spanish (Spain)",
|
||||
"path": "lang/es-es.json"
|
||||
},
|
||||
{
|
||||
"lang": "it",
|
||||
"name": "Italian (Italy)",
|
||||
"path": "lang/it-it.json"
|
||||
}
|
||||
],
|
||||
"media": [
|
||||
{
|
||||
"type": "screenshot",
|
||||
"url": "https://gitlab.com/teaml5r/l5r5e/-/raw/master/screenshoots/login.jpg?raw=true",
|
||||
"caption": "Login screen"
|
||||
},
|
||||
{
|
||||
"type": "screenshot",
|
||||
"url": "https://gitlab.com/teaml5r/l5r5e/-/raw/master/screenshoots/roll.jpg?raw=true",
|
||||
"caption": "DicePicker and Roll and Keep"
|
||||
},
|
||||
{
|
||||
"type": "screenshot",
|
||||
"url": "https://gitlab.com/teaml5r/l5r5e/-/raw/master/screenshoots/school.jpg?raw=true",
|
||||
"caption": "Experience and School"
|
||||
},
|
||||
{
|
||||
"type": "screenshot",
|
||||
"url": "https://gitlab.com/teaml5r/l5r5e/-/raw/master/screenshoots/sheet_pc.jpg?raw=true",
|
||||
"caption": "PC sheet"
|
||||
},
|
||||
{
|
||||
"type": "screenshot",
|
||||
"url": "https://gitlab.com/teaml5r/l5r5e/-/raw/master/screenshoots/sheet_npc_army.jpg?raw=true",
|
||||
"caption": "NPC and Army sheets"
|
||||
},
|
||||
{
|
||||
"type": "screenshot",
|
||||
"url": "https://gitlab.com/teaml5r/l5r5e/-/raw/master/screenshoots/compendiums.jpg?raw=true",
|
||||
"caption": "Compendiums"
|
||||
}
|
||||
]
|
||||
}
|
||||
393
system/.history/system_20260423143056.json
Normal file
393
system/.history/system_20260423143056.json
Normal file
@@ -0,0 +1,393 @@
|
||||
{
|
||||
"id": "l5rx-chiaroscuro",
|
||||
"title": "Chiaroscuro - L5R",
|
||||
"description": "This is an authorised multilingual game system En|Fr|Es, for Legend of the Five Rings (5th Edition) by <a href='https://edge-studio.net/'>Edge Studio</a> <p> - Join the official Discord server: <a href='https://discord.gg/foundryvtt'> Official Discord</a></p><p> - Rejoignez la communauté Francophone: <a href='https://discord.gg/pPSDNJk'>Francophone Discord</a></p>",
|
||||
"url": "https://gitlab.com/teaml5r/l5r5e",
|
||||
"readme": "https://gitlab.com/teaml5r/l5r5e/-/blob/master/README.md",
|
||||
"changelog": "https://gitlab.com/teaml5r/l5r5e/-/blob/master/CHANGELOG.md",
|
||||
"license": "https://gitlab.com/teaml5r/l5r5e/-/blob/master/LICENSE.md",
|
||||
"manifest": "https://gitlab.com/teaml5r/l5r5e/-/raw/master/system/system.json",
|
||||
"download": "https://gitlab.com/teaml5r/l5r5e/-/jobs/artifacts/v1.13.4/raw/l5r5e.zip?job=build",
|
||||
"version": "14.0.0",
|
||||
"compatibility": {
|
||||
"minimum": "13",
|
||||
"verified": "14"
|
||||
},
|
||||
"socket": true,
|
||||
"authors": [
|
||||
{
|
||||
"name": "Vlyan",
|
||||
"discord": "Vlyan#6771",
|
||||
"url": "https://ko-fi.com/vlyan"
|
||||
},
|
||||
{
|
||||
"name": "Mandar",
|
||||
"discord": "Mandar#3440"
|
||||
},
|
||||
{
|
||||
"name": "Carter",
|
||||
"discord": "Carter#2703",
|
||||
"url": "https://fr.tipeee.com/carter-foundryvtt"
|
||||
},
|
||||
{
|
||||
"name": "Litasa",
|
||||
"discord": "Litasa#3139"
|
||||
}
|
||||
],
|
||||
"background": "systems/l5r5e/assets/l5r-header.webp",
|
||||
"scripts": [],
|
||||
"esmodules": [
|
||||
"./scripts/main-l5r5e.js"
|
||||
],
|
||||
"styles": [
|
||||
"./styles/l5r5e.css"
|
||||
],
|
||||
"packFolders": [
|
||||
{
|
||||
"name": "L5R5e System",
|
||||
"color": "#9a0909",
|
||||
"sorting": "m",
|
||||
"folders": [
|
||||
{
|
||||
"name": "Character related",
|
||||
"color": "#019806",
|
||||
"sorting": "m",
|
||||
"packs": [
|
||||
"core-peculiarities-distinctions",
|
||||
"core-peculiarities-passions",
|
||||
"core-peculiarities-adversities",
|
||||
"core-peculiarities-anxieties",
|
||||
"core-bonds",
|
||||
"core-titles",
|
||||
"core-journal-school-curriculum",
|
||||
"core-journal-great-clans-presentation"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Techniques",
|
||||
"color": "#4b1eb3",
|
||||
"sorting": "m",
|
||||
"packs": [
|
||||
"core-techniques-kata",
|
||||
"core-techniques-kiho",
|
||||
"core-techniques-inversions",
|
||||
"core-techniques-invocations",
|
||||
"core-techniques-rituals",
|
||||
"core-techniques-shuji",
|
||||
"core-techniques-maho",
|
||||
"core-techniques-ninjutsu",
|
||||
"core-techniques-mantra",
|
||||
"core-techniques-school",
|
||||
"core-techniques-mastery"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Objects related",
|
||||
"color": "#0985ae",
|
||||
"sorting": "m",
|
||||
"packs": [
|
||||
"core-properties",
|
||||
"core-item-patterns",
|
||||
"core-items",
|
||||
"core-armors",
|
||||
"core-weapons",
|
||||
"core-signature-scrolls",
|
||||
"core-celestial-implement-boons"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Helpers",
|
||||
"color": "#6b3d1f",
|
||||
"sorting": "m",
|
||||
"packs": [
|
||||
"core-journal-conditions",
|
||||
"core-journal-terrain-qualities",
|
||||
"core-journal-opportunities"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Tools",
|
||||
"color": "#834949",
|
||||
"sorting": "m",
|
||||
"packs": [
|
||||
"core-name-tables",
|
||||
"core-macros"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"packs": [
|
||||
{
|
||||
"name": "core-properties",
|
||||
"label": "Properties",
|
||||
"path": "packs/core-properties.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-techniques-kata",
|
||||
"label": "Techniques Kata",
|
||||
"path": "packs/core-techniques-kata.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-techniques-kiho",
|
||||
"label": "Techniques Kihõ",
|
||||
"path": "packs/core-techniques-kiho.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-techniques-inversions",
|
||||
"label": "Techniques Inversions",
|
||||
"path": "packs/core-techniques-inversions.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-techniques-invocations",
|
||||
"label": "Techniques Invocations",
|
||||
"path": "packs/core-techniques-invocations.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-techniques-rituals",
|
||||
"label": "Techniques Rituals",
|
||||
"path": "packs/core-techniques-rituals.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-techniques-shuji",
|
||||
"label": "Techniques Shuji",
|
||||
"path": "packs/core-techniques-shuji.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-techniques-maho",
|
||||
"label": "Techniques Mahõ",
|
||||
"path": "packs/core-techniques-maho.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-techniques-ninjutsu",
|
||||
"label": "Techniques Ninjutsu",
|
||||
"path": "packs/core-techniques-ninjutsu.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-techniques-mantra",
|
||||
"label": "Techniques Mantra",
|
||||
"path": "packs/core-techniques-mantra.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-techniques-school",
|
||||
"label": "School Abilities",
|
||||
"path": "packs/core-techniques-school.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-techniques-mastery",
|
||||
"label": "Mastery Abilities",
|
||||
"path": "packs/core-techniques-mastery.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-items",
|
||||
"label": "Items",
|
||||
"path": "packs/core-items.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-armors",
|
||||
"label": "Armors",
|
||||
"path": "packs/core-armors.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-weapons",
|
||||
"label": "Weapons",
|
||||
"path": "packs/core-weapons.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-peculiarities-distinctions",
|
||||
"label": "Distinctions",
|
||||
"path": "packs/core-peculiarities-distinctions.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-peculiarities-passions",
|
||||
"label": "Passions",
|
||||
"path": "packs/core-peculiarities-passions.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-peculiarities-adversities",
|
||||
"label": "Adversities",
|
||||
"path": "packs/core-peculiarities-adversities.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-peculiarities-anxieties",
|
||||
"label": "Anxieties",
|
||||
"path": "packs/core-peculiarities-anxieties.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-bonds",
|
||||
"label": "Bonds",
|
||||
"path": "packs/core-bonds.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-titles",
|
||||
"label": "Titles",
|
||||
"path": "packs/core-titles.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-item-patterns",
|
||||
"label": "Item Patterns",
|
||||
"path": "packs/core-item-patterns.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-signature-scrolls",
|
||||
"label": "Signature Scrolls",
|
||||
"path": "packs/core-signature-scrolls.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-celestial-implement-boons",
|
||||
"label": "Celestial Implement Boons",
|
||||
"path": "packs/core-celestial-implement-boons.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-journal-school-curriculum",
|
||||
"label": "School Curriculum",
|
||||
"path": "packs/core-journal-school-curriculum.db",
|
||||
"type": "JournalEntry",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-journal-conditions",
|
||||
"label": "Conditions",
|
||||
"path": "packs/core-journal-conditions.db",
|
||||
"type": "JournalEntry",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-journal-terrain-qualities",
|
||||
"label": "Terrain Qualities",
|
||||
"path": "packs/core-journal-terrain-qualities.db",
|
||||
"type": "JournalEntry",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-journal-great-clans-presentation",
|
||||
"label": "Great Clans Presentation",
|
||||
"path": "packs/core-journal-great-clans-presentation.db",
|
||||
"type": "JournalEntry",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-journal-opportunities",
|
||||
"label": "Opportunities",
|
||||
"path": "packs/core-journal-opportunities.db",
|
||||
"type": "JournalEntry",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-name-tables",
|
||||
"label": "Name Tables",
|
||||
"path": "packs/core-name-tables.db",
|
||||
"type": "RollTable",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-macros",
|
||||
"label": "L5R5E Macros",
|
||||
"path": "packs/core-macros.db",
|
||||
"type": "Macro",
|
||||
"system": "l5r5e"
|
||||
}
|
||||
],
|
||||
"languages": [
|
||||
{
|
||||
"lang": "en",
|
||||
"name": "English",
|
||||
"path": "lang/en-en.json"
|
||||
},
|
||||
{
|
||||
"lang": "fr",
|
||||
"name": "French (France)",
|
||||
"path": "lang/fr-fr.json"
|
||||
},
|
||||
{
|
||||
"lang": "es",
|
||||
"name": "Spanish (Spain)",
|
||||
"path": "lang/es-es.json"
|
||||
},
|
||||
{
|
||||
"lang": "it",
|
||||
"name": "Italian (Italy)",
|
||||
"path": "lang/it-it.json"
|
||||
}
|
||||
],
|
||||
"media": [
|
||||
{
|
||||
"type": "screenshot",
|
||||
"url": "https://gitlab.com/teaml5r/l5r5e/-/raw/master/screenshoots/login.jpg?raw=true",
|
||||
"caption": "Login screen"
|
||||
},
|
||||
{
|
||||
"type": "screenshot",
|
||||
"url": "https://gitlab.com/teaml5r/l5r5e/-/raw/master/screenshoots/roll.jpg?raw=true",
|
||||
"caption": "DicePicker and Roll and Keep"
|
||||
},
|
||||
{
|
||||
"type": "screenshot",
|
||||
"url": "https://gitlab.com/teaml5r/l5r5e/-/raw/master/screenshoots/school.jpg?raw=true",
|
||||
"caption": "Experience and School"
|
||||
},
|
||||
{
|
||||
"type": "screenshot",
|
||||
"url": "https://gitlab.com/teaml5r/l5r5e/-/raw/master/screenshoots/sheet_pc.jpg?raw=true",
|
||||
"caption": "PC sheet"
|
||||
},
|
||||
{
|
||||
"type": "screenshot",
|
||||
"url": "https://gitlab.com/teaml5r/l5r5e/-/raw/master/screenshoots/sheet_npc_army.jpg?raw=true",
|
||||
"caption": "NPC and Army sheets"
|
||||
},
|
||||
{
|
||||
"type": "screenshot",
|
||||
"url": "https://gitlab.com/teaml5r/l5r5e/-/raw/master/screenshoots/compendiums.jpg?raw=true",
|
||||
"caption": "Compendiums"
|
||||
}
|
||||
]
|
||||
}
|
||||
393
system/.history/system_20260423143057.json
Normal file
393
system/.history/system_20260423143057.json
Normal file
@@ -0,0 +1,393 @@
|
||||
{
|
||||
"id": "l5rx-chiaroscuro",
|
||||
"title": "Chiaroscuro - L5R",
|
||||
"description": "This is an authorised multilingual game system En|Fr|Es, for Legend of the Five Rings (5th Edition) by <a href='https://edge-studio.net/'>Edge Studio</a> <p> - Join the official Discord server: <a href='https://discord.gg/foundryvtt'> Official Discord</a></p><p> - Rejoignez la communauté Francophone: <a href='https://discord.gg/pPSDNJk'>Francophone Discord</a></p>",
|
||||
"url": "https://gitlab.com/teaml5r/l5r5e",
|
||||
"readme": "https://gitlab.com/teaml5r/l5r5e/-/blob/master/README.md",
|
||||
"changelog": "https://gitlab.com/teaml5r/l5r5e/-/blob/master/CHANGELOG.md",
|
||||
"license": "https://gitlab.com/teaml5r/l5r5e/-/blob/master/LICENSE.md",
|
||||
"manifest": "https://gitlab.com/teaml5r/l5r5e/-/raw/master/system/system.json",
|
||||
"download": "https://gitlab.com/teaml5r/l5r5e/-/jobs/artifacts/v1.13.4/raw/l5r5e.zip?job=build",
|
||||
"version": "14.0.0",
|
||||
"compatibility": {
|
||||
"minimum": "13",
|
||||
"verified": "14"
|
||||
},
|
||||
"socket": true,
|
||||
"authors": [
|
||||
{
|
||||
"name": "Vlyan",
|
||||
"discord": "Vlyan#6771",
|
||||
"url": "https://ko-fi.com/vlyan"
|
||||
},
|
||||
{
|
||||
"name": "Mandar",
|
||||
"discord": "Mandar#3440"
|
||||
},
|
||||
{
|
||||
"name": "Carter",
|
||||
"discord": "Carter#2703",
|
||||
"url": "https://fr.tipeee.com/carter-foundryvtt"
|
||||
},
|
||||
{
|
||||
"name": "Litasa",
|
||||
"discord": "Litasa#3139"
|
||||
}
|
||||
],
|
||||
"background": "systems/l5r5e/assets/l5r-header.webp",
|
||||
"scripts": [],
|
||||
"esmodules": [
|
||||
"./scripts/main-l5r5e.js"
|
||||
],
|
||||
"styles": [
|
||||
"./styles/l5r5e.css"
|
||||
],
|
||||
"packFolders": [
|
||||
{
|
||||
"name": "L5R5e System",
|
||||
"color": "#9a0909",
|
||||
"sorting": "m",
|
||||
"folders": [
|
||||
{
|
||||
"name": "Character related",
|
||||
"color": "#019806",
|
||||
"sorting": "m",
|
||||
"packs": [
|
||||
"core-peculiarities-distinctions",
|
||||
"core-peculiarities-passions",
|
||||
"core-peculiarities-adversities",
|
||||
"core-peculiarities-anxieties",
|
||||
"core-bonds",
|
||||
"core-titles",
|
||||
"core-journal-school-curriculum",
|
||||
"core-journal-great-clans-presentation"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Techniques",
|
||||
"color": "#4b1eb3",
|
||||
"sorting": "m",
|
||||
"packs": [
|
||||
"core-techniques-kata",
|
||||
"core-techniques-kiho",
|
||||
"core-techniques-inversions",
|
||||
"core-techniques-invocations",
|
||||
"core-techniques-rituals",
|
||||
"core-techniques-shuji",
|
||||
"core-techniques-maho",
|
||||
"core-techniques-ninjutsu",
|
||||
"core-techniques-mantra",
|
||||
"core-techniques-school",
|
||||
"core-techniques-mastery"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Objects related",
|
||||
"color": "#0985ae",
|
||||
"sorting": "m",
|
||||
"packs": [
|
||||
"core-properties",
|
||||
"core-item-patterns",
|
||||
"core-items",
|
||||
"core-armors",
|
||||
"core-weapons",
|
||||
"core-signature-scrolls",
|
||||
"core-celestial-implement-boons"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Helpers",
|
||||
"color": "#6b3d1f",
|
||||
"sorting": "m",
|
||||
"packs": [
|
||||
"core-journal-conditions",
|
||||
"core-journal-terrain-qualities",
|
||||
"core-journal-opportunities"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Tools",
|
||||
"color": "#834949",
|
||||
"sorting": "m",
|
||||
"packs": [
|
||||
"core-name-tables",
|
||||
"core-macros"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"packs": [
|
||||
{
|
||||
"name": "core-properties",
|
||||
"label": "Properties",
|
||||
"path": "packs/core-properties.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-techniques-kata",
|
||||
"label": "Techniques Kata",
|
||||
"path": "packs/core-techniques-kata.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-techniques-kiho",
|
||||
"label": "Techniques Kihõ",
|
||||
"path": "packs/core-techniques-kiho.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-techniques-inversions",
|
||||
"label": "Techniques Inversions",
|
||||
"path": "packs/core-techniques-inversions.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-techniques-invocations",
|
||||
"label": "Techniques Invocations",
|
||||
"path": "packs/core-techniques-invocations.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-techniques-rituals",
|
||||
"label": "Techniques Rituals",
|
||||
"path": "packs/core-techniques-rituals.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-techniques-shuji",
|
||||
"label": "Techniques Shuji",
|
||||
"path": "packs/core-techniques-shuji.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-techniques-maho",
|
||||
"label": "Techniques Mahõ",
|
||||
"path": "packs/core-techniques-maho.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-techniques-ninjutsu",
|
||||
"label": "Techniques Ninjutsu",
|
||||
"path": "packs/core-techniques-ninjutsu.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-techniques-mantra",
|
||||
"label": "Techniques Mantra",
|
||||
"path": "packs/core-techniques-mantra.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-techniques-school",
|
||||
"label": "School Abilities",
|
||||
"path": "packs/core-techniques-school.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-techniques-mastery",
|
||||
"label": "Mastery Abilities",
|
||||
"path": "packs/core-techniques-mastery.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-items",
|
||||
"label": "Items",
|
||||
"path": "packs/core-items.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-armors",
|
||||
"label": "Armors",
|
||||
"path": "packs/core-armors.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-weapons",
|
||||
"label": "Weapons",
|
||||
"path": "packs/core-weapons.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-peculiarities-distinctions",
|
||||
"label": "Distinctions",
|
||||
"path": "packs/core-peculiarities-distinctions.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-peculiarities-passions",
|
||||
"label": "Passions",
|
||||
"path": "packs/core-peculiarities-passions.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-peculiarities-adversities",
|
||||
"label": "Adversities",
|
||||
"path": "packs/core-peculiarities-adversities.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-peculiarities-anxieties",
|
||||
"label": "Anxieties",
|
||||
"path": "packs/core-peculiarities-anxieties.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-bonds",
|
||||
"label": "Bonds",
|
||||
"path": "packs/core-bonds.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-titles",
|
||||
"label": "Titles",
|
||||
"path": "packs/core-titles.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-item-patterns",
|
||||
"label": "Item Patterns",
|
||||
"path": "packs/core-item-patterns.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-signature-scrolls",
|
||||
"label": "Signature Scrolls",
|
||||
"path": "packs/core-signature-scrolls.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-celestial-implement-boons",
|
||||
"label": "Celestial Implement Boons",
|
||||
"path": "packs/core-celestial-implement-boons.db",
|
||||
"type": "Item",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-journal-school-curriculum",
|
||||
"label": "School Curriculum",
|
||||
"path": "packs/core-journal-school-curriculum.db",
|
||||
"type": "JournalEntry",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-journal-conditions",
|
||||
"label": "Conditions",
|
||||
"path": "packs/core-journal-conditions.db",
|
||||
"type": "JournalEntry",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-journal-terrain-qualities",
|
||||
"label": "Terrain Qualities",
|
||||
"path": "packs/core-journal-terrain-qualities.db",
|
||||
"type": "JournalEntry",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-journal-great-clans-presentation",
|
||||
"label": "Great Clans Presentation",
|
||||
"path": "packs/core-journal-great-clans-presentation.db",
|
||||
"type": "JournalEntry",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-journal-opportunities",
|
||||
"label": "Opportunities",
|
||||
"path": "packs/core-journal-opportunities.db",
|
||||
"type": "JournalEntry",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-name-tables",
|
||||
"label": "Name Tables",
|
||||
"path": "packs/core-name-tables.db",
|
||||
"type": "RollTable",
|
||||
"system": "l5r5e"
|
||||
},
|
||||
{
|
||||
"name": "core-macros",
|
||||
"label": "L5R5E Macros",
|
||||
"path": "packs/core-macros.db",
|
||||
"type": "Macro",
|
||||
"system": "l5r5e"
|
||||
}
|
||||
],
|
||||
"languages": [
|
||||
{
|
||||
"lang": "en",
|
||||
"name": "English",
|
||||
"path": "lang/en-en.json"
|
||||
},
|
||||
{
|
||||
"lang": "fr",
|
||||
"name": "French (France)",
|
||||
"path": "lang/fr-fr.json"
|
||||
},
|
||||
{
|
||||
"lang": "es",
|
||||
"name": "Spanish (Spain)",
|
||||
"path": "lang/es-es.json"
|
||||
},
|
||||
{
|
||||
"lang": "it",
|
||||
"name": "Italian (Italy)",
|
||||
"path": "lang/it-it.json"
|
||||
}
|
||||
],
|
||||
"media": [
|
||||
{
|
||||
"type": "screenshot",
|
||||
"url": "https://gitlab.com/teaml5r/l5r5e/-/raw/master/screenshoots/login.jpg?raw=true",
|
||||
"caption": "Login screen"
|
||||
},
|
||||
{
|
||||
"type": "screenshot",
|
||||
"url": "https://gitlab.com/teaml5r/l5r5e/-/raw/master/screenshoots/roll.jpg?raw=true",
|
||||
"caption": "DicePicker and Roll and Keep"
|
||||
},
|
||||
{
|
||||
"type": "screenshot",
|
||||
"url": "https://gitlab.com/teaml5r/l5r5e/-/raw/master/screenshoots/school.jpg?raw=true",
|
||||
"caption": "Experience and School"
|
||||
},
|
||||
{
|
||||
"type": "screenshot",
|
||||
"url": "https://gitlab.com/teaml5r/l5r5e/-/raw/master/screenshoots/sheet_pc.jpg?raw=true",
|
||||
"caption": "PC sheet"
|
||||
},
|
||||
{
|
||||
"type": "screenshot",
|
||||
"url": "https://gitlab.com/teaml5r/l5r5e/-/raw/master/screenshoots/sheet_npc_army.jpg?raw=true",
|
||||
"caption": "NPC and Army sheets"
|
||||
},
|
||||
{
|
||||
"type": "screenshot",
|
||||
"url": "https://gitlab.com/teaml5r/l5r5e/-/raw/master/screenshoots/compendiums.jpg?raw=true",
|
||||
"caption": "Compendiums"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -8,7 +8,7 @@
|
||||
Created by potrace 1.15, written by Peter Selinger 2001-2017
|
||||
</metadata>
|
||||
<g transform="translate(0.000000,1264.000000) scale(0.100000,-0.100000)"
|
||||
fill="#000000" stroke="none">
|
||||
fill="currentColor" stroke="none">
|
||||
<path d="M5925 12625 c-248 -21 -380 -39 -378 -51 1 -7 -56 -18 -148 -29 -83
|
||||
-9 -190 -25 -237 -35 -244 -53 -454 -105 -602 -151 -91 -28 -210 -64 -264 -81
|
||||
-465 -138 -1038 -415 -1493 -719 -234 -157 -585 -429 -773 -600 -215 -196
|
||||
|
||||
|
Before Width: | Height: | Size: 6.0 KiB After Width: | Height: | Size: 6.0 KiB |
@@ -1,13 +1,20 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 24.1.2, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
width="48.2px" height="48.2px" viewBox="0 0 48.2 48.2" style="enable-background:new 0 0 48.2 48.2;" xml:space="preserve">
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
width="48.2px" height="48.2px" viewBox="0 0 48.2 48.2" xml:space="preserve">
|
||||
<defs>
|
||||
<linearGradient id="iconGradient" x1="0%" y1="0%" x2="0%" y2="100%">
|
||||
<stop offset="0%" style="stop-color:#E0E0E0;stop-opacity:1" />
|
||||
<stop offset="100%" style="stop-color:#FFFFFF;stop-opacity:1" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<style type="text/css">
|
||||
.st0{fill:#030104;}
|
||||
/* Gradient fill with contrasting stroke */
|
||||
.fill-gradient{fill:url(#iconGradient);}
|
||||
.stroke-contrast{stroke:#2a2a2a;stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round;}
|
||||
</style>
|
||||
<g>
|
||||
<g>
|
||||
<path class="st0" d="M43,40c-0.9-7.2-2.3-13.9-5.7-20.2c-1-1.9-2.6-3.5-3.8-5.3c-0.2-0.3-0.5-0.7-0.7-1.1c0.7-0.6,1.4-1.3,2.1-2
|
||||
<path class="fill-gradient stroke-contrast" d="M43,40c-0.9-7.2-2.3-13.9-5.7-20.2c-1-1.9-2.6-3.5-3.8-5.3c-0.2-0.3-0.5-0.7-0.7-1.1c0.7-0.6,1.4-1.3,2.1-2
|
||||
c0.8-0.8,1.5-1.5,2.1-2.3c0.7-0.8,1.2-1.5,1.7-2.1c1-1.3,1.5-2.3,1.5-2.3s-1,0.5-2.3,1.5c-0.7,0.5-1.4,1.1-2.1,1.7
|
||||
c-0.8,0.7-1.5,1.4-2.3,2.1c-0.4,0.4-0.9,0.9-1.3,1.4c-0.7-3.4-3.5-6.2-7-6.6c-3.7-0.5-7.6,1.7-8.5,5.4c-0.1,0.5-0.3,1-0.4,1.4
|
||||
c-0.5-0.5-1-1-1.5-1.5C14,9.3,13.2,8.6,12.5,8c-0.8-0.7-1.5-1.2-2.1-1.7C9,5.3,8,4.8,8,4.8s0.5,1,1.5,2.3c0.5,0.7,1.1,1.4,1.7,2.1
|
||||
@@ -17,10 +24,10 @@
|
||||
c0.5,0.1,1,0,1.4-0.2c0.4-0.2,0.8-0.6,1.1-1.1c0.5-0.7,0.7-0.3,1.3,0.6c0.5,0.9,1.6,1.2,3,1.4c2.9,0.4,2.8,0.6,2.5,3.5
|
||||
c0,0.5,0,1-0.1,1.4c-0.5,2.3,0.1,5.1-1.8,6.9c-0.8,0.7-1.6,1.1-1.5,1.2c0.1,0.1,1.1,0,2.1-0.1c2.4-0.3,4.9-0.7,7.4-1
|
||||
C42.3,42.1,43.1,41.1,43,40z M21.3,8.2C20.2,9,19.2,9.3,19,9s0.4-1.2,1.5-1.9c1-0.7,2.1-1.1,2.3-0.7C23,6.6,22.3,7.5,21.3,8.2z"/>
|
||||
<path class="st0" d="M32,35.9c0-0.2-0.9-0.2-1.9-0.1c-1,0.1-1.8,0.4-1.8,0.7c0,0.2,0.9,0.3,1.9,0.1C31.3,36.4,32,36.1,32,35.9z"/>
|
||||
<path class="st0" d="M18.2,35.8c-0.9-0.2-1.7-0.1-1.8,0.1c0,0.2,0.7,0.5,1.6,0.7c0.9,0.2,1.7,0.1,1.8-0.1
|
||||
<path class="fill-gradient stroke-contrast" d="M32,35.9c0-0.2-0.9-0.2-1.9-0.1c-1,0.1-1.8,0.4-1.8,0.7c0,0.2,0.9,0.3,1.9,0.1C31.3,36.4,32,36.1,32,35.9z"/>
|
||||
<path class="fill-gradient stroke-contrast" d="M18.2,35.8c-0.9-0.2-1.7-0.1-1.8,0.1c0,0.2,0.7,0.5,1.6,0.7c0.9,0.2,1.7,0.1,1.8-0.1
|
||||
C19.9,36.3,19.2,36,18.2,35.8z"/>
|
||||
<path class="st0" d="M25.3,40.3c-0.1,0-0.3,0-0.5-0.1c-0.1,0-0.2-0.1-0.3-0.1c-0.1,0-0.2,0-0.2-0.1c-0.1,0-0.3-0.1-0.4,0
|
||||
<path class="fill-gradient stroke-contrast" d="M25.3,40.3c-0.1,0-0.3,0-0.5-0.1c-0.1,0-0.2-0.1-0.3-0.1c-0.1,0-0.2,0-0.2-0.1c-0.1,0-0.3-0.1-0.4,0
|
||||
c-0.1,0-0.3,0-0.4,0c-0.1,0-0.2,0.1-0.2,0.1c-0.1,0-0.2,0.1-0.2,0.1c-0.2,0.1-0.4,0-0.5,0.1c-0.1,0-0.2,0.1-0.2,0.1s0,0.1,0,0.3
|
||||
c0,0.2,0,0.3,0.1,0.6c0.1,0.1,0.1,0.2,0.3,0.3c0.1,0.1,0.2,0.2,0.4,0.3c0.1,0.1,0.3,0.2,0.4,0.2c0.2,0,0.3,0.1,0.5,0.1
|
||||
c0.2,0,0.3,0,0.5-0.1c0.2,0,0.3-0.1,0.4-0.2c0.3-0.1,0.5-0.4,0.6-0.6c0.1-0.2,0.2-0.4,0.2-0.6c0-0.2,0-0.2,0-0.2
|
||||
|
||||
|
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 2.7 KiB |
@@ -1,9 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 24.1.2, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
width="48.2px" height="48.2px" viewBox="0 0 48.2 48.2" style="enable-background:new 0 0 48.2 48.2;" xml:space="preserve">
|
||||
width="48.2px" height="48.2px" viewBox="-1 -1 50.2 50.2" style="enable-background:new -1 -1 50.2 50.2;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#1D1C1A;}
|
||||
.st0{fill:#030104;}
|
||||
</style>
|
||||
<g>
|
||||
<path class="st0" d="M48.7,4.8c0,0-0.1,0-0.2,0.1c-0.9,0.6-4.4,2-9.3,3.1c-4.6,1-10.8,1.8-16.7,2.3c-6.2,0.6-14.9,0.8-21.3-0.5
|
||||
|
||||
|
Before Width: | Height: | Size: 4.6 KiB After Width: | Height: | Size: 4.6 KiB |
@@ -262,7 +262,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "Journal of observations",
|
||||
"id": "Journal of Observations",
|
||||
"name": "Journal d'observations",
|
||||
"description": "",
|
||||
"source_reference": {
|
||||
@@ -972,6 +972,198 @@
|
||||
"source_reference": {
|
||||
"page": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "Glass Ornament (Dragonfly)",
|
||||
"name": "Le Verre de Libellule",
|
||||
"description": "",
|
||||
"source_reference": {
|
||||
"page": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "Arrows: Armor-Piercing",
|
||||
"name": "Flèches : Perce-armure",
|
||||
"description": "",
|
||||
"source_reference": {
|
||||
"page": "236"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "Arrows: Flesh-Cutter",
|
||||
"name": "Flèches : Fouilleuse d’entrailles",
|
||||
"description": "",
|
||||
"source_reference": {
|
||||
"page": "236"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "Arrows: Humming-Bulb",
|
||||
"name": "Flèches : Bulbe bourdonnant",
|
||||
"description": "",
|
||||
"source_reference": {
|
||||
"page": "236"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "Journal",
|
||||
"name": "Journal",
|
||||
"description": "",
|
||||
"source_reference": {
|
||||
"page": "66"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "Smithing hammer",
|
||||
"name": "Marteau de forgeron",
|
||||
"description": "",
|
||||
"source_reference": {
|
||||
"page": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "Sumai Garb",
|
||||
"name": "Tenue de Sumai",
|
||||
"description": "",
|
||||
"source_reference": {
|
||||
"page": "76"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "Drafting Paper",
|
||||
"name": "Papier à dessin",
|
||||
"description": "",
|
||||
"source_reference": {
|
||||
"page": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "Fine set of Chisels",
|
||||
"name": "Ensemble de burins de grande qualité",
|
||||
"description": "",
|
||||
"source_reference": {
|
||||
"page": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "Omamori (Boon of Fukurokujin)",
|
||||
"name": "Omamori (Bienfait de Fukurokujin)",
|
||||
"description": "",
|
||||
"source_reference": {
|
||||
"page": "243"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "Omamori (Boon of Bishamon)",
|
||||
"name": "Omamori (Bienfait de Bishamon)",
|
||||
"description": "",
|
||||
"source_reference": {
|
||||
"page": "243"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "Omamori (Boon of Benten)",
|
||||
"name": "Omamori (Bienfait de Benten)",
|
||||
"description": "",
|
||||
"source_reference": {
|
||||
"page": "243"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "Poison - Noxious Poison (One Vial)",
|
||||
"name": "Poison - Toxines (un flacon)",
|
||||
"description": "",
|
||||
"source_reference": {
|
||||
"page": "244"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "Poison - Fire Biter (One Vial)",
|
||||
"name": "Poison - Morsure Brûlante (un flacon)",
|
||||
"description": "",
|
||||
"source_reference": {
|
||||
"page": "244"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "Poison - Night Milk (One Vial)",
|
||||
"name": "Poison - Lait de la Nuit (un flacon)",
|
||||
"description": "",
|
||||
"source_reference": {
|
||||
"page": "244"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "Blanket",
|
||||
"name": "Couverture",
|
||||
"description": "",
|
||||
"source_reference": {
|
||||
"page": "245"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "Bowl",
|
||||
"name": "Bol",
|
||||
"description": "",
|
||||
"source_reference": {
|
||||
"page": "245"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "Flint and Tinder",
|
||||
"name": "Silex et amadou",
|
||||
"description": "",
|
||||
"source_reference": {
|
||||
"page": "245"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "Furoshiki",
|
||||
"name": "Furoshiki",
|
||||
"description": "",
|
||||
"source_reference": {
|
||||
"page": "245"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "The Obsidian Journal",
|
||||
"name": "Le Journal d’obsidienne",
|
||||
"description": "",
|
||||
"source_reference": {
|
||||
"page": "128"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "Pouch of Insence",
|
||||
"name": "Bourse d’Encens",
|
||||
"description": "",
|
||||
"source_reference": {
|
||||
"page": "85"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "Religious texts",
|
||||
"name": "Textes religieux",
|
||||
"description": "",
|
||||
"source_reference": {
|
||||
"page": "86"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "Small Sachel of Ingredients",
|
||||
"name": "Petit sachet d'ingrédients",
|
||||
"description": "",
|
||||
"source_reference": {
|
||||
"page": "80"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "Blessed Glass vial",
|
||||
"name": "Fiole en verre bénie",
|
||||
"description": "",
|
||||
"source_reference": {
|
||||
"page": "80"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -40,8 +40,8 @@
|
||||
},
|
||||
"Compendium": {
|
||||
"HideDisabledSources": {
|
||||
"Title": "[Compendium] Hide sources filter without reference",
|
||||
"Hint": "Hide empty source with no elements in source filter."
|
||||
"Title": "[Compendium] Hide unavailable sources",
|
||||
"Hint": "Hide sources that have no available content from the source filter dropdown."
|
||||
},
|
||||
"HideEmptySourcesFromPlayers": {
|
||||
"Title": "[Compendium] Hide elements with empty reference",
|
||||
@@ -76,7 +76,10 @@
|
||||
"signature_scroll": "Signature Scroll",
|
||||
"item_pattern": "Item Pattern",
|
||||
"army_fortification": "Fortification",
|
||||
"army_cohort": "Cohort"
|
||||
"army_cohort": "Cohort",
|
||||
"arcane": "Arcane",
|
||||
"etat": "State",
|
||||
"mystere": "Mystery"
|
||||
},
|
||||
"Journal": {
|
||||
"journal": "Journal"
|
||||
@@ -136,6 +139,7 @@
|
||||
"player_filter_label": "Player filter",
|
||||
"player_filter_tooltip": "Apply player filter",
|
||||
"already_in_filter": "Already in filter",
|
||||
"no_results": "Not Found",
|
||||
"sources_categories": {
|
||||
"rules": "Rules",
|
||||
"adventures": "Adventures",
|
||||
@@ -317,7 +321,8 @@
|
||||
"school_ability": "School Ability",
|
||||
"mastery_ability": "Mastery Ability",
|
||||
"title_ability": "Title Ability",
|
||||
"specificity": "Specificity"
|
||||
"specificity": "Specificity",
|
||||
"mot_invocation": "Invocation Word"
|
||||
},
|
||||
"peculiarities": {
|
||||
"types": {
|
||||
@@ -492,7 +497,10 @@
|
||||
"rarity_modifier": "Rarity modifier",
|
||||
"item_pattern": "Item Patterns",
|
||||
"signature_scroll": "Signature Scrolls",
|
||||
"school_curriculum_journal": "Drop curriculum's journal in sheet to link it"
|
||||
"school_curriculum_journal": "Drop curriculum's journal in sheet to link it",
|
||||
"warning": {
|
||||
"total_less_then_spent": "Total Experience is less then Used Experience."
|
||||
}
|
||||
},
|
||||
"character_types": {
|
||||
"character": "Player Character",
|
||||
@@ -807,14 +815,15 @@
|
||||
"filter": {
|
||||
"rank": "Rank",
|
||||
"rarity": "Rarity",
|
||||
"ring": "Ring"
|
||||
"ring": "Ring",
|
||||
"clear": "Clear Filter"
|
||||
}
|
||||
},
|
||||
"source_reference": {
|
||||
"core_rulebook": "Core Rulebook",
|
||||
"emerald_empire": "Emerald Empire",
|
||||
"shadowlands": "Shadowlands",
|
||||
"court_of_stones": "Court of Stones",
|
||||
"court_of_stones": "Courts of Stone",
|
||||
"path_of_waves": "Path of Waves",
|
||||
"celestial_realms": "Celestial Realms",
|
||||
"fields_of_victory": "Fields of Victory",
|
||||
@@ -864,5 +873,142 @@
|
||||
"range_band": "Range Band {band}",
|
||||
"range_abbreviation": "RB {range}"
|
||||
}
|
||||
},
|
||||
"chiaroscuro": {
|
||||
"skill_ranks": {
|
||||
"0": "—",
|
||||
"initie": "Initiate",
|
||||
"expert": "Expert",
|
||||
"maitre": "Master",
|
||||
"parangon1": "Paragon I",
|
||||
"parangon2": "Paragon II",
|
||||
"parangon3": "Paragon III"
|
||||
},
|
||||
"difficulties": {
|
||||
"simple": "Simple (7)",
|
||||
"moyenne": "Average (10)",
|
||||
"assez_difficile": "Somewhat Difficult (13)",
|
||||
"difficile": "Difficult (16)",
|
||||
"tres_difficile": "Very Difficult (22)",
|
||||
"heroique": "Heroic (28)",
|
||||
"improbable": "Improbable (32)"
|
||||
},
|
||||
"aspects": {
|
||||
"solar": "Solar Aspect",
|
||||
"lunar": "Lunar Aspect",
|
||||
"gauge": "Aspect Gauge",
|
||||
"desequilibre_solaire": "Solar Imbalance",
|
||||
"desequilibre_lunaire": "Lunar Imbalance"
|
||||
},
|
||||
"danger": {
|
||||
"simple": "Simple",
|
||||
"moyenne": "Average",
|
||||
"assez_difficile": "Somewhat Difficult",
|
||||
"difficile": "Difficult"
|
||||
},
|
||||
"arcane": {
|
||||
"title": "Arcanes",
|
||||
"label": "Arcane",
|
||||
"arcane_type": "Type",
|
||||
"application": "Skills",
|
||||
"bonus": "Bonus",
|
||||
"progression": "Progression",
|
||||
"xp_cost": "XP Cost"
|
||||
},
|
||||
"etat": {
|
||||
"title": "States",
|
||||
"label": "State",
|
||||
"application": "Application",
|
||||
"mod": "Modifier",
|
||||
"effect": "Effect",
|
||||
"elimination": "Elimination Condition"
|
||||
},
|
||||
"mystere": {
|
||||
"title": "Mysteries",
|
||||
"label": "Mystery",
|
||||
"mystere_type": "Type",
|
||||
"mineur": "Minor",
|
||||
"majeur": "Major",
|
||||
"prerequisite_skill": "Prerequisite Skill",
|
||||
"prerequisite_condition": "Prerequisite Condition"
|
||||
},
|
||||
"character": {
|
||||
"is_samurai": "Samurai",
|
||||
"quick_info": "Quick Info",
|
||||
"default_ring": "Default Ring",
|
||||
"region": "Region",
|
||||
"education": "Education",
|
||||
"past_problems": "Problematic Past",
|
||||
"koku": "Koku",
|
||||
"bu": "Bu",
|
||||
"zeni": "Zeni"
|
||||
},
|
||||
"weapon": {
|
||||
"bonus": "Bonus",
|
||||
"categories": {
|
||||
"arbalete": "Crossbow",
|
||||
"arc": "Bow",
|
||||
"contondante": "Bludgeoning Weapon",
|
||||
"poing": "Hand Weapon",
|
||||
"hast": "Polearm",
|
||||
"improvisee": "Improvised Weapon",
|
||||
"shinobi": "Shinobi Weapon",
|
||||
"specialisee": "Specialized Weapon",
|
||||
"bouclier": "Shield",
|
||||
"hache": "Axe",
|
||||
"naturel": "Natural",
|
||||
"sabre": "Sword",
|
||||
"nemuranai": "Nemuranai"
|
||||
}
|
||||
},
|
||||
"armor": {
|
||||
"categories": {
|
||||
"vetement": "Clothing",
|
||||
"leger": "Light",
|
||||
"moyen": "Medium",
|
||||
"lourd": "Heavy",
|
||||
"nemuranai": "Nemuranai"
|
||||
}
|
||||
},
|
||||
"item": {
|
||||
"types": {
|
||||
"ordinaire": "Ordinary",
|
||||
"shinobi": "Shinobi",
|
||||
"interdit": "Forbidden",
|
||||
"gaijin": "Gaijin",
|
||||
"nemuranai": "Nemuranai"
|
||||
}
|
||||
},
|
||||
"technique": {
|
||||
"mot_invocation": "Invocation Word",
|
||||
"invocation_type": "Invocation Type",
|
||||
"invocation_types": {
|
||||
"general": "General",
|
||||
"neutre": "Neutral",
|
||||
"precis": "Precise"
|
||||
},
|
||||
"mode_invocation": "Invocation Mode"
|
||||
},
|
||||
"tabs": {
|
||||
"invocations": "Invocations",
|
||||
"identity": "Identity",
|
||||
"identity_text1": "Appearance",
|
||||
"identity_text2": "Biography"
|
||||
},
|
||||
"dice": {
|
||||
"title": "Chiaroscuro Roll",
|
||||
"difficulty_label": "Difficulty",
|
||||
"modifier_label": "Modifier",
|
||||
"options": "Options",
|
||||
"aspect_point": "Aspect Point",
|
||||
"assistance": "Assistance",
|
||||
"total_dice": "Dice to roll",
|
||||
"bonus": "Rank bonus",
|
||||
"roll": "Roll",
|
||||
"dice_result": "Dice total",
|
||||
"adjusted": "Adjusted (Parangon)",
|
||||
"success": "Success",
|
||||
"failure": "Failure"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -136,6 +136,7 @@
|
||||
"player_filter_label": "Filtro de jugador",
|
||||
"player_filter_tooltip": "Aplicar filtro de jugador",
|
||||
"already_in_filter": "Ya en el filtro",
|
||||
"no_results": "Not Found",
|
||||
"sources_categories": {
|
||||
"rules": "Reglas",
|
||||
"adventures": "Aventuras",
|
||||
@@ -492,7 +493,10 @@
|
||||
"rarity_modifier": "Modificador de rareza",
|
||||
"item_pattern": "Patrones de objetos",
|
||||
"signature_scroll": "Pergaminos espaciales",
|
||||
"school_curriculum_journal": "Arrastra el diario del programa en la hoja para vincularlo"
|
||||
"school_curriculum_journal": "Arrastra el diario del programa en la hoja para vincularlo",
|
||||
"warning": {
|
||||
"total_less_then_spent": "La experiencia total es menor que la experiencia utilizada."
|
||||
}
|
||||
},
|
||||
"character_types": {
|
||||
"character": "Personaje jugador",
|
||||
@@ -807,7 +811,8 @@
|
||||
"filter": {
|
||||
"rank": "Rango",
|
||||
"rarity": "Rareza",
|
||||
"ring": "Anillo"
|
||||
"ring": "Anillo",
|
||||
"clear": "Clear Filter"
|
||||
}
|
||||
},
|
||||
"source_reference": {
|
||||
|
||||
@@ -76,7 +76,10 @@
|
||||
"signature_scroll": "Rouleau de marque",
|
||||
"item_pattern": "Procédé de fabrication",
|
||||
"army_fortification": "Fortification",
|
||||
"army_cohort": "Régiment"
|
||||
"army_cohort": "Régiment",
|
||||
"arcane": "Arcane",
|
||||
"etat": "État",
|
||||
"mystere": "Mystère"
|
||||
},
|
||||
"Journal": {
|
||||
"journal": "Journal"
|
||||
@@ -136,6 +139,7 @@
|
||||
"player_filter_label": "Filtre joueur",
|
||||
"player_filter_tooltip": "Applique le filtre des joueurs",
|
||||
"already_in_filter": "Filtre déjà appliqué",
|
||||
"no_results": "Aucun résultat",
|
||||
"sources_categories": {
|
||||
"rules": "Règles",
|
||||
"adventures": "Aventures",
|
||||
@@ -317,7 +321,8 @@
|
||||
"school_ability": "Capacité d'école",
|
||||
"mastery_ability": "Capacité de maîtrise",
|
||||
"title_ability": "Capacité de Titre",
|
||||
"specificity": "Particularité"
|
||||
"specificity": "Particularité",
|
||||
"mot_invocation": "Mot d'Invocation"
|
||||
},
|
||||
"peculiarities": {
|
||||
"types": {
|
||||
@@ -492,7 +497,10 @@
|
||||
"rarity_modifier": "Modificateur de rareté",
|
||||
"item_pattern": "Procédés de fabrication",
|
||||
"signature_scroll": "Rouleaux de marque",
|
||||
"school_curriculum_journal": "Déposer un journal de Cursus dans la feuille pour le lier"
|
||||
"school_curriculum_journal": "Déposer un journal de Cursus dans la feuille pour le lier",
|
||||
"warning": {
|
||||
"total_less_then_spent": "L'expérience totale est inférieure à l'expérience utilisée."
|
||||
}
|
||||
},
|
||||
"character_types": {
|
||||
"character": "Personnage Joueur",
|
||||
@@ -807,7 +815,8 @@
|
||||
"filter": {
|
||||
"rank": "Rang",
|
||||
"rarity": "Rareté",
|
||||
"ring": "Anneau"
|
||||
"ring": "Anneau",
|
||||
"clear": "Suppr. les Filtres"
|
||||
}
|
||||
},
|
||||
"source_reference": {
|
||||
@@ -864,5 +873,142 @@
|
||||
"range_band": "Portée {band}",
|
||||
"range_abbreviation": "NP {range}"
|
||||
}
|
||||
},
|
||||
"chiaroscuro": {
|
||||
"skill_ranks": {
|
||||
"0": "—",
|
||||
"initie": "Initié",
|
||||
"expert": "Expert",
|
||||
"maitre": "Maître",
|
||||
"parangon1": "Parangon I",
|
||||
"parangon2": "Parangon II",
|
||||
"parangon3": "Parangon III"
|
||||
},
|
||||
"difficulties": {
|
||||
"simple": "Simple (7)",
|
||||
"moyenne": "Moyenne (10)",
|
||||
"assez_difficile": "Assez difficile (13)",
|
||||
"difficile": "Difficile (16)",
|
||||
"tres_difficile": "Très difficile (22)",
|
||||
"heroique": "Héroïque (28)",
|
||||
"improbable": "Improbable (32)"
|
||||
},
|
||||
"aspects": {
|
||||
"solar": "Aspect Solaire",
|
||||
"lunar": "Aspect Lunaire",
|
||||
"gauge": "Jauge d'Aspect",
|
||||
"desequilibre_solaire": "Déséquilibre Solaire",
|
||||
"desequilibre_lunaire": "Déséquilibre Lunaire"
|
||||
},
|
||||
"danger": {
|
||||
"simple": "Simple",
|
||||
"moyenne": "Moyenne",
|
||||
"assez_difficile": "Assez Difficile",
|
||||
"difficile": "Difficile"
|
||||
},
|
||||
"arcane": {
|
||||
"title": "Arcanes",
|
||||
"label": "Arcane",
|
||||
"arcane_type": "Type",
|
||||
"application": "Compétences",
|
||||
"bonus": "Bonus",
|
||||
"progression": "Progression",
|
||||
"xp_cost": "Coût XP"
|
||||
},
|
||||
"etat": {
|
||||
"title": "États",
|
||||
"label": "État",
|
||||
"application": "Application",
|
||||
"mod": "Modificateur",
|
||||
"effect": "Effet",
|
||||
"elimination": "Condition d'élimination"
|
||||
},
|
||||
"mystere": {
|
||||
"title": "Mystères",
|
||||
"label": "Mystère",
|
||||
"mystere_type": "Type",
|
||||
"mineur": "Mineur",
|
||||
"majeur": "Majeur",
|
||||
"prerequisite_skill": "Compétence prérequis",
|
||||
"prerequisite_condition": "Condition prérequis"
|
||||
},
|
||||
"character": {
|
||||
"is_samurai": "Samouraï",
|
||||
"quick_info": "Info rapide",
|
||||
"default_ring": "Anneau par défaut",
|
||||
"region": "Région",
|
||||
"education": "Éducation",
|
||||
"past_problems": "Passé problématique",
|
||||
"koku": "Koku",
|
||||
"bu": "Bu",
|
||||
"zeni": "Zeni"
|
||||
},
|
||||
"weapon": {
|
||||
"bonus": "Bonus",
|
||||
"categories": {
|
||||
"arbalete": "Arbalète",
|
||||
"arc": "Arc",
|
||||
"contondante": "Arme Contondante",
|
||||
"poing": "Arme de Poing",
|
||||
"hast": "Arme Hast",
|
||||
"improvisee": "Arme Improvisée",
|
||||
"shinobi": "Arme Shinobi",
|
||||
"specialisee": "Arme Spécialisée",
|
||||
"bouclier": "Bouclier",
|
||||
"hache": "Hache",
|
||||
"naturel": "Naturel",
|
||||
"sabre": "Sabre",
|
||||
"nemuranai": "Nemuranai"
|
||||
}
|
||||
},
|
||||
"armor": {
|
||||
"categories": {
|
||||
"vetement": "Vêtement",
|
||||
"leger": "Léger",
|
||||
"moyen": "Moyen",
|
||||
"lourd": "Lourd",
|
||||
"nemuranai": "Nemuranai"
|
||||
}
|
||||
},
|
||||
"item": {
|
||||
"types": {
|
||||
"ordinaire": "Ordinaire",
|
||||
"shinobi": "Shinobi",
|
||||
"interdit": "Interdit",
|
||||
"gaijin": "Gaijin",
|
||||
"nemuranai": "Nemuranai"
|
||||
}
|
||||
},
|
||||
"technique": {
|
||||
"mot_invocation": "Mot d'Invocation",
|
||||
"invocation_type": "Type d'invocation",
|
||||
"invocation_types": {
|
||||
"general": "Général",
|
||||
"neutre": "Neutre",
|
||||
"precis": "Précis"
|
||||
},
|
||||
"mode_invocation": "Mode d'Invocation"
|
||||
},
|
||||
"tabs": {
|
||||
"invocations": "Invocations",
|
||||
"identity": "Identité",
|
||||
"identity_text1": "Apparence",
|
||||
"identity_text2": "Biographie"
|
||||
},
|
||||
"dice": {
|
||||
"title": "Jet Chiaroscuro",
|
||||
"difficulty_label": "Difficulté",
|
||||
"modifier_label": "Modificateur",
|
||||
"options": "Options",
|
||||
"aspect_point": "Point d'Aspect",
|
||||
"assistance": "Assistance",
|
||||
"total_dice": "Dés à lancer",
|
||||
"bonus": "Bonus rang",
|
||||
"roll": "Lancer les dés",
|
||||
"dice_result": "Somme des dés",
|
||||
"adjusted": "Ajusté (Parangon)",
|
||||
"success": "Réussite",
|
||||
"failure": "Échec"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -136,6 +136,7 @@
|
||||
"player_filter_label": "Player filter",
|
||||
"player_filter_tooltip": "Apply player filter",
|
||||
"already_in_filter": "Already in filter",
|
||||
"no_results": "Not Found",
|
||||
"sources_categories": {
|
||||
"rules": "Rules",
|
||||
"adventures": "Adventures",
|
||||
@@ -492,7 +493,10 @@
|
||||
"rarity_modifier": "Modificatore rarità",
|
||||
"item_pattern": "Item Patterns",
|
||||
"signature_scroll": "Signature Scrolls",
|
||||
"school_curriculum_journal": "Trascina il diario del curriculum sulla scheda per collegarlo"
|
||||
"school_curriculum_journal": "Trascina il diario del curriculum sulla scheda per collegarlo",
|
||||
"warning": {
|
||||
"total_less_then_spent": "L'esperienza totale è inferiore all'esperienza utilizzata."
|
||||
}
|
||||
},
|
||||
"character_types": {
|
||||
"character": "Personaggio giocante",
|
||||
@@ -705,6 +709,7 @@
|
||||
"demeanor": {
|
||||
"adaptable": "Flessibile",
|
||||
"aggressive": "Aggressivo",
|
||||
"alluring": "Alluring",
|
||||
"ambitious": "Ambizioso",
|
||||
"amiable": "Affabile",
|
||||
"analytical": "Analitico",
|
||||
@@ -713,6 +718,7 @@
|
||||
"assertive": "Risoluto",
|
||||
"beguiling": "Ammaliante",
|
||||
"bitter": "Amaro",
|
||||
"bloodthirsty": "Bloodthirsty",
|
||||
"bold": "Ardito",
|
||||
"calculating": "Calcolatore",
|
||||
"calm": "Calmo",
|
||||
@@ -723,37 +729,68 @@
|
||||
"confused": "Confuso",
|
||||
"courageous": "Coraggioso",
|
||||
"cowardly": "Codardo",
|
||||
"crestfallen": "Crestfallen",
|
||||
"curious": "Curioso",
|
||||
"defensive": "Defensive",
|
||||
"dependable": "Affidabile",
|
||||
"detached": "Distaccato",
|
||||
"determined": "Determined",
|
||||
"devoted": "Devoted",
|
||||
"direct": "Direct",
|
||||
"disheartened": "Sconfortato",
|
||||
"dour": "Dour",
|
||||
"duplicitous": "Duplicitous",
|
||||
"effusive": "Effusive",
|
||||
"enraged": "Infuriato",
|
||||
"fanatical": "Fanatical",
|
||||
"feral": "Selvaggio",
|
||||
"fervent": "Fervent",
|
||||
"fickle": "Volubile",
|
||||
"fierce": "Agguerrito",
|
||||
"flighty": "Volubile",
|
||||
"flippant": "Irriverente",
|
||||
"friendly": "Amichevole",
|
||||
"gruff": "Burbero",
|
||||
"honorable": "Honorable",
|
||||
"hubristic": "Prétentieuse",
|
||||
"hungry": "Affamato",
|
||||
"idealistic": "Idealistic",
|
||||
"imposing": "Imposing",
|
||||
"inquisitive": "Inquisitive",
|
||||
"intense": "Intenso",
|
||||
"intimidating": "Intimidatorio",
|
||||
"irritable": "Irritabile",
|
||||
"loyal": "Leale",
|
||||
"methodical": "Methodical",
|
||||
"meticulous": "Meticulous",
|
||||
"mischievous": "Malandrino",
|
||||
"moon_blessed": "Moon-blessed",
|
||||
"morose": "Cupo",
|
||||
"near_feral": "Near feral",
|
||||
"nurturing": "Materno",
|
||||
"obsessed": "Obsessed",
|
||||
"obstinate": "Ostinato",
|
||||
"opportunistic": "Opportunista",
|
||||
"otherworldly": "Otherworldly",
|
||||
"outgoing": "Outgoing",
|
||||
"passionate": "Appassionato",
|
||||
"patient": "Patient",
|
||||
"personable": "Personable",
|
||||
"playful": "Giocoso",
|
||||
"power_hungry": "Affamato di potere",
|
||||
"proud": "Orgoglioso",
|
||||
"refined": "Refined",
|
||||
"reserved": "Reserved",
|
||||
"restrained": "Contenuto",
|
||||
"righteous": "Righteous",
|
||||
"scheming": "Cospiratore",
|
||||
"serene": "Sereno",
|
||||
"serious": "Serio",
|
||||
"shrewd": "Scaltro",
|
||||
"sinister": "Sinister",
|
||||
"sociable": "Sociable",
|
||||
"stoic": "Stoic",
|
||||
"starved": "Starved",
|
||||
"stubborn": "Testardo",
|
||||
"suspicious": "Sospettoso",
|
||||
"teasing": "Stuzzicante",
|
||||
@@ -761,7 +798,12 @@
|
||||
"uncertain": "Incerto",
|
||||
"unenthused": "Non entusiasta",
|
||||
"vain": "Vanesio",
|
||||
"wary": "Diffidente"
|
||||
"vengeful": "Vengeful",
|
||||
"vindictive": "Vindictive",
|
||||
"wary": "Diffidente",
|
||||
"watchful": "Watchful",
|
||||
"wrathful": "Wrathful",
|
||||
"zealous": "Zealous"
|
||||
},
|
||||
"compendium": {
|
||||
"filter_rank": "Show Rank",
|
||||
@@ -769,14 +811,15 @@
|
||||
"filter": {
|
||||
"rank": "Rank",
|
||||
"rarity": "Rarity",
|
||||
"ring": "Ring"
|
||||
"ring": "Ring",
|
||||
"clear": "Clear Filter"
|
||||
}
|
||||
},
|
||||
"source_reference": {
|
||||
"core_rulebook": "Core Rulebook",
|
||||
"emerald_empire": "Emerald Empire",
|
||||
"shadowlands": "Shadowlands",
|
||||
"court_of_stones": "Court of Stones",
|
||||
"court_of_stones": "Courts of Stone",
|
||||
"path_of_waves": "Path of Waves",
|
||||
"celestial_realms": "Celestial Realms",
|
||||
"fields_of_victory": "Fields of Victory",
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
{"_id":"L5RCoreIte000030","name":"Tent (Yurt)","permission":{"default":0},"type":"item","data":{"equipped":false,"quantity":1,"weight":"2","rarity":"5","zeni":"10 koku","properties":[],"description":"","source_reference":{"source":"core_rulebook","page":"245"}},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/items/item.svg","effects":[]}
|
||||
{"_id":"L5RCoreIte000031","name":"Scroll satchel","permission":{"default":0},"type":"item","data":{"equipped":false,"quantity":1,"weight":"0","rarity":"3","zeni":"1 bu","properties":[],"description":"","source_reference":{"source":"core_rulebook","page":"60"}},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/items/item.svg","effects":[]}
|
||||
{"_id":"L5RCoreIte000032","name":"Traveling pack","permission":{"default":0},"type":"item","data":{"equipped":false,"quantity":1,"weight":"0","rarity":"1","zeni":"10 koku","properties":[{"id":"L5RCorePro000012","name":"Mundane"}],"description":"","source_reference":{"source":"core_rulebook","page":"245"}},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/items/item.svg","effects":[]}
|
||||
{"_id":"L5RCoreIte000033","name":"Journal of observations","permission":{"default":0},"type":"item","data":{"equipped":false,"quantity":1,"weight":"0","rarity":"3","zeni":"1 bu","properties":[],"description":"","source_reference":{"source":"core_rulebook","page":"67"}},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/items/item.svg","effects":[]}
|
||||
{"_id":"L5RCoreIte000033","name":"Journal of Observations","permission":{"default":0},"type":"item","data":{"equipped":false,"quantity":1,"weight":"0","rarity":"3","zeni":"1 bu","properties":[],"description":"","source_reference":{"source":"core_rulebook","page":"67"}},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/items/item.svg","effects":[]}
|
||||
{"_id":"L5RCoreIte000034","name":"Omamori (Boon of Jurojin)","permission":{"default":0},"type":"item","data":{"equipped":false,"quantity":1,"weight":"0","rarity":"2","zeni":"5 bu","properties":[],"description":"","source_reference":{"source":"celestial_realms","page":"97"}},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/items/item.svg","effects":[]}
|
||||
{"_id":"L5RCoreIte000035","name":"Omamori (Boon of Kisshoten)","permission":{"default":0},"type":"item","data":{"equipped":false,"quantity":1,"weight":"0","rarity":"2","zeni":"5 bu","properties":[],"description":"","source_reference":{"source":"celestial_realms","page":"97"}},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/items/item.svg","effects":[]}
|
||||
{"_id":"L5RCoreIte000036","name":"Omamori (Boon of Hotei)","permission":{"default":0},"type":"item","data":{"equipped":false,"quantity":1,"weight":"0","rarity":"2","zeni":"5 bu","properties":[],"description":"","source_reference":{"source":"celestial_realms","page":"97"}},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/items/item.svg","effects":[]}
|
||||
@@ -119,3 +119,27 @@
|
||||
{"_id":"L5RCoreIte000121","name":"Word of the Prophet","permission":{"default":0},"type":"item","data":{"equipped":false,"quantity":1,"weight":"0","rarity":"9","zeni":"15 Koku","properties":[],"description":"","source_reference":{"source":"children_of_the_five_winds","page":"103"}},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/items/item.svg","effects":[]}
|
||||
{"_id":"L5RCoreIte000122","name":"Talisman of the Sun [Blessed Treasure]","permission":{"default":0},"type":"item","data":{"equipped":false,"quantity":1,"weight":"0","rarity":"10","zeni":"0","properties":[],"description":"","source_reference":{"source":"children_of_the_five_winds","page":"104"}},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/items/item.svg","effects":[]}
|
||||
{"_id":"L5RCoreIte000123","name":"Fox Pipe [Blessed Treasure]","permission":{"default":0},"type":"item","data":{"equipped":false,"quantity":1,"weight":"0","rarity":"10","zeni":"0","properties":[],"description":"","source_reference":{"source":"children_of_the_five_winds","page":"105"}},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/items/item.svg","effects":[]}
|
||||
{"_id":"L5RCoreIte000124","name":"Glass Ornament (Dragonfly)","permission":{"default":0},"type":"item","data":{"equipped":false,"quantity":1,"weight":"0","rarity":"6","zeni":"1 koku","properties":[],"description":"","source_reference":{"source":"writ_of_the_wild","page":"83"}},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/items/item.svg","effects":[]}
|
||||
{"_id":"L5RCoreIte000125","name":"Arrows: Armor-Piercing","permission":{"default":0},"type":"item","data":{"equipped":false,"quantity":1,"weight":"0","rarity":"2","zeni":"0","properties":[],"description":"","source_reference":{"source":"core_rulebook","page":"236"}},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/items/item.svg","effects":[]}
|
||||
{"_id":"L5RCoreIte000126","name":"Arrows: Flesh-Cutter","permission":{"default":0},"type":"item","data":{"equipped":false,"quantity":1,"weight":"0","rarity":"2","zeni":"0","properties":[],"description":"","source_reference":{"source":"core_rulebook","page":"236"}},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/items/item.svg","effects":[]}
|
||||
{"_id":"L5RCoreIte000127","name":"Arrows: Humming-Bulb","permission":{"default":0},"type":"item","data":{"equipped":false,"quantity":1,"weight":"0","rarity":"2","zeni":"0","properties":[],"description":"","source_reference":{"source":"core_rulebook","page":"236"}},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/items/item.svg","effects":[]}
|
||||
{"_id":"L5RCoreIte000128","name":"Journal","permission":{"default":0},"type":"item","data":{"equipped":false,"quantity":1,"weight":"0","rarity":"1","zeni":"0","properties":[],"description":"","source_reference":{"source":"core_rulebook","page":"66"}},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/items/item.svg","effects":[]}
|
||||
{"_id":"L5RCoreIte000129","name":"Smithing hammer","permission":{"default":0},"type":"item","data":{"equipped":false,"quantity":1,"weight":"0","rarity":"1","zeni":"0","properties":[],"description":"","source_reference":{"source":"shadowlands","page":"89"}},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/items/item.svg","effects":[]}
|
||||
{"_id":"L5RCoreIte000130","name":"Sumai Garb","permission":{"default":0},"type":"item","data":{"equipped":false,"quantity":1,"weight":"0","rarity":"1","zeni":"0","properties":[],"description":"","source_reference":{"source":"fields_of_victory","page":"89"}},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/items/item.svg","effects":[]}
|
||||
{"_id":"L5RCoreIte000131","name":"Drafting Paper","permission":{"default":0},"type":"item","data":{"equipped":false,"quantity":1,"weight":"0","rarity":"1","zeni":"0","properties":[],"description":"","source_reference":{"source":"celestial_realms","page":"84"}},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/items/item.svg","effects":[]}
|
||||
{"_id":"L5RCoreIte000132","name":"Fine set of Chisels","permission":{"default":0},"type":"item","data":{"equipped":false,"quantity":1,"weight":"0","rarity":"1","zeni":"0","properties":[],"description":"","source_reference":{"source":"celestial_realms","page":"84"}},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/items/item.svg","effects":[]}
|
||||
{"_id":"L5RCoreIte000133","name":"Omamori (Boon of Fukurokujin)","permission":{"default":0},"type":"item","data":{"equipped":false,"quantity":1,"weight":"0","rarity":"2","zeni":"5 bu","properties":[],"description":"","source_reference":{"source":"core_rulebook","page":"243"}},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/items/item.svg","effects":[]}
|
||||
{"_id":"L5RCoreIte000134","name":"Omamori (Boon of Bishamon)","permission":{"default":0},"type":"item","data":{"equipped":false,"quantity":1,"weight":"0","rarity":"2","zeni":"5 bu","properties":[],"description":"","source_reference":{"source":"core_rulebook","page":"243"}},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/items/item.svg","effects":[]}
|
||||
{"_id":"L5RCoreIte000135","name":"Omamori (Boon of Benten)","permission":{"default":0},"type":"item","data":{"equipped":false,"quantity":1,"weight":"0","rarity":"2","zeni":"5 bu","properties":[],"description":"","source_reference":{"source":"core_rulebook","page":"243"}},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/items/item.svg","effects":[]}
|
||||
{"_id":"L5RCoreIte000136","name":"Poison - Noxious Poison (One Vial)","permission":{"default":0},"type":"item","data":{"equipped":false,"quantity":1,"weight":"0","rarity":"5","zeni":"30 zeni","properties":[{"id":"L5RCorePro000009","name":"Forbidden"}],"description":"","source_reference":{"source":"core_rulebook","page":"244"}},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/items/item.svg","effects":[]}
|
||||
{"_id":"L5RCoreIte000137","name":"Poison - Fire Biter (One Vial)","permission":{"default":0},"type":"item","data":{"equipped":false,"quantity":1,"weight":"0","rarity":"5","zeni":"30 zeni","properties":[{"id":"L5RCorePro000009","name":"Forbidden"}],"description":"","source_reference":{"source":"core_rulebook","page":"244"}},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/items/item.svg","effects":[]}
|
||||
{"_id":"L5RCoreIte000138","name":"Poison - Night Milk (One Vial)","permission":{"default":0},"type":"item","data":{"equipped":false,"quantity":1,"weight":"0","rarity":"5","zeni":"30 zeni","properties":[{"id":"L5RCorePro000009","name":"Forbidden"}],"description":"","source_reference":{"source":"core_rulebook","page":"244"}},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/items/item.svg","effects":[]}
|
||||
{"_id":"L5RCoreIte000139","name":"Blanket","permission":{"default":0},"type":"item","data":{"equipped":false,"quantity":1,"weight":"0","rarity":"0","zeni":"1 zeni","properties":[],"description":"","source_reference":{"source":"core_rulebook","page":"245"}},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/items/item.svg","effects":[]}
|
||||
{"_id":"L5RCoreIte000140","name":"Bowl","permission":{"default":0},"type":"item","data":{"equipped":false,"quantity":1,"weight":"0","rarity":"0","zeni":"1 zeni","properties":[],"description":"","source_reference":{"source":"core_rulebook","page":"245"}},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/items/item.svg","effects":[]}
|
||||
{"_id":"L5RCoreIte000141","name":"Flint and Tinder","permission":{"default":0},"type":"item","data":{"equipped":false,"quantity":1,"weight":"0","rarity":"0","zeni":"1 zeni","properties":[],"description":"","source_reference":{"source":"core_rulebook","page":"245"}},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/items/item.svg","effects":[]}
|
||||
{"_id":"L5RCoreIte000142","name":"Furoshiki","permission":{"default":0},"type":"item","data":{"equipped":false,"quantity":1,"weight":"0","rarity":"0","zeni":"1 zeni","properties":[],"description":"","source_reference":{"source":"core_rulebook","page":"245"}},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/items/item.svg","effects":[]}
|
||||
{"_id":"L5RCoreIte000143","name":"The Obsidian Journal","permission":{"default":0},"type":"item","data":{"equipped":false,"quantity":1,"weight":"0","rarity":"10","zeni":"0","properties":[{"id":"L5RCorePro000009","name":"Forbidden"},{"id":"L5RCorePro000008","name":"Unholy"}],"description":"","source_reference":{"source":"core_rulebook","page":"127"}},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/items/item.svg","effects":[]}
|
||||
{"_id":"L5RCoreIte000144","name":"Pouch of Insence","permission":{"default":0},"type":"item","data":{"equipped":false,"quantity":1,"weight":"0","rarity":"2","zeni":"0","properties":[],"description":"","source_reference":{"source":"celestial_realms","page":"85"}},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/items/item.svg","effects":[]}
|
||||
{"_id":"L5RCoreIte000145","name":"Religious texts","permission":{"default":0},"type":"item","data":{"equipped":false,"quantity":1,"weight":"0","rarity":"2","zeni":"0","properties":[],"description":"","source_reference":{"source":"celestial_realms","page":"86"}},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/items/item.svg","effects":[]}
|
||||
{"_id":"L5RCoreIte000146","name":"Small Sachel of Ingredients","permission":{"default":0},"type":"item","data":{"equipped":false,"quantity":1,"weight":"0","rarity":"2","zeni":"10 bu","properties":[],"description":"","source_reference":{"source":"celestial_realms","page":"80"}},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/items/item.svg","effects":[]}
|
||||
{"_id":"L5RCoreIte000147","name":"Blessed Glass vial","permission":{"default":0},"type":"item","data":{"equipped":false,"quantity":1,"weight":"0","rarity":"2","zeni":"0","properties":[],"description":"","source_reference":{"source":"celestial_realms","page":"80"}},"sort":100001,"flags":{},"img":"systems/l5r5e/assets/icons/items/item.svg","effects":[]}
|
||||
|
||||
@@ -624,6 +624,36 @@ export class BaseCharacterSheetL5r5e extends BaseSheetL5r5e {
|
||||
});
|
||||
break;
|
||||
|
||||
case "honor":
|
||||
await this.actor.update({
|
||||
system: {
|
||||
social: {
|
||||
honor: Math.max(0, this.actor.system.social.honor + mod),
|
||||
},
|
||||
},
|
||||
});
|
||||
break;
|
||||
|
||||
case "glory":
|
||||
await this.actor.update({
|
||||
system: {
|
||||
social: {
|
||||
glory: Math.max(0, this.actor.system.social.glory + mod),
|
||||
},
|
||||
},
|
||||
});
|
||||
break;
|
||||
|
||||
case "status":
|
||||
await this.actor.update({
|
||||
system: {
|
||||
social: {
|
||||
status: Math.max(0, this.actor.system.social.status + mod),
|
||||
},
|
||||
},
|
||||
});
|
||||
break;
|
||||
|
||||
default:
|
||||
console.warn("L5R5E | BCS | Unsupported type", type);
|
||||
break;
|
||||
|
||||
@@ -320,7 +320,7 @@ export class CharacterGenerator {
|
||||
}
|
||||
|
||||
// Img (only if system defaults)
|
||||
const folder = "systems/l5r5e/assets/icons/actors";
|
||||
const folder = "systems/l5rx-chiaroscuro/assets/icons/actors";
|
||||
const newImg = [
|
||||
`${folder}/npc.svg`,
|
||||
`${folder}/traditional-japanese-man.svg`,
|
||||
|
||||
@@ -56,11 +56,60 @@ export class CharacterSheetL5r5e extends BaseCharacterSheetL5r5e {
|
||||
// Split Others advancements, and calculate xp spent and add it to total
|
||||
this._prepareOthersAdvancement(sheetData);
|
||||
|
||||
// Update spent_xp to actor
|
||||
this.actor.system.xp_spent = sheetData.data.system.xp_spent;
|
||||
|
||||
// Total
|
||||
sheetData.data.system.xp_saved = Math.floor(
|
||||
parseInt(sheetData.data.system.xp_total) - parseInt(sheetData.data.system.xp_spent)
|
||||
);
|
||||
|
||||
// Chiaroscuro: Skill ranks list for <select>
|
||||
sheetData.data.skillRanksList = Object.keys(CONFIG.l5r5e.skillRanks).map((id) => ({
|
||||
id,
|
||||
label: game.i18n.localize(`chiaroscuro.skill_ranks.${id}`),
|
||||
}));
|
||||
|
||||
// Chiaroscuro: Normalize skill values 0 (number) → "0" (string) for selectOptions matching
|
||||
for (const category of Object.values(sheetData.data.system.skills)) {
|
||||
for (const [key, value] of Object.entries(category)) {
|
||||
if (value === 0) category[key] = "0";
|
||||
}
|
||||
}
|
||||
|
||||
// Chiaroscuro: Aspects gauge data
|
||||
const aspectsData = sheetData.data.system.aspects?.aspects ?? {};
|
||||
const gauge = aspectsData.gauge ?? 0;
|
||||
sheetData.data.aspectsData = {
|
||||
solar: aspectsData.solar ?? 0,
|
||||
lunar: aspectsData.lunar ?? 0,
|
||||
gauge,
|
||||
gaugePercent: ((gauge + 10) / 20) * 100,
|
||||
gaugeColor: gauge > 0 ? "#d4a855" : gauge < 0 ? "#5588aa" : "#888888",
|
||||
};
|
||||
|
||||
// Chiaroscuro: État items active on the character
|
||||
sheetData.data.etatItems = sheetData.items.filter((i) => i.type === "etat");
|
||||
|
||||
// Chiaroscuro: Invocations split by type (from splitTechniquesList)
|
||||
const invocations = sheetData.data.splitTechniquesList["mot_invocation"] ?? [];
|
||||
sheetData.data.splitInvocationsList = {
|
||||
general: invocations.filter((t) => !t.system.invocation_type || t.system.invocation_type === "general"),
|
||||
neutre: invocations.filter((t) => t.system.invocation_type === "neutre"),
|
||||
precis: invocations.filter((t) => t.system.invocation_type === "precis"),
|
||||
};
|
||||
|
||||
// Chiaroscuro: Arcane items
|
||||
sheetData.data.arcaneItems = sheetData.items.filter((i) => i.type === "arcane");
|
||||
|
||||
// Chiaroscuro: Identity tabs enriched HTML
|
||||
sheetData.data.enrichedHtml.identity_text1 = await foundry.applications.ux.TextEditor.implementation.enrichHTML(
|
||||
this.actor.system.identity_text1 ?? "", { async: true }
|
||||
);
|
||||
sheetData.data.enrichedHtml.identity_text2 = await foundry.applications.ux.TextEditor.implementation.enrichHTML(
|
||||
this.actor.system.identity_text2 ?? "", { async: true }
|
||||
);
|
||||
|
||||
return sheetData;
|
||||
}
|
||||
|
||||
@@ -114,6 +163,17 @@ export class CharacterSheetL5r5e extends BaseCharacterSheetL5r5e {
|
||||
// Money +/-
|
||||
html.find(".money-control").on("click", this._modifyMoney.bind(this));
|
||||
|
||||
// XP +/-
|
||||
html.find(".xp-control").on("click", this._modifyXP.bind(this));
|
||||
|
||||
// Chiaroscuro: set default ring on ring-name click
|
||||
html.find(".ring-set-default").on("click", (event) => {
|
||||
event.preventDefault();
|
||||
const ring = $(event.currentTarget).data("ring");
|
||||
this.actor.update({ "system.default_ring": ring });
|
||||
});
|
||||
|
||||
|
||||
// Advancements Tab to current rank onload
|
||||
// TODO class "Active" Bug on load, dunno why :/
|
||||
this._tabs
|
||||
@@ -121,6 +181,18 @@ export class CharacterSheetL5r5e extends BaseCharacterSheetL5r5e {
|
||||
.activate("advancement_rank_" + (this.actor.system.identity.school_rank || 0));
|
||||
}
|
||||
|
||||
/**
|
||||
* Override base dice picker to open Chiaroscuro d6 dialog.
|
||||
* @param {Event} event
|
||||
*/
|
||||
_openDicePickerForSkill(event) {
|
||||
event.preventDefault();
|
||||
const el = $(event.currentTarget);
|
||||
const skillId = el.data("skill");
|
||||
const ringId = el.data("ring") || this.actor.system?.default_ring || "void";
|
||||
new game.l5r5e.ChiaroscuroDiceDialog({ actor: this.actor, ringId, skillId }).render(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Split the school advancement, calculate the total xp spent and the current total xp spent by rank
|
||||
*/
|
||||
@@ -149,6 +221,12 @@ export class CharacterSheetL5r5e extends BaseCharacterSheetL5r5e {
|
||||
adv[rank].spent.total += xp_used_total;
|
||||
adv[rank].spent.curriculum += xp_used;
|
||||
});
|
||||
|
||||
// If we finished the rank but haven't added anything to the next rank we should show an empty tab
|
||||
// note: adv is index from 1, not 0 because of rank starting at 1
|
||||
if(adv.length -1 < sheetData.data.system.identity.school_rank) {
|
||||
adv.push({list: [], rank: sheetData.data.system.identity.school_rank, spent: { total: 0, curriculum: 0}});
|
||||
}
|
||||
sheetData.data.advancementsListByRank = adv;
|
||||
}
|
||||
|
||||
@@ -206,6 +284,13 @@ export class CharacterSheetL5r5e extends BaseCharacterSheetL5r5e {
|
||||
delete formData["system.money.zeni"];
|
||||
}
|
||||
|
||||
// Chiaroscuro: convert skill rank "0" (string from <select>) back to 0 (number)
|
||||
for (const [key, value] of Object.entries(formData)) {
|
||||
if (key.startsWith("system.skills.") && value === "0") {
|
||||
formData[key] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Save computed values
|
||||
const currentData = this.object.system;
|
||||
formData["system.focus"] = currentData.focus;
|
||||
@@ -285,6 +370,35 @@ export class CharacterSheetL5r5e extends BaseCharacterSheetL5r5e {
|
||||
this.render(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add or Subtract XP (+/- buttons)
|
||||
* @param {Event} event
|
||||
* @private
|
||||
*/
|
||||
async _modifyXP(event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
const elmt = $(event.currentTarget);
|
||||
let mod = elmt.data("value");
|
||||
if (!mod) {
|
||||
return;
|
||||
}
|
||||
|
||||
const new_xp_total = Math.max(0, this.actor.system.xp_total + mod);
|
||||
this.actor.update({
|
||||
system: {
|
||||
xp_total: new_xp_total,
|
||||
},
|
||||
});
|
||||
|
||||
if(this.actor.system.xp_spent > new_xp_total) {
|
||||
ui.notifications.warn("l5r5e.advancements.warning.total_less_then_spent", { localize: true })
|
||||
}
|
||||
|
||||
this.render(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add +1 to actor school rank
|
||||
* @param {Event} event
|
||||
|
||||
@@ -50,6 +50,21 @@ export class NpcSheetL5r5e extends BaseCharacterSheetL5r5e {
|
||||
label: game.i18n.localize("l5r5e.character_types." + e),
|
||||
}));
|
||||
|
||||
// Danger levels for martial/social danger selects
|
||||
const dangerLevels = ["simple", "moyenne", "assez_difficile", "difficile"];
|
||||
sheetData.data.dangerList = dangerLevels.map((id) => ({
|
||||
id,
|
||||
label: game.i18n.localize(`chiaroscuro.danger.${id}`),
|
||||
}));
|
||||
|
||||
// Invocations list (mot_invocation techniques, split by type like character sheet)
|
||||
const invocations = sheetData.data.splitTechniquesList?.["mot_invocation"] ?? [];
|
||||
sheetData.data.splitInvocationsList = {
|
||||
general: invocations.filter((t) => !t.system.invocation_type || t.system.invocation_type === "general"),
|
||||
neutre: invocations.filter((t) => t.system.invocation_type === "neutre"),
|
||||
precis: invocations.filter((t) => t.system.invocation_type === "precis"),
|
||||
};
|
||||
|
||||
return sheetData;
|
||||
}
|
||||
|
||||
@@ -101,4 +116,16 @@ export class NpcSheetL5r5e extends BaseCharacterSheetL5r5e {
|
||||
|
||||
return super._updateObject(event, formData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Override base dice picker to open Chiaroscuro d6 dialog.
|
||||
* @param {Event} event
|
||||
*/
|
||||
_openDicePickerForSkill(event) {
|
||||
event.preventDefault();
|
||||
const el = $(event.currentTarget);
|
||||
const skillId = el.data("skill");
|
||||
const ringId = el.data("ring") || this.actor.system?.default_ring || "void";
|
||||
new game.l5r5e.ChiaroscuroDiceDialog({ actor: this.actor, ringId, skillId }).render(true);
|
||||
}
|
||||
}
|
||||
|
||||
11
system/scripts/compendium/l5r5e-compendium-directory.js
Normal file
11
system/scripts/compendium/l5r5e-compendium-directory.js
Normal file
@@ -0,0 +1,11 @@
|
||||
const { CompendiumDirectory } = foundry.applications.sidebar.tabs;
|
||||
|
||||
export class CompendiumDirectoryL5r5e extends CompendiumDirectory {
|
||||
|
||||
/** @inheritdoc */
|
||||
async _prepareContext(options) {
|
||||
const context = await super._prepareContext(options);
|
||||
context.sidebarIcon = foundry.applications.sidebar.Sidebar.TABS.compendium.icon;
|
||||
return context;
|
||||
}
|
||||
}
|
||||
497
system/scripts/compendium/l5r5e-item-compendium.js
Normal file
497
system/scripts/compendium/l5r5e-item-compendium.js
Normal file
@@ -0,0 +1,497 @@
|
||||
import { L5r5eHtmlMultiSelectElement } from "../misc/l5r5e-multiselect.js";
|
||||
|
||||
const { Compendium } = foundry.applications.sidebar.apps;
|
||||
|
||||
/**
|
||||
* Extended Compendium application for L5R5e.
|
||||
* Adds source/rank/ring/rarity filters to Item compendiums
|
||||
* @extends {Compendium}
|
||||
*/
|
||||
export class ItemCompendiumL5r5e extends Compendium {
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
actions: {
|
||||
applyPlayerView: ItemCompendiumL5r5e.#onApplyPlayerView,
|
||||
},
|
||||
window: {
|
||||
resizable: true
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Our own entry partial which mirrors Foundry's index-partial.hbs structure
|
||||
* and appends ring/rarity/rank badges using data from _prepareDirectoryContext.
|
||||
*
|
||||
* NOTE: We intentionally duplicate Foundry's <li> structure here rather than
|
||||
* trying to include their partial, because their partial renders a complete <li>
|
||||
* element which cannot be nested or extended from outside. If Foundry ever
|
||||
* changes their index-partial.hbs, this file will need updating to match.
|
||||
* @override
|
||||
*/
|
||||
static _entryPartial = "systems/l5rx-chiaroscuro/templates/" + "compendium/l5r5e-index-partial.html";
|
||||
|
||||
/**
|
||||
* Sources present in this specific compendium, populated during _prepareContext.
|
||||
* @type {Set<string>}
|
||||
*/
|
||||
#sourcesInThisCompendium = new Set();
|
||||
|
||||
/**
|
||||
* Sources unavailable to players based on permission settings.
|
||||
* @type {Set<string>}
|
||||
*/
|
||||
#unavailableSourceForPlayersSet = new Set();
|
||||
|
||||
/**
|
||||
* Whether to hide entries with empty sources from players.
|
||||
* @type {boolean}
|
||||
*/
|
||||
#hideEmptySourcesFromPlayers = false;
|
||||
|
||||
/**
|
||||
* Which filter UI controls are worth showing.
|
||||
* Determined during _prepareContext by checking whether at least two
|
||||
* distinct values exist for each filterable property.
|
||||
* @type {{ rank: boolean, rarity: boolean, source: boolean, ring: boolean }|null}
|
||||
*/
|
||||
#filtersToShow = null;
|
||||
|
||||
/**
|
||||
* Cached active filter values, read from the DOM once at the start of
|
||||
* each filter pass in #reapplyFilters and held for _onMatchSearchEntry
|
||||
* to consume per-entry without re-querying the DOM.
|
||||
* @type {{ userFilter: string[], rankFilter: string[], ringFilter: string[], rarityFilter: string[] }}
|
||||
*/
|
||||
#activeFilters = {
|
||||
userFilter: [],
|
||||
rankFilter: [],
|
||||
ringFilter: [],
|
||||
rarityFilter: [],
|
||||
};
|
||||
|
||||
/**
|
||||
* Insert the filter part between header and directory by composing with
|
||||
* the parent parts rather than replacing them, so future Foundry changes
|
||||
* to Compendium.PARTS are picked up automatically.
|
||||
* @override
|
||||
*/
|
||||
_configureRenderParts(options) {
|
||||
const parts = super._configureRenderParts(options);
|
||||
|
||||
const ordered = {};
|
||||
for (const [key, value] of Object.entries(parts)) {
|
||||
ordered[key] = value;
|
||||
if (key === "header") {
|
||||
ordered.filter = {
|
||||
template: `${CONFIG.l5r5e.paths.templates}compendium/filter-bar.html`,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return ordered;
|
||||
}
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
async _prepareContext(options) {
|
||||
const context = await super._prepareContext(options);
|
||||
this.#sourcesInThisCompendium = new Set();
|
||||
this.#resolvePermissions();
|
||||
this.#filtersToShow = this.#computeFilterVisibility();
|
||||
return context;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
async _preparePartContext(partId, context, options) {
|
||||
context = await super._preparePartContext(partId, context, options);
|
||||
|
||||
if (partId === "filter") {
|
||||
const ns = CONFIG.l5r5e.namespace;
|
||||
const allCompendiumReferencesSet = game.settings.get(ns, "all-compendium-references");
|
||||
const hideDisabledOptions = game.settings.get(ns, "compendium-hide-disabled-sources");
|
||||
|
||||
context.filtersToShow = this.#filtersToShow;
|
||||
context.ranks = [1, 2, 3, 4, 5];
|
||||
context.rarities = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
|
||||
context.rings = ["fire", "water", "earth", "air", "void"];
|
||||
context.hideDisabledOptions = hideDisabledOptions;
|
||||
context.showPlayerView = game.user.isGM && this.#unavailableSourceForPlayersSet.size > 0;
|
||||
|
||||
// Source multiselect options — plain data for {{selectOptions}} in the template.
|
||||
context.sources = [...allCompendiumReferencesSet].map((reference) => ({
|
||||
value: reference,
|
||||
label: CONFIG.l5r5e.sourceReference[reference]?.label ?? reference,
|
||||
translate: true,
|
||||
group:
|
||||
CONFIG.l5r5e.sourceReference[reference]?.type.split(",")[0] ??
|
||||
"l5r5e.multiselect.sources_categories.others",
|
||||
disabled:
|
||||
!this.#sourcesInThisCompendium.has(reference) ||
|
||||
(!game.user.isGM && this.#unavailableSourceForPlayersSet.has(reference)),
|
||||
}));
|
||||
}
|
||||
|
||||
if (partId === "directory") {
|
||||
context.entryFilterData = Object.fromEntries(
|
||||
[...this.collection.index.values()].map((entry) => [
|
||||
entry._id,
|
||||
{
|
||||
rank: entry.system?.rank,
|
||||
ring: entry.system?.ring,
|
||||
rarity: entry.system?.rarity,
|
||||
},
|
||||
])
|
||||
);
|
||||
}
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
async _onRender(context, options) {
|
||||
await super._onRender(context, options);
|
||||
|
||||
if (options.parts.includes("filter")) {
|
||||
this.#bindButtonFilter(".rank-filter");
|
||||
this.#bindButtonFilter(".rarity-filter");
|
||||
this.#bindButtonFilter(".ring-filter");
|
||||
this.#bindSourceFilter();
|
||||
}
|
||||
|
||||
// Reapply filters whenever the filter controls or the entry list changes.
|
||||
if (options.parts.some((p) => p === "filter" || p === "directory")) {
|
||||
this.#reapplyFilters();
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
_preSyncPartState(partId, newElement, priorElement, state) {
|
||||
super._preSyncPartState(partId, newElement, priorElement, state);
|
||||
|
||||
if (partId === "filter") {
|
||||
state.selectedRanks = [...priorElement.querySelectorAll(".rank-filter .selected")].map((element) => element.dataset.rank);
|
||||
state.selectedRarities = [...priorElement.querySelectorAll(".rarity-filter .selected")].map((element) => element.dataset.rarity);
|
||||
state.selectedRings = [...priorElement.querySelectorAll(".ring-filter .selected")].map((element) => element.dataset.ring);
|
||||
state.sourceValue = priorElement.querySelector("l5r5e-multi-select")?.value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore filter selections after the filter part has been re-rendered.
|
||||
* The [data-clear] button visibility is derived from whether any values
|
||||
* were restored — no extra state needed.
|
||||
* @override
|
||||
*/
|
||||
_syncPartState(partId, newElement, priorElement, state) {
|
||||
super._syncPartState(partId, newElement, priorElement, state);
|
||||
|
||||
if (partId === "filter") {
|
||||
for (const rank of state.selectedRanks ?? []) {
|
||||
newElement.querySelector(`.rank-filter [data-rank="${rank}"]`)?.classList.add("selected");
|
||||
}
|
||||
const rankClear = newElement.querySelector(".rank-filter [data-clear]");
|
||||
if (rankClear) {
|
||||
rankClear.style.display = state.selectedRanks?.length ? "" : "none";
|
||||
}
|
||||
|
||||
for (const rarity of state.selectedRarities ?? []) {
|
||||
newElement.querySelector(`.rarity-filter [data-rarity="${rarity}"]`)?.classList.add("selected");
|
||||
}
|
||||
const rarityClear = newElement.querySelector(".rarity-filter [data-clear]");
|
||||
if (rarityClear) {
|
||||
rarityClear.style.display = state.selectedRarities?.length ? "" : "none";
|
||||
}
|
||||
|
||||
for (const ring of state.selectedRings ?? []) {
|
||||
newElement.querySelector(`.ring-filter [data-ring="${ring}"]`)?.classList.add("selected");
|
||||
}
|
||||
const ringClear = newElement.querySelector(".ring-filter [data-clear]");
|
||||
if (ringClear) {
|
||||
ringClear.style.display = state.selectedRings?.length ? "" : "none";
|
||||
}
|
||||
|
||||
if (state.sourceValue) {
|
||||
const multiSelect = newElement.querySelector("l5r5e-multi-select");
|
||||
if (multiSelect) {
|
||||
multiSelect.value = state.sourceValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
_onMatchSearchEntry(query, entryIds, entry, options) {
|
||||
super._onMatchSearchEntry(query, entryIds, entry, options);
|
||||
if (entry.style.display === "none") {
|
||||
return;
|
||||
}
|
||||
this.#applyEntryFilter(entry);
|
||||
}
|
||||
|
||||
/**
|
||||
* Snapshot active filter state then re-run the search filter (or walk entries directly as fallback).
|
||||
* @private
|
||||
*/
|
||||
#reapplyFilters() {
|
||||
this.#refreshActiveFilters();
|
||||
|
||||
const searchFilter = this._searchFilters?.[0];
|
||||
if (searchFilter) {
|
||||
searchFilter.filter(null, searchFilter.query);
|
||||
return;
|
||||
}
|
||||
|
||||
// Fallback
|
||||
for (const entry of this.element.querySelectorAll(".directory-item")) {
|
||||
this.#applyEntryFilter(entry);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read current filter selections from the DOM and cache them in #activeFilters.
|
||||
* @private
|
||||
*/
|
||||
#refreshActiveFilters() {
|
||||
const filterElement = this.element.querySelector("[data-application-part=\"filter\"]");
|
||||
const multiSelect = filterElement?.querySelector("l5r5e-multi-select");
|
||||
|
||||
const collectSelected = (containerSelector, dataKey) =>
|
||||
[...(filterElement?.querySelectorAll(`${containerSelector} .selected`) ?? [])]
|
||||
.map((element) => element.dataset[dataKey])
|
||||
.filter(Boolean);
|
||||
|
||||
this.#activeFilters = {
|
||||
userFilter: multiSelect?.value ?? [],
|
||||
rankFilter: collectSelected(".rank-filter", "rank"),
|
||||
ringFilter: collectSelected(".ring-filter", "ring"),
|
||||
rarityFilter: collectSelected(".rarity-filter", "rarity"),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply all active filters to a single directory entry, showing or hiding it accordingly.
|
||||
* @param {HTMLElement} entry
|
||||
* @private
|
||||
*/
|
||||
#applyEntryFilter(entry) {
|
||||
const indexEntry = this.collection.index.get(entry.dataset.entryId);
|
||||
if (!indexEntry) {
|
||||
return;
|
||||
}
|
||||
|
||||
const system = indexEntry.system;
|
||||
const lineSource = system?.source_reference?.source ?? null;
|
||||
const { userFilter, rankFilter, ringFilter, rarityFilter } = this.#activeFilters;
|
||||
let shouldShow = true;
|
||||
|
||||
const sourceUnavailable =
|
||||
(lineSource && this.#unavailableSourceForPlayersSet.has(lineSource)) ||
|
||||
(lineSource === "" && this.#hideEmptySourcesFromPlayers);
|
||||
|
||||
if (sourceUnavailable) {
|
||||
if (game.user.isGM) {
|
||||
entry.classList.add("not-for-players");
|
||||
entry.dataset.tooltip = game.i18n.localize("l5r5e.compendium.not_for_players");
|
||||
} else {
|
||||
shouldShow = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (rankFilter.length) {
|
||||
shouldShow &&= rankFilter.includes(String(system?.rank));
|
||||
}
|
||||
if (rarityFilter.length) {
|
||||
shouldShow &&= rarityFilter.includes(String(system?.rarity));
|
||||
}
|
||||
if (ringFilter.length) {
|
||||
shouldShow &&= ringFilter.includes(system?.ring);
|
||||
}
|
||||
if (userFilter.length) {
|
||||
shouldShow &&= userFilter.includes(lineSource);
|
||||
}
|
||||
|
||||
entry.style.display = shouldShow ? "" : "none";
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterate the compendium index to:
|
||||
* 1. Populate #sourcesInThisCompendium for source filter options
|
||||
* 2. Determine which filter controls have enough distinct values to show
|
||||
* @returns {{ rank: boolean, rarity: boolean, source: boolean, ring: boolean }}
|
||||
* @private
|
||||
*/
|
||||
#computeFilterVisibility() {
|
||||
const filtersToShow = { rank: false, rarity: false, source: true, ring: false };
|
||||
const firstSeen = { rank: null, rarity: null, ring: null };
|
||||
|
||||
const markIfDistinct = (prop, value) => {
|
||||
if (filtersToShow[prop] || value === undefined || value === null) {
|
||||
return;
|
||||
}
|
||||
if (firstSeen[prop] === null) {
|
||||
firstSeen[prop] = value;
|
||||
} else if (firstSeen[prop] !== value) {
|
||||
filtersToShow[prop] = true;
|
||||
}
|
||||
};
|
||||
|
||||
for (const entry of this.collection.index.values()) {
|
||||
const sys = entry.system;
|
||||
if (!sys) {
|
||||
continue;
|
||||
}
|
||||
if (sys.rank !== undefined) {
|
||||
markIfDistinct("rank", sys.rank);
|
||||
}
|
||||
if (sys.ring !== undefined) {
|
||||
markIfDistinct("ring", sys.ring);
|
||||
}
|
||||
if (sys.rarity !== undefined) {
|
||||
markIfDistinct("rarity", sys.rarity);
|
||||
}
|
||||
if (sys.source_reference?.source !== undefined) {
|
||||
this.#sourcesInThisCompendium.add(sys.source_reference.source);
|
||||
}
|
||||
}
|
||||
|
||||
return filtersToShow;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve which sources are restricted from players and cache the result
|
||||
* in instance-level sets for use by #applyEntryFilter.
|
||||
* @private
|
||||
*/
|
||||
#resolvePermissions() {
|
||||
const ns = CONFIG.l5r5e.namespace;
|
||||
const officialSet = game.settings.get(ns, "compendium-official-content-for-players");
|
||||
const unofficialSet = game.settings.get(ns, "compendium-unofficial-content-for-players");
|
||||
const allRefsSet = game.settings.get(ns, "all-compendium-references");
|
||||
|
||||
this.#hideEmptySourcesFromPlayers = game.settings.get(ns, "compendium-hide-empty-sources-from-players");
|
||||
|
||||
this.#unavailableSourceForPlayersSet = new Set(
|
||||
[...allRefsSet].filter((ref) => {
|
||||
if (CONFIG.l5r5e.sourceReference[ref]) {
|
||||
return officialSet.size > 0 ? !officialSet.has(ref) : false;
|
||||
}
|
||||
return unofficialSet.size > 0 ? !unofficialSet.has(ref) : false;
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Bind toggle-selection click handlers to all children of a button filter container.
|
||||
* A [data-clear] element at the end of the container acts as an inline reset:
|
||||
* - It is hidden (display:none in the template) when no values are selected.
|
||||
* - It becomes visible as soon as any value is selected.
|
||||
* - Clicking it deselects all values and hides itself again.
|
||||
* @param {string} containerSelector
|
||||
* @private
|
||||
*/
|
||||
#bindButtonFilter(containerSelector) {
|
||||
const container = this.element.querySelector(containerSelector);
|
||||
if (!container) {
|
||||
return;
|
||||
}
|
||||
|
||||
const clearButton = container.querySelector("[data-clear]");
|
||||
|
||||
const updateClearButton = () => {
|
||||
if (!clearButton) {
|
||||
return;
|
||||
}
|
||||
const anySelected = [...container.children].some(
|
||||
(element) => element.dataset.clear === undefined && element.classList.contains("selected")
|
||||
);
|
||||
clearButton.style.display = anySelected ? "" : "none";
|
||||
};
|
||||
|
||||
for (const child of container.children) {
|
||||
child.addEventListener("click", (event) => {
|
||||
const target = event.currentTarget;
|
||||
|
||||
if (target.dataset.clear !== undefined) {
|
||||
// Clicked the clear button — deselect all value elements
|
||||
for (const element of container.children) {
|
||||
element.classList.remove("selected");
|
||||
}
|
||||
} else {
|
||||
// Clicked a value element — toggle it
|
||||
target.classList.toggle("selected");
|
||||
}
|
||||
|
||||
updateClearButton();
|
||||
this.#reapplyFilters();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wire up the change listener on the already-rendered multiselect element.
|
||||
* The element and its options are fully declared in filter-bar.html via
|
||||
* {{selectOptions}} — no imperative construction needed here.
|
||||
* @private
|
||||
*/
|
||||
#bindSourceFilter() {
|
||||
const multiSelect = this.element.querySelector("l5r5e-multi-select[name=\"filter-sources\"]");
|
||||
if (!multiSelect) {
|
||||
return;
|
||||
}
|
||||
multiSelect.addEventListener("change", () => this.#reapplyFilters());
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the GM player-view button, selecting only the sources that are
|
||||
* both visible to players and present in this specific compendium.
|
||||
* @this {ItemCompendiumL5r5e}
|
||||
* @private
|
||||
*/
|
||||
static #onApplyPlayerView() {
|
||||
const ns = CONFIG.l5r5e.namespace;
|
||||
const allRefsSet = game.settings.get(ns, "all-compendium-references");
|
||||
|
||||
const availableForPlayers = [...allRefsSet]
|
||||
.filter((ref) => !this.#unavailableSourceForPlayersSet.has(ref))
|
||||
.filter((ref) => this.#sourcesInThisCompendium.has(ref));
|
||||
|
||||
const multiSelect = this.element.querySelector("l5r5e-multi-select[name=\"filter-sources\"]");
|
||||
if (!multiSelect) {
|
||||
return;
|
||||
}
|
||||
|
||||
multiSelect.value = availableForPlayers;
|
||||
this.#reapplyFilters();
|
||||
}
|
||||
|
||||
/**
|
||||
* Register this compendium class and extend the index fields for all Item packs.
|
||||
*/
|
||||
static applyToPacks() {
|
||||
CONFIG.Item.compendiumIndexFields = [
|
||||
...(CONFIG.Item.compendiumIndexFields ?? []),
|
||||
"system.rank",
|
||||
"system.ring",
|
||||
"system.rarity",
|
||||
"system.source_reference.source",
|
||||
];
|
||||
|
||||
for (const pack of game.packs.filter((p) => p.metadata.type === "Item")) {
|
||||
pack.applicationClass = ItemCompendiumL5r5e;
|
||||
pack.getIndex(); // rebuild index with new fields — no need to await since this happens before anyone have a chance to act
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
export const L5R5E = {
|
||||
namespace: "l5r5e",
|
||||
paths: {
|
||||
assets: "systems/l5r5e/assets/",
|
||||
templates: "systems/l5r5e/templates/",
|
||||
assets: "systems/l5rx-chiaroscuro/assets/",
|
||||
templates: "systems/l5rx-chiaroscuro/templates/",
|
||||
},
|
||||
money: [50, 10],
|
||||
stances: ["earth", "air", "water", "fire", "void"],
|
||||
@@ -14,172 +14,226 @@ export const L5R5E = {
|
||||
skillCostMultiplier: 2,
|
||||
techniqueCost: 3,
|
||||
},
|
||||
|
||||
// --- Chiaroscuro additions ---
|
||||
|
||||
/** Skill rank enum values and associated flat bonus */
|
||||
skillRanks: {
|
||||
0: { bonus: 0 },
|
||||
initie: { bonus: 1 },
|
||||
expert: { bonus: 2 },
|
||||
maitre: { bonus: 3 },
|
||||
parangon1: { bonus: 3, passive: 1 }, // dice results of 1 count as 2
|
||||
parangon2: { bonus: 3, passive: 2 }, // dice results of 1-2 count as 3
|
||||
parangon3: { bonus: 3, passive: 3 }, // dice results of 1-3 count as 4
|
||||
},
|
||||
|
||||
/** Difficulty thresholds (Chiaroscuro scale) */
|
||||
difficulties: {
|
||||
simple: 7,
|
||||
moyenne: 10,
|
||||
assez_difficile: 13,
|
||||
difficile: 16,
|
||||
tres_difficile: 22,
|
||||
heroique: 28,
|
||||
improbable: 32,
|
||||
},
|
||||
|
||||
/** Ring colors for Chiaroscuro visual style */
|
||||
ringColors: {
|
||||
air: "rgb(145, 120, 150)",
|
||||
water: "rgb(95, 145, 155)",
|
||||
fire: "rgb(155, 115, 80)",
|
||||
earth: "rgb(105, 150, 120)",
|
||||
void: "rgb(75, 70, 65)",
|
||||
},
|
||||
|
||||
/** Aspect gauge configuration */
|
||||
aspects: {
|
||||
solarConditionId: "desequilibre_lunaire",
|
||||
lunarConditionId: "desequilibre_solaire",
|
||||
imbalanceThreshold: 5,
|
||||
resetThreshold: 10,
|
||||
},
|
||||
|
||||
// --- End Chiaroscuro additions ---
|
||||
|
||||
// For rings wound to be aligned, add them first
|
||||
conditions: [{
|
||||
id: "lightly_wounded_fire",
|
||||
name: "l5r5e.conditions.lightly_wounded_fire",
|
||||
img: "systems/l5r5e/assets/icons/conditions/lightly_wounded_fire.webp",
|
||||
img: "systems/l5rx-chiaroscuro/assets/icons/conditions/lightly_wounded_fire.webp",
|
||||
system: { id: "L5RCoreCon000016" }
|
||||
},{
|
||||
id: "lightly_wounded_water",
|
||||
name: "l5r5e.conditions.lightly_wounded_water",
|
||||
img: "systems/l5r5e/assets/icons/conditions/lightly_wounded_water.webp",
|
||||
img: "systems/l5rx-chiaroscuro/assets/icons/conditions/lightly_wounded_water.webp",
|
||||
system: { id: "L5RCoreCon000016" }
|
||||
},{
|
||||
id: "lightly_wounded_air",
|
||||
name: "l5r5e.conditions.lightly_wounded_air",
|
||||
img: "systems/l5r5e/assets/icons/conditions/lightly_wounded_air.webp",
|
||||
img: "systems/l5rx-chiaroscuro/assets/icons/conditions/lightly_wounded_air.webp",
|
||||
system: { id: "L5RCoreCon000016" }
|
||||
},{
|
||||
id: "lightly_wounded_earth",
|
||||
name: "l5r5e.conditions.lightly_wounded_earth",
|
||||
img: "systems/l5r5e/assets/icons/conditions/lightly_wounded_earth.webp",
|
||||
img: "systems/l5rx-chiaroscuro/assets/icons/conditions/lightly_wounded_earth.webp",
|
||||
system: { id: "L5RCoreCon000016" }
|
||||
},{
|
||||
id: "lightly_wounded_void",
|
||||
name: "l5r5e.conditions.lightly_wounded_void",
|
||||
img: "systems/l5r5e/assets/icons/conditions/lightly_wounded_void.webp",
|
||||
img: "systems/l5rx-chiaroscuro/assets/icons/conditions/lightly_wounded_void.webp",
|
||||
system: { id: "L5RCoreCon000016" }
|
||||
},{
|
||||
id: "severely_wounded_fire",
|
||||
name: "l5r5e.conditions.severely_wounded_fire",
|
||||
img: "systems/l5r5e/assets/icons/conditions/heavily_wounded_fire.webp",
|
||||
img: "systems/l5rx-chiaroscuro/assets/icons/conditions/heavily_wounded_fire.webp",
|
||||
system: { id: "L5RCoreCon000016" }
|
||||
},{
|
||||
id: "severely_wounded_water",
|
||||
name: "l5r5e.conditions.severely_wounded_water",
|
||||
img: "systems/l5r5e/assets/icons/conditions/heavily_wounded_water.webp",
|
||||
img: "systems/l5rx-chiaroscuro/assets/icons/conditions/heavily_wounded_water.webp",
|
||||
system: { id: "L5RCoreCon000016" }
|
||||
},{
|
||||
id: "severely_wounded_air",
|
||||
name: "l5r5e.conditions.severely_wounded_air",
|
||||
img: "systems/l5r5e/assets/icons/conditions/heavily_wounded_air.webp",
|
||||
img: "systems/l5rx-chiaroscuro/assets/icons/conditions/heavily_wounded_air.webp",
|
||||
system: { id: "L5RCoreCon000016" }
|
||||
},{
|
||||
id: "severely_wounded_earth",
|
||||
name: "l5r5e.conditions.severely_wounded_earth",
|
||||
img: "systems/l5r5e/assets/icons/conditions/heavily_wounded_earth.webp",
|
||||
img: "systems/l5rx-chiaroscuro/assets/icons/conditions/heavily_wounded_earth.webp",
|
||||
system: { id: "L5RCoreCon000016" }
|
||||
},{
|
||||
id: "severely_wounded_void",
|
||||
name: "l5r5e.conditions.severely_wounded_void",
|
||||
img: "systems/l5r5e/assets/icons/conditions/heavily_wounded_void.webp",
|
||||
img: "systems/l5rx-chiaroscuro/assets/icons/conditions/heavily_wounded_void.webp",
|
||||
system: { id: "L5RCoreCon000016" }
|
||||
},{
|
||||
id: "afflicted",
|
||||
name: "l5r5e.conditions.afflicted",
|
||||
img: "systems/l5r5e/assets/icons/conditions/afflicted.webp",
|
||||
img: "systems/l5rx-chiaroscuro/assets/icons/conditions/afflicted.webp",
|
||||
system: { id: "L5RCoreCon000001" }
|
||||
},{
|
||||
id: "bleeding",
|
||||
name: "l5r5e.conditions.bleeding",
|
||||
img: "systems/l5r5e/assets/icons/conditions/bleeding.webp",
|
||||
img: "systems/l5rx-chiaroscuro/assets/icons/conditions/bleeding.webp",
|
||||
system: { id: "L5RCoreCon000002" }
|
||||
},{
|
||||
id: "burning",
|
||||
name: "l5r5e.conditions.burning",
|
||||
img: "systems/l5r5e/assets/icons/conditions/burning.webp",
|
||||
img: "systems/l5rx-chiaroscuro/assets/icons/conditions/burning.webp",
|
||||
system: { id: "L5RCoreCon000003" }
|
||||
},{
|
||||
id: "centered",
|
||||
name: "l5r5e.conditions.centered",
|
||||
img: "systems/l5r5e/assets/icons/conditions/centered.webp",
|
||||
img: "systems/l5rx-chiaroscuro/assets/icons/conditions/centered.webp",
|
||||
system: { id: "L5RCoreCon000022" }
|
||||
},{
|
||||
id: "compromised",
|
||||
name: "l5r5e.conditions.compromised",
|
||||
img: "systems/l5r5e/assets/icons/conditions/compromised.webp",
|
||||
img: "systems/l5rx-chiaroscuro/assets/icons/conditions/compromised.webp",
|
||||
system: { id: "L5RCoreCon000004" }
|
||||
},{
|
||||
id: "dazed",
|
||||
name: "l5r5e.conditions.dazed",
|
||||
img: "systems/l5r5e/assets/icons/conditions/dazed.webp",
|
||||
img: "systems/l5rx-chiaroscuro/assets/icons/conditions/dazed.webp",
|
||||
system: { id: "L5RCoreCon000005" }
|
||||
},{
|
||||
id: "disoriented",
|
||||
name: "l5r5e.conditions.disoriented",
|
||||
img: "systems/l5r5e/assets/icons/conditions/disoriented.webp",
|
||||
img: "systems/l5rx-chiaroscuro/assets/icons/conditions/disoriented.webp",
|
||||
system: { id: "L5RCoreCon000006" }
|
||||
},{
|
||||
id: "dying",
|
||||
name: "l5r5e.conditions.dying",
|
||||
img: "systems/l5r5e/assets/icons/conditions/dying_1.webp",
|
||||
img: "systems/l5rx-chiaroscuro/assets/icons/conditions/dying_1.webp",
|
||||
system: { id: "L5RCoreCon000007" }
|
||||
},{
|
||||
id: "emboldened",
|
||||
name: "l5r5e.conditions.emboldened",
|
||||
img: "systems/l5r5e/assets/icons/conditions/emboldened.webp",
|
||||
img: "systems/l5rx-chiaroscuro/assets/icons/conditions/emboldened.webp",
|
||||
system: { id: "L5RCoreCon000023" }
|
||||
},{
|
||||
id: "enraged",
|
||||
name: "l5r5e.conditions.enraged",
|
||||
img: "systems/l5r5e/assets/icons/conditions/enraged.webp",
|
||||
img: "systems/l5rx-chiaroscuro/assets/icons/conditions/enraged.webp",
|
||||
system: { id: "L5RCoreCon000008" }
|
||||
},{
|
||||
id: "exhausted",
|
||||
name: "l5r5e.conditions.exhausted",
|
||||
img: "systems/l5r5e/assets/icons/conditions/exhausted.webp",
|
||||
img: "systems/l5rx-chiaroscuro/assets/icons/conditions/exhausted.webp",
|
||||
system: { id: "L5RCoreCon000009" }
|
||||
},{
|
||||
id: "illness_coughing_illness",
|
||||
name: "l5r5e.conditions.illness_coughing_illness",
|
||||
img: "systems/l5r5e/assets/icons/conditions/illness_coughing_illness.webp",
|
||||
img: "systems/l5rx-chiaroscuro/assets/icons/conditions/illness_coughing_illness.webp",
|
||||
system: { id: "L5RCoreCon000019" }
|
||||
},{
|
||||
id: "illness_fire_rash",
|
||||
name: "l5r5e.conditions.illness_fire_rash",
|
||||
img: "systems/l5r5e/assets/icons/conditions/illness_fire_rash.webp",
|
||||
img: "systems/l5rx-chiaroscuro/assets/icons/conditions/illness_fire_rash.webp",
|
||||
system: { id: "L5RCoreCon000021" }
|
||||
},{
|
||||
id: "illness_gut_sickness",
|
||||
name: "l5r5e.conditions.illness_gut_sickness",
|
||||
img: "systems/l5r5e/assets/icons/conditions/illness_gut_sickness.webp",
|
||||
img: "systems/l5rx-chiaroscuro/assets/icons/conditions/illness_gut_sickness.webp",
|
||||
system: { id: "L5RCoreCon000018" }
|
||||
},{
|
||||
id: "illness_oozing_sore_disease",
|
||||
name: "l5r5e.conditions.illness_oozing_sore_disease",
|
||||
img: "systems/l5r5e/assets/icons/conditions/illness_oozing_sore_disease.webp",
|
||||
img: "systems/l5rx-chiaroscuro/assets/icons/conditions/illness_oozing_sore_disease.webp",
|
||||
system: { id: "L5RCoreCon000017" }
|
||||
},{
|
||||
id: "illness_unsteady_illness",
|
||||
name: "l5r5e.conditions.illness_unsteady_illness",
|
||||
img: "systems/l5r5e/assets/icons/conditions/illness_unsteady_illness.webp",
|
||||
img: "systems/l5rx-chiaroscuro/assets/icons/conditions/illness_unsteady_illness.webp",
|
||||
system: { id: "L5RCoreCon000020" }
|
||||
},{
|
||||
id: "immobilized",
|
||||
name: "l5r5e.conditions.immobilized",
|
||||
img: "systems/l5r5e/assets/icons/conditions/immobilized.webp",
|
||||
img: "systems/l5rx-chiaroscuro/assets/icons/conditions/immobilized.webp",
|
||||
system: { id: "L5RCoreCon000010" }
|
||||
},{
|
||||
id: "incapacitated",
|
||||
name: "l5r5e.conditions.incapacitated",
|
||||
img: "systems/l5r5e/assets/icons/conditions/incapacitated.webp",
|
||||
img: "systems/l5rx-chiaroscuro/assets/icons/conditions/incapacitated.webp",
|
||||
system: { id: "L5RCoreCon000011" }
|
||||
},{
|
||||
id: "intoxicated",
|
||||
name: "l5r5e.conditions.intoxicated",
|
||||
img: "systems/l5r5e/assets/icons/conditions/intoxicated.webp",
|
||||
img: "systems/l5rx-chiaroscuro/assets/icons/conditions/intoxicated.webp",
|
||||
system: { id: "L5RCoreCon000012" }
|
||||
},{
|
||||
id: "possessed",
|
||||
name: "l5r5e.conditions.possessed",
|
||||
img: "systems/l5r5e/assets/icons/conditions/possesed.webp",
|
||||
img: "systems/l5rx-chiaroscuro/assets/icons/conditions/possesed.webp",
|
||||
system: { id: "L5RCoreCon000024" }
|
||||
},{
|
||||
id: "prone",
|
||||
name: "l5r5e.conditions.prone",
|
||||
img: "systems/l5r5e/assets/icons/conditions/prone.webp",
|
||||
img: "systems/l5rx-chiaroscuro/assets/icons/conditions/prone.webp",
|
||||
system: { id: "L5RCoreCon000013" }
|
||||
},{
|
||||
id: "silenced",
|
||||
name: "l5r5e.conditions.silenced",
|
||||
img: "systems/l5r5e/assets/icons/conditions/silenced.webp",
|
||||
img: "systems/l5rx-chiaroscuro/assets/icons/conditions/silenced.webp",
|
||||
system: { id: "L5RCoreCon000014" }
|
||||
},{
|
||||
id: "unconscious",
|
||||
name: "l5r5e.conditions.unconscious",
|
||||
img: "systems/l5r5e/assets/icons/conditions/unconscious.webp",
|
||||
img: "systems/l5rx-chiaroscuro/assets/icons/conditions/unconscious.webp",
|
||||
system: { id: "L5RCoreCon000015" }
|
||||
},{
|
||||
id: "desequilibre_solaire",
|
||||
name: "chiaroscuro.aspects.desequilibre_solaire",
|
||||
img: "systems/l5rx-chiaroscuro/assets/icons/conditions/desequilibre_solaire.webp",
|
||||
system: { id: "ChiaCon000001" }
|
||||
},{
|
||||
id: "desequilibre_lunaire",
|
||||
name: "chiaroscuro.aspects.desequilibre_lunaire",
|
||||
img: "systems/l5rx-chiaroscuro/assets/icons/conditions/desequilibre_lunaire.webp",
|
||||
system: { id: "ChiaCon000002" }
|
||||
}],
|
||||
regex: {
|
||||
techniqueDifficulty: /^@([TS]):([^|]+?)(?:\|(min|max)(?:\(([^)]+?)\))?)?$/,
|
||||
@@ -344,6 +398,8 @@ L5R5E.techniques.set("mastery_ability", { type: "school", displayInTypes: false
|
||||
L5R5E.techniques.set("title_ability", { type: "title", displayInTypes: false });
|
||||
// Custom
|
||||
L5R5E.techniques.set("specificity", { type: "custom", displayInTypes: false });
|
||||
// Chiaroscuro
|
||||
L5R5E.techniques.set("mot_invocation", { type: "chiaroscuro", displayInTypes: true });
|
||||
|
||||
// *** SkillId - CategoryId ***
|
||||
L5R5E.skills = new Map();
|
||||
|
||||
@@ -1,47 +1,110 @@
|
||||
import { L5r5eHtmlMultiSelectElement } from "../misc/l5r5e-multiselect.js";
|
||||
|
||||
/**
|
||||
* A subclass of [ArrayField]{@link ArrayField} which supports a set of contained elements.
|
||||
* Elements in this set are treated as fungible and may be represented in any order or discarded if invalid.
|
||||
* A Foundry `SetField` that renders as an {@link L5r5eHtmlMultiSelectElement} chip-input.
|
||||
*
|
||||
* Use this in a DataModel schema whenever a field stores an unordered collection of
|
||||
* string values drawn from a fixed option list. On form submission the element returns a
|
||||
* comma-separated string; `clean()` splits it back into an Array before Foundry processes
|
||||
* it, and `initialize()` wraps the result in a `Set` for use in the model.
|
||||
*
|
||||
* @example
|
||||
* // In a DataModel schema:
|
||||
* skills: new L5r5eSetField({
|
||||
* options: [
|
||||
* { value: "athletics", label: "Athletics" },
|
||||
* { value: "meditation", label: "Meditation", disabled: true, tooltip: "Requires rank 3" },
|
||||
* ]
|
||||
* })
|
||||
*
|
||||
* // Renders automatically via {{formGroup}} in a Handlebars template:
|
||||
* // {{formGroup fields.skills name="skills" value=data.skills localize=true}}
|
||||
*
|
||||
* @param {object} options
|
||||
* @param {{ value: string, label: string, disabled?: boolean, tooltip?: string }[]} options.options
|
||||
* Flat list of selectable items. Passed directly to {@link L5r5eHtmlMultiSelectElement.create}.
|
||||
* @param {object[]} [options.groups]
|
||||
* Optional optgroup definitions, forwarded to the element factory unchanged.
|
||||
* @param {boolean} [options.hideDisabledOptions=false]
|
||||
* When true, disabled options are hidden from the dropdown instead of greyed out.
|
||||
*/
|
||||
export class L5r5eSetField extends foundry.data.fields.SetField {
|
||||
/**
|
||||
* Saved constructor options, used to reconstruct the multiselect input on form render.
|
||||
* @type {object}
|
||||
*/
|
||||
#savedOptions;
|
||||
|
||||
// We don't get the options we expect when we convert this to input,
|
||||
// So store them here
|
||||
#savedOptions;
|
||||
/**
|
||||
* @param {object} options
|
||||
* @param {object} context
|
||||
*/
|
||||
constructor(options = {}, context = {}) {
|
||||
super(
|
||||
new foundry.data.fields.StringField({
|
||||
choices: options.options?.map((option) => option.value) ?? [],
|
||||
}),
|
||||
options,
|
||||
context
|
||||
);
|
||||
|
||||
constructor(options={}, context={}) {
|
||||
super(new foundry.data.fields.StringField({
|
||||
choices: options.options.map((option) => option.value)
|
||||
}), options, context);
|
||||
|
||||
this.#savedOptions = options;
|
||||
}
|
||||
|
||||
/** @override */
|
||||
initialize(value, model, options={}) {
|
||||
if ( !value ) return value;
|
||||
return new Set(super.initialize(value, model, options));
|
||||
this.#savedOptions = options;
|
||||
}
|
||||
|
||||
/** @override */
|
||||
/**
|
||||
* @param {*} value
|
||||
* @param {object} model
|
||||
* @param {object} options
|
||||
* @return {Set}
|
||||
* @override
|
||||
*/
|
||||
initialize(value, model, options = {}) {
|
||||
if (!value || (Array.isArray(value) && value.length === 0)) {
|
||||
return new Set();
|
||||
}
|
||||
|
||||
return new Set(super.initialize(value, model, options).filter(Boolean));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Set} value
|
||||
* @return {*[]|*}
|
||||
* @override
|
||||
*/
|
||||
toObject(value) {
|
||||
if ( !value ) return value;
|
||||
return Array.from(value).map(v => this.element.toObject(v));
|
||||
if (!value) {
|
||||
return value;
|
||||
}
|
||||
return Array.from(value).map((v) => this.element.toObject(v));
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/* Form Field Integration */
|
||||
/* -------------------------------------------- */
|
||||
/**
|
||||
* @param {string|Array} value
|
||||
* @param {object} options
|
||||
* @return {Array}
|
||||
* @override
|
||||
*/
|
||||
clean(value, options) {
|
||||
// Settings forms submit comma-separated strings; split before normal cleaning.
|
||||
if (typeof value === "string") {
|
||||
value = value.length ? value.split(",").filter(Boolean) : [];
|
||||
}
|
||||
return super.clean(value, options);
|
||||
}
|
||||
|
||||
/** @override */
|
||||
/**
|
||||
* @param {object} config
|
||||
* @return {L5r5eHtmlMultiSelectElement}
|
||||
* @override
|
||||
*/
|
||||
_toInput(config) {
|
||||
const e = this.element;
|
||||
return L5r5eHtmlMultiSelectElement.create({
|
||||
name: config.name,
|
||||
options: this.#savedOptions.options,
|
||||
groups: this.#savedOptions.groups,
|
||||
value: config.value,
|
||||
localize: config.localize
|
||||
});
|
||||
return L5r5eHtmlMultiSelectElement.create({
|
||||
name: config.name,
|
||||
options: this.#savedOptions.options,
|
||||
groups: this.#savedOptions.groups,
|
||||
value: config.value,
|
||||
localize: config.localize,
|
||||
hideDisabledOptions: this.#savedOptions.hideDisabledOptions,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
334
system/scripts/dice/chiaroscuro-dice-dialog.js
Normal file
334
system/scripts/dice/chiaroscuro-dice-dialog.js
Normal file
@@ -0,0 +1,334 @@
|
||||
/**
|
||||
* Chiaroscuro Dice Dialog
|
||||
*
|
||||
* d6 pool system: ring value × multiplier d6, sum vs difficulty.
|
||||
* Multiplier: ×1 base, ×2 if aspect or assistance, ×3 if both.
|
||||
* Parangon passives adjust individual die results before summing.
|
||||
*/
|
||||
export class ChiaroscuroDiceDialog extends FormApplication {
|
||||
/**
|
||||
* Current Actor
|
||||
* @type {ActorL5r5e}
|
||||
* @private
|
||||
*/
|
||||
_actor = null;
|
||||
|
||||
/**
|
||||
* Payload Object
|
||||
*/
|
||||
object = {
|
||||
ring: { id: "void", value: 1 },
|
||||
skill: { id: "", name: "", bonus: 0, rank: "0" },
|
||||
difficulty: { id: "moyenne", value: 10 },
|
||||
modifier: 0,
|
||||
useAspectPoint: false,
|
||||
aspectType: "solar",
|
||||
useAssistance: false,
|
||||
};
|
||||
|
||||
static get defaultOptions() {
|
||||
return foundry.utils.mergeObject(super.defaultOptions, {
|
||||
id: "l5r5e-chiaroscuro-dice-dialog",
|
||||
classes: ["l5r5e", "chiaroscuro-dice-dialog"],
|
||||
template: CONFIG.l5r5e.paths.templates + "dice/chiaroscuro-dice-dialog.html",
|
||||
title: game.i18n.localize("chiaroscuro.dice.title"),
|
||||
width: 440,
|
||||
height: "auto",
|
||||
});
|
||||
}
|
||||
|
||||
get id() {
|
||||
return `l5r5e-chiaroscuro-dice-dialog-${this._actor?.id ?? "no-actor"}`;
|
||||
}
|
||||
|
||||
get title() {
|
||||
return game.i18n.localize("chiaroscuro.dice.title") + (this._actor ? " — " + this._actor.name : "");
|
||||
}
|
||||
|
||||
/**
|
||||
* Total dice to roll (ring value × multiplier)
|
||||
* @return {number}
|
||||
*/
|
||||
get totalDice() {
|
||||
const base = this.object.ring.value;
|
||||
const both = this.object.useAspectPoint && this.object.useAssistance;
|
||||
const either = this.object.useAspectPoint || this.object.useAssistance;
|
||||
return base * (both ? 3 : either ? 2 : 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param options actor, actorId, ringId, skillId
|
||||
*/
|
||||
constructor(options = {}) {
|
||||
super({}, options);
|
||||
|
||||
// Resolve actor
|
||||
[
|
||||
options?.actor,
|
||||
game.actors.get(options?.actorId),
|
||||
canvas.tokens.controlled[0]?.actor,
|
||||
game.user.character,
|
||||
].forEach((actor) => {
|
||||
if (!this._actor && actor instanceof Actor && actor.isOwner) {
|
||||
this._actor = actor;
|
||||
}
|
||||
});
|
||||
|
||||
// Default ring: options > actor default_ring > void
|
||||
const ringId = options.ringId ?? this._actor?.system?.default_ring ?? "void";
|
||||
this.ringId = ringId;
|
||||
|
||||
// Skill
|
||||
if (options.skillId) {
|
||||
this.skillId = options.skillId;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set ring (id + value from actor)
|
||||
* @param {string} ringId
|
||||
*/
|
||||
set ringId(ringId) {
|
||||
this.object.ring.id = CONFIG.l5r5e.stances.includes(ringId) ? ringId : "void";
|
||||
this.object.ring.value = this._actor?.system?.rings?.[this.object.ring.id] || 1;
|
||||
// Auto-derive aspect type from ring (fire/earth → solar, air/water → lunar; void = manual)
|
||||
if (this.object.ring.id !== "void") {
|
||||
this.object.aspectType = ["fire", "earth"].includes(this.object.ring.id) ? "solar" : "lunar";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set skill (id, name, rank, bonus)
|
||||
* @param {string} skillId
|
||||
*/
|
||||
set skillId(skillId) {
|
||||
if (!skillId) return;
|
||||
const catId = CONFIG.l5r5e.skills.get(skillId.toLowerCase().trim());
|
||||
const rank = this._actor?.system?.skills?.[catId]?.[skillId] ?? "0";
|
||||
this.object.skill = {
|
||||
...this.object.skill,
|
||||
id: skillId,
|
||||
name: catId ? game.i18n.localize(`l5r5e.skills.${catId}.${skillId}`) : skillId,
|
||||
rank,
|
||||
bonus: CONFIG.l5r5e.skillRanks?.[rank]?.bonus ?? 0,
|
||||
};
|
||||
}
|
||||
|
||||
async getData(options = null) {
|
||||
const difficultiesList = Object.entries(CONFIG.l5r5e.difficulties).map(([id, value]) => ({
|
||||
id,
|
||||
label: game.i18n.localize(`chiaroscuro.difficulties.${id}`),
|
||||
value,
|
||||
}));
|
||||
|
||||
const aspectsList = [
|
||||
{ id: "solar", label: game.i18n.localize("chiaroscuro.aspects.solar") },
|
||||
{ id: "lunar", label: game.i18n.localize("chiaroscuro.aspects.lunar") },
|
||||
];
|
||||
|
||||
return {
|
||||
...(await super.getData(options)),
|
||||
actor: this._actor,
|
||||
data: this.object,
|
||||
totalDice: this.totalDice,
|
||||
ringsList: game.l5r5e.HelpersL5r5e.getRingsList(this._actor),
|
||||
difficultiesList,
|
||||
aspectsList,
|
||||
isVoidRing: this.object.ring.id === "void",
|
||||
quickInfo: this._actor?.system?.quick_info ?? "",
|
||||
};
|
||||
}
|
||||
|
||||
activateListeners(html) {
|
||||
super.activateListeners(html);
|
||||
|
||||
// Ring selector
|
||||
html.find(".ring-selection-chi").on("click", async (event) => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
this.ringId = event.currentTarget.dataset.ringid;
|
||||
this.render(false);
|
||||
});
|
||||
|
||||
// Difficulty select
|
||||
html.find("select[name='difficulty.id']").on("change", (event) => {
|
||||
this.object.difficulty.id = event.target.value;
|
||||
this.object.difficulty.value = CONFIG.l5r5e.difficulties[this.object.difficulty.id];
|
||||
this.render(false);
|
||||
});
|
||||
|
||||
// Flat modifier
|
||||
html.find("input[name='modifier']").on("change", (event) => {
|
||||
this.object.modifier = parseInt(event.target.value) || 0;
|
||||
});
|
||||
|
||||
// Aspect point checkbox
|
||||
html.find("#use_aspect_point").on("change", (event) => {
|
||||
this.object.useAspectPoint = event.target.checked;
|
||||
this.render(false);
|
||||
});
|
||||
|
||||
// Aspect type select (solar / lunar)
|
||||
html.find("select[name='aspectType']").on("change", (event) => {
|
||||
this.object.aspectType = event.target.value;
|
||||
});
|
||||
|
||||
// Assistance checkbox
|
||||
html.find("#use_assistance").on("change", (event) => {
|
||||
this.object.useAssistance = event.target.checked;
|
||||
this.render(false);
|
||||
});
|
||||
|
||||
// Roll button — explicit submit trigger
|
||||
html.find("button[name='roll']").on("click", (event) => {
|
||||
event.preventDefault();
|
||||
this._onSubmit(event);
|
||||
});
|
||||
}
|
||||
|
||||
async _updateObject(event, formData) {
|
||||
const nbDice = this.totalDice;
|
||||
const skillRank = this.object.skill.rank;
|
||||
const skillBonus = this.object.skill.bonus;
|
||||
const flatModifier = this.object.modifier;
|
||||
const difficultyObj = this.object.difficulty;
|
||||
const difficultyValue = difficultyObj.value;
|
||||
|
||||
// Roll the dice using FoundryVTT Roll API
|
||||
const roll = await new Roll(`${nbDice}d6`).evaluate();
|
||||
const rawResults = roll.dice[0].results.map((r) => r.result);
|
||||
|
||||
// Apply parangon passive adjustments
|
||||
const adjustedResults = rawResults.map((r) => this._applyParangon(r, skillRank));
|
||||
const diceAdjustedFlags = rawResults.map((r, i) => adjustedResults[i] !== r);
|
||||
const wasAdjusted = diceAdjustedFlags.some(Boolean);
|
||||
|
||||
// Compute total
|
||||
const rawSum = adjustedResults.reduce((a, b) => a + b, 0);
|
||||
const total = rawSum + skillBonus + flatModifier;
|
||||
const success = total >= difficultyValue;
|
||||
const bonus = success ? total - difficultyValue : 0;
|
||||
|
||||
// Update aspect gauge after roll
|
||||
if (this._actor && this.object.useAspectPoint) {
|
||||
await this._updateAspectGauge();
|
||||
}
|
||||
|
||||
// Post chat message
|
||||
await this._sendChatMessage({
|
||||
nbDice,
|
||||
rawResults,
|
||||
adjustedResults,
|
||||
diceAdjustedFlags,
|
||||
wasAdjusted,
|
||||
rawSum,
|
||||
total,
|
||||
skillBonus,
|
||||
flatModifier,
|
||||
difficulty: difficultyObj,
|
||||
success,
|
||||
bonus,
|
||||
});
|
||||
|
||||
return this.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply parangon rank passive: replace low die results with higher value.
|
||||
* parangon1: 1 → 2
|
||||
* parangon2: 1–2 → 3
|
||||
* parangon3: 1–3 → 4
|
||||
* @param {number} result
|
||||
* @param {string} rank
|
||||
* @return {number}
|
||||
*/
|
||||
_applyParangon(result, rank) {
|
||||
if (rank === "parangon3" && result <= 3) return 4;
|
||||
if (rank === "parangon2" && result <= 2) return 3;
|
||||
if (rank === "parangon1" && result <= 1) return 2;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the aspect gauge on the actor after an aspect point roll.
|
||||
* Gauge positive = solar side, negative = lunar side.
|
||||
* ±5 → apply Déséquilibre. ±10 → full reset.
|
||||
*/
|
||||
async _updateAspectGauge() {
|
||||
// Support both single-nested (system.aspects) and double-nested (system.aspects.aspects)
|
||||
const aspectsPath = this._actor.system.aspects?.aspects !== undefined
|
||||
? "system.aspects.aspects"
|
||||
: "system.aspects";
|
||||
const aspects = foundry.utils.getProperty(this._actor, aspectsPath) ?? {};
|
||||
|
||||
const gaugeDirection = this.object.aspectType === "solar" ? 1 : -1;
|
||||
const newGauge = (aspects.gauge ?? 0) + gaugeDirection;
|
||||
|
||||
if (Math.abs(newGauge) >= 10) {
|
||||
// Full reset
|
||||
await this._actor.update({
|
||||
[`${aspectsPath}.gauge`]: 0,
|
||||
[`${aspectsPath}.solar`]: 0,
|
||||
[`${aspectsPath}.lunar`]: 0,
|
||||
});
|
||||
// Remove all desequilibre conditions
|
||||
const toRemove = this._actor.items
|
||||
.filter((i) => i.type === "etat" && ["desequilibre_solaire", "desequilibre_lunaire"].includes(i.system?.condition_type))
|
||||
.map((i) => i.id);
|
||||
if (toRemove.length) {
|
||||
await this._actor.deleteEmbeddedDocuments("Item", toRemove);
|
||||
}
|
||||
} else {
|
||||
await this._actor.update({ [`${aspectsPath}.gauge`]: newGauge });
|
||||
|
||||
if (Math.abs(newGauge) >= 5) {
|
||||
// Apply opposing desequilibre
|
||||
const condType = this.object.aspectType === "solar" ? "desequilibre_lunaire" : "desequilibre_solaire";
|
||||
const existing = this._actor.items.find(
|
||||
(i) => i.type === "etat" && i.system?.condition_type === condType
|
||||
);
|
||||
if (!existing) {
|
||||
await this._actor.createEmbeddedDocuments("Item", [
|
||||
{
|
||||
type: "etat",
|
||||
name: game.i18n.localize(`chiaroscuro.aspects.${condType}`),
|
||||
system: { condition_type: condType },
|
||||
},
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and send the chat message.
|
||||
*/
|
||||
async _sendChatMessage(rollData) {
|
||||
const content = await foundry.applications.handlebars.renderTemplate(
|
||||
CONFIG.l5r5e.paths.templates + "dice/chiaroscuro-chat-roll.html",
|
||||
{
|
||||
actor: this._actor,
|
||||
profileImg: this._actor?.img ?? "icons/svg/mystery-man.svg",
|
||||
ring: this.object.ring,
|
||||
skill: this.object.skill,
|
||||
difficulty: this.object.difficulty,
|
||||
useAspectPoint: this.object.useAspectPoint,
|
||||
aspectType: this.object.aspectType,
|
||||
useAssistance: this.object.useAssistance,
|
||||
modifier: this.object.modifier,
|
||||
quickInfo: this._actor?.system?.quick_info ?? "",
|
||||
...rollData,
|
||||
}
|
||||
);
|
||||
|
||||
return ChatMessage.implementation.create({
|
||||
user: game.user.id,
|
||||
speaker: {
|
||||
actor: this._actor?.id ?? null,
|
||||
alias: this._actor?.name ?? null,
|
||||
},
|
||||
content,
|
||||
sound: CONFIG.sounds.dice,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -513,6 +513,9 @@ export class DicePickerDialog extends FormApplication {
|
||||
this._updateVoidPointUsage();
|
||||
this.render(false);
|
||||
});
|
||||
|
||||
// Open journal on effect name
|
||||
html.find(".effect-name").on("click", this._openEffectJournal.bind(this));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -687,7 +690,7 @@ export class DicePickerDialog extends FormApplication {
|
||||
type: "script",
|
||||
scope: "actor",
|
||||
command,
|
||||
img: this._actor?.img || "systems/l5r5e/assets/dices/default/ring_et.svg",
|
||||
img: this._actor?.img || "systems/l5rx-chiaroscuro/assets/dices/default/ring_et.svg",
|
||||
});
|
||||
}
|
||||
|
||||
@@ -864,4 +867,34 @@ export class DicePickerDialog extends FormApplication {
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Open the core linked journal effect if exist
|
||||
* @param {Event} event
|
||||
* @private
|
||||
*/
|
||||
async _openEffectJournal(event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
const effectId = $(event.currentTarget).data("effect-id");
|
||||
if (!effectId) {
|
||||
return;
|
||||
}
|
||||
|
||||
const effect = this._actor?.effects?.get(effectId);
|
||||
if (!effect?.system?.id && !effect?.system?.uuid) {
|
||||
return;
|
||||
}
|
||||
|
||||
const journal = await game.l5r5e.HelpersL5r5e.getObjectGameOrPack({
|
||||
id: effect.system.id,
|
||||
uuid: effect.system.uuid,
|
||||
type: "JournalEntry",
|
||||
});
|
||||
if (journal) {
|
||||
// Open on the "rules" section. If non exists then it will open the first page
|
||||
journal.sheet.render(true, {pageIndex: 2});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -268,6 +268,9 @@ export class RollnKeepDialog extends FormApplication {
|
||||
], { jQuery: false });
|
||||
}
|
||||
|
||||
// Open journal on effect name
|
||||
html.find(".effect-name").on("click", this._openEffectJournal.bind(this));
|
||||
|
||||
// *** Everything below here is only needed if the sheet is editable ***
|
||||
if (!this.isEditable) {
|
||||
return;
|
||||
@@ -802,4 +805,34 @@ export class RollnKeepDialog extends FormApplication {
|
||||
// Re-enable the button
|
||||
button.attr("disabled", false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Open the core linked journal effect if exist
|
||||
* @param {Event} event
|
||||
* @private
|
||||
*/
|
||||
async _openEffectJournal(event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
const effectId = $(event.currentTarget).data("effect-id");
|
||||
if (!effectId) {
|
||||
return;
|
||||
}
|
||||
|
||||
const effect = this.roll.l5r5e?.actor?.effects?.get(effectId);
|
||||
if (!effect?.system?.id && !effect?.system?.uuid) {
|
||||
return;
|
||||
}
|
||||
|
||||
const journal = await game.l5r5e.HelpersL5r5e.getObjectGameOrPack({
|
||||
id: effect.system.id,
|
||||
uuid: effect.system.uuid,
|
||||
type: "JournalEntry",
|
||||
});
|
||||
if (journal) {
|
||||
// Open on the "rules" section. If non exists then it will open the first page
|
||||
journal.sheet.render(true, {pageIndex: 2});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,11 +73,11 @@ export class GmMonitor extends HandlebarsApplicationMixin(ApplicationV2) {
|
||||
},
|
||||
character: {
|
||||
id: "character",
|
||||
template: "systems/l5r5e/templates/" + "gm/monitor/character-view.html"
|
||||
template: "systems/l5rx-chiaroscuro/templates/" + "gm/monitor/character-view.html"
|
||||
},
|
||||
army: {
|
||||
if: "army",
|
||||
template: "systems/l5r5e/templates/" + "gm/monitor/army-view.html"
|
||||
template: "systems/l5rx-chiaroscuro/templates/" + "gm/monitor/army-view.html"
|
||||
}
|
||||
};
|
||||
|
||||
@@ -166,6 +166,15 @@ export class GmMonitor extends HandlebarsApplicationMixin(ApplicationV2) {
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// Apply global interface theme if it is set
|
||||
if (!this.options.classes.includes("themed")) {
|
||||
this.element.classList.remove("theme-light", "theme-dark");
|
||||
const {colorScheme} = game.settings.get("core", "uiConfig");
|
||||
if (colorScheme.interface) {
|
||||
this.element.classList.add("themed", `theme-${colorScheme.interface}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** @override ApplicationV2 */
|
||||
|
||||
@@ -5,10 +5,11 @@ export class GmToolbox extends HandlebarsApplicationMixin(ApplicationV2) {
|
||||
/** @override ApplicationV2 */
|
||||
static get DEFAULT_OPTIONS() { return {
|
||||
id: "l5r5e-gm-toolbox",
|
||||
classes: ["faded-ui"],
|
||||
window: {
|
||||
contentClasses: ["l5r5e", "gm-toolbox", "faded-ui"],
|
||||
contentClasses: ["l5r5e", "gm-toolbox"],
|
||||
title: "l5r5e.gm.toolbox.title",
|
||||
minimizable: true,
|
||||
minimizable: false,
|
||||
},
|
||||
position: {
|
||||
width: "auto",
|
||||
@@ -43,7 +44,7 @@ export class GmToolbox extends HandlebarsApplicationMixin(ApplicationV2) {
|
||||
static PARTS = {
|
||||
main: {
|
||||
id: "gm-tool-content",
|
||||
template: "systems/l5r5e/templates/" + "gm/gm-toolbox.html"
|
||||
template: "systems/l5rx-chiaroscuro/templates/" + "gm/gm-toolbox.html"
|
||||
}
|
||||
};
|
||||
|
||||
@@ -89,6 +90,19 @@ export class GmToolbox extends HandlebarsApplicationMixin(ApplicationV2) {
|
||||
options.position.left = 220; //x - 630;
|
||||
}
|
||||
|
||||
async _onRender(context, options) {
|
||||
await super._onRender(context, options);
|
||||
|
||||
if (this.options.classes.includes("themed")) {
|
||||
return;
|
||||
}
|
||||
this.element.classList.remove("theme-light", "theme-dark");
|
||||
const {colorScheme} = game.settings.get("core", "uiConfig");
|
||||
if (colorScheme.interface) {
|
||||
this.element.classList.add("themed", `theme-${colorScheme.interface}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The GM Toolbox should not be removed when toggling the main menu with the esc key etc.
|
||||
* @override ApplicationV2
|
||||
|
||||
@@ -64,6 +64,11 @@ export const RegisterHandlebars = function () {
|
||||
return objects.join("");
|
||||
});
|
||||
|
||||
// Chiaroscuro: return the flat bonus for a given skill rank id
|
||||
Handlebars.registerHelper("skillRankBonus", (rankId) => {
|
||||
return CONFIG.l5r5e.skillRanks?.[rankId]?.bonus ?? 0;
|
||||
});
|
||||
|
||||
// Add a setter
|
||||
Handlebars.registerHelper("setVar", function (varName, varValue, options) {
|
||||
options.data.root[varName] = varValue;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { L5r5eHtmlMultiSelectElement } from "./misc/l5r5e-multiselect.js";
|
||||
import { ItemCompendiumL5r5e } from "./compendium/l5r5e-item-compendium.js"
|
||||
|
||||
export default class HooksL5r5e {
|
||||
/**
|
||||
@@ -26,6 +26,8 @@ export default class HooksL5r5e {
|
||||
) {
|
||||
game.babele.setSystemTranslationsDir("babele"); // Since Babele v2.0.7
|
||||
}
|
||||
|
||||
ItemCompendiumL5r5e.applyToPacks();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -245,236 +247,6 @@ export default class HooksL5r5e {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Compendium display (Add filters)
|
||||
*/
|
||||
static async renderCompendium(app, html, data) {
|
||||
html = $(html); // basic patch for v13
|
||||
|
||||
if (app.collection.documentName === "Item") {
|
||||
const content = await app.collection.getDocuments();
|
||||
const sourcesInThisCompendium = new Set([]);
|
||||
const filtersToShow = {
|
||||
rank: false,
|
||||
rarity: false,
|
||||
source: false,
|
||||
ring: false,
|
||||
};
|
||||
// Used to auto hide same values for a full compendium
|
||||
const previousValue = {
|
||||
rank: null,
|
||||
rarity: null,
|
||||
source: null,
|
||||
ring: null,
|
||||
};
|
||||
|
||||
// Cache
|
||||
const header = html.find(".directory-header");
|
||||
const entries = html.find(".directory-item");
|
||||
|
||||
// Add additional data to the entries to make it faster to lookup.
|
||||
// Add Ring/rank/rarity information
|
||||
for (const document of content) {
|
||||
const entry = entries.filter(`[data-entry-id="${document.id}"]`);
|
||||
|
||||
// Hide filter if only one value of this type is found in the compendium
|
||||
const autoDisplayFilter = (props, documentData = null) => {
|
||||
documentData ??= document.system[props];
|
||||
|
||||
if (filtersToShow[props] || previousValue[props] === documentData) {
|
||||
return;
|
||||
}
|
||||
filtersToShow[props] = previousValue[props] !== null && previousValue[props] !== documentData;
|
||||
previousValue[props] = documentData;
|
||||
};
|
||||
|
||||
if (document.system?.rank) {
|
||||
autoDisplayFilter('rank');
|
||||
entry.data("rank", document.system.rank);
|
||||
}
|
||||
|
||||
if (document.system?.source_reference.source) {
|
||||
autoDisplayFilter('source', document.system.source_reference.source);
|
||||
sourcesInThisCompendium.add(document.system.source_reference.source);
|
||||
entry.data("source", document.system.source_reference);
|
||||
}
|
||||
|
||||
if (document.system?.ring) {
|
||||
autoDisplayFilter('ring');
|
||||
entry.data("ring", document.system.ring);
|
||||
}
|
||||
|
||||
if (document.system?.rarity) {
|
||||
autoDisplayFilter('rarity');
|
||||
entry.data("rarity", document.system.rarity);
|
||||
}
|
||||
|
||||
// Add ring/rank/rarity information on the item in the compendium view
|
||||
if (document.system?.ring || document.system?.rarity || document.system?.rank) {
|
||||
const ringRarityRank = await foundry.applications.handlebars.renderTemplate(`${CONFIG.l5r5e.paths.templates}compendium/ring-rarity-rank.html`, document.system);
|
||||
entry.append(ringRarityRank);
|
||||
}
|
||||
}
|
||||
|
||||
// Setup filters
|
||||
const officialContentSet = game.settings.get(CONFIG.l5r5e.namespace, "compendium-official-content-for-players");
|
||||
const unofficialContentSet = game.settings.get(CONFIG.l5r5e.namespace, "compendium-unofficial-content-for-players");
|
||||
const allCompendiumReferencesSet = game.settings.get(CONFIG.l5r5e.namespace, "all-compendium-references")
|
||||
const hideEmptySourcesFromPlayers = game.settings.get(CONFIG.l5r5e.namespace, "compendium-hide-empty-sources-from-players");
|
||||
|
||||
const unavailableSourceForPlayersSet = new Set([...allCompendiumReferencesSet].filter((element) => {
|
||||
if (CONFIG.l5r5e.sourceReference[element]) {
|
||||
return officialContentSet.size > 0 ? !officialContentSet.has(element) : false;
|
||||
}
|
||||
return unofficialContentSet.size > 0 ? !unofficialContentSet.has(element) : false;
|
||||
}));
|
||||
|
||||
// Create filter function
|
||||
const applyCompendiumFilter = () => {
|
||||
const userFilter = header.find("l5r5e-multi-select").val();
|
||||
const rankFilter = header.find(".rank-filter .selected").data("rank");
|
||||
const ringFilter = header.find(".ring-filter .selected").data("ring");
|
||||
const rarityFilter = header.find(".rarity-filter .selected").data("rarity");
|
||||
|
||||
entries.each(function () {
|
||||
const lineSource = $(this).data("source")?.source;
|
||||
|
||||
// We might have stuff in the compendium view that does not have a source (folders etc.) Ignore those.
|
||||
if (lineSource === null || lineSource === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
let shouldShow = true;
|
||||
|
||||
// Handle unavailable sources
|
||||
if (unavailableSourceForPlayersSet.has(lineSource)) {
|
||||
if (game.user.isGM) {
|
||||
shouldShow &= true;
|
||||
$(this)
|
||||
.addClass("not-for-players")
|
||||
.attr("data-tooltip", game.i18n.localize("l5r5e.compendium.not_for_players"));
|
||||
} else {
|
||||
shouldShow &= false;
|
||||
}
|
||||
}
|
||||
|
||||
// Handle empty sources
|
||||
if (lineSource === "" && hideEmptySourcesFromPlayers) {
|
||||
if (game.user.isGM) {
|
||||
shouldShow &= true;
|
||||
$(this)
|
||||
.addClass("not-for-players")
|
||||
.attr("data-tooltip", game.i18n.localize("l5r5e.compendium.not_for_players"));
|
||||
} else {
|
||||
shouldShow &= false;
|
||||
}
|
||||
}
|
||||
|
||||
// Apply filters
|
||||
if (rankFilter) {
|
||||
shouldShow &= $(this).data("rank") == rankFilter;
|
||||
}
|
||||
if (userFilter?.length) {
|
||||
shouldShow &= userFilter.includes(lineSource);
|
||||
}
|
||||
if (ringFilter) {
|
||||
shouldShow &= $(this).data("ring") == ringFilter;
|
||||
}
|
||||
if (rarityFilter >= 0) {
|
||||
shouldShow &= $(this).data("rarity") == rarityFilter;
|
||||
}
|
||||
|
||||
// Show or hide this entry based on the result
|
||||
shouldShow ? $(this).show() : $(this).hide();
|
||||
});
|
||||
};
|
||||
|
||||
// Filter setup
|
||||
const addFilter = async (filterType, templateFile, templateData) => {
|
||||
if (!filtersToShow[filterType]) {
|
||||
return;
|
||||
}
|
||||
const filterTemplate = await foundry.applications.handlebars.renderTemplate(
|
||||
`${CONFIG.l5r5e.paths.templates}compendium/${templateFile}.html`,
|
||||
templateData
|
||||
);
|
||||
header.append(filterTemplate);
|
||||
|
||||
header.find(`.${filterType}-filter`).children().each(function () {
|
||||
$(this).on("click", (event) => {
|
||||
const selected = $(event.target).hasClass("selected");
|
||||
header.find(`.${filterType}-filter`).children().removeClass("selected");
|
||||
$(event.target).toggleClass("selected", !selected);
|
||||
applyCompendiumFilter();
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
// Add Rank, Rarity, Ring Filters
|
||||
await Promise.all([
|
||||
addFilter('rank' , 'rank-filter', { type: "rank", number: [1, 2, 3, 4, 5] }),
|
||||
addFilter('rarity', 'rank-filter', { type: "rarity", number: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] }),
|
||||
addFilter('ring' , 'ring-filter', {}),
|
||||
]);
|
||||
|
||||
if (filtersToShow.source) {
|
||||
// Build the source select
|
||||
const selectableSourcesArray = [...allCompendiumReferencesSet].map((reference) => ({
|
||||
value: reference,
|
||||
label: CONFIG.l5r5e.sourceReference[reference]?.label ?? reference,
|
||||
translate: true,
|
||||
group: CONFIG.l5r5e.sourceReference[reference]?.type.split(",")[0] ?? "l5r5e.multiselect.sources_categories.others",
|
||||
disabled: !sourcesInThisCompendium.has(reference) || (!game.user.isGM && unavailableSourceForPlayersSet.has(reference))
|
||||
}));
|
||||
const filterSourcesBox = L5r5eHtmlMultiSelectElement.create({
|
||||
name: "filter-sources",
|
||||
options: selectableSourcesArray,
|
||||
localize: true,
|
||||
});
|
||||
header.append(filterSourcesBox.outerHTML);
|
||||
$("l5r5e-multi-select").on("change", applyCompendiumFilter);
|
||||
|
||||
// If gm add an extra button to easily filter the content to see the same stuff as a player
|
||||
if (game.user.isGM && unavailableSourceForPlayersSet.size > 0) {
|
||||
const buttonHTML = `<button type="button" class="gm" data-tooltip="${game.i18n.localize('l5r5e.multiselect.player_filter_tooltip')}">`
|
||||
+ game.i18n.localize('l5r5e.multiselect.player_filter_label')
|
||||
+ '</button>'
|
||||
|
||||
const filterPlayerViewArray = [...allCompendiumReferencesSet]
|
||||
.filter((item) => !unavailableSourceForPlayersSet.has(item))
|
||||
.filter((item) => sourcesInThisCompendium.has(item));
|
||||
|
||||
$(buttonHTML).appendTo($(header).find("l5r5e-multi-select")).click(function() {
|
||||
header.find("l5r5e-multi-select")[0].value = filterPlayerViewArray;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: This delay is a workaround and should be addressed in another way.
|
||||
// This is ugly but if we hide the content too early then it won't be hidden for some reason.
|
||||
// Current guess is that the foundry search filter is doing something.
|
||||
// Adding a delay here so that we hide the content. This will fail on slow computers/network...
|
||||
setTimeout(() => {
|
||||
applyCompendiumFilter();
|
||||
}, 250);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static updateCompendium(pack, documents, options, userId) {
|
||||
documents.forEach((document) => {
|
||||
const inc_reference = document?.system?.source_reference?.source?.trim();
|
||||
if (!!inc_reference) {
|
||||
const references = game.settings.get(CONFIG.l5r5e.namespace, "all-compendium-references");
|
||||
if (!references.includes(inc_reference)) {
|
||||
references.push(inc_reference);
|
||||
game.settings.set(CONFIG.l5r5e.namespace, "all-compendium-references", references);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* DiceSoNice - Add L5R DicePresets
|
||||
*/
|
||||
|
||||
@@ -90,12 +90,12 @@ export class AdvancementSheetL5r5e extends ItemSheetL5r5e {
|
||||
// Modify image to reflect choice
|
||||
if (newChoice.ring) {
|
||||
name = game.i18n.localize(`l5r5e.rings.${newChoice.ring}`) + "+1";
|
||||
img = `systems/l5r5e/assets/icons/rings/${newChoice.ring}.svg`;
|
||||
img = `systems/l5rx-chiaroscuro/assets/icons/rings/${newChoice.ring}.svg`;
|
||||
} else if (newChoice.skill) {
|
||||
name =
|
||||
game.i18n.localize(`l5r5e.skills.${CONFIG.l5r5e.skills.get(newChoice.skill)}.${newChoice.skill}`) +
|
||||
"+1";
|
||||
img = `systems/l5r5e/assets/dices/default/skill_blank.svg`;
|
||||
img = `systems/l5rx-chiaroscuro/assets/dices/default/skill_blank.svg`;
|
||||
}
|
||||
|
||||
// Object embed in actor ?
|
||||
|
||||
44
system/scripts/items/arcane-sheet.js
Normal file
44
system/scripts/items/arcane-sheet.js
Normal file
@@ -0,0 +1,44 @@
|
||||
import { BaseItemSheetL5r5e } from "./base-item-sheet.js";
|
||||
|
||||
/**
|
||||
* Sheet for Arcane items (Chiaroscuro).
|
||||
* @extends {BaseItemSheetL5r5e}
|
||||
*/
|
||||
export class ArcaneSheetL5r5e extends BaseItemSheetL5r5e {
|
||||
/** @override */
|
||||
static get defaultOptions() {
|
||||
return foundry.utils.mergeObject(super.defaultOptions, {
|
||||
classes: ["l5r5e", "sheet", "arcane"],
|
||||
template: CONFIG.l5r5e.paths.templates + "items/arcane/arcane-sheet.html",
|
||||
tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "attributes" }],
|
||||
});
|
||||
}
|
||||
|
||||
/** @override */
|
||||
async getData(options = {}) {
|
||||
const sheetData = await super.getData(options);
|
||||
|
||||
// Convert application array to comma-separated string for display
|
||||
const app = sheetData.data.system.application;
|
||||
sheetData.data.system.applicationDisplay = Array.isArray(app) ? app.join(", ") : (app ?? "");
|
||||
|
||||
sheetData.data.enrichedHtml = {
|
||||
description: await foundry.applications.ux.TextEditor.implementation.enrichHTML(
|
||||
sheetData.data.system.description ?? "",
|
||||
{ async: true }
|
||||
),
|
||||
};
|
||||
|
||||
return sheetData;
|
||||
}
|
||||
|
||||
/** @override */
|
||||
async _updateObject(event, formData) {
|
||||
// Convert comma-separated application string back to array
|
||||
const raw = formData["system.applicationDisplay"] ?? "";
|
||||
formData["system.application"] = raw.split(",").map((s) => s.trim()).filter(Boolean);
|
||||
delete formData["system.applicationDisplay"];
|
||||
|
||||
return super._updateObject(event, formData);
|
||||
}
|
||||
}
|
||||
@@ -11,4 +11,16 @@ export class ArmorSheetL5r5e extends ItemSheetL5r5e {
|
||||
template: CONFIG.l5r5e.paths.templates + "items/armor/armor-sheet.html",
|
||||
});
|
||||
}
|
||||
|
||||
/** @override */
|
||||
async getData(options = {}) {
|
||||
const sheetData = await super.getData(options);
|
||||
|
||||
const catObj = game.l5r5e.HelpersL5r5e.getLocalizedRawObject("chiaroscuro.armor.categories") ?? {};
|
||||
sheetData.data.armorCategories = Object.entries(catObj)
|
||||
.filter(([k]) => k !== "label")
|
||||
.map(([id, label]) => ({ id, label }));
|
||||
|
||||
return sheetData;
|
||||
}
|
||||
}
|
||||
|
||||
30
system/scripts/items/etat-sheet.js
Normal file
30
system/scripts/items/etat-sheet.js
Normal file
@@ -0,0 +1,30 @@
|
||||
import { BaseItemSheetL5r5e } from "./base-item-sheet.js";
|
||||
|
||||
/**
|
||||
* Sheet for État items (Chiaroscuro).
|
||||
* @extends {BaseItemSheetL5r5e}
|
||||
*/
|
||||
export class EtatSheetL5r5e extends BaseItemSheetL5r5e {
|
||||
/** @override */
|
||||
static get defaultOptions() {
|
||||
return foundry.utils.mergeObject(super.defaultOptions, {
|
||||
classes: ["l5r5e", "sheet", "etat"],
|
||||
template: CONFIG.l5r5e.paths.templates + "items/etat/etat-sheet.html",
|
||||
tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "attributes" }],
|
||||
});
|
||||
}
|
||||
|
||||
/** @override */
|
||||
async getData(options = {}) {
|
||||
const sheetData = await super.getData(options);
|
||||
|
||||
sheetData.data.enrichedHtml = {
|
||||
description: await foundry.applications.ux.TextEditor.implementation.enrichHTML(
|
||||
sheetData.data.system.description ?? "",
|
||||
{ async: true }
|
||||
),
|
||||
};
|
||||
|
||||
return sheetData;
|
||||
}
|
||||
}
|
||||
@@ -50,7 +50,7 @@ export class ItemSheetL5r5e extends BaseItemSheetL5r5e {
|
||||
id: property.id,
|
||||
name: property.name,
|
||||
type: "property",
|
||||
img: "systems/l5r5e/assets/icons/items/property.svg",
|
||||
img: "systems/l5rx-chiaroscuro/assets/icons/items/property.svg",
|
||||
removed: true,
|
||||
};
|
||||
}));
|
||||
|
||||
35
system/scripts/items/mystere-sheet.js
Normal file
35
system/scripts/items/mystere-sheet.js
Normal file
@@ -0,0 +1,35 @@
|
||||
import { BaseItemSheetL5r5e } from "./base-item-sheet.js";
|
||||
|
||||
/**
|
||||
* Sheet for Mystère items (Chiaroscuro).
|
||||
* @extends {BaseItemSheetL5r5e}
|
||||
*/
|
||||
export class MystereSheetL5r5e extends BaseItemSheetL5r5e {
|
||||
/** @override */
|
||||
static get defaultOptions() {
|
||||
return foundry.utils.mergeObject(super.defaultOptions, {
|
||||
classes: ["l5r5e", "sheet", "mystere"],
|
||||
template: CONFIG.l5r5e.paths.templates + "items/mystere/mystere-sheet.html",
|
||||
tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "attributes" }],
|
||||
});
|
||||
}
|
||||
|
||||
/** @override */
|
||||
async getData(options = {}) {
|
||||
const sheetData = await super.getData(options);
|
||||
|
||||
sheetData.data.mystereTypes = [
|
||||
{ id: "mineur", label: game.i18n.localize("chiaroscuro.mystere.mineur") },
|
||||
{ id: "majeur", label: game.i18n.localize("chiaroscuro.mystere.majeur") },
|
||||
];
|
||||
|
||||
sheetData.data.enrichedHtml = {
|
||||
description: await foundry.applications.ux.TextEditor.implementation.enrichHTML(
|
||||
sheetData.data.system.description ?? "",
|
||||
{ async: true }
|
||||
),
|
||||
};
|
||||
|
||||
return sheetData;
|
||||
}
|
||||
}
|
||||
@@ -17,12 +17,27 @@ export class TechniqueSheetL5r5e extends ItemSheetL5r5e {
|
||||
const sheetData = await super.getData(options);
|
||||
|
||||
// List all available techniques type
|
||||
const types = ["core", "school", "title"];
|
||||
const types = ["core", "school", "title", "chiaroscuro"];
|
||||
if (game.settings.get(CONFIG.l5r5e.namespace, "techniques-customs")) {
|
||||
types.push("custom");
|
||||
}
|
||||
sheetData.data.techniquesList = game.l5r5e.HelpersL5r5e.getTechniquesList({ types });
|
||||
|
||||
// Invocation sub-type fields (visible only for mot_invocation)
|
||||
sheetData.data.isMotInvocation = sheetData.data.system.technique_type === "mot_invocation";
|
||||
sheetData.data.invocationTypes = [
|
||||
{ id: "general", label: game.i18n.localize("chiaroscuro.technique.invocation_types.general") },
|
||||
{ id: "neutre", label: game.i18n.localize("chiaroscuro.technique.invocation_types.neutre") },
|
||||
{ id: "precis", label: game.i18n.localize("chiaroscuro.technique.invocation_types.precis") },
|
||||
];
|
||||
sheetData.data.modeInvocationValues = [
|
||||
{ id: "-3", label: "-3" },
|
||||
{ id: "0", label: "0" },
|
||||
{ id: "3", label: "+3" },
|
||||
];
|
||||
// Convert mode_invocation to string for selectOptions matching
|
||||
sheetData.data.system.mode_invocation_str = String(sheetData.data.system.mode_invocation ?? 0);
|
||||
|
||||
// Sanitize Difficulty and Skill list
|
||||
sheetData.data.system.difficulty = TechniqueSheetL5r5e.formatDifficulty(sheetData.data.system.difficulty);
|
||||
sheetData.data.system.skill = TechniqueSheetL5r5e.translateSkillsList(
|
||||
@@ -55,6 +70,12 @@ export class TechniqueSheetL5r5e extends ItemSheetL5r5e {
|
||||
TechniqueSheetL5r5e.translateSkillsList(formData["system.skill"].split(","), true)
|
||||
).join(",");
|
||||
|
||||
// Convert mode_invocation_str back to number
|
||||
if ("system.mode_invocation_str" in formData) {
|
||||
formData["system.mode_invocation"] = parseInt(formData["system.mode_invocation_str"] ?? "0", 10);
|
||||
delete formData["system.mode_invocation_str"];
|
||||
}
|
||||
|
||||
return super._updateObject(event, formData);
|
||||
}
|
||||
|
||||
|
||||
@@ -23,6 +23,12 @@ export class WeaponSheetL5r5e extends ItemSheetL5r5e {
|
||||
label: "l5r5e.skills." + cat.toLowerCase() + "." + id.toLowerCase(),
|
||||
}));
|
||||
|
||||
// Weapon categories (Chiaroscuro)
|
||||
const catObj = game.l5r5e.HelpersL5r5e.getLocalizedRawObject("chiaroscuro.weapon.categories") ?? {};
|
||||
sheetData.data.weaponCategories = [{ id: "", label: "—" }].concat(
|
||||
Object.entries(catObj).map(([id, label]) => ({ id, label }))
|
||||
);
|
||||
|
||||
return sheetData;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ import { RingDie } from "./dice/dietype/ring-die.js";
|
||||
import { RollL5r5e } from "./dice/roll.js";
|
||||
import { DicePickerDialog } from "./dice/dice-picker-dialog.js";
|
||||
import { RollnKeepDialog } from "./dice/roll-n-keep-dialog.js";
|
||||
import { ChiaroscuroDiceDialog } from "./dice/chiaroscuro-dice-dialog.js";
|
||||
import { CombatL5r5e } from "./combat.js";
|
||||
// Items
|
||||
import { ItemL5r5e } from "./item.js";
|
||||
@@ -33,11 +34,16 @@ import { TitleSheetL5r5e } from "./items/title-sheet.js";
|
||||
import { BondSheetL5r5e } from "./items/bond-sheet.js";
|
||||
import { SignatureScrollSheetL5r5e } from "./items/signature-scroll-sheet.js";
|
||||
import { ItemPatternSheetL5r5e } from "./items/item-pattern-sheet.js";
|
||||
import { ArcaneSheetL5r5e } from "./items/arcane-sheet.js";
|
||||
import { EtatSheetL5r5e } from "./items/etat-sheet.js";
|
||||
import { MystereSheetL5r5e } from "./items/mystere-sheet.js";
|
||||
import { ArmyCohortSheetL5r5e } from "./items/army-cohort-sheet.js";
|
||||
import { ArmyFortificationSheetL5r5e } from "./items/army-fortification-sheet.js";
|
||||
// JournalEntry
|
||||
import { JournalL5r5e } from "./journal.js";
|
||||
import { BaseJournalSheetL5r5e } from "./journals/base-journal-sheet.js";
|
||||
// Compendium
|
||||
import { CompendiumDirectoryL5r5e } from "./compendium/l5r5e-compendium-directory.js";
|
||||
// Specific
|
||||
import { MigrationL5r5e } from "./migration.js";
|
||||
import { GmToolbox } from "./gm/gm-toolbox.js";
|
||||
@@ -45,8 +51,10 @@ import { GmMonitor } from "./gm/gm-monitor.js";
|
||||
import { Storage } from "./storage.js";
|
||||
// Misc
|
||||
import { L5r5eHtmlMultiSelectElement } from "./misc/l5r5e-multiselect.js";
|
||||
import { L5R5eHtmlComboBoxElement } from "./misc/l5r5e-combo-box.js";
|
||||
|
||||
window.customElements.define(L5r5eHtmlMultiSelectElement.tagName, L5r5eHtmlMultiSelectElement);
|
||||
window.customElements.define(L5R5eHtmlComboBoxElement.tagName, L5R5eHtmlComboBoxElement);
|
||||
|
||||
/* ------------------------------------ */
|
||||
/* Initialize system */
|
||||
@@ -66,6 +74,23 @@ Hooks.once("init", async () => {
|
||||
// Global access to L5R Config
|
||||
CONFIG.l5r5e = L5R5E;
|
||||
|
||||
// Setting up sidebar icons
|
||||
CONFIG.ChatMessage.sidebarIcon = "l5r5e chatIcon";
|
||||
CONFIG.Combat.sidebarIcon = "l5r5e combatIcon";
|
||||
CONFIG.Scene.sidebarIcon = "l5r5e sceneIcon";
|
||||
CONFIG.Actor.sidebarIcon = "l5r5e actorIcon";
|
||||
CONFIG.Item.sidebarIcon = "l5r5e itemIcon";
|
||||
CONFIG.JournalEntry.sidebarIcon = "l5r5e journalIcon";
|
||||
CONFIG.RollTable.sidebarIcon = "l5r5e rolltableIcon";
|
||||
CONFIG.Playlist.sidebarIcon = "l5r5e playlistIcon";
|
||||
// Note: We don't have any custom icons here so just append l5r5e and type
|
||||
CONFIG.Cards.sidebarIcon += " l5r5e cardsIcon";
|
||||
CONFIG.Macro.sidebarIcon += " l5r5e macroIcon";
|
||||
|
||||
// The compendium and the settings menu is registered a little different.
|
||||
foundry.applications.sidebar.Sidebar.TABS.compendium.icon = "l5r5e compendiumIcon";
|
||||
foundry.applications.sidebar.Sidebar.TABS.settings.icon = "l5r5e settingsIcon";
|
||||
|
||||
// Assign custom classes and constants here
|
||||
CONFIG.Combat.documentClass = CombatL5r5e;
|
||||
CONFIG.Actor.documentClass = ActorL5r5e;
|
||||
@@ -76,6 +101,8 @@ Hooks.once("init", async () => {
|
||||
CONFIG.Token.rulerClass = TokenRulerL5r5e;
|
||||
CONFIG.Canvas.rulerClass = RulerL5r5e;
|
||||
|
||||
CONFIG.ui.compendium = CompendiumDirectoryL5r5e;
|
||||
|
||||
// Define custom Roll class
|
||||
CONFIG.Dice.rolls.unshift(RollL5r5e);
|
||||
|
||||
@@ -95,6 +122,7 @@ Hooks.once("init", async () => {
|
||||
ActorL5r5e,
|
||||
DicePickerDialog,
|
||||
RollnKeepDialog,
|
||||
ChiaroscuroDiceDialog,
|
||||
GmToolbox,
|
||||
GmMonitor,
|
||||
storage: new Storage(),
|
||||
@@ -200,6 +228,21 @@ Hooks.once("init", async () => {
|
||||
label: "TYPES.Item.army_fortification",
|
||||
makeDefault: true,
|
||||
});
|
||||
fdc.Items.registerSheet(L5R5E.namespace, ArcaneSheetL5r5e, {
|
||||
types: ["arcane"],
|
||||
label: "TYPES.Item.arcane",
|
||||
makeDefault: true,
|
||||
});
|
||||
fdc.Items.registerSheet(L5R5E.namespace, EtatSheetL5r5e, {
|
||||
types: ["etat"],
|
||||
label: "TYPES.Item.etat",
|
||||
makeDefault: true,
|
||||
});
|
||||
fdc.Items.registerSheet(L5R5E.namespace, MystereSheetL5r5e, {
|
||||
types: ["mystere"],
|
||||
label: "TYPES.Item.mystere",
|
||||
makeDefault: true,
|
||||
});
|
||||
|
||||
// Journal
|
||||
fdc.Journal.unregisterSheet("core", fav1s.JournalSheet);
|
||||
@@ -265,6 +308,4 @@ Hooks.on("renderSidebarTab", (app, html, data) => HooksL5r5e.renderSidebarTab(ap
|
||||
Hooks.on("activateSettings", async (app)=> HooksL5r5e.activateSettings(app));
|
||||
Hooks.on("renderChatMessageHTML", (message, html, data) => HooksL5r5e.renderChatMessage(message, html, data));
|
||||
Hooks.on("renderCombatTracker", (app, html, data) => HooksL5r5e.renderCombatTracker(app, html, data));
|
||||
Hooks.on("renderCompendium", async (app, html, data) => HooksL5r5e.renderCompendium(app, html, data));
|
||||
Hooks.on("diceSoNiceRollStart", (messageId, context) => HooksL5r5e.diceSoNiceRollStart(messageId, context));
|
||||
Hooks.on("updateCompendium", (pack, documents, options, userId) => HooksL5r5e.updateCompendium(pack, documents, options, userId));
|
||||
|
||||
@@ -309,6 +309,29 @@ export class MigrationL5r5e {
|
||||
}
|
||||
// ***** End of 1.3.0 *****
|
||||
|
||||
// ***** Start of 2.0.0 (Chiaroscuro) *****
|
||||
if (options?.force || MigrationL5r5e.needUpdate("2.0.0")) {
|
||||
// Migrate character skill ranks from numeric (1-5) to Chiaroscuro string enum.
|
||||
// Rank 0 (unranked) stays as the number 0 — this is intentional: the template
|
||||
// defaults to 0 (number) and JS coerces it correctly when keying into skillRanks.
|
||||
if (actor.type === "character" && system.skills) {
|
||||
const rankMap = { 1: "initie", 2: "expert", 3: "maitre", 4: "parangon1", 5: "parangon2" };
|
||||
const groups = ["artisan", "martial", "scholar", "social", "trade"];
|
||||
for (const group of groups) {
|
||||
const groupSkills = system.skills[group];
|
||||
if (!groupSkills) continue;
|
||||
for (const [skillName, rank] of Object.entries(groupSkills)) {
|
||||
const numRank = Number(rank);
|
||||
// Only migrate non-zero numeric ranks; 0 is already valid as-is
|
||||
if (numRank > 0 && rankMap[numRank]) {
|
||||
updateData[`system.skills.${group}.${skillName}`] = rankMap[numRank];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// ***** End of 2.0.0 (Chiaroscuro) *****
|
||||
|
||||
return updateData;
|
||||
}
|
||||
|
||||
|
||||
257
system/scripts/misc/l5r5e-combo-box.js
Normal file
257
system/scripts/misc/l5r5e-combo-box.js
Normal file
@@ -0,0 +1,257 @@
|
||||
import { DropdownMixin } from "./l5r5e-dropdown-mixin.js";
|
||||
|
||||
const { AbstractFormInputElement } = foundry.applications.elements;
|
||||
|
||||
/**
|
||||
* A custom `<l5r5e-combo-box>` combining a free-text input with a filterable option dropdown.
|
||||
*
|
||||
* Stores a **single string value** — either a predefined option's `value` attribute, or
|
||||
* whatever the user typed freely. Use this when a field holds exactly one value, whether
|
||||
* chosen from a list or entered manually (e.g. a weapon name, a title, a custom skill).
|
||||
* For storing multiple values from a list, use {@link L5r5eHtmlMultiSelectElement} instead.
|
||||
*
|
||||
* Picking a predefined option stores its `value` attribute while displaying its human-readable
|
||||
* label. Free-typing stores the typed string as both value and label. Fires `input` on every
|
||||
* keystroke and `change` only on commit (blur or Enter) to avoid triggering sheet re-renders
|
||||
* mid-typing. Picking from the dropdown fires both `input` and `change` immediately.
|
||||
*
|
||||
* Use `{{selectOptions}}` without `selected=` to render the available options, and set the
|
||||
* current value via the `value` attribute on the element directly.
|
||||
*
|
||||
* @example
|
||||
* ```hbs
|
||||
* {{!-- Pass current value via the element's `value` attribute, not selectOptions selected= --}}
|
||||
* <l5r5e-combo-box name="weapon" value="{{data.weapon}}">
|
||||
* {{selectOptions choices localize=true}}
|
||||
* </l5r5e-combo-box>
|
||||
* ```
|
||||
*
|
||||
* @example
|
||||
* // Programmatic update — query the element by its name attribute, then set value directly.
|
||||
* // The visible input label updates automatically to match the selected option's label.
|
||||
* const el = document.querySelector("l5r5e-combo-box[name='weapon']");
|
||||
* el.value = "axe"; // input shows "Battleaxe", el.value returns "axe"
|
||||
*
|
||||
* // Free-text entry (no matching option) — value and label are both set to the typed string:
|
||||
* el.value = "naginata"; // input shows "naginata", el.value returns "naginata"
|
||||
*/
|
||||
export class L5R5eHtmlComboBoxElement extends DropdownMixin(
|
||||
AbstractFormInputElement,
|
||||
{ multiSelect: false, debounceMs: 150, clearOnClose: false }
|
||||
) {
|
||||
/**
|
||||
* The label currently shown in the text input. Differs from `_value` when a predefined
|
||||
* option is selected (value = option's value attribute, label = option's display text).
|
||||
* @type {string}
|
||||
*/
|
||||
_label = "";
|
||||
|
||||
/** @override */
|
||||
static tagName = "l5r5e-combo-box";
|
||||
|
||||
/** @override */
|
||||
static observedAttributes = ["disabled", "placeholder", "value"];
|
||||
|
||||
/**
|
||||
* Flat descriptor list built once in _initialize(), mirrors the light-DOM options.
|
||||
* @type {{ value: string, label: string, group: string|null }[]}
|
||||
*/
|
||||
#options = [];
|
||||
|
||||
/**
|
||||
* Value snapshot taken when the input receives focus.
|
||||
* Used by the blur handler to decide whether to fire a change event.
|
||||
* @type {string}
|
||||
*/
|
||||
#valueAtFocus = "";
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/* Accessors */
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/** @override */
|
||||
get value() {
|
||||
return this._value ?? "";
|
||||
}
|
||||
|
||||
set value(value) {
|
||||
const match = this.#options.find(option => option.value === String(value ?? ""));
|
||||
if (match) {
|
||||
this._value = match.value;
|
||||
this._label = match.label;
|
||||
}
|
||||
else {
|
||||
this._value = String(value ?? "");
|
||||
this._label = this._value;
|
||||
}
|
||||
this._internals.setFormValue(this._value);
|
||||
if (this._dropdownInput) {
|
||||
this._dropdownInput.value = this._label;
|
||||
}
|
||||
this.dispatchEvent(new Event("input", { bubbles: true, cancelable: true }));
|
||||
this.dispatchEvent(new Event("change", { bubbles: true, cancelable: true }));
|
||||
}
|
||||
|
||||
/**
|
||||
* AbstractFormInputElement does not have an _initialize() hook, so we override
|
||||
* connectedCallback to snapshot options from the light DOM before _buildElements()
|
||||
* is called by super.connectedCallback().
|
||||
*
|
||||
* We keep this minimal: just build the flat #options list so _getDropdownOptions()
|
||||
* and the value setter can look options up by value.
|
||||
* @override
|
||||
*/
|
||||
connectedCallback() {
|
||||
this.#snapshotOptions();
|
||||
this.#resolveInitialValue();
|
||||
super.connectedCallback();
|
||||
}
|
||||
|
||||
#snapshotOptions() {
|
||||
const makeOption = (option, group = null) => ({
|
||||
value: option.value,
|
||||
label: option.innerText,
|
||||
group,
|
||||
});
|
||||
|
||||
this.#options = [...this.children].flatMap(child => {
|
||||
if (child instanceof HTMLOptGroupElement) {
|
||||
return [...child.querySelectorAll("option")]
|
||||
.filter(option => option.value)
|
||||
.map(option => makeOption(option, child.label));
|
||||
}
|
||||
if (child instanceof HTMLOptionElement && child.value) {
|
||||
return makeOption(child);
|
||||
}
|
||||
return [];
|
||||
});
|
||||
}
|
||||
|
||||
#resolveInitialValue() {
|
||||
// Honour a `value` attribute if set, otherwise find a selected option.
|
||||
const attrValue = this.getAttribute("value");
|
||||
const initial = attrValue ?? this.#options.find(option => option.selected)?.value ?? "";
|
||||
const match = this.#options.find(option => option.value === initial);
|
||||
if (match) {
|
||||
this._value = match.value;
|
||||
this._label = match.label;
|
||||
} else {
|
||||
this._value = initial;
|
||||
this._label = initial;
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/* Element Lifecycle */
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/** @override */
|
||||
_buildElements() {
|
||||
const wrapper = this._buildDropdownElements({
|
||||
placeholder: this.getAttribute("placeholder") ?? "",
|
||||
});
|
||||
|
||||
this._dropdownInput.value = this._label || this._value || "";
|
||||
this._primaryInput = this._dropdownInput;
|
||||
|
||||
return [wrapper];
|
||||
}
|
||||
|
||||
/** @override */
|
||||
_activateListeners() {
|
||||
const signal = this.abortSignal;
|
||||
this._activateDropdownListeners();
|
||||
|
||||
// Prevent the inner <input>'s own native change from reaching Foundry's form handler.
|
||||
// We dispatch our own change at commit time only (see below).
|
||||
this._dropdownInput.addEventListener("change", (e) => e.stopPropagation(), { signal });
|
||||
|
||||
// Free typing: update value and fire `input` immediately.
|
||||
// Do NOT fire `change` here — Foundry's form handler re-renders the sheet on
|
||||
// every `change` event, which would destroy the element mid-typing.
|
||||
// `change` is fired at commit time: on blur (if value changed) or Enter.
|
||||
this._dropdownInput.addEventListener("input", () => {
|
||||
const typed = this._dropdownInput.value;
|
||||
this._label = typed;
|
||||
this._value = typed;
|
||||
this._internals.setFormValue(typed);
|
||||
this.dispatchEvent(new Event("input", { bubbles: true, cancelable: true }));
|
||||
// DropdownMixin's #onInput fires the debounced dropdown re-render.
|
||||
}, { signal });
|
||||
|
||||
// Commit on blur if the value has changed since the element was focused.
|
||||
this._dropdownInput.addEventListener("focus", () => {
|
||||
this.#valueAtFocus = this._value;
|
||||
}, { signal });
|
||||
|
||||
this._dropdownInput.addEventListener("blur", () => {
|
||||
if (this._value !== this.#valueAtFocus) {
|
||||
this.dispatchEvent(new Event("change", { bubbles: true, cancelable: true }));
|
||||
}
|
||||
}, { signal });
|
||||
|
||||
// Commit on Enter for free-text values (not picked from the dropdown).
|
||||
this._dropdownInput.addEventListener("keydown", (e) => {
|
||||
if (e.key === "Enter") {
|
||||
e.preventDefault();
|
||||
this._dropdownInput.blur();
|
||||
}
|
||||
}, { signal });
|
||||
}
|
||||
|
||||
/** @override */
|
||||
_toggleDisabled(disabled) {
|
||||
this._toggleDropdownDisabled(disabled);
|
||||
// Add/remove .disabled on the wrapper so CSS can dim the whole control.
|
||||
const wrapper = this.querySelector(".wrapper");
|
||||
if (wrapper) {
|
||||
wrapper.classList.toggle("disabled", disabled);
|
||||
}
|
||||
}
|
||||
|
||||
/** @override */
|
||||
attributeChangedCallback(attrName, oldValue, newValue) {
|
||||
super.attributeChangedCallback(attrName, oldValue, newValue);
|
||||
if (attrName === "disabled") {
|
||||
this._toggleDropdownDisabled(newValue !== null);
|
||||
}
|
||||
}
|
||||
|
||||
/** @override */
|
||||
_refresh() {
|
||||
if (!this._dropdownInput)
|
||||
return;
|
||||
|
||||
this._dropdownInput.value = this._label ?? "";
|
||||
this._internals.setFormValue(this._value ?? "");
|
||||
this._dropdownRefresh();
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/* DropdownMixin Contract */
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/** @override */
|
||||
_getDropdownOptions() {
|
||||
return this.#options;
|
||||
}
|
||||
|
||||
/** @override */
|
||||
_isOptionSelected(value) {
|
||||
return this._value === value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Commit the picked option as the current value and close the dropdown.
|
||||
* @override
|
||||
*/
|
||||
_onDropdownPick(option) {
|
||||
this._value = option.value;
|
||||
this._label = option.label;
|
||||
this._dropdownInput.value = option.label;
|
||||
this._internals.setFormValue(option.value);
|
||||
this._dropdownInput.blur();
|
||||
this.dispatchEvent(new Event("input", { bubbles: true, cancelable: true }));
|
||||
this.dispatchEvent(new Event("change", { bubbles: true, cancelable: true }));
|
||||
}
|
||||
}
|
||||
492
system/scripts/misc/l5r5e-dropdown-mixin.js
Normal file
492
system/scripts/misc/l5r5e-dropdown-mixin.js
Normal file
@@ -0,0 +1,492 @@
|
||||
/**
|
||||
* @typedef {Object} DropdownMixinConfig
|
||||
* @property {boolean} [multiSelect=false]
|
||||
* When true the dropdown toggles selection and stays open after a pick.
|
||||
* When false a pick commits the value and closes (combo-box mode).
|
||||
* @property {number} [debounceMs=150]
|
||||
* Trailing-debounce delay in milliseconds for dropdown re-renders while typing.
|
||||
*/
|
||||
|
||||
/**
|
||||
* DropdownMixin
|
||||
*
|
||||
* Adds a fully custom `<ul role="listbox">` dropdown to any AbstractFormInputElement
|
||||
* subclass. Handles UI only — building, opening, closing, rendering options, and keyboard
|
||||
* navigation. Has no opinion about how options are stored or how values are managed.
|
||||
*
|
||||
* ### Contract: three methods the host must implement
|
||||
*
|
||||
* - `_getDropdownOptions()`
|
||||
* Return `{ value, label, group, disabled, tooltip }[]` — the full unfiltered list.
|
||||
*
|
||||
* - `_isOptionSelected(value)` → boolean
|
||||
* Return whether a given value is currently selected.
|
||||
*
|
||||
* - `_onDropdownPick(option)` → void
|
||||
* Called when the user picks an option. The mixin handles post-pick behaviour
|
||||
* (close in single mode, re-render in multi mode) after this returns.
|
||||
*
|
||||
* ### Host responsibilities
|
||||
* - Call `this._buildDropdownElements({ placeholder })` inside `_buildElements()`
|
||||
* and include the returned wrapper in the returned array.
|
||||
* - Call `this._activateDropdownListeners()` inside `_activateListeners()`.
|
||||
* - Call `this._toggleDropdownDisabled(disabled)` inside `_toggleDisabled()`.
|
||||
* - Call `this._dropdownRefresh()` inside `_refresh()` to keep checkmarks in sync.
|
||||
*
|
||||
* @param {typeof AbstractFormInputElement} Base
|
||||
* @param {DropdownMixinConfig} [mixinConfig={}]
|
||||
* @return {typeof Base}
|
||||
*/
|
||||
export function DropdownMixin(Base, mixinConfig = {}) {
|
||||
const {
|
||||
multiSelect = false,
|
||||
debounceMs = 150,
|
||||
/**
|
||||
* When true, closing the dropdown clears the search input text.
|
||||
* Use true for multi-select (search is transient) and false for
|
||||
* combo-box (the input IS the value and must persist after close).
|
||||
*/
|
||||
clearOnClose = true,
|
||||
} = mixinConfig;
|
||||
|
||||
return class DropdownMixinElement extends Base {
|
||||
|
||||
/* --------------------------------------------------------- */
|
||||
/* Private Fields */
|
||||
/* --------------------------------------------------------- */
|
||||
|
||||
/** @type {HTMLInputElement} */
|
||||
#searchInput;
|
||||
|
||||
/** @type {HTMLUListElement} */
|
||||
#list;
|
||||
|
||||
/** @type {boolean} */
|
||||
#open = false;
|
||||
|
||||
/**
|
||||
* Snapshot of #open at the moment a focus event fires.
|
||||
* Lets us distinguish a fresh focus (should open) from a click
|
||||
* on an already-focused input (should toggle closed).
|
||||
* @type {boolean}
|
||||
*/
|
||||
#wasOpenOnFocus = false;
|
||||
|
||||
/** @type {number} */
|
||||
#activeIndex = -1;
|
||||
|
||||
/** @type {HTMLLIElement[]} — flat list of pickable <li>s, excludes group headers */
|
||||
#optionElements = [];
|
||||
|
||||
/** @type {Function} */
|
||||
#debouncedOpen;
|
||||
|
||||
/**
|
||||
* Per-instance key so multiple elements on the same page never share a timer.
|
||||
* @type {string}
|
||||
*/
|
||||
#debounceId = `l5r5e-dropdown-${foundry.utils.randomID()}`;
|
||||
|
||||
/**
|
||||
* The search input element. The host should assign this to `this._primaryInput`.
|
||||
* @return {HTMLInputElement}
|
||||
*/
|
||||
get _dropdownInput() {
|
||||
return this.#searchInput;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the search `<input>` + `<ul>` dropdown inside a positioned wrapper div.
|
||||
* Include the returned element in the array returned from `_buildElements()`.
|
||||
*
|
||||
* @param {object} [opts]
|
||||
* @param {string} [opts.placeholder=""]
|
||||
* @return {HTMLDivElement}
|
||||
*/
|
||||
_buildDropdownElements({ placeholder = "" } = {}) {
|
||||
const wrapper = document.createElement("div");
|
||||
wrapper.classList.add("wrapper");
|
||||
|
||||
this.#searchInput = document.createElement("input");
|
||||
this.#searchInput.type = "text";
|
||||
this.#searchInput.classList.add("input");
|
||||
this.#searchInput.setAttribute("autocomplete", "off");
|
||||
this.#searchInput.setAttribute("role", "combobox");
|
||||
this.#searchInput.setAttribute("aria-autocomplete", "list");
|
||||
this.#searchInput.setAttribute("aria-expanded", "false");
|
||||
this.#searchInput.setAttribute("aria-haspopup", "listbox");
|
||||
if (placeholder) {
|
||||
this.#searchInput.setAttribute("placeholder", placeholder);
|
||||
}
|
||||
|
||||
this.#list = document.createElement("ul");
|
||||
this.#list.classList.add("dropdown");
|
||||
this.#list.setAttribute("role", "listbox");
|
||||
if (multiSelect) {
|
||||
this.#list.setAttribute("aria-multiselectable", "true");
|
||||
}
|
||||
this.#list.hidden = true;
|
||||
|
||||
this.#syncOffset();
|
||||
wrapper.append(this.#searchInput, this.#list);
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
/** Attach dropdown event listeners. Call inside `_activateListeners()`. */
|
||||
_activateDropdownListeners() {
|
||||
const signal = this.abortSignal;
|
||||
|
||||
this.#debouncedOpen = game.l5r5e.HelpersL5r5e.debounce(
|
||||
this.#debounceId,
|
||||
(query) => this.#openDropdown(query),
|
||||
debounceMs,
|
||||
false // trailing — fires after the user pauses
|
||||
);
|
||||
|
||||
this.#searchInput.addEventListener("mousedown", this.#onMouseDown.bind(this), { signal });
|
||||
this.#searchInput.addEventListener("focus", this.#onFocus.bind(this), { signal });
|
||||
this.#searchInput.addEventListener("input", this.#onInput.bind(this), { signal });
|
||||
this.#searchInput.addEventListener("keydown", this.#onKeydown.bind(this), { signal });
|
||||
this.#searchInput.addEventListener("blur", this.#onBlur.bind(this), { signal });
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable or disable the search input. Call inside `_toggleDisabled()`.
|
||||
* @param {boolean} disabled
|
||||
*/
|
||||
_toggleDropdownDisabled(disabled) {
|
||||
if (this.#searchInput) {
|
||||
this.#searchInput.disabled = disabled;
|
||||
}
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------- */
|
||||
/* Refresh */
|
||||
/* --------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Re-render the open dropdown in place so checkmarks and disabled states
|
||||
* stay in sync with the current value. Call inside `_refresh()`.
|
||||
*/
|
||||
_dropdownRefresh() {
|
||||
if (this.#open) {
|
||||
this.#renderOptions(this.#filter(this.#searchInput?.value ?? ""));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @abstract
|
||||
* @return {{ value: string, label: string, group: string|null, disabled?: boolean, tooltip?: string }[]}
|
||||
*/
|
||||
_getDropdownOptions() {
|
||||
throw new Error(`${this.constructor.name} must implement _getDropdownOptions()`);
|
||||
}
|
||||
|
||||
/**
|
||||
* @abstract
|
||||
* @param {string} value
|
||||
* @return {boolean}
|
||||
*/
|
||||
_isOptionSelected(value) {
|
||||
throw new Error(`${this.constructor.name} must implement _isOptionSelected()`);
|
||||
}
|
||||
|
||||
/**
|
||||
* @abstract
|
||||
* @param {{ value: string, label: string }} option
|
||||
*/
|
||||
_onDropdownPick(option) {
|
||||
throw new Error(`${this.constructor.name} must implement _onDropdownPick()`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Case-insensitive label filter over `_getDropdownOptions()`.
|
||||
* Returns all options when query is empty.
|
||||
* @param {string} query
|
||||
* @return {object[]}
|
||||
*/
|
||||
#filter(query) {
|
||||
const all = this._getDropdownOptions();
|
||||
if (!query) {
|
||||
return all;
|
||||
}
|
||||
const lower = query.toLowerCase();
|
||||
return all.filter(option => option.label.toLowerCase().includes(lower));
|
||||
}
|
||||
|
||||
#openDropdown(query = "") {
|
||||
this.#renderOptions(this.#filter(query));
|
||||
this.#list.hidden = false;
|
||||
this.#searchInput.setAttribute("aria-expanded", "true");
|
||||
this.#open = true;
|
||||
this.#activeIndex = -1;
|
||||
this._onDropdownOpened();
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the dropdown opens. Override in host classes to snapshot
|
||||
* the current value so _onDropdownClosed can compare against it.
|
||||
* Default is a no-op.
|
||||
* @protected
|
||||
*/
|
||||
_onDropdownOpened() {}
|
||||
|
||||
#closeDropdown() {
|
||||
this.#list.hidden = true;
|
||||
this.#searchInput.setAttribute("aria-expanded", "false");
|
||||
this.#open = false;
|
||||
this.#wasOpenOnFocus = false;
|
||||
this.#activeIndex = -1;
|
||||
this.#optionElements = [];
|
||||
// In combo-box mode the input IS the value, so we leave it intact.
|
||||
// In multi-select mode the search text is transient and should reset.
|
||||
if (clearOnClose && this.#searchInput) {
|
||||
this.#searchInput.value = "";
|
||||
}
|
||||
// Notify the host that the dropdown has closed. Hosts can override this
|
||||
// to fire a single change event after a multi-pick session.
|
||||
this._onDropdownClosed();
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the dropdown closes. Override in host classes to fire a
|
||||
* consolidated change event after a multi-pick session.
|
||||
* Default is a no-op.
|
||||
* @protected
|
||||
*/
|
||||
_onDropdownClosed() {}
|
||||
|
||||
#renderOptions(options) {
|
||||
this.#list.innerHTML = "";
|
||||
this.#optionElements = [];
|
||||
|
||||
// hideDisabledOptions is a host-level attribute, read via the DOM.
|
||||
const visible = this.hasAttribute("hidedisabledoptions")
|
||||
? options.filter(o => !o.disabled)
|
||||
: options;
|
||||
|
||||
if (!visible.length) {
|
||||
const empty = document.createElement("li");
|
||||
empty.classList.add("no-results");
|
||||
empty.textContent = game.i18n.localize("l5r5e.multiselect.no_results") ?? "No matches";
|
||||
empty.setAttribute("aria-disabled", "true");
|
||||
this.#list.append(empty);
|
||||
return;
|
||||
}
|
||||
|
||||
// Bucket into groups, preserving insertion order.
|
||||
const groups = new Map();
|
||||
const ungrouped = [];
|
||||
for (const option of visible) {
|
||||
if (option.group) {
|
||||
if (!groups.has(option.group)) groups.set(option.group, []);
|
||||
groups.get(option.group).push(option);
|
||||
} else {
|
||||
ungrouped.push(option);
|
||||
}
|
||||
}
|
||||
|
||||
for (const [label, options] of groups) {
|
||||
const header = document.createElement("li");
|
||||
header.classList.add("group");
|
||||
header.setAttribute("role", "presentation");
|
||||
header.textContent = label;
|
||||
this.#list.append(header);
|
||||
for (const option of options) {
|
||||
this.#list.append(this.#buildOptionEl(option));
|
||||
}
|
||||
}
|
||||
for (const option of ungrouped){
|
||||
this.#list.append(this.#buildOptionEl(option));
|
||||
}
|
||||
}
|
||||
|
||||
#buildOptionEl(option) {
|
||||
const selected = this._isOptionSelected(option.value);
|
||||
const disabled = !!option.disabled;
|
||||
|
||||
const li = document.createElement("li");
|
||||
li.classList.add("option");
|
||||
if (selected) {
|
||||
li.classList.add("selected");
|
||||
}
|
||||
if (disabled) {
|
||||
li.classList.add("disabled");
|
||||
}
|
||||
li.setAttribute("role", "option");
|
||||
li.setAttribute("aria-selected", String(selected));
|
||||
li.setAttribute("aria-disabled", String(disabled));
|
||||
li.dataset.value = option.value;
|
||||
|
||||
if (multiSelect) {
|
||||
const check = document.createElement("span");
|
||||
check.classList.add("checkmark");
|
||||
check.setAttribute("aria-hidden", "true");
|
||||
li.append(check);
|
||||
}
|
||||
|
||||
const labelEl = document.createElement("span");
|
||||
labelEl.classList.add("label");
|
||||
labelEl.textContent = option.label;
|
||||
li.append(labelEl);
|
||||
|
||||
if (selected && multiSelect) {
|
||||
li.title = game.i18n.localize("l5r5e.multiselect.already_in_filter");
|
||||
} else if (disabled && option.tooltip) {
|
||||
li.title = option.tooltip;
|
||||
}
|
||||
|
||||
if (!disabled) {
|
||||
li.addEventListener("mouseenter", () => {
|
||||
for (const element of this.#optionElements) {
|
||||
element.classList.remove("active");
|
||||
}
|
||||
this.#activeIndex = this.#optionElements.indexOf(li);
|
||||
li.classList.add("active");
|
||||
});
|
||||
li.addEventListener("mouseleave", () => {
|
||||
li.classList.remove("active");
|
||||
this.#activeIndex = -1;
|
||||
});
|
||||
li.addEventListener("mousedown", (event) => {
|
||||
event.preventDefault(); // keep focus on the search input
|
||||
this.#pick(option);
|
||||
});
|
||||
}
|
||||
|
||||
this.#optionElements.push(li);
|
||||
return li;
|
||||
}
|
||||
|
||||
#pick(option) {
|
||||
this._onDropdownPick(option);
|
||||
if (multiSelect) {
|
||||
// Stay open — re-render so checkmarks reflect the new state.
|
||||
this.#renderOptions(this.#filter(this.#searchInput.value));
|
||||
} else {
|
||||
this.#closeDropdown();
|
||||
}
|
||||
}
|
||||
|
||||
#moveHighlight(direction) {
|
||||
if (!this.#optionElements.length) {
|
||||
return;
|
||||
}
|
||||
const prev = this.#optionElements[this.#activeIndex];
|
||||
if (prev) {
|
||||
prev.classList.remove("active");
|
||||
}
|
||||
|
||||
this.#activeIndex = Math.max(
|
||||
-1,
|
||||
Math.min(this.#optionElements.length - 1, this.#activeIndex + direction)
|
||||
);
|
||||
|
||||
const next = this.#optionElements[this.#activeIndex];
|
||||
if (next) {
|
||||
next.classList.add("active");
|
||||
next.scrollIntoView({ block: "nearest" });
|
||||
}
|
||||
}
|
||||
|
||||
#syncOffset() {
|
||||
if (!this.#searchInput || !this.#list) {
|
||||
return;
|
||||
}
|
||||
const offset = this.#searchInput.offsetLeft;
|
||||
this.#list.style.left = `${offset}px`;
|
||||
this.#list.style.right = `-${offset}px`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles click-to-toggle behaviour.
|
||||
*
|
||||
* Three cases:
|
||||
* 1. Dropdown is open → close it. preventDefault stops blur firing, which
|
||||
* would otherwise trigger a second close via #onBlur.
|
||||
* 2. Dropdown is closed AND input is already focused → open immediately.
|
||||
* In this case focus will NOT fire again (input never blurred after the
|
||||
* previous preventDefault), so we must open here rather than in #onFocus.
|
||||
* 3. Dropdown is closed AND input is not yet focused → do nothing; the
|
||||
* browser will fire focus naturally and #onFocus will open the dropdown.
|
||||
*/
|
||||
#onMouseDown(event) {
|
||||
this.#wasOpenOnFocus = this.#open;
|
||||
if (this.#open) {
|
||||
event.preventDefault();
|
||||
this.#closeDropdown();
|
||||
} else if (document.activeElement === this.#searchInput) {
|
||||
// Case 2: already focused, focus won't re-fire — open directly.
|
||||
this.#openDropdown(this.#searchInput.value);
|
||||
}
|
||||
}
|
||||
|
||||
#onFocus(event) {
|
||||
// Only open if mousedown didn't already handle it (cases 1 & 2 above).
|
||||
if (!this.#wasOpenOnFocus && document.activeElement === this.#searchInput) {
|
||||
this.#openDropdown(this.#searchInput.value);
|
||||
}
|
||||
}
|
||||
|
||||
#onInput(event) {
|
||||
this.#debouncedOpen(this.#searchInput.value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the dropdown when focus genuinely leaves the component.
|
||||
*
|
||||
* event.relatedTarget is the element that is RECEIVING focus. If it is
|
||||
* inside our host element (e.g. the clear button, a chip remove span that
|
||||
* managed to steal focus) we leave the dropdown open. Only when focus moves
|
||||
* completely outside do we close — and we do so synchronously, so that
|
||||
* _onDropdownClosed fires its change event BEFORE the browser hands control
|
||||
* to whatever the user clicked. This eliminates the 100 ms race where Foundry
|
||||
* could read stale FormData between the blur and a deferred close.
|
||||
*/
|
||||
#onBlur(event) {
|
||||
if (this.contains(event.relatedTarget)) {
|
||||
return;
|
||||
}
|
||||
this.#closeDropdown();
|
||||
}
|
||||
|
||||
#onKeydown(event) {
|
||||
if (!this.#open) {
|
||||
if (event.key === "ArrowDown" || event.key === "ArrowUp") {
|
||||
event.preventDefault();
|
||||
this.#openDropdown(this.#searchInput.value);
|
||||
}
|
||||
return;
|
||||
}
|
||||
switch (event.key) {
|
||||
case "ArrowDown": {
|
||||
event.preventDefault();
|
||||
this.#moveHighlight(1);
|
||||
} break;
|
||||
case "ArrowUp": {
|
||||
event.preventDefault();
|
||||
this.#moveHighlight(-1);
|
||||
}break;
|
||||
case "Enter": {
|
||||
event.preventDefault();
|
||||
if (this.#activeIndex >= 0) {
|
||||
const li = this.#optionElements[this.#activeIndex];
|
||||
const option = this._getDropdownOptions().find(option => option.value === li.dataset.value);
|
||||
if (option) {
|
||||
this.#pick(option);
|
||||
}
|
||||
} else {
|
||||
this.#closeDropdown();
|
||||
}
|
||||
} break;
|
||||
case "Escape": {
|
||||
event.preventDefault();
|
||||
this.#closeDropdown();
|
||||
} break;
|
||||
case "Tab": {
|
||||
this.#closeDropdown();
|
||||
} break;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -1,301 +1,424 @@
|
||||
import { DropdownMixin } from "./l5r5e-dropdown-mixin.js";
|
||||
|
||||
const { AbstractMultiSelectElement } = foundry.applications.elements;
|
||||
|
||||
/**
|
||||
* Provide a multi-select workflow using a select element as the input mechanism.
|
||||
* It is a expanded copy of the HTMLMultiselect with support for disabling options
|
||||
* and a clear all button. Also have support for hover-over information using titlea
|
||||
* A custom `<l5r5e-multi-select>` form element providing Select2-style chip multi-selection.
|
||||
*
|
||||
* @example Multi-Select HTML Markup
|
||||
* ```html
|
||||
* <l5r5e-multi-select name="select-many-things">
|
||||
* <optgroup label="Basic Options">
|
||||
* <option value="foo">Foo</option>
|
||||
* <option value="bar">Bar</option>
|
||||
* <option value="baz">Baz</option>
|
||||
* </optgroup>
|
||||
* <optgroup label="Advanced Options">
|
||||
* <option value="fizz">Fizz</option>
|
||||
* <option value="buzz">Buzz</option>
|
||||
* </optgroup>
|
||||
* Stores **multiple string values** from a fixed option list, shown as removable chips inside
|
||||
* the input box. A live-search input filters the dropdown as the user types. Use this when a
|
||||
* field holds an unordered collection of values (e.g. a set of skills, tags, or abilities).
|
||||
* For storing a single value — predefined or free-text — use {@link L5R5eHtmlComboBoxElement} instead.
|
||||
*
|
||||
* The element's `value` getter returns a comma-separated string (e.g. `"fire,water"`),
|
||||
* which is what `FormData` will read on submission. `_getValue()` returns a plain Array,
|
||||
* which is what `FormDataExtended` will use.
|
||||
*
|
||||
* Pre-selection on render is handled via the `value` attribute on the element — NOT via
|
||||
* `{{selectOptions selected=...}}`, which cannot handle comma-separated strings. Use
|
||||
* `{{selectOptions}}` without `selected` purely to render the available options, and let
|
||||
* the `value` attribute drive pre-selection. Since `getAttribute()` always returns a string,
|
||||
* passing a `Set` or `Array` via Handlebars will not work correctly — always pass a
|
||||
* comma-separated string to `value=`.
|
||||
*
|
||||
* Prefer {@link L5r5eSetField} + `{{formGroup}}` when wiring this into a DataModel — the
|
||||
* field handles the full round-trip automatically.
|
||||
*
|
||||
* @example
|
||||
* ```hbs
|
||||
* {{!-- Use value= (comma-separated string) for pre-selection, not selectOptions selected= --}}
|
||||
* <l5r5e-multi-select name="elements" value="{{data.elements}}">
|
||||
* {{selectOptions choices localize=true}}
|
||||
* </l5r5e-multi-select>
|
||||
* ```
|
||||
*
|
||||
* @example
|
||||
* // Static factory — use only when building outside of Foundry's field/template system:
|
||||
* const el = L5r5eHtmlMultiSelectElement.create({
|
||||
* name: "elements",
|
||||
* options: [{ value: "fire", label: "Fire" }, { value: "water", label: "Water" }],
|
||||
* value: "fire,water", // comma-separated pre-selection
|
||||
* });
|
||||
* form.appendChild(el);
|
||||
*
|
||||
* // Reading the value back:
|
||||
* el.value; // "fire,water" — comma-separated string, compatible with FormData
|
||||
* el._getValue(); // ["fire","water"] — array, compatible with FormDataExtended
|
||||
*/
|
||||
export class L5r5eHtmlMultiSelectElement extends AbstractMultiSelectElement {
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.#setup();
|
||||
}
|
||||
|
||||
export class L5r5eHtmlMultiSelectElement extends DropdownMixin(
|
||||
AbstractMultiSelectElement,
|
||||
{ multiSelect: true, debounceMs: 150 }
|
||||
) {
|
||||
/** @override */
|
||||
static tagName = "l5r5e-multi-select";
|
||||
|
||||
/**
|
||||
* A select element used to choose options.
|
||||
* @type {HTMLSelectElement}
|
||||
*/
|
||||
#select;
|
||||
/** @type {HTMLDivElement} — outer box containing chips, input, clear button */
|
||||
#selectionBox;
|
||||
|
||||
/** @type {HTMLDivElement} — chips are injected here */
|
||||
#chipList;
|
||||
|
||||
/** @type {HTMLSpanElement} — auto-sizing wrapper around the search input */
|
||||
#inputSizer;
|
||||
|
||||
/** @type {HTMLButtonElement} — trailing clear-all button */
|
||||
#clearButton;
|
||||
|
||||
/** @type {Set<string>} */
|
||||
#disabledValues = new Set();
|
||||
|
||||
/** @type {Map<string, string>} */
|
||||
#tooltips = new Map();
|
||||
|
||||
|
||||
/**
|
||||
* A display element which lists the chosen options.
|
||||
* @type {HTMLDivElement}
|
||||
* Returns a comma-separated string
|
||||
* FormData reads this via field.value.
|
||||
* @override
|
||||
*/
|
||||
#tags;
|
||||
get value() {
|
||||
return Array.from(this._value).join(",");
|
||||
}
|
||||
|
||||
/** @override */
|
||||
set value(val) {
|
||||
this._value.clear();
|
||||
const values = Array.isArray(val) ? val : String(val).split(",").filter(Boolean);
|
||||
for (const v of values) {
|
||||
this._value.add(v);
|
||||
}
|
||||
this._internals.setFormValue(this.value);
|
||||
this._refresh();
|
||||
}
|
||||
|
||||
/**
|
||||
* A button element which clear all the options.
|
||||
* @type {HTMLButtonElement}
|
||||
* Return an array so FormDataExtended.object[name] matches Foundry's own
|
||||
* HTMLMultiSelectElement — both field.value (string) and .object (array) are correct.
|
||||
* @override
|
||||
* @protected
|
||||
*/
|
||||
#clearAll;
|
||||
_getValue() {
|
||||
return Array.from(this._value);
|
||||
}
|
||||
|
||||
/**
|
||||
* A Set containing the values that should always be disabled.
|
||||
* @type {Set}
|
||||
* Accept either an array or comma-separated string when Foundry calls _setValue().
|
||||
* @override
|
||||
* @protected
|
||||
*/
|
||||
#disabledValues;
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
// We will call initialize twice (one in the parent constructor) then one in #setup
|
||||
// required since when we want to build the elements we should to an initialize first
|
||||
// and we cannot override _initialize since we don't have access to #disabledValues there
|
||||
#setup() {
|
||||
super._initialize();
|
||||
this.#disabledValues = new Set();
|
||||
for (const option of this.querySelectorAll("option")) {
|
||||
if (option.value === "") {
|
||||
option.label = game.i18n.localize("l5r5e.multiselect.empty_tag");
|
||||
this._choices[option.value] = game.i18n.localize("l5r5e.multiselect.empty_tag");
|
||||
}
|
||||
if (option.disabled) {
|
||||
this.#disabledValues.add(option.value);
|
||||
}
|
||||
_setValue(val) {
|
||||
const values = Array.isArray(val) ? val : String(val).split(",").filter(Boolean);
|
||||
if (values.some(v => v && !(v in this._choices))) {
|
||||
throw new Error("The values assigned to a multi-select element must all be valid options.");
|
||||
}
|
||||
this._value.clear();
|
||||
for (const v of values) {
|
||||
this._value.add(v);
|
||||
}
|
||||
}
|
||||
|
||||
/** @override */
|
||||
_initialize() {
|
||||
super._initialize(); // fills this._choices, this._value, this._options
|
||||
for (const option of this.querySelectorAll("option")) {
|
||||
if (option.disabled)
|
||||
this.#disabledValues.add(option.value);
|
||||
if (option.title)
|
||||
this.#tooltips.set(option.value, option.title);
|
||||
}
|
||||
if (this.hasAttribute("value")) {
|
||||
this._setValue(this.getAttribute("value"));
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/* Element Lifecycle */
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/** @override */
|
||||
_buildElements() {
|
||||
this.#setup();
|
||||
|
||||
// Create select element
|
||||
this.#select = this._primaryInput = document.createElement("select");
|
||||
this.#select.insertAdjacentHTML("afterbegin", `<option id="l5r5e-multiselect-placeholder" value="" disabled selected hidden>${game.i18n.localize("l5r5e.multiselect.placeholder")}</option>`);
|
||||
this.#select.append(...this._options);
|
||||
this.#select.disabled = !this.editable;
|
||||
|
||||
// Create a div element for display
|
||||
this.#tags = document.createElement("div");
|
||||
this.#tags.className = "tags input-element-tags";
|
||||
|
||||
// Create a clear all button
|
||||
this.#clearAll = document.createElement("button");
|
||||
this.#clearAll.textContent = "X";
|
||||
return [this.#select, this.#clearAll, this.#tags];
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/** @override */
|
||||
_refresh() {
|
||||
// Update the displayed tags
|
||||
const tags = Array.from(this._value).map(id => {
|
||||
return foundry.applications.elements.HTMLStringTagsElement.renderTag(id, this._choices[id], this.editable);
|
||||
// Ask mixin to build <input> + <ul>, then re-home them into our structure.
|
||||
const mixinWrapper = this._buildDropdownElements({
|
||||
placeholder: this.getAttribute("placeholder")
|
||||
?? game.i18n.localize("l5r5e.multiselect.placeholder"),
|
||||
});
|
||||
this.#tags.replaceChildren(...tags);
|
||||
const searchInput = mixinWrapper.querySelector("input.input");
|
||||
const dropdownList = mixinWrapper.querySelector("ul.dropdown");
|
||||
|
||||
// Figure out if we are overflowing the tag div.
|
||||
if($(this.#tags).css("max-height")) {
|
||||
const numericMaxHeight = parseInt($(this.#tags).css("max-height"), 10);
|
||||
if(numericMaxHeight) {
|
||||
if($(this.#tags).prop("scrollHeight") > numericMaxHeight) {
|
||||
this.#tags.classList.add("overflowing");
|
||||
}
|
||||
else {
|
||||
this.#tags.classList.remove("overflowing");
|
||||
}
|
||||
}
|
||||
}
|
||||
// Selection box
|
||||
this.#selectionBox = document.createElement("div");
|
||||
this.#selectionBox.classList.add("selection-box");
|
||||
|
||||
// Disable selected options
|
||||
const hideDisabled = game.settings.get(CONFIG.l5r5e.namespace, "compendium-hide-disabled-sources");
|
||||
for (const option of this.#select) {
|
||||
if (this._value.has(option.value)) {
|
||||
option.disabled = true;
|
||||
option.title = game.i18n.localize("l5r5e.multiselect.already_in_filter");
|
||||
continue;
|
||||
}
|
||||
if (this.#disabledValues.has(option.value)) {
|
||||
option.disabled = true;
|
||||
option.hidden = hideDisabled;
|
||||
continue;
|
||||
}
|
||||
option.disabled = false;
|
||||
option.removeAttribute("title");
|
||||
}
|
||||
// Chip list
|
||||
this.#chipList = document.createElement("div");
|
||||
this.#chipList.classList.add("chip-list");
|
||||
|
||||
// Auto-sizing sizer — CSS grid trick: ::after mirrors data-value, input shares the cell
|
||||
this.#inputSizer = document.createElement("span");
|
||||
this.#inputSizer.classList.add("input-sizer");
|
||||
this.#inputSizer.dataset.value = "";
|
||||
this.#inputSizer.append(searchInput);
|
||||
|
||||
// Clear-all button
|
||||
this.#clearButton = document.createElement("button");
|
||||
this.#clearButton.type = "button";
|
||||
this.#clearButton.classList.add("clear-btn");
|
||||
this.#clearButton.setAttribute("aria-label",
|
||||
game.i18n.localize("l5r5e.multiselect.clear_all") ?? "Clear all");
|
||||
this.#clearButton.textContent = "×";
|
||||
this.#clearButton.hidden = true;
|
||||
|
||||
this.#selectionBox.append(this.#chipList, this.#inputSizer, this.#clearButton);
|
||||
|
||||
// Container: selection box + dropdown must share the same positioned ancestor.
|
||||
const container = document.createElement("div");
|
||||
container.classList.add("multi-select-container");
|
||||
container.append(this.#selectionBox, dropdownList);
|
||||
|
||||
this._primaryInput = searchInput;
|
||||
return [container];
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/** @override */
|
||||
_activateListeners() {
|
||||
this.#select.addEventListener("change", this.#onChangeSelect.bind(this));
|
||||
this.#clearAll.addEventListener("click", this.#onClickClearAll.bind(this));
|
||||
this.#tags.addEventListener("click", this.#onClickTag.bind(this));
|
||||
this._activateDropdownListeners();
|
||||
const signal = this.abortSignal;
|
||||
|
||||
this.#tags.addEventListener("mouseleave", this.#onMouseLeave.bind(this));
|
||||
this.#selectionBox.addEventListener("mousedown", this.#onBoxMouseDown.bind(this), { signal });
|
||||
this.#chipList.addEventListener("click", this.#onChipClick.bind(this), { signal });
|
||||
this.#clearButton.addEventListener("click", this.#onClearAll.bind(this), { signal });
|
||||
// stop the clear button from opening the selection box when pressing it
|
||||
this.#clearButton.addEventListener("mousedown", (event) => {event.preventDefault(); event.stopPropagation();}, {signal});
|
||||
this._dropdownInput.addEventListener("input", () => this.#updateInputSizer(), { signal });
|
||||
}
|
||||
|
||||
#onMouseLeave(event) {
|
||||
// Figure out if we are overflowing the tag div.
|
||||
if($(this.#tags).css("max-height")) {
|
||||
const numericMaxHeight = parseInt($(this.#tags).css("max-height"), 10);
|
||||
|
||||
if($(this.#tags).prop("scrollHeight") > numericMaxHeight) {
|
||||
this.#tags.classList.add("overflowing");
|
||||
}
|
||||
else {
|
||||
this.#tags.classList.remove("overflowing");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Handle changes to the Select input, marking the selected option as a chosen value.
|
||||
* @param {Event} event The change event on the select element
|
||||
*/
|
||||
#onChangeSelect(event) {
|
||||
event.preventDefault();
|
||||
event.stopImmediatePropagation();
|
||||
const select = event.currentTarget;
|
||||
if (select.valueIndex === 0)
|
||||
return; // Ignore placeholder
|
||||
this.select(select.value);
|
||||
select.value = "";
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Handle click events on a tagged value, removing it from the chosen set.
|
||||
* @param {PointerEvent} event The originating click event on a chosen tag
|
||||
*/
|
||||
#onClickTag(event) {
|
||||
event.preventDefault();
|
||||
if (!event.target.classList.contains("remove"))
|
||||
return;
|
||||
if (!this.editable)
|
||||
return;
|
||||
const tag = event.target.closest(".tag");
|
||||
this.unselect(tag.dataset.key);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Handle clickling the clear all button
|
||||
* @param {Event} event The originating click event on the clear all button
|
||||
*/
|
||||
#onClickClearAll(event) {
|
||||
event.preventDefault();
|
||||
var _this = this;
|
||||
$(this.#tags).children().each(function () {
|
||||
_this.unselect($(this).data("key"));
|
||||
})
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/** @override */
|
||||
_toggleDisabled(disabled) {
|
||||
this.#select.toggleAttribute("disabled", disabled);
|
||||
this._toggleDropdownDisabled(disabled);
|
||||
|
||||
if (this.#selectionBox) {
|
||||
this.#selectionBox.classList.toggle("disabled", disabled);
|
||||
}
|
||||
|
||||
if (this.#chipList) {
|
||||
this._refresh(); // re-render chips so × appears/disappears
|
||||
}
|
||||
}
|
||||
|
||||
/** @override */
|
||||
_refresh() {
|
||||
const values = Array.from(this._value);
|
||||
this._internals.setFormValue(values.length ? values.join(",") : "");
|
||||
|
||||
this.#renderChips(values);
|
||||
|
||||
// Clear button: only visible when editable and something is selected.
|
||||
if (this.#clearButton) {
|
||||
this.#clearButton.hidden = (!this.editable || values.length === 0);
|
||||
}
|
||||
|
||||
this.#updateInputSizer();
|
||||
this._dropdownRefresh();
|
||||
}
|
||||
|
||||
/** @param {string[]} values */
|
||||
#renderChips(values) {
|
||||
if (!this.#chipList){
|
||||
return
|
||||
}
|
||||
this.#chipList.replaceChildren(...values.map(id => this.#buildChip(id)));
|
||||
}
|
||||
|
||||
/** @param {string} id */
|
||||
#buildChip(id) {
|
||||
const chip = document.createElement("span");
|
||||
chip.classList.add("chip");
|
||||
chip.dataset.key = id;
|
||||
|
||||
const label = document.createElement("span");
|
||||
label.classList.add("chip-label");
|
||||
label.textContent = this._choices[id] ?? id;
|
||||
chip.append(label);
|
||||
|
||||
// Only add × when the element is editable (not disabled, not readonly).
|
||||
if (this.editable) {
|
||||
const remove = document.createElement("span");
|
||||
remove.classList.add("chip-remove");
|
||||
remove.setAttribute("aria-label", `Remove ${this._choices[id] ?? id}`);
|
||||
remove.setAttribute("aria-hidden", "true");
|
||||
remove.textContent = "×";
|
||||
chip.append(remove);
|
||||
}
|
||||
return chip;
|
||||
}
|
||||
|
||||
/** Mirror typed text into the sizer span so CSS sizes the input correctly. */
|
||||
#updateInputSizer() {
|
||||
if (!this.#inputSizer || !this._dropdownInput)
|
||||
return;
|
||||
|
||||
const input = this._dropdownInput;
|
||||
const text = input.value || input.placeholder || "";
|
||||
this.#inputSizer.dataset.value = text;
|
||||
}
|
||||
|
||||
/** @override */
|
||||
_getDropdownOptions() {
|
||||
const makeOption = (option, group = null) => ({
|
||||
value: option.value,
|
||||
label: this._choices[option.value] ?? option.innerText,
|
||||
group,
|
||||
disabled: this.#disabledValues.has(option.value),
|
||||
tooltip: this.#tooltips.get(option.value) ?? "",
|
||||
});
|
||||
|
||||
return this._options.flatMap(child => {
|
||||
if (child instanceof HTMLOptGroupElement) {
|
||||
return [...child.querySelectorAll("option")]
|
||||
.filter(option => option.value)
|
||||
.map(option => makeOption(option, child.label));
|
||||
}
|
||||
if (child instanceof HTMLOptionElement && child.value) {
|
||||
return makeOption(child);
|
||||
}
|
||||
return [];
|
||||
});
|
||||
}
|
||||
|
||||
/** @override */
|
||||
_isOptionSelected(value) {
|
||||
return this._value.has(value);
|
||||
}
|
||||
|
||||
/** @override */
|
||||
_onDropdownPick(option) {
|
||||
const inValue = this._value.has(option.value);
|
||||
const inChoices = option.value in this._choices;
|
||||
if(!(inValue || inChoices))
|
||||
return;
|
||||
|
||||
if (inValue) {
|
||||
this._value.delete(option.value);
|
||||
}
|
||||
else if(inChoices) {
|
||||
this._value.add(option.value);
|
||||
}
|
||||
|
||||
this._internals.setFormValue(this.value);
|
||||
this._refresh();
|
||||
this.dispatchEvent(new Event("change", { bubbles: true, cancelable: true }));
|
||||
}
|
||||
|
||||
#onBoxMouseDown(event) {
|
||||
// Fully block interaction when not editable.
|
||||
if (!this.editable) {
|
||||
event.preventDefault();
|
||||
return;
|
||||
}
|
||||
if (event.target.classList.contains("chip-remove"))
|
||||
return;
|
||||
if (event.target === this._dropdownInput)
|
||||
return;
|
||||
|
||||
event.preventDefault();
|
||||
this._dropdownInput?.focus();
|
||||
}
|
||||
|
||||
#onChipClick(event) {
|
||||
if (!event.target.classList.contains("chip-remove") || !this.editable)
|
||||
return;
|
||||
|
||||
const chip = event.target.closest(".chip");
|
||||
if (!chip)
|
||||
return;
|
||||
|
||||
this._value.delete(chip.dataset.key);
|
||||
this._internals.setFormValue(this.value);
|
||||
this._refresh();
|
||||
this.dispatchEvent(new Event("change", { bubbles: true, cancelable: true }));
|
||||
this._dropdownInput?.focus();
|
||||
}
|
||||
|
||||
#onClearAll(event) {
|
||||
event.preventDefault();
|
||||
if (!this.editable)
|
||||
return;
|
||||
|
||||
this._value.clear();
|
||||
this._internals.setFormValue("");
|
||||
this._refresh();
|
||||
this.dispatchEvent(new Event("change", { bubbles: true, cancelable: true }));
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/* Static Factory */
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Create a HTML_l5r5e_MultiSelectElement using provided configuration data.
|
||||
* @param {FormInputConfig<string[]> & Omit<SelectInputConfig, "blank">} config
|
||||
* @returns {L5r5eHtmlMultiSelectElement}
|
||||
*/
|
||||
static create(config) {
|
||||
// Foundry creates either a select with tag multi-select or multi-checkboxes. We want a l5r5e-multi-select
|
||||
// Copied the implementation from foundry.applications.fields.createMultiSelectInput with our required changes.
|
||||
const groups = prepareSelectOptionGroups(config);
|
||||
const element = document.createElement(L5r5eHtmlMultiSelectElement.tagName);
|
||||
element.name = config.name;
|
||||
foundry.applications.fields.setInputAttributes(element, config);
|
||||
if (config.hideDisabledOptions) {
|
||||
element.toggleAttribute("hidedisabledoptions", true);
|
||||
}
|
||||
|
||||
//Setup the HTML
|
||||
const select = document.createElement(L5r5eHtmlMultiSelectElement.tagName);
|
||||
select.name = config.name;
|
||||
foundry.applications.fields.setInputAttributes(select, config);
|
||||
for (const group_entry of groups) {
|
||||
let parent = select;
|
||||
if (group_entry.group) {
|
||||
parent = _appendOptgroupHtml(group_entry.group, select);
|
||||
for (const groupEntry of groups) {
|
||||
let parent = element;
|
||||
if (groupEntry.group) {
|
||||
parent = _appendOptgroup(groupEntry.group, element);
|
||||
}
|
||||
for (const option_entry of group_entry.options) {
|
||||
_appendOptionHtml(option_entry, parent);
|
||||
for (const groupOption of groupEntry.options){
|
||||
_appendOption(groupOption, parent);
|
||||
}
|
||||
}
|
||||
return select;
|
||||
return element;
|
||||
}
|
||||
}
|
||||
|
||||
/** Stolen from foundry.applications.fields.prepareSelectOptionGroups: Needed to add support for tooltips
|
||||
*
|
||||
*/
|
||||
/* -------------------------------------------- */
|
||||
/* Module Helpers */
|
||||
/* -------------------------------------------- */
|
||||
|
||||
function prepareSelectOptionGroups(config) {
|
||||
const result = foundry.applications.fields.prepareSelectOptionGroups(config);
|
||||
|
||||
// Disable options based on input
|
||||
config.options.filter((option) => option?.disabled || option?.tooltip).forEach((SpecialOption) => {
|
||||
result.forEach((group) => {
|
||||
group.options.forEach((option) => {
|
||||
if (SpecialOption.value === option.value) {
|
||||
option.disabled = SpecialOption.disabled;
|
||||
option.tooltip = SpecialOption?.tooltip;
|
||||
config.options.filter(option => option?.disabled || option?.tooltip).forEach(special => {
|
||||
result.forEach(group => {
|
||||
group.options.forEach(groupOption => {
|
||||
if (groupOption.value === special.value) {
|
||||
groupOption.disabled = special.disabled;
|
||||
groupOption.tooltip = special.tooltip;
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
});
|
||||
});
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Stolen from foundry.applications.fields
|
||||
* Create and append an optgroup element to a parent select.
|
||||
* @param {string} label
|
||||
* @param {HTMLSelectElement} parent
|
||||
* @returns {HTMLOptGroupElement}
|
||||
* @internal
|
||||
*/
|
||||
function _appendOptgroupHtml(label, parent) {
|
||||
const optgroup = document.createElement("optgroup");
|
||||
optgroup.label = label;
|
||||
parent.appendChild(optgroup);
|
||||
return optgroup;
|
||||
function _appendOptgroup(label, parent) {
|
||||
const element = document.createElement("optgroup");
|
||||
element.label = label;
|
||||
parent.appendChild(element);
|
||||
|
||||
return element;
|
||||
}
|
||||
|
||||
/** Stolen from foundry.applications.fields
|
||||
* Create and append an option element to a parent select or optgroup.
|
||||
* @param {FormSelectOption} option
|
||||
* @param {HTMLSelectElement|HTMLOptGroupElement} parent
|
||||
* @internal
|
||||
*/
|
||||
function _appendOptionHtml(option, parent) {
|
||||
function _appendOption(option, parent) {
|
||||
const { value, label, selected, disabled, rule, tooltip } = option;
|
||||
if ((value !== undefined) && (label !== undefined)) {
|
||||
const option_html = document.createElement("option");
|
||||
option_html.value = value;
|
||||
option_html.innerText = label;
|
||||
if (value !== undefined && label !== undefined) {
|
||||
const element = document.createElement("option");
|
||||
element.value = value;
|
||||
element.innerText = label;
|
||||
if (selected) {
|
||||
option_html.toggleAttribute("selected", true);
|
||||
element.toggleAttribute("selected", true);
|
||||
}
|
||||
if (disabled) {
|
||||
option_html.toggleAttribute("disabled", true);
|
||||
element.toggleAttribute("disabled", true);
|
||||
}
|
||||
if (tooltip) {
|
||||
option_html.setAttribute("title", tooltip);
|
||||
element.setAttribute("title", tooltip);
|
||||
}
|
||||
parent.appendChild(option_html);
|
||||
parent.appendChild(element);
|
||||
}
|
||||
if (rule) {
|
||||
parent.insertAdjacentHTML("beforeend", "<hr>");
|
||||
|
||||
@@ -1,16 +1,19 @@
|
||||
export const PreloadTemplates = async function () {
|
||||
const tpl = CONFIG.l5r5e.paths.templates;
|
||||
return foundry.applications.handlebars.loadTemplates([
|
||||
// Add paths to "systems/l5r5e/templates"
|
||||
// Add paths to "systems/l5rx-chiaroscuro/templates"
|
||||
// *** Actors : PC ***
|
||||
`${tpl}actors/character/advancement-school.html`,
|
||||
`${tpl}actors/character/advancement-others.html`,
|
||||
`${tpl}actors/character/aspects.html`,
|
||||
`${tpl}actors/character/attributes.html`,
|
||||
`${tpl}actors/character/category.html`,
|
||||
`${tpl}actors/character/conflict.html`,
|
||||
`${tpl}actors/character/experience.html`,
|
||||
`${tpl}actors/character/identity.html`,
|
||||
`${tpl}actors/character/identity-text.html`,
|
||||
`${tpl}actors/character/inventory.html`,
|
||||
`${tpl}actors/character/invocations.html`,
|
||||
`${tpl}actors/character/narrative.html`,
|
||||
`${tpl}actors/character/rings.html`,
|
||||
`${tpl}actors/character/effects.html`,
|
||||
@@ -74,5 +77,6 @@ export const PreloadTemplates = async function () {
|
||||
`${tpl}items/weapon/weapon-sheet.html`,
|
||||
`${tpl}items/army-cohort/army-cohort-entry.html`,
|
||||
`${tpl}items/army-fortification/army-fortification-entry.html`,
|
||||
`${tpl}dice/chiaroscuro-chat-roll.html`,
|
||||
]);
|
||||
};
|
||||
|
||||
@@ -241,25 +241,24 @@ export const RegisterSettings = function () {
|
||||
/* -------------------------------------- */
|
||||
/* Grid Settings (GM only) */
|
||||
/* -------------------------------------- */
|
||||
|
||||
// UI Configuration
|
||||
game.settings.register(CONFIG.l5r5e.namespace, "tactical-grid-settings-world", {
|
||||
scope: "world",
|
||||
config: false,
|
||||
type: TacticalGridSettingsL5R5E.worldSchema,
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
game.settings.register(CONFIG.l5r5e.namespace, "tactical-grid-settings-client", {
|
||||
scope: "client",
|
||||
config: false,
|
||||
type: TacticalGridSettingsL5R5E.clientSchema,
|
||||
});
|
||||
|
||||
game.settings.registerMenu(CONFIG.l5r5e.namespace, "tactical-grid-settings", {
|
||||
});
|
||||
|
||||
game.settings.registerMenu(CONFIG.l5r5e.namespace, "tactical-grid-settings", {
|
||||
name: "l5r5e.tactical_grid.settings.title",
|
||||
label: "l5r5e.tactical_grid.settings.label",
|
||||
hint: "l5r5e.tactical_grid.settings.hint",
|
||||
icon: "fa-solid fa-table-layout",
|
||||
type: TacticalGridSettingsL5R5E
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
@@ -43,7 +43,7 @@ export class TacticalGridSettingsL5R5E extends HandlebarsApplicationMixin(Applic
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
form: {
|
||||
template: "systems/l5r5e/templates/" + "settings/tactical-grid-settings.html",
|
||||
template: "systems/l5rx-chiaroscuro/templates/" + "settings/tactical-grid-settings.html",
|
||||
scrollable: [""],
|
||||
},
|
||||
footer: {
|
||||
|
||||
@@ -11,7 +11,7 @@ function getRangeband(gridSettings, distance) {
|
||||
|
||||
export class RulerL5r5e extends foundry.canvas.interaction.Ruler {
|
||||
|
||||
static WAYPOINT_LABEL_TEMPLATE = "systems/l5r5e/templates/" + "hud/tactical-grid-ruler.html"
|
||||
static WAYPOINT_LABEL_TEMPLATE = "systems/l5rx-chiaroscuro/templates/" + "hud/tactical-grid-ruler.html"
|
||||
|
||||
/** @override */
|
||||
_getWaypointLabelContext(waypoint, state) {
|
||||
@@ -44,7 +44,7 @@ export class RulerL5r5e extends foundry.canvas.interaction.Ruler {
|
||||
}
|
||||
|
||||
export class TokenRulerL5r5e extends foundry.canvas.placeables.tokens.TokenRuler {
|
||||
static WAYPOINT_LABEL_TEMPLATE = "systems/l5r5e/templates/" + "hud/tactical-grid-ruler.html"
|
||||
static WAYPOINT_LABEL_TEMPLATE = "systems/l5rx-chiaroscuro/templates/" + "hud/tactical-grid-ruler.html"
|
||||
|
||||
/** @override */
|
||||
_getWaypointLabelContext(waypoint, state) {
|
||||
|
||||
@@ -21,5 +21,6 @@
|
||||
@import "../scss/items";
|
||||
@import "../scss/twenty-questions";
|
||||
@import "../scss/tactical-grid";
|
||||
@import "../scss/chiaroscuro";
|
||||
}
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -10,8 +10,6 @@
|
||||
|
||||
.readiness {
|
||||
flex: 0 0 100%;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
|
||||
ul {
|
||||
display: flex;
|
||||
@@ -21,15 +19,20 @@
|
||||
|
||||
li {
|
||||
flex: 25%;
|
||||
display: inline-grid;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
|
||||
.attributes-buttons {
|
||||
position: relative;
|
||||
line-height: 13px;
|
||||
top: 0.3rem;
|
||||
right: 1.2rem;
|
||||
width: 12px;
|
||||
.increment-control {
|
||||
position: absolute;
|
||||
right: -0.70rem;
|
||||
top: 15%;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap:0.1rem;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
strong {
|
||||
@@ -40,14 +43,19 @@
|
||||
}
|
||||
|
||||
label {
|
||||
flex: 100%;
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
input {
|
||||
background: transparent;
|
||||
border: 0 none;
|
||||
text-align: center;
|
||||
margin: 0.3rem 1.6rem 0 1.5rem;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 2rem;
|
||||
}
|
||||
|
||||
&:after {
|
||||
@@ -55,8 +63,6 @@
|
||||
width: 2rem;
|
||||
height: 2rem;
|
||||
position: absolute;
|
||||
right: calc(50% - 0.9rem);
|
||||
top: 0.1rem;
|
||||
background: transparent url("../assets/icons/circle.svg") no-repeat 0 0;
|
||||
background-size: contain;
|
||||
opacity: 0.25;
|
||||
@@ -64,9 +70,6 @@
|
||||
}
|
||||
|
||||
&:nth-child(1) {
|
||||
input {
|
||||
margin: 0.3rem 1rem 0 1.5rem;
|
||||
}
|
||||
&:after {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
@@ -79,9 +82,6 @@
|
||||
}
|
||||
|
||||
&:nth-child(3) {
|
||||
input {
|
||||
margin: 0.3rem 1rem 0 1.5rem;
|
||||
}
|
||||
&:after {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
376
system/styles/scss/chiaroscuro.scss
Normal file
376
system/styles/scss/chiaroscuro.scss
Normal file
@@ -0,0 +1,376 @@
|
||||
// ── Chiaroscuro UI Styles ──────────────────────────────────────────────────
|
||||
|
||||
// ── Aspects (header block on character sheet) ─────────────────────────────
|
||||
.aspects-section {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
gap: 0.25rem 0.5rem;
|
||||
padding: 0.25rem 0.5rem;
|
||||
border: 1px solid rgba($chi-title, 0.3);
|
||||
border-radius: 0.25rem;
|
||||
font-size: 0.85rem;
|
||||
|
||||
.aspect-fields {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
gap: 0.25rem;
|
||||
flex: 1;
|
||||
|
||||
.attribute-label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.25rem;
|
||||
&:nth-child(1) { color: $chi-solar; } // solar
|
||||
&:nth-child(2) { color: $chi-lunar; } // lunar
|
||||
input[type="number"] {
|
||||
width: 3rem;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
.gauge-bar-wrapper {
|
||||
flex: 0 0 100%;
|
||||
height: 0.4rem;
|
||||
background: linear-gradient(to right, $chi-lunar, rgba(128,128,128,0.3) 50%, $chi-solar);
|
||||
border-radius: 0.25rem;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
.gauge-bar {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
height: 100%;
|
||||
border-radius: 0.25rem;
|
||||
opacity: 0.8;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ── État badges (character sheet header) ─────────────────────────────────
|
||||
.etat-summary {
|
||||
flex: 0 0 100%;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
gap: 0.2rem;
|
||||
padding: 0.1rem 0;
|
||||
font-size: 0.8rem;
|
||||
.etat-summary-label {
|
||||
color: $l5r5e-label;
|
||||
font-style: italic;
|
||||
margin-right: 0.2rem;
|
||||
}
|
||||
.etat-badge {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.2rem;
|
||||
padding: 0.1rem 0.35rem;
|
||||
border-radius: 0.2rem;
|
||||
background: rgba($chi-title, 0.18);
|
||||
border: 1px solid rgba($chi-title, 0.4);
|
||||
color: $chi-title;
|
||||
cursor: default;
|
||||
&:hover { background: rgba($chi-title, 0.32); }
|
||||
}
|
||||
}
|
||||
|
||||
// ── NPC Danger levels (identity.html) ────────────────────────────────────
|
||||
.danger-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.4rem;
|
||||
margin: 0.2rem 0;
|
||||
}
|
||||
|
||||
.danger-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.3rem;
|
||||
.danger-select {
|
||||
font-size: 0.85rem;
|
||||
background: $l5r5e-white;
|
||||
border: 0 none;
|
||||
color: $l5r5e-bold;
|
||||
font-family: $font-primary;
|
||||
}
|
||||
}
|
||||
|
||||
.danger-icons {
|
||||
display: flex;
|
||||
gap: 0.15rem;
|
||||
.danger-icon {
|
||||
font-size: 0.9rem;
|
||||
&.fa-skull { color: $l5r5e-red; }
|
||||
&.fa-star { color: $l5r5e-shuji; }
|
||||
}
|
||||
}
|
||||
|
||||
// ── Chiaroscuro Dice Dialog ───────────────────────────────────────────────
|
||||
&.chiaroscuro-dice-dialog {
|
||||
// Header: portrait + actor name
|
||||
.chi-dice-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
padding: 0.5rem;
|
||||
border-bottom: 1px solid rgba($chi-title, 0.3);
|
||||
.profile-img {
|
||||
width: 3rem;
|
||||
height: 3rem;
|
||||
object-fit: cover;
|
||||
border-radius: 50%;
|
||||
border: 2px solid rgba($chi-title, 0.5);
|
||||
}
|
||||
.chi-dice-actor-info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
strong { font-family: $font-secondary; font-size: 1.1rem; color: $chi-title; }
|
||||
.chi-dice-quick-info { font-size: 0.8rem; color: $l5r5e-label; font-style: italic; }
|
||||
}
|
||||
}
|
||||
|
||||
// Section fieldsets
|
||||
.chi-dice-section {
|
||||
flex: 0 0 100%;
|
||||
border: 1px solid rgba($chi-subtitle, 0.35);
|
||||
border-radius: 0.25rem;
|
||||
margin: 0.35rem 0.5rem 0;
|
||||
padding: 0.25rem 0.5rem 0.4rem;
|
||||
legend {
|
||||
font-family: $font-tertiary;
|
||||
font-size: 0.8rem;
|
||||
color: $chi-subtitle;
|
||||
padding: 0 0.25rem;
|
||||
}
|
||||
}
|
||||
|
||||
// Ring selector
|
||||
.chi-rings {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.2rem;
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
li { flex: 1; }
|
||||
.ring-selection-chi {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 0.2rem;
|
||||
border-radius: 0.2rem;
|
||||
border: 1px solid rgba($l5r5e-title, 0.2);
|
||||
cursor: pointer;
|
||||
font-size: 0.75rem;
|
||||
&:hover { border-color: rgba($chi-title, 0.6); background: rgba($chi-title, 0.08); }
|
||||
&.ring-selected {
|
||||
border-color: $chi-title;
|
||||
background: rgba($chi-title, 0.15);
|
||||
strong { text-decoration: underline; }
|
||||
}
|
||||
i { font-size: 1.5rem; }
|
||||
.ring-value { font-weight: bold; font-size: 0.9rem; }
|
||||
}
|
||||
.earth.ring-selection-chi { color: $l5r5e-earth; }
|
||||
.air.ring-selection-chi { color: $l5r5e-air; }
|
||||
.water.ring-selection-chi { color: $l5r5e-water; }
|
||||
.fire.ring-selection-chi { color: $l5r5e-fire; }
|
||||
.void.ring-selection-chi { color: $l5r5e-void-light; }
|
||||
}
|
||||
|
||||
// Skill info row
|
||||
.chi-skill-row {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
gap: 0.4rem;
|
||||
.chi-skill-name { font-weight: bold; flex: 1; }
|
||||
.chi-skill-rank { font-size: 0.8rem; color: $l5r5e-label; }
|
||||
.chi-skill-bonus { font-size: 0.85rem; color: $chi-solar; font-weight: bold; }
|
||||
}
|
||||
|
||||
// Difficulty + modifier row
|
||||
.chi-difficulty-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
select { flex: 1; }
|
||||
.chi-modifier-label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.25rem;
|
||||
font-size: 0.85rem;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
// Options checkboxes
|
||||
.chi-options-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
padding: 0.15rem 0;
|
||||
label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.35rem;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
.chi-auto-aspect { font-size: 0.8rem; color: $l5r5e-label; }
|
||||
}
|
||||
|
||||
// Dice total summary
|
||||
.chi-dice-total-summary {
|
||||
flex: 0 0 100%;
|
||||
text-align: center;
|
||||
padding: 0.4rem;
|
||||
font-size: 0.9rem;
|
||||
.chi-total-dice { font-size: 1.3rem; color: $chi-title; margin: 0 0.2rem; }
|
||||
}
|
||||
|
||||
// Submit button
|
||||
.chi-dice-submit {
|
||||
flex: 0 0 100%;
|
||||
padding: 0.4rem 0.5rem;
|
||||
button[type="submit"] {
|
||||
width: 100%;
|
||||
background: rgba($chi-title, 0.85);
|
||||
border: 1px solid $chi-title;
|
||||
color: $white;
|
||||
font-family: $font-tertiary;
|
||||
font-size: 1rem;
|
||||
padding: 0.4rem;
|
||||
cursor: pointer;
|
||||
border-radius: 0.2rem;
|
||||
&:hover { background: $chi-title; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ── Chiaroscuro Chat Roll ─────────────────────────────────────────────────
|
||||
.chiaroscuro-chat-roll {
|
||||
padding: 0.35rem;
|
||||
font-size: 0.9rem;
|
||||
|
||||
// Header: portrait + actor + badges
|
||||
.chi-chat-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.4rem;
|
||||
margin-bottom: 0.3rem;
|
||||
.profile-img {
|
||||
width: 2.5rem;
|
||||
height: 2.5rem;
|
||||
object-fit: cover;
|
||||
border-radius: 50%;
|
||||
border: 2px solid rgba($chi-title, 0.5);
|
||||
}
|
||||
.chi-chat-actor {
|
||||
flex: 1;
|
||||
strong { font-family: $font-secondary; color: $chi-title; }
|
||||
.chi-chat-quick-info { font-size: 0.75rem; color: $l5r5e-label; font-style: italic; }
|
||||
}
|
||||
.chi-chat-badges {
|
||||
display: flex;
|
||||
gap: 0.2rem;
|
||||
align-items: center;
|
||||
.chi-aspect-badge {
|
||||
font-size: 1rem;
|
||||
&.solar { color: $chi-solar; }
|
||||
&.lunar { color: $chi-lunar; }
|
||||
}
|
||||
.chi-assistance-badge { color: $l5r5e-label; font-size: 1rem; }
|
||||
}
|
||||
}
|
||||
|
||||
// Description line
|
||||
.chi-chat-desc {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.3rem;
|
||||
margin-bottom: 0.3rem;
|
||||
font-size: 0.85rem;
|
||||
.chi-chat-skill { font-weight: bold; color: $chi-title; }
|
||||
.chi-chat-vs { color: $l5r5e-label; }
|
||||
.chi-chat-diff { color: $chi-subtitle; font-style: italic; }
|
||||
}
|
||||
|
||||
// Dice pool
|
||||
.chi-chat-dice-pool {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.25rem;
|
||||
margin-bottom: 0.35rem;
|
||||
.chi-die {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 1.8rem;
|
||||
height: 1.8rem;
|
||||
border-radius: 0.25rem;
|
||||
font-weight: bold;
|
||||
font-size: 1rem;
|
||||
background: rgba($l5r5e-black, 0.35);
|
||||
border: 1px solid rgba($l5r5e-title, 0.4);
|
||||
position: relative;
|
||||
&.die-low { color: $l5r5e-red; border-color: rgba($l5r5e-red, 0.5); }
|
||||
&.die-high { color: $chi-solar; border-color: rgba($chi-solar, 0.5); }
|
||||
.die-adj-icon {
|
||||
position: absolute;
|
||||
top: -0.3rem;
|
||||
right: -0.2rem;
|
||||
font-size: 0.6rem;
|
||||
color: $chi-solar;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Breakdown
|
||||
.chi-chat-breakdown {
|
||||
font-size: 0.85rem;
|
||||
margin-bottom: 0.25rem;
|
||||
color: $l5r5e-label;
|
||||
strong { color: $white; }
|
||||
}
|
||||
|
||||
// Result banner
|
||||
.chi-chat-result {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.3rem;
|
||||
font-family: $font-tertiary;
|
||||
font-size: 1rem;
|
||||
padding: 0.25rem 0.5rem;
|
||||
border-radius: 0.2rem;
|
||||
&.chi-success {
|
||||
background: rgba($chi-subtitle, 0.25);
|
||||
border: 1px solid rgba($chi-subtitle, 0.5);
|
||||
color: $chi-subtitle;
|
||||
}
|
||||
&.chi-failure {
|
||||
background: rgba($l5r5e-red, 0.12);
|
||||
border: 1px solid rgba($l5r5e-red, 0.35);
|
||||
color: $l5r5e-red;
|
||||
}
|
||||
.chi-bonus-successes {
|
||||
font-size: 0.85rem;
|
||||
opacity: 0.85;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ── Skill rank: bonus display ──────────────────────────────────────────────
|
||||
.skill-bonus {
|
||||
color: $chi-solar;
|
||||
font-size: 0.8rem;
|
||||
font-weight: bold;
|
||||
margin-left: 0.2rem;
|
||||
}
|
||||
|
||||
// ── Default ring indicator ────────────────────────────────────────────────
|
||||
.rings .default-ring {
|
||||
text-decoration: underline 2px $chi-title;
|
||||
text-underline-offset: 2px;
|
||||
cursor: pointer;
|
||||
}
|
||||
@@ -53,7 +53,23 @@ $l5r5e-chat-color-roll: rgba(225, 215, 200, 0.75);
|
||||
$l5r5e-chat-color-blind: transparent;
|
||||
$l5r5e-chat-color-whisper: rgba(225, 200, 225, 0.75);
|
||||
|
||||
// -- Rings
|
||||
// Misc
|
||||
$l5r5e-selection-circle-color: #8a1a00;
|
||||
|
||||
// -- Chiaroscuro Colors
|
||||
|
||||
// Title (was: rgba(186, 187, 177, 0.5) → spec: rgb(158, 65, 76))
|
||||
$chi-title: rgb(158, 65, 76);
|
||||
// Subtitle (spec: rgb(103, 128, 119))
|
||||
$chi-subtitle: rgb(103, 128, 119);
|
||||
// Solar aspect (spec: rgb(150, 119, 116))
|
||||
$chi-solar: rgb(150, 119, 116);
|
||||
// Lunar aspect (spec: rgb(100, 147, 137))
|
||||
$chi-lunar: rgb(100, 147, 137);
|
||||
// Active tab accent
|
||||
$chi-tab-active: rgb(158, 65, 76);
|
||||
// Tab hover accent
|
||||
$chi-tab-hover: rgb(103, 128, 119);
|
||||
|
||||
// Earth
|
||||
$l5r5e-earth: rgb(105, 150, 120);
|
||||
@@ -65,6 +81,7 @@ $l5r5e-water: rgb(95, 145, 155);
|
||||
$l5r5e-fire: rgb(155, 115, 80);
|
||||
// Void
|
||||
$l5r5e-void: rgb(75, 70, 65);
|
||||
$l5r5e-void-light: rgba(207,207,207,.8);
|
||||
|
||||
// -- Clans
|
||||
|
||||
|
||||
@@ -5,9 +5,55 @@
|
||||
cursor: url("../assets/cursors/pointer.webp"), pointer;
|
||||
}
|
||||
|
||||
// define a mixin
|
||||
@mixin roll-effects-base {
|
||||
clear: both;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
gap: 2px 4px;
|
||||
|
||||
.effect-container {
|
||||
border: 1px solid #5a6e5a;
|
||||
border-radius: 4px;
|
||||
background-color: rgba(0, 0, 0, 0.4);
|
||||
padding: 3px;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.effect-delete {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
background-repeat: no-repeat;
|
||||
background-size: contain;
|
||||
text-align: end;
|
||||
cursor: url("../assets/cursors/pointer.webp"), pointer;
|
||||
}
|
||||
|
||||
.effect-icon {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
background-repeat: no-repeat;
|
||||
background-size: contain;
|
||||
}
|
||||
|
||||
.effect-name {
|
||||
vertical-align: top;
|
||||
white-space: nowrap;
|
||||
color: $white;
|
||||
margin-left: 4px;
|
||||
font-size: 14px;
|
||||
line-height: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
// Dice Picker
|
||||
.dice-picker-dialog {
|
||||
min-width: 35rem;
|
||||
.effects {
|
||||
@include roll-effects-base();
|
||||
}
|
||||
|
||||
width: 35rem;
|
||||
min-height: auto;
|
||||
// Utility
|
||||
* {
|
||||
@@ -206,6 +252,12 @@
|
||||
|
||||
.profil {
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.1);
|
||||
display: flex;
|
||||
flex-direction: column; // stack profile ul and effects ul vertically
|
||||
|
||||
.effects {
|
||||
@include roll-effects-base();
|
||||
}
|
||||
}
|
||||
|
||||
.dropbox {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
.application {
|
||||
color: var(--color-text-dark-primary);
|
||||
color: var(--color-text-primary);
|
||||
|
||||
.scrollable {
|
||||
--scroll-margin: 0;
|
||||
@@ -48,10 +48,69 @@
|
||||
}
|
||||
}
|
||||
|
||||
// Handle Sidebar here. Starting with custom icons
|
||||
$l5r5e-custom-icons: (
|
||||
chatIcon: "../assets/ui/sidebar/chat.svg",
|
||||
combatIcon: "../assets/ui/sidebar/combat-tracker.svg",
|
||||
sceneIcon: "../assets/ui/sidebar/scenes.svg",
|
||||
actorIcon: "../assets/ui/sidebar/actors.svg",
|
||||
itemIcon: "../assets/ui/sidebar/object.svg",
|
||||
journalIcon: "../assets/ui/sidebar/journal.svg",
|
||||
rolltableIcon: "../assets/ui/sidebar/rolltable.svg",
|
||||
playlistIcon: "../assets/ui/sidebar/playlist.svg",
|
||||
compendiumIcon: "../assets/ui/sidebar/compendium.svg",
|
||||
settingsIcon: "../assets/ui/sidebar/settings.svg"
|
||||
);
|
||||
|
||||
$selectors: (
|
||||
"#sidebar-tabs button.l5r5e",
|
||||
"#sidebar-content .create-button.l5r5e",
|
||||
"#sidebar-content i.l5r5e"
|
||||
);
|
||||
|
||||
@each $selector in $selectors {
|
||||
#{$selector} {
|
||||
position: relative;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
@if str-index($selector, "i.") {
|
||||
width: 2em;
|
||||
height: 2em;
|
||||
color: currentColor;
|
||||
}
|
||||
|
||||
@if str-index($selector, "create-button") {
|
||||
filter: drop-shadow(0 0 3px var(--color-dark-1));
|
||||
}
|
||||
|
||||
// Apply masks for each icon
|
||||
@each $name, $url in $l5r5e-custom-icons {
|
||||
&.#{$name}::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
width: 95%;
|
||||
height: 95%;
|
||||
background-color: currentColor;
|
||||
mask: url($url) no-repeat center / contain;
|
||||
-webkit-mask: url($url) no-repeat center / contain;
|
||||
z-index: 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Generic plus icon badge
|
||||
&.icon-plus::after {
|
||||
z-index: 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#sidebar-tabs > menu {
|
||||
gap: 4px; // halve the distance between menu icons
|
||||
}
|
||||
|
||||
|
||||
#sidebar-content.expanded {
|
||||
background: url("../assets/ui/bgSidebar.webp") no-repeat;
|
||||
border-image: url("../assets/ui/macro-button.webp") 10 repeat;
|
||||
|
||||
@@ -28,7 +28,7 @@ nav {
|
||||
.item {
|
||||
flex: 1;
|
||||
&:hover {
|
||||
background-color: $l5r5e-label;
|
||||
background-color: $chi-tab-hover;
|
||||
color: $white-light;
|
||||
text-shadow: none;
|
||||
clip-path: polygon(
|
||||
@@ -44,7 +44,7 @@ nav {
|
||||
}
|
||||
}
|
||||
.item.active {
|
||||
background-color: rgba(73, 12, 11, 0.85);
|
||||
background-color: $chi-tab-active;
|
||||
color: rgba(255, 255, 255, 1);
|
||||
clip-path: polygon(
|
||||
0% var(--notchSize),
|
||||
@@ -58,7 +58,7 @@ nav {
|
||||
);
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(73, 12, 11, 0.85);
|
||||
background-color: $chi-tab-active;
|
||||
cursor: default;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -326,7 +326,7 @@
|
||||
margin: 0.25rem 0;
|
||||
flex-direction: row-reverse;
|
||||
strong {
|
||||
flex: 0 0 calc(100% - 3.5rem);
|
||||
flex: 0 0 calc(100% - 4.5rem);
|
||||
}
|
||||
input {
|
||||
flex: 0 0 3rem;
|
||||
@@ -444,7 +444,7 @@
|
||||
width: 3.5rem;
|
||||
}
|
||||
}
|
||||
.attributes-buttons {
|
||||
.increment-control {
|
||||
line-height: 13px;
|
||||
position: relative;
|
||||
top: 0.2rem;
|
||||
@@ -751,12 +751,22 @@
|
||||
flex: calc(100% / 3);
|
||||
padding: 0.5rem;
|
||||
font-size: 0.85rem;
|
||||
align-items: center;
|
||||
input {
|
||||
margin-left: 0.5rem;
|
||||
}
|
||||
}
|
||||
.xp-buttons,
|
||||
.money-buttons {
|
||||
line-height: 13px;
|
||||
padding-left: 0.3em;
|
||||
}
|
||||
.increment-control {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding-left: 0.2rem;
|
||||
flex: none;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,18 +1,17 @@
|
||||
{
|
||||
"id": "l5r5e",
|
||||
"title": "Legend of the Five Rings (5th Edition)",
|
||||
"id": "l5rx-chiaroscuro",
|
||||
"title": "Chiaroscuro - L5R",
|
||||
"description": "This is an authorised multilingual game system En|Fr|Es, for Legend of the Five Rings (5th Edition) by <a href='https://edge-studio.net/'>Edge Studio</a> <p> - Join the official Discord server: <a href='https://discord.gg/foundryvtt'> Official Discord</a></p><p> - Rejoignez la communauté Francophone: <a href='https://discord.gg/pPSDNJk'>Francophone Discord</a></p>",
|
||||
"url": "https://gitlab.com/teaml5r/l5r5e",
|
||||
"readme": "https://gitlab.com/teaml5r/l5r5e/-/blob/master/README.md",
|
||||
"changelog": "https://gitlab.com/teaml5r/l5r5e/-/blob/master/CHANGELOG.md",
|
||||
"license": "https://gitlab.com/teaml5r/l5r5e/-/blob/master/LICENSE.md",
|
||||
"manifest": "https://gitlab.com/teaml5r/l5r5e/-/raw/master/system/system.json",
|
||||
"download": "https://gitlab.com/teaml5r/l5r5e/-/jobs/artifacts/v1.13.3/raw/l5r5e.zip?job=build",
|
||||
"version": "1.13.3",
|
||||
"download": "https://gitlab.com/teaml5r/l5r5e/-/jobs/artifacts/v1.13.4/raw/l5r5e.zip?job=build",
|
||||
"version": "14.0.0",
|
||||
"compatibility": {
|
||||
"minimum": "13",
|
||||
"verified": "13",
|
||||
"maximum": "13"
|
||||
"verified": "14"
|
||||
},
|
||||
"socket": true,
|
||||
"authors": [
|
||||
@@ -29,6 +28,10 @@
|
||||
"name": "Carter",
|
||||
"discord": "Carter#2703",
|
||||
"url": "https://fr.tipeee.com/carter-foundryvtt"
|
||||
},
|
||||
{
|
||||
"name": "Litasa",
|
||||
"discord": "Litasa#3139"
|
||||
}
|
||||
],
|
||||
"background": "systems/l5r5e/assets/l5r-header.webp",
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
"age": "",
|
||||
"clan": "",
|
||||
"family": "",
|
||||
"region": "",
|
||||
"education": "",
|
||||
"female": null,
|
||||
"marital_status": "",
|
||||
"roles": "",
|
||||
@@ -36,6 +38,7 @@
|
||||
"status": 0,
|
||||
"ninjo": "",
|
||||
"giri": "",
|
||||
"past_problems": "",
|
||||
"bushido_tenets": {
|
||||
"paramount": "",
|
||||
"less_significant": ""
|
||||
@@ -118,18 +121,34 @@
|
||||
"mantra": false,
|
||||
"specificity": true
|
||||
}
|
||||
},
|
||||
"aspects": {
|
||||
"aspects": {
|
||||
"solar": 0,
|
||||
"lunar": 0,
|
||||
"gauge": 0
|
||||
}
|
||||
}
|
||||
},
|
||||
"character": {
|
||||
"templates": ["softlock", "identity", "rings", "social", "skills", "techniques", "conflict", "advancement"],
|
||||
"templates": ["softlock", "identity", "rings", "social", "skills", "techniques", "conflict", "advancement", "aspects"],
|
||||
"template": "core",
|
||||
"twenty_questions": {},
|
||||
"zeni": 0
|
||||
"is_samurai": true,
|
||||
"quick_info": "",
|
||||
"default_ring": "void",
|
||||
"koku": 0,
|
||||
"bu": 0,
|
||||
"zeni": 0,
|
||||
"identity_text1": "",
|
||||
"identity_text2": "",
|
||||
"twenty_questions": {}
|
||||
},
|
||||
"npc": {
|
||||
"templates": ["softlock", "identity", "rings", "social", "techniques", "conflict"],
|
||||
"type": "adversary",
|
||||
"attitude": "",
|
||||
"martial_danger": "simple",
|
||||
"social_danger": "simple",
|
||||
"conflict_rank": {
|
||||
"martial": 0,
|
||||
"social": 0
|
||||
@@ -194,7 +213,10 @@
|
||||
"signature_scroll",
|
||||
"item_pattern",
|
||||
"army_cohort",
|
||||
"army_fortification"
|
||||
"army_fortification",
|
||||
"arcane",
|
||||
"etat",
|
||||
"mystere"
|
||||
],
|
||||
"templates": {
|
||||
"basics": {
|
||||
@@ -224,10 +246,12 @@
|
||||
}
|
||||
},
|
||||
"item": {
|
||||
"templates": ["basics", "item"]
|
||||
"templates": ["basics", "item"],
|
||||
"item_type": ""
|
||||
},
|
||||
"armor": {
|
||||
"templates": ["basics", "item"],
|
||||
"armor_category": "",
|
||||
"armor": {
|
||||
"physical": 0,
|
||||
"supernatural": 0
|
||||
@@ -236,6 +260,7 @@
|
||||
"weapon": {
|
||||
"templates": ["basics", "item"],
|
||||
"category": "",
|
||||
"bonus": 0,
|
||||
"skill": "melee",
|
||||
"readied": false,
|
||||
"range": "0",
|
||||
@@ -248,7 +273,9 @@
|
||||
"templates": ["basics", "advancement"],
|
||||
"skill": "",
|
||||
"difficulty": "",
|
||||
"technique_type": "kata"
|
||||
"technique_type": "kata",
|
||||
"invocation_type": "",
|
||||
"mode_invocation": 0
|
||||
},
|
||||
"property": {
|
||||
"templates": ["basics"],
|
||||
@@ -303,6 +330,27 @@
|
||||
"difficulty": 0,
|
||||
"attrition_reduction": 0,
|
||||
"notes": ""
|
||||
},
|
||||
"arcane": {
|
||||
"templates": ["basics"],
|
||||
"arcane_type": "",
|
||||
"application": [],
|
||||
"bonus": 2,
|
||||
"progression": "",
|
||||
"xp_cost": 1
|
||||
},
|
||||
"etat": {
|
||||
"templates": ["basics"],
|
||||
"application": "",
|
||||
"mod": 0,
|
||||
"effect": "",
|
||||
"elimination": ""
|
||||
},
|
||||
"mystere": {
|
||||
"templates": ["basics"],
|
||||
"mystere_type": "mineur",
|
||||
"prerequisite_skill": "",
|
||||
"prerequisite_condition": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,9 +70,9 @@
|
||||
{{#each list as |technique|}}
|
||||
<li>
|
||||
{{#ifCond techName '==' 'title_ability'}}
|
||||
{{> 'systems/l5r5e/templates/items/title/title-text.html' data=technique editable=../../options.editable}}
|
||||
{{> 'systems/l5rx-chiaroscuro/templates/items/title/title-text.html' data=technique editable=../../options.editable}}
|
||||
{{else}}
|
||||
{{> 'systems/l5r5e/templates/items/technique/technique-text.html' data=technique editable=../../options.editable}}
|
||||
{{> 'systems/l5rx-chiaroscuro/templates/items/technique/technique-text.html' data=technique editable=../../options.editable}}
|
||||
{{/ifCond}}
|
||||
</li>
|
||||
{{/each}}
|
||||
@@ -86,7 +86,7 @@
|
||||
<ul>
|
||||
{{#each actor.items as |scroll|}}
|
||||
{{#ifCond scroll.type '==' 'signature_scroll'}}
|
||||
<li>{{> 'systems/l5r5e/templates/items/signature-scroll/signature-scroll-text.html' data=scroll editable=../options.editable}}</li>
|
||||
<li>{{> 'systems/l5rx-chiaroscuro/templates/items/signature-scroll/signature-scroll-text.html' data=scroll editable=../options.editable}}</li>
|
||||
{{/ifCond}}
|
||||
{{/each}}
|
||||
</ul>
|
||||
@@ -97,7 +97,7 @@
|
||||
<ul>
|
||||
{{#each data.items as |item|}}
|
||||
{{#ifCond '["distinction","passion"]' 'includes' item.system.peculiarity_type}}
|
||||
<li>{{> 'systems/l5r5e/templates/items/peculiarity/peculiarity-text.html' data=item editable=../options.editable}}</li>
|
||||
<li>{{> 'systems/l5rx-chiaroscuro/templates/items/peculiarity/peculiarity-text.html' data=item editable=../options.editable}}</li>
|
||||
{{/ifCond}}
|
||||
{{/each}}
|
||||
</ul>
|
||||
@@ -107,7 +107,7 @@
|
||||
<ul>
|
||||
{{#each data.items as |item|}}
|
||||
{{#ifCond '["adversity","anxiety"]' 'includes' item.system.peculiarity_type}}
|
||||
<li>{{> 'systems/l5r5e/templates/items/peculiarity/peculiarity-text.html' data=item editable=../options.editable}}</li>
|
||||
<li>{{> 'systems/l5rx-chiaroscuro/templates/items/peculiarity/peculiarity-text.html' data=item editable=../options.editable}}</li>
|
||||
{{/ifCond}}
|
||||
{{/each}}
|
||||
</ul>
|
||||
@@ -117,7 +117,7 @@
|
||||
<ul>
|
||||
{{#each data.items as |bond|}}
|
||||
{{#ifCond bond.type '==' 'bond'}}
|
||||
<li>{{> 'systems/l5r5e/templates/items/bond/bond-text.html' data=bond editable=../options.editable}}</li>
|
||||
<li>{{> 'systems/l5rx-chiaroscuro/templates/items/bond/bond-text.html' data=bond editable=../options.editable}}</li>
|
||||
{{/ifCond}}
|
||||
{{/each}}
|
||||
</ul>
|
||||
@@ -133,7 +133,7 @@
|
||||
<strong>{{localize (localize 'l5r5e.{type}s.title' type=type)}} ({{cat.length}})</strong>
|
||||
<ul>
|
||||
{{#each cat as |item|}}
|
||||
<li>{{> 'systems/l5r5e/templates/items/item/item-text.html' data=item editable=../../options.editable}}</li>
|
||||
<li>{{> 'systems/l5rx-chiaroscuro/templates/items/item/item-text.html' data=item editable=../../options.editable}}</li>
|
||||
{{/each}}
|
||||
</ul>
|
||||
</li>
|
||||
@@ -145,7 +145,7 @@
|
||||
<ul>
|
||||
{{#each actor.items as |pattern|}}
|
||||
{{#ifCond pattern.type '==' 'item_pattern'}}
|
||||
<li>{{> 'systems/l5r5e/templates/items/item-pattern/item-pattern-text.html' data=pattern editable=../options.editable}}</li>
|
||||
<li>{{> 'systems/l5rx-chiaroscuro/templates/items/item-pattern/item-pattern-text.html' data=pattern editable=../options.editable}}</li>
|
||||
{{/ifCond}}
|
||||
{{/each}}
|
||||
</ul>
|
||||
|
||||
@@ -13,9 +13,9 @@
|
||||
<div class="readiness">
|
||||
<ul>
|
||||
<li>
|
||||
<label class="attribute-label-casualties">
|
||||
<label class="attribute-label casualties">
|
||||
<input name="system.battle_readiness.casualties_strength.value" type="number" value="{{data.system.battle_readiness.casualties_strength.value}}" {{^if data.editable_not_soft_locked}}disabled{{/if}}/>
|
||||
<span class="attributes-buttons">
|
||||
<span class="increment-control casualties">
|
||||
<i class="addsub-control pointer-choice fa fa-plus-square" data-type="casualties" data-value="1"></i>
|
||||
<i class="addsub-control pointer-choice fa fa-minus-square" data-type="casualties" data-value="-1"></i>
|
||||
</span>
|
||||
@@ -23,15 +23,15 @@
|
||||
<strong>{{localize 'l5r5e.army.battle_readiness.casualties'}}</strong>
|
||||
</li>
|
||||
<li>
|
||||
<label class="attribute-label-strength">
|
||||
<label class="attribute-label strength">
|
||||
<input name="system.battle_readiness.casualties_strength.max" type="number" value="{{data.system.battle_readiness.casualties_strength.max}}" {{^if data.editable_not_soft_locked}}disabled{{/if}}/>
|
||||
</label>
|
||||
<strong>{{localize 'l5r5e.army.battle_readiness.strength'}}</strong>
|
||||
</li>
|
||||
<li>
|
||||
<label class="attribute-label-panic">
|
||||
<label class="attribute-label panic">
|
||||
<input name="system.battle_readiness.panic_discipline.value" type="number" value="{{data.system.battle_readiness.panic_discipline.value}}" {{^if data.editable_not_soft_locked}}disabled{{/if}}/>
|
||||
<span class="attributes-buttons">
|
||||
<span class="increment-control panic">
|
||||
<i class="addsub-control pointer-choice fa fa-plus-square" data-type="panic" data-value="1"></i>
|
||||
<i class="addsub-control pointer-choice fa fa-minus-square" data-type="panic" data-value="-1"></i>
|
||||
</span>
|
||||
@@ -39,7 +39,7 @@
|
||||
<strong>{{localize 'l5r5e.army.battle_readiness.panic'}}</strong>
|
||||
</li>
|
||||
<li>
|
||||
<label class="attribute-label-discipline">
|
||||
<label class="attribute-label discipline">
|
||||
<input name="system.battle_readiness.panic_discipline.max" type="number" value="{{data.system.battle_readiness.panic_discipline.max}}" {{^if data.editable_not_soft_locked}}disabled{{/if}}/>
|
||||
</label>
|
||||
<strong>{{localize 'l5r5e.army.battle_readiness.discipline'}}</strong>
|
||||
@@ -60,22 +60,22 @@
|
||||
|
||||
{{!-- Army Tab --}}
|
||||
<article class="tab army" data-group="primary" data-tab="army">
|
||||
{{> 'systems/l5r5e/templates/actors/army/army.html'}}
|
||||
{{> 'systems/l5rx-chiaroscuro/templates/actors/army/army.html'}}
|
||||
</article>
|
||||
|
||||
{{!-- Cohort Tab --}}
|
||||
<article class="tab cohort" data-group="primary" data-tab="cohort">
|
||||
{{> 'systems/l5r5e/templates/actors/army/cohort.html'}}
|
||||
{{> 'systems/l5rx-chiaroscuro/templates/actors/army/cohort.html'}}
|
||||
</article>
|
||||
|
||||
{{!-- Fortification Tab --}}
|
||||
<article class="tab fortification" data-group="primary" data-tab="fortification">
|
||||
{{> 'systems/l5r5e/templates/actors/army/fortification.html'}}
|
||||
{{> 'systems/l5rx-chiaroscuro/templates/actors/army/fortification.html'}}
|
||||
</article>
|
||||
|
||||
{{!-- Others Tab --}}
|
||||
<article class="tab others" data-group="primary" data-tab="others">
|
||||
{{> 'systems/l5r5e/templates/actors/army/others.html'}}
|
||||
{{> 'systems/l5rx-chiaroscuro/templates/actors/army/others.html'}}
|
||||
</article>
|
||||
</section>
|
||||
</form>
|
||||
@@ -7,7 +7,7 @@
|
||||
</legend>
|
||||
<ul class="item-list">
|
||||
{{#each data.splitItemsList.army_cohort as |item|}}
|
||||
{{> 'systems/l5r5e/templates/items/army-cohort/army-cohort-entry.html' cohort=item editable=../data.editable_not_soft_locked}}
|
||||
{{> 'systems/l5rx-chiaroscuro/templates/items/army-cohort/army-cohort-entry.html' cohort=item editable=../data.editable_not_soft_locked}}
|
||||
{{/each}}
|
||||
</ul>
|
||||
</fieldset>
|
||||
@@ -7,7 +7,7 @@
|
||||
</legend>
|
||||
<ul class="item-list">
|
||||
{{#each data.splitItemsList.army_fortification as |item|}}
|
||||
{{> 'systems/l5r5e/templates/items/army-fortification/army-fortification-entry.html' fortification=item editable=../data.editable_not_soft_locked}}
|
||||
{{> 'systems/l5rx-chiaroscuro/templates/items/army-fortification/army-fortification-entry.html' fortification=item editable=../data.editable_not_soft_locked}}
|
||||
{{/each}}
|
||||
</ul>
|
||||
</fieldset>
|
||||
@@ -15,62 +15,77 @@
|
||||
<input name="name" type="text" value="{{data.name}}" placeholder="Name" {{^if
|
||||
data.editable_not_soft_locked}}disabled{{/if}} />
|
||||
</h1>
|
||||
{{> 'systems/l5r5e/templates/actors/character/identity.html'}}
|
||||
{{> 'systems/l5rx-chiaroscuro/templates/actors/character/identity.html'}}
|
||||
</div>
|
||||
<div class="header-fields mid-wrapper">
|
||||
<div class="side-col">
|
||||
<h2>{{localize 'l5r5e.social.title'}}</h2>
|
||||
{{> 'systems/l5r5e/templates/actors/character/social.html'}}
|
||||
{{> 'systems/l5rx-chiaroscuro/templates/actors/character/social.html'}}
|
||||
</div>
|
||||
<div class="central-col">{{> 'systems/l5r5e/templates/actors/character/rings.html'}}</div>
|
||||
<div class="central-col">{{> 'systems/l5rx-chiaroscuro/templates/actors/character/rings.html'}}</div>
|
||||
<div class="side-col">
|
||||
<h2 class="right">{{localize 'l5r5e.attributes.title'}}</h2>
|
||||
{{> 'systems/l5r5e/templates/actors/character/attributes.html'}}
|
||||
{{> 'systems/l5rx-chiaroscuro/templates/actors/character/attributes.html'}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="header-fields chiaroscuro-aspects-wrapper">
|
||||
{{> 'systems/l5rx-chiaroscuro/templates/actors/character/aspects.html'}}
|
||||
</div>
|
||||
</header>
|
||||
{{!-- Sheet Body --}}
|
||||
<section class="sheet-body">
|
||||
{{!-- Active effects --}}
|
||||
{{> 'systems/l5r5e/templates/actors/character/effects.html'}}
|
||||
{{> 'systems/l5rx-chiaroscuro/templates/actors/character/effects.html'}}
|
||||
|
||||
{{!-- Sheet Tab Navigation --}}
|
||||
<nav class="sheet-tabs tabs" data-group="primary">
|
||||
<a class="item" data-tab="skills">{{localize 'l5r5e.skills.title'}}</a>
|
||||
<a class="item" data-tab="narrative">{{localize 'l5r5e.sheets.narrative'}}</a>
|
||||
<a class="item" data-tab="invocations">{{localize 'chiaroscuro.tabs.invocations'}}</a>
|
||||
<a class="item" data-tab="conflict">{{localize 'l5r5e.conflict.title'}}</a>
|
||||
<a class="item" data-tab="inventory">{{localize 'l5r5e.sheets.inventory'}}</a>
|
||||
<a class="item" data-tab="experience">{{localize 'l5r5e.sheets.experience'}}</a>
|
||||
<a class="item" data-tab="identity">{{localize 'chiaroscuro.tabs.identity'}}</a>
|
||||
</nav>
|
||||
|
||||
{{!-- Skills Tab --}}
|
||||
<article class="tab skills" data-group="primary" data-tab="skills">
|
||||
<ul class="skills-wrapper">
|
||||
{{#each data.system.skills as |category id|}} {{>
|
||||
'systems/l5r5e/templates/actors/character/category.html' category=category categoryId=id data=../data}}
|
||||
'systems/l5rx-chiaroscuro/templates/actors/character/category.html' category=category categoryId=id data=../data}}
|
||||
{{/each}}
|
||||
</ul>
|
||||
{{> 'systems/l5r5e/templates/actors/character/techniques.html'}}
|
||||
{{> 'systems/l5rx-chiaroscuro/templates/actors/character/techniques.html'}}
|
||||
</article>
|
||||
|
||||
{{!-- Narrative Tab --}}
|
||||
<article class="tab narrative" data-group="primary" data-tab="narrative">
|
||||
{{> 'systems/l5r5e/templates/actors/character/narrative.html'}}
|
||||
{{> 'systems/l5rx-chiaroscuro/templates/actors/character/narrative.html'}}
|
||||
</article>
|
||||
|
||||
{{!-- Conflict Tab --}}
|
||||
<article class="tab conflict" data-group="primary" data-tab="conflict">
|
||||
{{> 'systems/l5r5e/templates/actors/character/conflict.html'}}
|
||||
{{> 'systems/l5rx-chiaroscuro/templates/actors/character/conflict.html'}}
|
||||
</article>
|
||||
|
||||
{{!-- Inventory Tab --}}
|
||||
<article class="tab inventory" data-group="primary" data-tab="inventory">
|
||||
{{> 'systems/l5r5e/templates/actors/character/inventory.html'}}
|
||||
{{> 'systems/l5rx-chiaroscuro/templates/actors/character/inventory.html'}}
|
||||
</article>
|
||||
|
||||
{{!-- Experience Tab --}}
|
||||
<article class="tab experience" data-group="primary" data-tab="experience">
|
||||
{{> 'systems/l5r5e/templates/actors/character/experience.html'}}
|
||||
{{> 'systems/l5rx-chiaroscuro/templates/actors/character/experience.html'}}
|
||||
</article>
|
||||
|
||||
{{!-- Invocations Tab --}}
|
||||
<article class="tab invocations" data-group="primary" data-tab="invocations">
|
||||
{{> 'systems/l5rx-chiaroscuro/templates/actors/character/invocations.html'}}
|
||||
</article>
|
||||
|
||||
{{!-- Identity Tab --}}
|
||||
<article class="tab identity" data-group="primary" data-tab="identity">
|
||||
{{> 'systems/l5rx-chiaroscuro/templates/actors/character/identity-text.html'}}
|
||||
</article>
|
||||
</section>
|
||||
</form>
|
||||
|
||||
30
system/templates/actors/character/aspects.html
Normal file
30
system/templates/actors/character/aspects.html
Normal file
@@ -0,0 +1,30 @@
|
||||
<div class="aspects-section">
|
||||
<div class="aspect-fields">
|
||||
<label class="attribute-label">
|
||||
{{localize 'chiaroscuro.aspects.solar'}}
|
||||
<input type="number" name="system.aspects.aspects.solar" value="{{data.system.aspects.aspects.solar}}" class="select-on-focus" data-dtype="Number" min="0" max="100" {{^if data.editable_not_soft_locked}}disabled{{/if}}/>
|
||||
</label>
|
||||
<label class="attribute-label">
|
||||
{{localize 'chiaroscuro.aspects.lunar'}}
|
||||
<input type="number" name="system.aspects.aspects.lunar" value="{{data.system.aspects.aspects.lunar}}" class="select-on-focus" data-dtype="Number" min="0" max="100" {{^if data.editable_not_soft_locked}}disabled{{/if}}/>
|
||||
</label>
|
||||
<label class="attribute-label">
|
||||
{{localize 'chiaroscuro.aspects.gauge'}}
|
||||
<input type="number" name="system.aspects.aspects.gauge" value="{{data.system.aspects.aspects.gauge}}" class="select-on-focus" data-dtype="Number" min="-10" max="10" {{^if data.editable_not_soft_locked}}disabled{{/if}}/>
|
||||
</label>
|
||||
<div class="gauge-bar-wrapper">
|
||||
<div class="gauge-bar" style="width: {{data.aspectsData.gaugePercent}}%; background-color: {{data.aspectsData.gaugeColor}};"></div>
|
||||
</div>
|
||||
</div>
|
||||
{{#if data.etatItems.length}}
|
||||
<div class="etat-summary">
|
||||
<span class="etat-summary-label">{{localize 'chiaroscuro.etat.title'}}</span>
|
||||
{{#each data.etatItems as |etat|}}
|
||||
<span class="etat-badge l5r5e-tooltip" title="{{etat.system.effect}}">
|
||||
<img src="{{etat.img}}" width="16" height="16" />
|
||||
{{etat.name}}
|
||||
</span>
|
||||
{{/each}}
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
@@ -7,7 +7,7 @@
|
||||
<label class="attribute-label">
|
||||
<strong>{{localize 'l5r5e.attributes.fatigue'}}</strong>
|
||||
<input class="centered-input select-on-focus" type="number" name="system.fatigue.value" value="{{data.system.fatigue.value}}" data-dtype="Number" min="0" placeholder="0" {{^if data.editable_not_soft_locked}}disabled{{/if}}/>
|
||||
<span class="attributes-buttons">
|
||||
<span class="increment-control fatigue">
|
||||
<i class="addsub-control pointer-choice fa fa-plus-square" data-type="fatigue" data-value="1"></i>
|
||||
<i class="addsub-control pointer-choice fa fa-minus-square" data-type="fatigue" data-value="-1"></i>
|
||||
</span>
|
||||
@@ -22,7 +22,7 @@
|
||||
<label class="attribute-label">
|
||||
<strong>{{localize 'l5r5e.attributes.strife'}}</strong>
|
||||
<input class="centered-input select-on-focus" type="number" name="system.strife.value" value="{{data.system.strife.value}}" data-dtype="Number" min="0" placeholder="0" {{^if data.editable_not_soft_locked}}disabled{{/if}}/>
|
||||
<span class="attributes-buttons">
|
||||
<span class="increment-control strife">
|
||||
<i class="addsub-control pointer-choice fa fa-plus-square" data-type="strife" data-value="1"></i>
|
||||
<i class="addsub-control pointer-choice fa fa-minus-square" data-type="strife" data-value="-1"></i>
|
||||
</span>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<h4 class="section-header toggle-on-click" data-toggle="toggle-skill-category-{{categoryId}}">{{localizeSkill categoryId 'title'}}</h4>
|
||||
<ul class="skill-category-skills-list toggle-skill-category-{{categoryId}} {{#ifCond data.storeInfos 'includes' (concat 'toggle-skill-category-' categoryId)}}toggle-hidden{{/ifCond}}">
|
||||
{{#each category as |skill id|}}
|
||||
{{> 'systems/l5r5e/templates/actors/character/skill.html' categoryId=../categoryId skill=skill skillId=id data=../data}}
|
||||
{{> 'systems/l5rx-chiaroscuro/templates/actors/character/skill.html' categoryId=../categoryId skill=skill skillId=id data=../data}}
|
||||
{{/each}}
|
||||
</ul>
|
||||
<ul class="skill-category-ring-actions toggle-skill-category-{{categoryId}} {{#ifCond data.storeInfos 'includes' (concat 'toggle-skill-category-' categoryId)}}toggle-hidden{{/ifCond}}">
|
||||
|
||||
@@ -14,9 +14,9 @@
|
||||
<legend class="section-header">{{localize 'l5r5e.conflict.stance'}}</legend>
|
||||
<ul class="item-list">
|
||||
{{#each data.system.rings as |ringValue ringId|}}
|
||||
{{> 'systems/l5r5e/templates/actors/character/stance.html' stance=../data.system.stance ringId=ringId}}
|
||||
{{> 'systems/l5rx-chiaroscuro/templates/actors/character/stance.html' stance=../data.system.stance ringId=ringId}}
|
||||
{{/each}}
|
||||
</ul>
|
||||
</fieldset>
|
||||
{{> 'systems/l5r5e/templates/items/weapon/weapons.html' }}
|
||||
{{> 'systems/l5r5e/templates/items/armor/armors.html' }}
|
||||
{{> 'systems/l5rx-chiaroscuro/templates/items/weapon/weapons.html' }}
|
||||
{{> 'systems/l5rx-chiaroscuro/templates/items/armor/armors.html' }}
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
<label class="attribute-label">
|
||||
{{localize 'l5r5e.advancements.total'}}
|
||||
<input class="centered-input select-on-focus" type="number" name="system.xp_total" value="{{data.system.xp_total}}" data-dtype="Number" min="0" placeholder="0" {{^if data.editable_not_soft_locked}}disabled{{/if}}/>
|
||||
<span class="increment-control xp">
|
||||
<i class="xp-control pointer-choice fa fa-plus-square" data-type="xp" data-value="1"></i>
|
||||
<i class="xp-control pointer-choice fa fa-minus-square" data-type="xp" data-value="-1"></i>
|
||||
</span>
|
||||
</label>
|
||||
<label class="attribute-label">
|
||||
{{localize 'l5r5e.advancements.spent'}}
|
||||
@@ -48,7 +52,7 @@
|
||||
<tbody class="flex">
|
||||
{{#each data.advancementsListByRank as |rankObject|}}
|
||||
{{#each rankObject.list as |advancement advancementId|}}
|
||||
{{> 'systems/l5r5e/templates/actors/character/advancement-school.html' advancement=advancement rank=rankObject.rank editable=../../data.editable_not_soft_locked}}
|
||||
{{> 'systems/l5rx-chiaroscuro/templates/actors/character/advancement-school.html' advancement=advancement rank=rankObject.rank editable=../../data.editable_not_soft_locked}}
|
||||
{{/each}}
|
||||
{{#ifCond rankObject.rank '>' 0}}
|
||||
<tr class="tfoot flexrow row tab" data-group="advancements" data-tab="advancement_rank_{{rankObject.rank}}">
|
||||
@@ -94,7 +98,7 @@
|
||||
</thead>
|
||||
<tbody class="flex">
|
||||
{{#each data.advancementsOthers as |advancement advancementId|}}
|
||||
{{> 'systems/l5r5e/templates/actors/character/advancement-others.html' advancement=advancement show_curriculum_toggle=false editable=../data.editable_not_soft_locked}}
|
||||
{{> 'systems/l5rx-chiaroscuro/templates/actors/character/advancement-others.html' advancement=advancement show_curriculum_toggle=false editable=../data.editable_not_soft_locked}}
|
||||
{{/each}}
|
||||
</tbody>
|
||||
<tfoot class="flex">
|
||||
|
||||
10
system/templates/actors/character/identity-text.html
Normal file
10
system/templates/actors/character/identity-text.html
Normal file
@@ -0,0 +1,10 @@
|
||||
<div class="identity-text-wrapper flexrow">
|
||||
<fieldset class="identity-text-block">
|
||||
<legend class="text-block-header">{{localize 'chiaroscuro.tabs.identity_text1'}}</legend>
|
||||
{{editor data.enrichedHtml.identity_text1 target="system.identity_text1" button=true editable=options.editable engine="prosemirror" collaborate=false}}
|
||||
</fieldset>
|
||||
<fieldset class="identity-text-block">
|
||||
<legend class="text-block-header">{{localize 'chiaroscuro.tabs.identity_text2'}}</legend>
|
||||
{{editor data.enrichedHtml.identity_text2 target="system.identity_text2" button=true editable=options.editable engine="prosemirror" collaborate=false}}
|
||||
</fieldset>
|
||||
</div>
|
||||
@@ -1,21 +1,27 @@
|
||||
<ul class="identity-content">
|
||||
<li>
|
||||
<label class="attribute-label is-samurai-label">
|
||||
{{localize 'chiaroscuro.character.is_samurai'}}
|
||||
<input type="checkbox" name="system.is_samurai" {{checked data.system.is_samurai}} {{^if data.editable_not_soft_locked}}disabled{{/if}}/>
|
||||
</label>
|
||||
</li>
|
||||
<li>
|
||||
<label class="attribute-label">
|
||||
{{#ifCond data.system.template '==' 'pow'}}
|
||||
{{localize 'l5r5e.sheets.region'}}
|
||||
{{else}}
|
||||
{{#if data.system.is_samurai}}
|
||||
{{localize 'l5r5e.clans.label'}}
|
||||
{{/ifCond}}
|
||||
{{else}}
|
||||
{{localize 'chiaroscuro.character.region'}}
|
||||
{{/if}}
|
||||
<input type="text" name="system.identity.clan" value="{{data.system.identity.clan}}" {{^if data.editable_not_soft_locked}}disabled{{/if}}/>
|
||||
</label>
|
||||
</li>
|
||||
<li>
|
||||
<label class="attribute-label">
|
||||
{{#ifCond data.system.template '==' 'pow'}}
|
||||
{{localize 'l5r5e.sheets.upbringing'}}
|
||||
{{else}}
|
||||
{{#if data.system.is_samurai}}
|
||||
{{localize 'l5r5e.sheets.family'}}
|
||||
{{/ifCond}}
|
||||
{{else}}
|
||||
{{localize 'chiaroscuro.character.education'}}
|
||||
{{/if}}
|
||||
<input type="text" name="system.identity.family" value="{{data.system.identity.family}}" {{^if data.editable_not_soft_locked}}disabled{{/if}}/>
|
||||
</label>
|
||||
</li>
|
||||
@@ -37,4 +43,10 @@
|
||||
<input type="text" name="system.identity.roles" value="{{data.system.identity.roles}}" {{^if data.editable_not_soft_locked}}disabled{{/if}}/>
|
||||
</label>
|
||||
</li>
|
||||
<li>
|
||||
<label class="attribute-label quick-info-label">
|
||||
{{localize 'chiaroscuro.character.quick_info'}}
|
||||
<input type="text" name="system.quick_info" value="{{data.system.quick_info}}" {{^if data.editable_not_soft_locked}}disabled{{/if}}/>
|
||||
</label>
|
||||
</li>
|
||||
</ul>
|
||||
@@ -1,25 +1,25 @@
|
||||
<fieldset class="money money-wrapper">
|
||||
<legend class="section-header">{{localize 'l5r5e.money.title'}}</legend>
|
||||
<label>
|
||||
<label class="attribute-label money">
|
||||
{{localize 'l5r5e.money.koku'}}
|
||||
<input name="system.money.koku" type="number" value="{{data.system.money.koku}}" data-dtype="Number" min="0" placeholder="0" {{^if data.editable_not_soft_locked}}disabled{{/if}}/>
|
||||
<span class="money-buttons">
|
||||
<span class="increment-control money">
|
||||
<i class="money-control pointer-choice fa fa-plus-square" data-type="koku" data-value="1"></i>
|
||||
<i class="money-control pointer-choice fa fa-minus-square" data-type="koku" data-value="-1"></i>
|
||||
</span>
|
||||
</label>
|
||||
<label>
|
||||
<label class="attribute-label money">
|
||||
{{localize 'l5r5e.money.bu'}}
|
||||
<input name="system.money.bu" type="number" value="{{data.system.money.bu}}" data-dtype="Number" min="0" placeholder="0" {{^if data.editable_not_soft_locked}}disabled{{/if}}/>
|
||||
<span class="money-buttons">
|
||||
<span class="increment-control money">
|
||||
<i class="money-control pointer-choice fa fa-plus-square" data-type="bu" data-value="1"></i>
|
||||
<i class="money-control pointer-choice fa fa-minus-square" data-type="bu" data-value="-1"></i>
|
||||
</span>
|
||||
</label>
|
||||
<label>
|
||||
<label class="attribute-label money">
|
||||
{{localize 'l5r5e.money.zeni'}}
|
||||
<input name="system.money.zeni" type="number" value="{{data.system.money.zeni}}" data-dtype="Number" min="0" placeholder="0" {{^if data.editable_not_soft_locked}}disabled{{/if}}/>
|
||||
<span class="money-buttons">
|
||||
<span class="increment-control money">
|
||||
<i class="money-control pointer-choice fa fa-plus-square" data-type="zeni" data-value="1"></i>
|
||||
<i class="money-control pointer-choice fa fa-minus-square" data-type="zeni" data-value="-1"></i>
|
||||
</span>
|
||||
@@ -28,7 +28,7 @@
|
||||
{{!-- items list --}}
|
||||
<fieldset class="items-wrapper">
|
||||
<legend>{{localize 'l5r5e.sheets.equipment'}}</legend>
|
||||
{{> 'systems/l5r5e/templates/items/item/items.html'}}
|
||||
{{> 'systems/l5rx-chiaroscuro/templates/items/item/items.html'}}
|
||||
</fieldset>
|
||||
{{!-- item patterns list --}}
|
||||
<fieldset>
|
||||
@@ -41,7 +41,7 @@
|
||||
<ul class="item-list">
|
||||
{{#each actor.items as |pattern id|}}
|
||||
{{#ifCond pattern.type '==' 'item_pattern'}}
|
||||
{{> 'systems/l5r5e/templates/items/item-pattern/item-pattern-entry.html' pattern=pattern id=id editable=../data.editable_not_soft_locked}}
|
||||
{{> 'systems/l5rx-chiaroscuro/templates/items/item-pattern/item-pattern-entry.html' pattern=pattern id=id editable=../data.editable_not_soft_locked}}
|
||||
{{/ifCond}}
|
||||
{{/each}}
|
||||
</ul>
|
||||
|
||||
17
system/templates/actors/character/invocations.html
Normal file
17
system/templates/actors/character/invocations.html
Normal file
@@ -0,0 +1,17 @@
|
||||
<div class="invocations-wrapper">
|
||||
{{#each data.splitInvocationsList as |list type|}}
|
||||
<fieldset class="section-header flexrow">
|
||||
<legend class="technique-controls">
|
||||
<span>{{localize (concat 'chiaroscuro.technique.invocation_types.' type)}}</span>
|
||||
{{#if ../data.editable_not_soft_locked}}
|
||||
<a data-item-type="technique" class="technique-control item-add" data-tech-type="mot_invocation" title="{{localize 'l5r5e.global.add'}}"><i class="fas fa-plus"></i></a>
|
||||
{{/if}}
|
||||
</legend>
|
||||
<ul class="item-list">
|
||||
{{#each list as |item|}}
|
||||
{{> 'systems/l5rx-chiaroscuro/templates/items/technique/technique-entry.html' technique=item editable=../../data.editable_not_soft_locked}}
|
||||
{{/each}}
|
||||
</ul>
|
||||
</fieldset>
|
||||
{{/each}}
|
||||
</div>
|
||||
@@ -7,12 +7,16 @@
|
||||
<textarea type="text" name="system.social.ninjo" {{^if data.editable_not_soft_locked}}disabled{{/if}}>{{data.system.social.ninjo}}</textarea>
|
||||
</label>
|
||||
<label class="attribute-label">
|
||||
{{#ifCond data.system.template '==' 'pow'}}
|
||||
{{localize 'l5r5e.social.past'}}
|
||||
{{else}}
|
||||
{{#if data.system.is_samurai}}
|
||||
{{localize 'l5r5e.social.giri'}}
|
||||
{{/ifCond}}
|
||||
<textarea type="text" name="system.social.giri" {{^if data.editable_not_soft_locked}}disabled{{/if}}>{{data.system.social.giri}}</textarea>
|
||||
{{else}}
|
||||
{{localize 'chiaroscuro.character.past_problems'}}
|
||||
{{/if}}
|
||||
{{#if data.system.is_samurai}}
|
||||
<textarea type="text" name="system.social.giri" {{^if data.editable_not_soft_locked}}disabled{{/if}}>{{data.system.social.giri}}</textarea>
|
||||
{{else}}
|
||||
<textarea type="text" name="system.social.past_problems" {{^if data.editable_not_soft_locked}}disabled{{/if}}>{{data.system.social.past_problems}}</textarea>
|
||||
{{/if}}
|
||||
</label>
|
||||
</fieldset>
|
||||
{{!-- Bushido Tenets --}}
|
||||
@@ -40,7 +44,7 @@
|
||||
<ul class="item-list">
|
||||
{{#each actor.items as |item id|}}
|
||||
{{#ifCond '["distinction","passion"]' 'includes' item.system.peculiarity_type}}
|
||||
{{> 'systems/l5r5e/templates/items/peculiarity/peculiarity-entry.html' peculiarity=item id=id editable=../data.editable_not_soft_locked}}
|
||||
{{> 'systems/l5rx-chiaroscuro/templates/items/peculiarity/peculiarity-entry.html' peculiarity=item id=id editable=../data.editable_not_soft_locked}}
|
||||
{{/ifCond}}
|
||||
{{/each}}
|
||||
</ul>
|
||||
@@ -56,7 +60,7 @@
|
||||
<ul class="item-list">
|
||||
{{#each actor.items as |item id|}}
|
||||
{{#ifCond '["adversity","anxiety"]' 'includes' item.system.peculiarity_type}}
|
||||
{{> 'systems/l5r5e/templates/items/peculiarity/peculiarity-entry.html' peculiarity=item id=id editable=../data.editable_not_soft_locked}}
|
||||
{{> 'systems/l5rx-chiaroscuro/templates/items/peculiarity/peculiarity-entry.html' peculiarity=item id=id editable=../data.editable_not_soft_locked}}
|
||||
{{/ifCond}}
|
||||
{{/each}}
|
||||
</ul>
|
||||
@@ -72,7 +76,7 @@
|
||||
<ul class="item-list">
|
||||
{{#each actor.items as |bond id|}}
|
||||
{{#ifCond bond.type '==' 'bond'}}
|
||||
{{> 'systems/l5r5e/templates/items/bond/bond-entry.html' bond=bond id=id editable=../data.editable_not_soft_locked}}
|
||||
{{> 'systems/l5rx-chiaroscuro/templates/items/bond/bond-entry.html' bond=bond id=id editable=../data.editable_not_soft_locked}}
|
||||
{{/ifCond}}
|
||||
{{/each}}
|
||||
</ul>
|
||||
|
||||
@@ -2,35 +2,35 @@
|
||||
<li id="earth">
|
||||
<label class="earth {{#ifCond 'earth' '==' data.system.stance}}stance-active{{/ifCond}}">
|
||||
<i class="i_earth dice-picker rollable" data-ring="earth"></i>
|
||||
<strong>{{localizeRing 'earth'}}</strong>
|
||||
<strong class="ring-set-default {{#ifCond 'earth' '==' data.system.default_ring}}default-ring{{/ifCond}}" data-ring="earth" title="{{localize 'chiaroscuro.character.default_ring'}}">{{localizeRing 'earth'}}</strong>
|
||||
<input class="centered-input select-on-focus" type="number" name="system.rings.earth" value="{{data.system.rings.earth}}" data-dtype="Number" min="1" max="9" placeholder="0" {{^if data.editable_not_soft_locked}}disabled{{/if}}/>
|
||||
</label>
|
||||
</li>
|
||||
<li id="air">
|
||||
<label class="air {{#ifCond 'air' '==' data.system.stance}}stance-active{{/ifCond}}">
|
||||
<i class="i_air dice-picker rollable" data-ring="air"></i>
|
||||
<strong>{{localizeRing 'air'}}</strong>
|
||||
<strong class="ring-set-default {{#ifCond 'air' '==' data.system.default_ring}}default-ring{{/ifCond}}" data-ring="air" title="{{localize 'chiaroscuro.character.default_ring'}}">{{localizeRing 'air'}}</strong>
|
||||
<input class="centered-input select-on-focus" type="number" name="system.rings.air" value="{{data.system.rings.air}}" data-dtype="Number" min="1" max="9" placeholder="0" {{^if data.editable_not_soft_locked}}disabled{{/if}}/>
|
||||
</label>
|
||||
</li>
|
||||
<li id="water">
|
||||
<label class="water {{#ifCond 'water' '==' data.system.stance}}stance-active{{/ifCond}}">
|
||||
<i class="i_water dice-picker rollable" data-ring="water"></i>
|
||||
<strong>{{localizeRing 'water'}}</strong>
|
||||
<strong class="ring-set-default {{#ifCond 'water' '==' data.system.default_ring}}default-ring{{/ifCond}}" data-ring="water" title="{{localize 'chiaroscuro.character.default_ring'}}">{{localizeRing 'water'}}</strong>
|
||||
<input class="centered-input select-on-focus" type="number" name="system.rings.water" value="{{data.system.rings.water}}" data-dtype="Number" min="1" max="9" placeholder="0" {{^if data.editable_not_soft_locked}}disabled{{/if}}/>
|
||||
</label>
|
||||
</li>
|
||||
<li id="fire">
|
||||
<label class="fire {{#ifCond 'fire' '==' data.system.stance}}stance-active{{/ifCond}}">
|
||||
<i class="i_fire dice-picker rollable" data-ring="fire"></i>
|
||||
<strong>{{localizeRing 'fire'}}</strong>
|
||||
<strong class="ring-set-default {{#ifCond 'fire' '==' data.system.default_ring}}default-ring{{/ifCond}}" data-ring="fire" title="{{localize 'chiaroscuro.character.default_ring'}}">{{localizeRing 'fire'}}</strong>
|
||||
<input class="centered-input select-on-focus" type="number" name="system.rings.fire" value="{{data.system.rings.fire}}" data-dtype="Number" min="1" max="9" placeholder="0" {{^if data.editable_not_soft_locked}}disabled{{/if}}/>
|
||||
</label>
|
||||
</li>
|
||||
<li id="void">
|
||||
<label class="void {{#ifCond 'void' '==' data.system.stance}}stance-active{{/ifCond}}">
|
||||
<i class="i_void dice-picker rollable" data-ring="void"></i>
|
||||
<strong>{{localizeRing 'void'}}</strong>
|
||||
<strong class="ring-set-default {{#ifCond 'void' '==' data.system.default_ring}}default-ring{{/ifCond}}" data-ring="void" title="{{localize 'chiaroscuro.character.default_ring'}}">{{localizeRing 'void'}}</strong>
|
||||
<input class="centered-input select-on-focus" type="number" name="system.rings.void" value="{{data.system.rings.void}}" data-dtype="Number" min="1" max="9" placeholder="0" {{^if data.editable_not_soft_locked}}disabled{{/if}}/>
|
||||
</label>
|
||||
</li>
|
||||
|
||||
@@ -1,16 +1,9 @@
|
||||
<li class="skill skill-wrapper">
|
||||
<label class="skill-content">
|
||||
<span class="dice-picker attribute-label rollable" data-skill="{{skillId}}">{{localizeSkill categoryId skillId}}</span>
|
||||
<input
|
||||
class="centered-input select-on-focus"
|
||||
type="number"
|
||||
name="system.skills.{{categoryId}}.{{skillId}}"
|
||||
value="{{skill}}"
|
||||
data-dtype="Number"
|
||||
min="0"
|
||||
max="9"
|
||||
placeholder="0"
|
||||
{{^if data.editable_not_soft_locked}}disabled{{/if}}
|
||||
/>
|
||||
<select name="system.skills.{{categoryId}}.{{skillId}}" {{^if data.editable_not_soft_locked}}disabled{{/if}}>
|
||||
{{selectOptions data.skillRanksList selected=skill valueAttr='id' labelAttr='label'}}
|
||||
</select>
|
||||
{{#ifCond skill '!=' '0'}}<span class="skill-bonus">+{{skillRankBonus skill}}</span>{{/ifCond}}
|
||||
</label>
|
||||
</li>
|
||||
|
||||
@@ -2,18 +2,30 @@
|
||||
<li>
|
||||
<label class="attribute-label centered-input">
|
||||
<strong>{{localize 'l5r5e.social.honor'}}</strong>
|
||||
<span class="increment-control honor">
|
||||
<i class="addsub-control pointer-choice fa fa-plus-square" data-type="honor" data-value="1"></i>
|
||||
<i class="addsub-control pointer-choice fa fa-minus-square" data-type="honor" data-value="-1"></i>
|
||||
</span>
|
||||
<input class="centered-input select-on-focus" type="number" name="system.social.honor" value="{{data.system.social.honor}}" data-dtype="Number" placeholder="0" {{^if data.editable_not_soft_locked}}disabled{{/if}}/>
|
||||
</label>
|
||||
</li>
|
||||
<li>
|
||||
<label class="attribute-label centered-input">
|
||||
<strong>{{localize 'l5r5e.social.glory'}}</strong>
|
||||
<span class="increment-control glory">
|
||||
<i class="addsub-control pointer-choice fa fa-plus-square" data-type="glory" data-value="1"></i>
|
||||
<i class="addsub-control pointer-choice fa fa-minus-square" data-type="glory" data-value="-1"></i>
|
||||
</span>
|
||||
<input class="centered-input select-on-focus" type="number" name="system.social.glory" value="{{data.system.social.glory}}" data-dtype="Number" placeholder="0" {{^if data.editable_not_soft_locked}}disabled{{/if}}/>
|
||||
</label>
|
||||
</li>
|
||||
<li>
|
||||
<label class="attribute-label centered-input">
|
||||
<strong>{{localize 'l5r5e.social.status'}}</strong>
|
||||
<span class="increment-control status">
|
||||
<i class="addsub-control pointer-choice fa fa-plus-square" data-type="status" data-value="1"></i>
|
||||
<i class="addsub-control pointer-choice fa fa-minus-square" data-type="status" data-value="-1"></i>
|
||||
</span>
|
||||
<input class="centered-input select-on-focus" type="number" name="system.social.status" value="{{data.system.social.status}}" data-dtype="Number" placeholder="0" {{^if data.editable_not_soft_locked}}disabled{{/if}}/>
|
||||
</label>
|
||||
</li>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
</legend>
|
||||
<ul class="item-list toggle-technique-category-{{technique}} {{#ifCond ../data.storeInfos 'includes' (concat 'toggle-technique-category-' technique)}}toggle-hidden{{/ifCond}}">
|
||||
{{#each list as |item id|}}
|
||||
{{> 'systems/l5r5e/templates/items/technique/technique-entry.html' technique=item editable=../../data.editable_not_soft_locked}}
|
||||
{{> 'systems/l5rx-chiaroscuro/templates/items/technique/technique-entry.html' technique=item editable=../../data.editable_not_soft_locked}}
|
||||
{{/each}}
|
||||
</ul>
|
||||
</fieldset>
|
||||
@@ -40,9 +40,32 @@
|
||||
<ul class="item-list">
|
||||
{{#each actor.items as |scroll id|}}
|
||||
{{#ifCond scroll.type '==' 'signature_scroll'}}
|
||||
{{> 'systems/l5r5e/templates/items/signature-scroll/signature-scroll-entry.html' scroll=scroll id=id editable=../data.editable_not_soft_locked}}
|
||||
{{> 'systems/l5rx-chiaroscuro/templates/items/signature-scroll/signature-scroll-entry.html' scroll=scroll id=id editable=../data.editable_not_soft_locked}}
|
||||
{{/ifCond}}
|
||||
{{/each}}
|
||||
</ul>
|
||||
</fieldset>
|
||||
{{!-- Arcane items list --}}
|
||||
<fieldset class="section-header flexrow">
|
||||
<legend class="text-block-header">
|
||||
{{localize 'chiaroscuro.arcane.title'}}
|
||||
{{#if data.editable_not_soft_locked}}
|
||||
<a data-item-type="arcane" class="arcane-control item-add" title="{{localize 'l5r5e.global.add'}}"><i class="fas fa-plus"></i></a>
|
||||
{{/if}}
|
||||
</legend>
|
||||
<ul class="item-list">
|
||||
{{#each data.arcaneItems as |item|}}
|
||||
<li class="item technique flexcol" data-item-id="{{item._id}}">
|
||||
<ul class="item-header technique-controls">
|
||||
<li class="item-img"><img src="{{item.img}}" title="{{item.name}}" width="32px" height="32px"/></li>
|
||||
<li class="item-name l5r5e-tooltip" data-item-id="{{item._id}}">{{item.name}}</li>
|
||||
{{#if ../data.editable_not_soft_locked}}
|
||||
<li data-item-id="{{item._id}}" class="item-control item-edit" title="{{localize 'l5r5e.global.edit'}}"><i class="fas fa-edit"></i></li>
|
||||
<li data-item-id="{{item._id}}" class="item-control item-delete" title="{{localize 'Delete'}}"><i class="fas fa-trash"></i></li>
|
||||
{{/if}}
|
||||
</ul>
|
||||
</li>
|
||||
{{/each}}
|
||||
</ul>
|
||||
</fieldset>
|
||||
</div>
|
||||
@@ -1,7 +1,7 @@
|
||||
<fieldset data-step="{{stepName}}" class="tq-drag-n-drop">
|
||||
<ul class="item-list">
|
||||
{{#each itemsList as |item id|}}
|
||||
{{> 'systems/l5r5e/templates/items/property/property-entry.html' property=item id=id editable=../options.editable}}
|
||||
{{> 'systems/l5rx-chiaroscuro/templates/items/property/property-entry.html' property=item id=id editable=../options.editable}}
|
||||
{{/each}}
|
||||
</ul>
|
||||
</fieldset>
|
||||
|
||||
@@ -15,56 +15,62 @@
|
||||
<input name="name" type="text" value="{{data.name}}" placeholder="Name" {{^if
|
||||
data.editable_not_soft_locked}}disabled{{/if}} />
|
||||
</h1>
|
||||
{{> 'systems/l5r5e/templates/actors/npc/identity.html'}}
|
||||
{{> 'systems/l5rx-chiaroscuro/templates/actors/npc/identity.html'}}
|
||||
</div>
|
||||
<div class="header-fields mid-wrapper">
|
||||
<div class="side-col">
|
||||
<h2>{{localize 'l5r5e.social.title'}}</h2>
|
||||
{{> 'systems/l5r5e/templates/actors/npc/social.html'}}
|
||||
{{> 'systems/l5rx-chiaroscuro/templates/actors/npc/social.html'}}
|
||||
</div>
|
||||
<div class="central-col">{{> 'systems/l5r5e/templates/actors/npc/rings.html'}}</div>
|
||||
<div class="central-col">{{> 'systems/l5rx-chiaroscuro/templates/actors/npc/rings.html'}}</div>
|
||||
<div class="side-col">
|
||||
<h2 class="right">{{localize 'l5r5e.attributes.title'}}</h2>
|
||||
{{> 'systems/l5r5e/templates/actors/npc/attributes.html'}}
|
||||
{{> 'systems/l5rx-chiaroscuro/templates/actors/npc/attributes.html'}}
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
{{!-- Sheet Body --}}
|
||||
<section class="sheet-body">
|
||||
{{!-- Active effects --}}
|
||||
{{> 'systems/l5r5e/templates/actors/npc/effects.html'}}
|
||||
{{> 'systems/l5rx-chiaroscuro/templates/actors/npc/effects.html'}}
|
||||
|
||||
{{!-- Skills No Tab --}}
|
||||
{{> 'systems/l5r5e/templates/actors/npc/skill.html'}}
|
||||
{{> 'systems/l5rx-chiaroscuro/templates/actors/npc/skill.html'}}
|
||||
|
||||
{{!-- Sheet Tab Navigation --}}
|
||||
<nav class="sheet-tabs tabs" data-group="primary">
|
||||
<a class="item" data-tab="skills">{{localize 'l5r5e.skills.title'}}</a>
|
||||
<a class="item" data-tab="narrative">{{localize 'l5r5e.sheets.narrative'}}</a>
|
||||
<a class="item" data-tab="invocations">{{localize 'chiaroscuro.tabs.invocations'}}</a>
|
||||
<a class="item" data-tab="conflict">{{localize 'l5r5e.conflict.title'}}</a>
|
||||
<a class="item" data-tab="inventory">{{localize 'l5r5e.sheets.inventory'}}</a>
|
||||
</nav>
|
||||
|
||||
{{!-- Techniques Tab --}}
|
||||
<article class="tab skills" data-group="primary" data-tab="skills">
|
||||
{{> 'systems/l5r5e/templates/actors/npc/techniques.html'}}
|
||||
{{> 'systems/l5rx-chiaroscuro/templates/actors/npc/techniques.html'}}
|
||||
</article>
|
||||
|
||||
{{!-- Narrative Tab --}}
|
||||
<article class="tab narrative" data-group="primary" data-tab="narrative">
|
||||
{{> 'systems/l5r5e/templates/actors/npc/narrative.html'}}
|
||||
{{> 'systems/l5rx-chiaroscuro/templates/actors/npc/narrative.html'}}
|
||||
</article>
|
||||
|
||||
{{!-- Invocations Tab --}}
|
||||
<article class="tab invocations" data-group="primary" data-tab="invocations">
|
||||
{{> 'systems/l5rx-chiaroscuro/templates/actors/character/invocations.html'}}
|
||||
</article>
|
||||
|
||||
{{!-- Conflict Tab --}}
|
||||
<article class="tab conflict" data-group="primary" data-tab="conflict">
|
||||
{{> 'systems/l5r5e/templates/actors/npc/conflict.html'}} {{>
|
||||
'systems/l5r5e/templates/items/weapon/weapons.html'}} {{>
|
||||
'systems/l5r5e/templates/items/armor/armors.html'}}
|
||||
{{> 'systems/l5rx-chiaroscuro/templates/actors/npc/conflict.html'}} {{>
|
||||
'systems/l5rx-chiaroscuro/templates/items/weapon/weapons.html'}} {{>
|
||||
'systems/l5rx-chiaroscuro/templates/items/armor/armors.html'}}
|
||||
</article>
|
||||
|
||||
{{!-- Inventory Tab --}}
|
||||
<article class="tab inventory" data-group="primary" data-tab="inventory">
|
||||
{{> 'systems/l5r5e/templates/actors/npc/inventory.html'}}
|
||||
{{> 'systems/l5rx-chiaroscuro/templates/actors/npc/inventory.html'}}
|
||||
</article>
|
||||
</section>
|
||||
</form>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<label class="attribute-label">
|
||||
<strong>{{localize 'l5r5e.attributes.fatigue'}}</strong>
|
||||
<input class="centered-input select-on-focus" type="number" name="system.fatigue.value" value="{{data.system.fatigue.value}}" data-dtype="Number" min="0" placeholder="0" {{^if data.editable_not_soft_locked}}disabled{{/if}}/>
|
||||
<span class="attributes-buttons">
|
||||
<span class="increment-control fatigue">
|
||||
<i class="addsub-control pointer-choice fa fa-plus-square" data-type="fatigue" data-value="1"></i>
|
||||
<i class="addsub-control pointer-choice fa fa-minus-square" data-type="fatigue" data-value="-1"></i>
|
||||
</span>
|
||||
@@ -22,7 +22,7 @@
|
||||
<label class="attribute-label">
|
||||
<strong>{{localize 'l5r5e.attributes.strife'}}</strong>
|
||||
<input class="centered-input select-on-focus" type="number" name="system.strife.value" value="{{data.system.strife.value}}" data-dtype="Number" min="0" placeholder="0" {{^if data.editable_not_soft_locked}}disabled{{/if}}/>
|
||||
<span class="attributes-buttons">
|
||||
<span class="increment-control strife">
|
||||
<i class="addsub-control pointer-choice fa fa-plus-square" data-type="strife" data-value="1"></i>
|
||||
<i class="addsub-control pointer-choice fa fa-minus-square" data-type="strife" data-value="-1"></i>
|
||||
</span>
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
<legend class="section-header">{{localize 'l5r5e.conflict.stance'}}</legend>
|
||||
<ul class="item-list">
|
||||
{{#each data.system.rings as |ringValue ringId|}}
|
||||
{{> 'systems/l5r5e/templates/actors/character/stance.html' stance=../data.system.stance ringId=ringId}}
|
||||
{{> 'systems/l5rx-chiaroscuro/templates/actors/character/stance.html' stance=../data.system.stance ringId=ringId}}
|
||||
{{/each}}
|
||||
</ul>
|
||||
</fieldset>
|
||||
|
||||
@@ -5,14 +5,34 @@
|
||||
{{selectOptions data.types selected=data.system.type valueAttr='id' labelAttr='label'}}
|
||||
</select>
|
||||
</li>
|
||||
{{!-- Martial --}}
|
||||
<li>
|
||||
{{!-- Martial Danger --}}
|
||||
<li class="danger-row">
|
||||
<i class="i_bushi" title="{{localize 'l5r5e.social.npc.combat'}}"></i>
|
||||
<input class="centered-input select-on-focus" type="number" name="system.conflict_rank.martial" value="{{data.system.conflict_rank.martial}}" data-dtype="Number" min="0" placeholder="0" {{^if data.editable_not_soft_locked}}disabled{{/if}}/>
|
||||
<div class="danger-wrapper">
|
||||
<select name="system.martial_danger" {{^if data.editable_not_soft_locked}}disabled{{/if}}>
|
||||
{{selectOptions data.dangerList selected=data.system.martial_danger valueAttr='id' labelAttr='label'}}
|
||||
</select>
|
||||
<div class="danger-icons">
|
||||
<i class="fas fa-skull danger-icon"></i>
|
||||
{{#ifCond '["moyenne","assez_difficile","difficile"]' 'includes' data.system.martial_danger}}<i class="fas fa-skull danger-icon"></i>{{/ifCond}}
|
||||
{{#ifCond '["assez_difficile","difficile"]' 'includes' data.system.martial_danger}}<i class="fas fa-skull danger-icon"></i>{{/ifCond}}
|
||||
{{#ifCond data.system.martial_danger '==' 'difficile'}}<i class="fas fa-skull danger-icon"></i>{{/ifCond}}
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
{{!-- Social --}}
|
||||
<li>
|
||||
{{!-- Social Danger --}}
|
||||
<li class="danger-row">
|
||||
<i class="i_courtier" title="{{localize 'l5r5e.social.npc.intrigue'}}"></i>
|
||||
<input class="centered-input select-on-focus" type="number" name="system.conflict_rank.social" value="{{data.system.conflict_rank.social}}" data-dtype="Number" min="0" placeholder="0" {{^if data.editable_not_soft_locked}}disabled{{/if}}/>
|
||||
<div class="danger-wrapper">
|
||||
<select name="system.social_danger" {{^if data.editable_not_soft_locked}}disabled{{/if}}>
|
||||
{{selectOptions data.dangerList selected=data.system.social_danger valueAttr='id' labelAttr='label'}}
|
||||
</select>
|
||||
<div class="danger-icons">
|
||||
<i class="fas fa-star danger-icon"></i>
|
||||
{{#ifCond '["moyenne","assez_difficile","difficile"]' 'includes' data.system.social_danger}}<i class="fas fa-star danger-icon"></i>{{/ifCond}}
|
||||
{{#ifCond '["assez_difficile","difficile"]' 'includes' data.system.social_danger}}<i class="fas fa-star danger-icon"></i>{{/ifCond}}
|
||||
{{#ifCond data.system.social_danger '==' 'difficile'}}<i class="fas fa-star danger-icon"></i>{{/ifCond}}
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
@@ -1,6 +1,6 @@
|
||||
<fieldset class="items-wrapper">
|
||||
<legend>{{localize 'l5r5e.sheets.equipment'}}</legend>
|
||||
{{> 'systems/l5r5e/templates/items/item/items.html'}}
|
||||
{{> 'systems/l5rx-chiaroscuro/templates/items/item/items.html'}}
|
||||
</fieldset>
|
||||
{{!-- item patterns list --}}
|
||||
<fieldset>
|
||||
@@ -13,7 +13,7 @@
|
||||
<ul class="item-list">
|
||||
{{#each actor.items as |pattern id|}}
|
||||
{{#ifCond pattern.type '==' 'item_pattern'}}
|
||||
{{> 'systems/l5r5e/templates/items/item-pattern/item-pattern-entry.html' pattern=pattern id=id editable=../data.editable_not_soft_locked}}
|
||||
{{> 'systems/l5rx-chiaroscuro/templates/items/item-pattern/item-pattern-entry.html' pattern=pattern id=id editable=../data.editable_not_soft_locked}}
|
||||
{{/ifCond}}
|
||||
{{/each}}
|
||||
</ul>
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
<ul class="item-list">
|
||||
{{#each actor.items as |item id|}}
|
||||
{{#ifCond '["distinction","passion"]' 'includes' item.system.peculiarity_type}}
|
||||
{{> 'systems/l5r5e/templates/items/peculiarity/peculiarity-entry.html' peculiarity=item id=id editable=../data.editable_not_soft_locked}}
|
||||
{{> 'systems/l5rx-chiaroscuro/templates/items/peculiarity/peculiarity-entry.html' peculiarity=item id=id editable=../data.editable_not_soft_locked}}
|
||||
{{/ifCond}}
|
||||
{{/each}}
|
||||
</ul>
|
||||
@@ -52,7 +52,7 @@
|
||||
<ul class="item-list">
|
||||
{{#each actor.items as |item id|}}
|
||||
{{#ifCond '["adversity","anxiety"]' 'includes' item.system.peculiarity_type}}
|
||||
{{> 'systems/l5r5e/templates/items/peculiarity/peculiarity-entry.html' peculiarity=item id=id editable=../data.editable_not_soft_locked}}
|
||||
{{> 'systems/l5rx-chiaroscuro/templates/items/peculiarity/peculiarity-entry.html' peculiarity=item id=id editable=../data.editable_not_soft_locked}}
|
||||
{{/ifCond}}
|
||||
{{/each}}
|
||||
</ul>
|
||||
@@ -68,7 +68,7 @@
|
||||
<ul class="item-list">
|
||||
{{#each actor.items as |bond id|}}
|
||||
{{#ifCond bond.type '==' 'bond'}}
|
||||
{{> 'systems/l5r5e/templates/items/bond/bond-entry.html' bond=bond id=id editable=../data.editable_not_soft_locked}}
|
||||
{{> 'systems/l5rx-chiaroscuro/templates/items/bond/bond-entry.html' bond=bond id=id editable=../data.editable_not_soft_locked}}
|
||||
{{/ifCond}}
|
||||
{{/each}}
|
||||
</ul>
|
||||
|
||||
@@ -2,18 +2,30 @@
|
||||
<li>
|
||||
<label class="attribute-label centered-input">
|
||||
<strong>{{localize 'l5r5e.social.honor'}}</strong>
|
||||
<span class="increment-control honor">
|
||||
<i class="addsub-control pointer-choice fa fa-plus-square" data-type="honor" data-value="1"></i>
|
||||
<i class="addsub-control pointer-choice fa fa-minus-square" data-type="honor" data-value="-1"></i>
|
||||
</span>
|
||||
<input class="centered-input select-on-focus" type="number" name="system.social.honor" value="{{data.system.social.honor}}" data-dtype="Number" placeholder="0" {{^if data.editable_not_soft_locked}}disabled{{/if}}/>
|
||||
</label>
|
||||
</li>
|
||||
<li>
|
||||
<label class="attribute-label centered-input">
|
||||
<strong>{{localize 'l5r5e.social.glory'}}</strong>
|
||||
<span class="increment-control glory">
|
||||
<i class="addsub-control pointer-choice fa fa-plus-square" data-type="glory" data-value="1"></i>
|
||||
<i class="addsub-control pointer-choice fa fa-minus-square" data-type="glory" data-value="-1"></i>
|
||||
</span>
|
||||
<input class="centered-input select-on-focus" type="number" name="system.social.glory" value="{{data.system.social.glory}}" data-dtype="Number" placeholder="0" {{^if data.editable_not_soft_locked}}disabled{{/if}}/>
|
||||
</label>
|
||||
</li>
|
||||
<li>
|
||||
<label class="attribute-label centered-input">
|
||||
<strong>{{localize 'l5r5e.social.status'}}</strong>
|
||||
<span class="increment-control status">
|
||||
<i class="addsub-control pointer-choice fa fa-plus-square" data-type="status" data-value="1"></i>
|
||||
<i class="addsub-control pointer-choice fa fa-minus-square" data-type="status" data-value="-1"></i>
|
||||
</span>
|
||||
<input class="centered-input select-on-focus" type="number" name="system.social.status" value="{{data.system.social.status}}" data-dtype="Number" placeholder="0" {{^if data.editable_not_soft_locked}}disabled{{/if}}/>
|
||||
</label>
|
||||
</li>
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
</legend>
|
||||
<ul class="item-list toggle-technique-category-{{technique}} {{#ifCond ../data.storeInfos 'includes' (concat 'toggle-technique-category-' technique)}}toggle-hidden{{/ifCond}}">
|
||||
{{#each list as |item id|}}
|
||||
{{> 'systems/l5r5e/templates/items/technique/technique-entry.html' technique=item editable=../../data.editable_not_soft_locked}}
|
||||
{{> 'systems/l5rx-chiaroscuro/templates/items/technique/technique-entry.html' technique=item editable=../../data.editable_not_soft_locked}}
|
||||
{{/each}}
|
||||
</ul>
|
||||
</fieldset>
|
||||
@@ -43,7 +43,7 @@
|
||||
<ul class="item-list">
|
||||
{{#each actor.items as |scroll id|}}
|
||||
{{#ifCond scroll.type '==' 'signature_scroll'}}
|
||||
{{> 'systems/l5r5e/templates/items/signature-scroll/signature-scroll-entry.html' scroll=scroll id=id editable=../data.editable_not_soft_locked}}
|
||||
{{> 'systems/l5rx-chiaroscuro/templates/items/signature-scroll/signature-scroll-entry.html' scroll=scroll id=id editable=../data.editable_not_soft_locked}}
|
||||
{{/ifCond}}
|
||||
{{/each}}
|
||||
</ul>
|
||||
|
||||
@@ -204,13 +204,13 @@
|
||||
<tr>
|
||||
<td class="fifty">
|
||||
{{localize 'l5r5e.twenty_questions.part2.school_ability'}}
|
||||
{{> 'systems/l5r5e/templates/actors/character/twenty-questions-item.html' itemsList=cache.step3.school_ability stepName='step3.school_ability' itemType='techniques' hideDndAt=1}}
|
||||
{{> 'systems/l5rx-chiaroscuro/templates/actors/character/twenty-questions-item.html' itemsList=cache.step3.school_ability stepName='step3.school_ability' itemType='techniques' hideDndAt=1}}
|
||||
{{localize 'l5r5e.twenty_questions.part2.starting_techniques'}}
|
||||
{{> 'systems/l5r5e/templates/actors/character/twenty-questions-item.html' itemsList=cache.step3.techniques stepName='step3.techniques' itemType='techniques' hideDndAt=6}}
|
||||
{{> 'systems/l5rx-chiaroscuro/templates/actors/character/twenty-questions-item.html' itemsList=cache.step3.techniques stepName='step3.techniques' itemType='techniques' hideDndAt=6}}
|
||||
</td>
|
||||
<td class="fifty">
|
||||
{{localize 'l5r5e.twenty_questions.part2.outfit'}}
|
||||
{{> 'systems/l5r5e/templates/actors/character/twenty-questions-item.html' itemsList=cache.step3.equipment stepName='step3.equipment' itemType='items' hideDndAt=20}}
|
||||
{{> 'systems/l5rx-chiaroscuro/templates/actors/character/twenty-questions-item.html' itemsList=cache.step3.equipment stepName='step3.equipment' itemType='items' hideDndAt=20}}
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
@@ -288,7 +288,7 @@
|
||||
<tr>
|
||||
<td class="" colspan="3">
|
||||
{{localize 'l5r5e.twenty_questions.or'}} {{localize 'l5r5e.twenty_questions.part3.object'}}
|
||||
{{> 'systems/l5r5e/templates/actors/character/twenty-questions-item.html' itemsList=cache.step8.item stepName='step8.item' itemType='items' hideDndAt=1}}
|
||||
{{> 'systems/l5rx-chiaroscuro/templates/actors/character/twenty-questions-item.html' itemsList=cache.step8.item stepName='step8.item' itemType='items' hideDndAt=1}}
|
||||
</td>
|
||||
</tr>
|
||||
{{/ifCond}}
|
||||
@@ -319,25 +319,25 @@
|
||||
<textarea name="step9.success">{{data.step9.success}}</textarea>
|
||||
<label>
|
||||
{{localize 'l5r5e.twenty_questions.part4.distinction'}}
|
||||
{{> 'systems/l5r5e/templates/actors/character/twenty-questions-item.html' itemsList=cache.step9.distinction stepName='step9.distinction' itemType='peculiarities' hideDndAt=1}}
|
||||
{{> 'systems/l5rx-chiaroscuro/templates/actors/character/twenty-questions-item.html' itemsList=cache.step9.distinction stepName='step9.distinction' itemType='peculiarities' hideDndAt=1}}
|
||||
</label>
|
||||
<h3>{{localize (localize 'l5r5e.twenty_questions.part4.q10{suffix}' suffix=suffix)}}</h3>
|
||||
<textarea name="step10.difficulty">{{data.step10.difficulty}}</textarea>
|
||||
<label>
|
||||
{{localize 'l5r5e.twenty_questions.part4.adversity'}}
|
||||
{{> 'systems/l5r5e/templates/actors/character/twenty-questions-item.html' itemsList=cache.step10.adversity stepName='step10.adversity' itemType='peculiarities' hideDndAt=1}}
|
||||
{{> 'systems/l5rx-chiaroscuro/templates/actors/character/twenty-questions-item.html' itemsList=cache.step10.adversity stepName='step10.adversity' itemType='peculiarities' hideDndAt=1}}
|
||||
</label>
|
||||
<h3>{{localize (localize 'l5r5e.twenty_questions.part4.q11{suffix}' suffix=suffix)}}</h3>
|
||||
<textarea name="step11.calms">{{data.step11.calms}}</textarea>
|
||||
<label>
|
||||
{{localize 'l5r5e.twenty_questions.part4.passion'}}
|
||||
{{> 'systems/l5r5e/templates/actors/character/twenty-questions-item.html' itemsList=cache.step11.passion stepName='step11.passion' itemType='peculiarities' hideDndAt=1}}
|
||||
{{> 'systems/l5rx-chiaroscuro/templates/actors/character/twenty-questions-item.html' itemsList=cache.step11.passion stepName='step11.passion' itemType='peculiarities' hideDndAt=1}}
|
||||
</label>
|
||||
<h3>{{localize (localize 'l5r5e.twenty_questions.part4.q12{suffix}' suffix=suffix)}}</h3>
|
||||
<textarea name="step12.worries">{{data.step12.worries}}</textarea>
|
||||
<label>
|
||||
{{localize 'l5r5e.twenty_questions.part4.anxiety'}}
|
||||
{{> 'systems/l5r5e/templates/actors/character/twenty-questions-item.html' itemsList=cache.step12.anxiety stepName='step12.anxiety' itemType='peculiarities' hideDndAt=1}}
|
||||
{{> 'systems/l5rx-chiaroscuro/templates/actors/character/twenty-questions-item.html' itemsList=cache.step12.anxiety stepName='step12.anxiety' itemType='peculiarities' hideDndAt=1}}
|
||||
</label>
|
||||
<h3>{{localize (localize 'l5r5e.twenty_questions.part4.q13{suffix}' suffix=suffix)}}</h3>
|
||||
<textarea name="step13.most_learn">{{data.step13.most_learn}}</textarea>
|
||||
@@ -346,7 +346,7 @@
|
||||
<td class="third">
|
||||
{{localize 'l5r5e.twenty_questions.part4.disadvantage'}}
|
||||
{{#ifCond data.step13.advantage.length '==' 0}}
|
||||
{{> 'systems/l5r5e/templates/actors/character/twenty-questions-item.html' itemsList=cache.step13.disadvantage stepName='step13.disadvantage' itemType='peculiarities' hideDndAt=1 }}
|
||||
{{> 'systems/l5rx-chiaroscuro/templates/actors/character/twenty-questions-item.html' itemsList=cache.step13.disadvantage stepName='step13.disadvantage' itemType='peculiarities' hideDndAt=1 }}
|
||||
{{/ifCond}}
|
||||
{{localize 'l5r5e.twenty_questions.and'}}
|
||||
{{localize 'l5r5e.twenty_questions.increase_skill1'}}
|
||||
@@ -367,7 +367,7 @@
|
||||
<td class="">
|
||||
{{localize 'l5r5e.twenty_questions.part4.advantage'}}
|
||||
{{#ifCond (ifCond data.step13.disadvantage.length '==' 0) '&&' (ifCond data.step13.skill '==' 'none')}}
|
||||
{{> 'systems/l5r5e/templates/actors/character/twenty-questions-item.html' itemsList=cache.step13.advantage stepName='step13.advantage' itemType='peculiarities' hideDndAt=1}}
|
||||
{{> 'systems/l5rx-chiaroscuro/templates/actors/character/twenty-questions-item.html' itemsList=cache.step13.advantage stepName='step13.advantage' itemType='peculiarities' hideDndAt=1}}
|
||||
{{/ifCond}}
|
||||
</td>
|
||||
</tr>
|
||||
@@ -380,7 +380,7 @@
|
||||
<textarea name="step14.first_sight">{{data.step14.first_sight}}</textarea>
|
||||
<label>
|
||||
{{localize 'l5r5e.twenty_questions.part5.accoutrement'}}
|
||||
{{> 'systems/l5r5e/templates/actors/character/twenty-questions-item.html' itemsList=cache.step14.special_features stepName='step14.special_features' itemType='items' hideDndAt=1}}
|
||||
{{> 'systems/l5rx-chiaroscuro/templates/actors/character/twenty-questions-item.html' itemsList=cache.step14.special_features stepName='step14.special_features' itemType='items' hideDndAt=1}}
|
||||
</label>
|
||||
<h3>{{localize (localize 'l5r5e.twenty_questions.part5.q15{suffix}' suffix=suffix)}}</h3>
|
||||
<textarea name="step15.stress">{{data.step15.stress}}</textarea>
|
||||
@@ -389,7 +389,7 @@
|
||||
<textarea name="step16.relations">{{data.step16.relations}}</textarea>
|
||||
<label>
|
||||
{{localize 'l5r5e.twenty_questions.part5.object'}}
|
||||
{{> 'systems/l5r5e/templates/actors/character/twenty-questions-item.html' itemsList=cache.step16.item stepName='step16.item' itemType='items' hideDndAt=1}}
|
||||
{{> 'systems/l5rx-chiaroscuro/templates/actors/character/twenty-questions-item.html' itemsList=cache.step16.item stepName='step16.item' itemType='items' hideDndAt=1}}
|
||||
</label>
|
||||
{{/ifCond}}
|
||||
<button class="next" name="next" type="button">{{localize 'l5r5e.twenty_questions.bt_next'}} <i class='fas fa-arrow-right'></i></button>
|
||||
@@ -401,7 +401,7 @@
|
||||
<textarea name="step16.relations">{{data.step16.relations}}</textarea>
|
||||
<label>
|
||||
{{localize 'l5r5e.twenty_questions.part5.object'}}
|
||||
{{> 'systems/l5r5e/templates/actors/character/twenty-questions-item.html' itemsList=cache.step16.item stepName='step16.item' itemType='items' hideDndAt=1}}
|
||||
{{> 'systems/l5rx-chiaroscuro/templates/actors/character/twenty-questions-item.html' itemsList=cache.step16.item stepName='step16.item' itemType='items' hideDndAt=1}}
|
||||
</label>
|
||||
{{/ifCond}}
|
||||
<h3>{{localize (localize 'l5r5e.twenty_questions.part6.q17{suffix}' suffix=suffix)}}</h3>
|
||||
@@ -421,7 +421,7 @@
|
||||
{{else}}
|
||||
<label>
|
||||
{{localize 'l5r5e.twenty_questions.part6.bond'}}
|
||||
{{> 'systems/l5r5e/templates/actors/character/twenty-questions-item.html' itemsList=cache.step17.bond stepName='step17.bond' itemType='bonds' hideDndAt=1}}
|
||||
{{> 'systems/l5rx-chiaroscuro/templates/actors/character/twenty-questions-item.html' itemsList=cache.step17.bond stepName='step17.bond' itemType='bonds' hideDndAt=1}}
|
||||
</label>
|
||||
{{/ifCond}}
|
||||
<h3>{{localize (localize 'l5r5e.twenty_questions.part6.q18{suffix}' suffix=suffix)}}</h3>
|
||||
@@ -474,7 +474,7 @@
|
||||
{{/each}}
|
||||
</select>
|
||||
{{localize 'l5r5e.twenty_questions.part6.d10r2_drop_items'}}
|
||||
{{> 'systems/l5r5e/templates/actors/character/twenty-questions-item.html' itemsList=cache.step18.heritage_item stepName='step18.heritage_item' itemType='items' hideDndAt=1}}
|
||||
{{> 'systems/l5rx-chiaroscuro/templates/actors/character/twenty-questions-item.html' itemsList=cache.step18.heritage_item stepName='step18.heritage_item' itemType='items' hideDndAt=1}}
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
52
system/templates/compendium/filter-bar.html
Normal file
52
system/templates/compendium/filter-bar.html
Normal file
@@ -0,0 +1,52 @@
|
||||
<div class="l5r5e filter-bar">
|
||||
|
||||
{{#if filtersToShow.rank}}
|
||||
<div class="flexrow l5r5e rank-filter number-filter">
|
||||
<label>{{localize 'l5r5e.compendium.filter.rank'}}:</label>
|
||||
{{#each ranks}}
|
||||
<a data-rank="{{this}}"
|
||||
data-tooltip="{{localize 'l5r5e.compendium.filter.rank'}} {{this}}">{{this}}</a>
|
||||
{{/each}}
|
||||
<a data-clear style="display:none" data-tooltip="{{localize 'l5r5e.compendium.filter.clear'}}">×</a>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
{{#if filtersToShow.rarity}}
|
||||
<div class="flexrow l5r5e rarity-filter number-filter">
|
||||
<label>{{localize 'l5r5e.compendium.filter.rarity'}}:</label>
|
||||
{{#each rarities}}
|
||||
<a data-rarity="{{this}}"
|
||||
data-tooltip="{{localize 'l5r5e.compendium.filter.rarity'}} {{this}}">{{this}}</a>
|
||||
{{/each}}
|
||||
<a data-clear style="display:none" data-tooltip="{{localize 'l5r5e.compendium.filter.clear'}}">×</a>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
{{#if filtersToShow.ring}}
|
||||
<div class="flexrow l5r5e ring-filter">
|
||||
<label>{{localize 'l5r5e.rings.label'}}:</label>
|
||||
{{#each rings}}
|
||||
<i data-ring="{{this}}"
|
||||
data-tooltip="{{localize (concat 'l5r5e.rings.' this)}}"
|
||||
class="i_{{this}}"></i>
|
||||
{{/each}}
|
||||
<a data-clear style="display:none" data-tooltip="{{localize 'l5r5e.compendium.filter.clear'}}">×</a>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
{{#if filtersToShow.source}}
|
||||
<div class="flexrow l5r5e source-filter">
|
||||
<l5r5e-multi-select name="filter-sources" {{#if hideDisabledOptions}}hidedisabledoptions{{/if}}>
|
||||
{{selectOptions sources localize=true}}
|
||||
</l5r5e-multi-select>
|
||||
</div>
|
||||
{{#if showPlayerView}}
|
||||
<button type="button" class="gm applyPlayerFilter"
|
||||
data-action="applyPlayerView"
|
||||
data-tooltip="{{localize 'l5r5e.multiselect.player_filter_tooltip'}}">
|
||||
{{localize 'l5r5e.multiselect.player_filter_label'}}
|
||||
</button>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
|
||||
</div>
|
||||
30
system/templates/compendium/l5r5e-index-partial.html
Normal file
30
system/templates/compendium/l5r5e-index-partial.html
Normal file
@@ -0,0 +1,30 @@
|
||||
{{!--
|
||||
L5R5e entry partial — mirrors Foundry's index-partial.hbs structure and adds
|
||||
ring/rarity/rank badges from entryFilterData injected by _prepareDirectoryContext.
|
||||
|
||||
NOTE: Foundry's index-partial.hbs renders a complete <li> element so it cannot
|
||||
be composed via {{> partial}} without nesting <li> inside <li>. We therefore
|
||||
duplicate its simple structure here and own it ourselves. If Foundry changes
|
||||
their index-partial.hbs, this file should be checked for parity.
|
||||
|
||||
Foundry original: templates/sidebar/apps/compendium/index-partial.hbs
|
||||
--}}
|
||||
<li class="directory-item entry document {{ @root.documentCls }} flexrow" data-entry-id="{{ _id }}">
|
||||
{{#if thumb}}
|
||||
<img class="thumbnail" src="{{ thumb }}" alt="{{ name }}" loading="lazy">
|
||||
{{else if img}}
|
||||
<img class="thumbnail" src="{{ img }}" alt="{{ name }}" loading="lazy">
|
||||
{{else}}
|
||||
<i class="{{ @root.sidebarIcon }}" inert></i>
|
||||
{{/if}}
|
||||
<a class="entry-name ellipsis" data-action="activateEntry">{{ name }}</a>
|
||||
{{#with (lookup @root.entryFilterData _id)}}
|
||||
{{#if (or ring rarity rank)}}
|
||||
<div class="l5r5e ring-rarity-rank" data-action="activateEntry">
|
||||
{{#if ring}} <i class="i_{{ring}}"></i>{{/if}}
|
||||
{{#if rarity}}<a>{{localize "l5r5e.sheets.rarity"}} {{rarity}}</a>{{/if}}
|
||||
{{#if rank}}<a>{{localize "l5r5e.sheets.rank"}} {{rank}}</a>{{/if}}
|
||||
</div>
|
||||
{{/if}}
|
||||
{{/with}}
|
||||
</li>
|
||||
@@ -1,6 +0,0 @@
|
||||
<div class="flexrow l5r5e {{type}}-filter number-filter">
|
||||
<label>{{localize (localize 'l5r5e.compendium.filter.{type}' type=type)}}:</label>
|
||||
{{#each number}}
|
||||
<a data-{{../type}}="{{.}}" data-tooltip="{{localize (localize 'l5r5e.compendium.filter.{type}' type=../type)}} {{.}}">{{.}}</a>
|
||||
{{/each}}
|
||||
</div>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user