Compare commits
37 Commits
bol-v12.1.
...
14.0.2
| Author | SHA1 | Date | |
|---|---|---|---|
| 405bcd7cf5 | |||
| 846e6f88b7 | |||
| 1a0f4cd3e9 | |||
| 8ef5c3c516 | |||
| 0eb952e43e | |||
| a549262d25 | |||
| 7adc1b3f07 | |||
| 6c70dc147c | |||
| 1ffb8b08fc | |||
| 8017bb207d | |||
| 364278527d | |||
| 93d35abde2 | |||
| 0409be64eb | |||
| ed76a49e7d | |||
| 2abd2c881a | |||
| 3fa5ca66d1 | |||
| 6de15eeda7 | |||
| 724c096743 | |||
| 3e3a4b9ec1 | |||
| 425a2a1fc0 | |||
| 203d7add66 | |||
| 8ae193dc34 | |||
| 3904f595b5 | |||
| 1bf21fae7f | |||
| 22579c21bc | |||
| 50c5c31e7b | |||
| a8c05cd4de | |||
| e1cea78059 | |||
| c2f9934f5f | |||
| 313c8a85fa | |||
| 74f6d4d54a | |||
| 2eb153ce14 | |||
| fe513e821a | |||
| 1b72c9c467 | |||
| 3c3a0901da | |||
| 3fc6d3e3df | |||
| 69b34669b0 |
@@ -1,6 +1,6 @@
|
|||||||
name: Release Creation
|
name: Release Creation
|
||||||
|
|
||||||
on:
|
on:
|
||||||
release:
|
release:
|
||||||
types: [published]
|
types: [published]
|
||||||
|
|
||||||
@@ -8,47 +8,56 @@ jobs:
|
|||||||
build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- run: echo "💡 The ${{ gitea.repository }} repository will cloned to the runner."
|
- run: echo "💡 The ${{ gitea.repository }} repository will cloned to the runner."
|
||||||
|
|
||||||
#- uses: actions/checkout@v3
|
|
||||||
- uses: RouxAntoine/checkout@v3.5.4
|
|
||||||
with:
|
|
||||||
ref: 'v10'
|
|
||||||
|
|
||||||
# get part of the tag after the `v`
|
#- uses: actions/checkout@v3
|
||||||
- name: Extract tag version number
|
- uses: RouxAntoine/checkout@v3.5.4
|
||||||
id: get_version
|
|
||||||
uses: battila7/get-version-action@v2
|
|
||||||
|
|
||||||
# Substitute the Manifest and Download URLs in the module.json
|
# get part of the tag after the `v`
|
||||||
- name: Substitute Manifest and Download Links For Versioned Ones
|
- name: Extract tag version number
|
||||||
id: sub_manifest_link_version
|
id: get_version
|
||||||
uses: microsoft/variable-substitution@v1
|
uses: battila7/get-version-action@v2
|
||||||
with:
|
|
||||||
files: 'system.json'
|
|
||||||
env:
|
|
||||||
version: ${{steps.get_version.outputs.version-without-v}}
|
|
||||||
url: https://www.uberwald.me/gitea/public/bol
|
|
||||||
manifest: https://www.uberwald.me/gitea/public/bol/releases/latest/system.json
|
|
||||||
download: https://www.uberwald.me/gitea/public/bol/releases/download/${{github.event.release.tag_name}}/bol.zip
|
|
||||||
|
|
||||||
# Create a zip file with all files required by the module to add to the release
|
|
||||||
- run: |
|
|
||||||
apt update -y
|
|
||||||
apt install -y zip
|
|
||||||
|
|
||||||
- run: zip -r ./bol.zip system.json template.json README.md LICENSE assets/ css/ fonts/ images/ lang/ module/ packs/ styles/ templates/ ui/
|
# Substitute the Manifest and Download URLs in the system.json
|
||||||
|
- name: Substitute Manifest and Download Links For Versioned Ones
|
||||||
- name: setup go
|
id: sub_manifest_link_version
|
||||||
uses: https://github.com/actions/setup-go@v4
|
uses: microsoft/variable-substitution@v1
|
||||||
with:
|
with:
|
||||||
go-version: '>=1.20.1'
|
files: "system.json"
|
||||||
|
env:
|
||||||
- name: Use Go Action
|
version: ${{steps.get_version.outputs.version-without-v}}
|
||||||
id: use-go-action
|
url: https://www.uberwald.me/gitea/${{gitea.repository}}
|
||||||
uses: https://gitea.com/actions/release-action@main
|
manifest: https://www.uberwald.me/gitea/public/bol/releases/download/latest/system.json
|
||||||
with:
|
download: https://www.uberwald.me/gitea/${{gitea.repository}}/releases/download/${{github.event.release.tag_name}}/bol.zip
|
||||||
files: |-
|
|
||||||
./bol.zip
|
# Create a zip file with all files required by the module to add to the release
|
||||||
system.json
|
- run: |
|
||||||
api_key: '${{secrets.RELEASE_TOKEN_UBERWALD}}'
|
apt update -y
|
||||||
|
apt install -y zip
|
||||||
|
|
||||||
|
- run: zip -r ./bol.zip system.json template.json README.md LICENSE assets/ compendiums/ css/ fonts/ images/ lang/ module/ packs/ styles/ templates/ ui/
|
||||||
|
|
||||||
|
- name: setup go
|
||||||
|
uses: https://github.com/actions/setup-go@v4
|
||||||
|
with:
|
||||||
|
go-version: ">=1.20.1"
|
||||||
|
|
||||||
|
- name: Use Go Action
|
||||||
|
id: use-go-action
|
||||||
|
uses: https://gitea.com/actions/release-action@main
|
||||||
|
with:
|
||||||
|
files: |-
|
||||||
|
./bol.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: "bol"
|
||||||
|
version: ${{github.event.release.tag_name}}
|
||||||
|
manifest: "https://www.uberwald.me/gitea/public/bol/releases/download/latest/system.json"
|
||||||
|
notes: "https://www.uberwald.me/gitea/${{gitea.repository}}/releases/download/${{github.event.release.tag_name}}/bol.zip"
|
||||||
|
compatibility-minimum: "13"
|
||||||
|
compatibility-verified: "14"
|
||||||
|
|||||||
1
.gitignore
vendored
@@ -8,3 +8,4 @@ todo.md
|
|||||||
/jsconfig.json
|
/jsconfig.json
|
||||||
/package.json
|
/package.json
|
||||||
/package-lock.json
|
/package-lock.json
|
||||||
|
/.github
|
||||||
BIN
assets/pages/help-en-attribute-dialog.png
Normal file
|
After Width: | Height: | Size: 84 KiB |
BIN
assets/pages/help-en-command.png
Normal file
|
After Width: | Height: | Size: 151 KiB |
BIN
assets/pages/help-en-compendium.png
Normal file
|
After Width: | Height: | Size: 517 KiB |
BIN
assets/pages/help-en-effect-sheet.png
Normal file
|
After Width: | Height: | Size: 109 KiB |
BIN
assets/pages/help-en-initiative-dialog.png
Normal file
|
After Width: | Height: | Size: 96 KiB |
BIN
assets/pages/help-en-sheet-actions.png
Normal file
|
After Width: | Height: | Size: 272 KiB |
BIN
assets/pages/help-en-sheet-attributes.png
Normal file
|
After Width: | Height: | Size: 275 KiB |
BIN
assets/pages/help-en-sheet-description.png
Normal file
|
After Width: | Height: | Size: 247 KiB |
BIN
assets/pages/help-en-sheet-equipment.png
Normal file
|
After Width: | Height: | Size: 248 KiB |
BIN
assets/pages/help-en-sheet-spells.png
Normal file
|
After Width: | Height: | Size: 242 KiB |
BIN
assets/pages/help-en-sheet-traits.png
Normal file
|
After Width: | Height: | Size: 274 KiB |
BIN
assets/pages/help-en-weapon-dialog.png
Normal file
|
After Width: | Height: | Size: 102 KiB |
41
changelog.md
@@ -1,25 +1,33 @@
|
|||||||
Changes :
|
|
||||||
|
|
||||||
# v12.1.0
|
# v13.0.0
|
||||||
|
|
||||||
|
- Foundry v13 only
|
||||||
|
|
||||||
|
# v12.1.7
|
||||||
|
|
||||||
|
- Enhance welcome message
|
||||||
|
|
||||||
|
# v12.1.1
|
||||||
|
|
||||||
## French
|
## French
|
||||||
|
|
||||||
- Correction sur les conditions des sorts
|
- Correction sur les conditions des sorts
|
||||||
- Jet d'armures correctement affichés
|
- Jet d'armures correctement affichés
|
||||||
- Dégat à 0 possibles sur les armes/capacités
|
- Dégat à 0 possibles sur les armes/capacités
|
||||||
|
|
||||||
## English
|
## English
|
||||||
|
|
||||||
- Corrected spell conditions
|
- Corrected spell conditions
|
||||||
- Armor rolls are now correctly displayed
|
- Armor rolls are now correctly displayed
|
||||||
- Weapon/capacity damage can now be set to 0
|
- Weapon/capacity damage can now be set to 0
|
||||||
|
|
||||||
|
|
||||||
# v12.1.0
|
# v12.1.0
|
||||||
|
|
||||||
- Gestion des Hordes
|
- Gestion des Hordes
|
||||||
- Ajout de la traduction Espagnole
|
- Ajout de la traduction Espagnole
|
||||||
- Nouvelles clés de traduction
|
- Nouvelles clés de traduction
|
||||||
- Petites amélioration diverses
|
- Petites amélioration diverses
|
||||||
|
|
||||||
# v11.1.2
|
# v11.1.2
|
||||||
|
|
||||||
- Ajout des traductions manquantes en anglais
|
- Ajout des traductions manquantes en anglais
|
||||||
@@ -39,20 +47,19 @@ Changes :
|
|||||||
|
|
||||||
# v11.0.8
|
# v11.0.8
|
||||||
|
|
||||||
- Correction sur les malus de bouclier (blocage)
|
- Correction sur les malus de bouclier (blocage)
|
||||||
- Corrrection sur le malus d'init des boucliers qui était mal affiché dans la fiche d'item
|
- Corrrection sur le malus d'init des boucliers qui était mal affiché dans la fiche d'item
|
||||||
|
|
||||||
# v10.4.0
|
# v10.4.0
|
||||||
|
|
||||||
- Ajout de la gestion d'effets
|
- Ajout de la gestion d'effets
|
||||||
- Aide intégré
|
- Aide intégré
|
||||||
- Intégration du PDF de la bougette
|
- Intégration du PDF de la bougette
|
||||||
|
|
||||||
# v10.3.3
|
# v10.3.3
|
||||||
|
|
||||||
- Nouvelles clés de traduction
|
- Nouvelles clés de traduction
|
||||||
- Lorsqu'une arme a un dé bonus, prise en compte plus claire du dé bonus et affichage de l'information dans la fenêtre de jet
|
- Lorsqu'une arme a un dé bonus, prise en compte plus claire du dé bonus et affichage de l'information dans la fenêtre de jet
|
||||||
- Lorsqu'une arme relance les 1 sur ses dégats, l'information est affichée dans le tchat
|
- Lorsqu'une arme relance les 1 sur ses dégats, l'information est affichée dans le tchat
|
||||||
- Termes corrects pour les PNJs (ie rival)
|
- Termes corrects pour les PNJs (ie rival)
|
||||||
- Nouveaux équipements issus du Dieu Voilé
|
- Nouveaux équipements issus du Dieu Voilé
|
||||||
|
|
||||||
|
|||||||
63
compendiums/en/bol.aides-de-jeu.json
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
{
|
||||||
|
"label": "Game Aid",
|
||||||
|
"mapping": {
|
||||||
|
"name": "name",
|
||||||
|
"description": "content",
|
||||||
|
"categories": {
|
||||||
|
"path": "categories",
|
||||||
|
"converter": "nameCollection"
|
||||||
|
},
|
||||||
|
"pages": {
|
||||||
|
"path": "pages",
|
||||||
|
"converter": "pages"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"entries": {
|
||||||
|
"Aide du Jeu": "Game Aid",
|
||||||
|
"8ihDiCxC47fcdKVA": {
|
||||||
|
"name": "Game Aid",
|
||||||
|
"pages": {
|
||||||
|
"8agBoLYo99u530d1": {
|
||||||
|
"name": "Credits",
|
||||||
|
"text": "<p>This system was started by Zigmund, then taken over, completed and maintained by LeRatierBretonnien.</p><p>You can contact me on the French Foundry Discord: LeRatierBretonnien#2065</p><p>The git repository is available here: <a href=\"https://www.uberwald.me/gitea/public/bol\">https://www.uberwald.me/gitea/public/bol</a></p><p>Barbarians of Lemuria is a game by Simon Washbourne (Beyond Belief Games), translated into French by Ludospherik.</p><p>The full range is available on this page: <a href=\"http://www.ludospherik.fr/content/14-barbarians-of-lemuria\">http://www.ludospherik.fr/content/14-barbarians-of-lemuria</a></p><img src=\"systems/bol/assets/pages/b9BjVFaWB6uyyKsD-pages-8agBoLYo99u530d1-image-Rg2nVaMlglfJ6Qcm.png\" />"
|
||||||
|
},
|
||||||
|
"NAcpMm6NlyhwvWRA": {
|
||||||
|
"name": "Features",
|
||||||
|
"text": "<p>The BoL system under Foundry allows you to:</p><ul><li><p>create characters and NPCs (minions, toughs, rivals),</p></li><li><p>create creatures,</p></li><li><p>make dice rolls for attributes, aptitudes, and careers,</p></li><li><p>make dice rolls for combat attacks,</p></li><li><p>manage initiative,</p></li><li><p>make dice rolls to cast spells or perform alchemical recipes,</p></li><li><p>manage damage and lifeblood loss,</p></li><li><p>display and manage automations in chat windows, with assistance for the use of Hero Points and critical successes.</p></li></ul>"
|
||||||
|
},
|
||||||
|
"hdQixhZGfAytdbSg": {
|
||||||
|
"name": "Compendiums",
|
||||||
|
"text": "<p>The system comes with a series of compendiums providing quick access to careers, boons, and equipment.</p><p>The official cards are available, with the kind permission of Ludospherik.</p><p>To use content from a compendium, simply drag and drop the item into the world. For example: open the armours compendium, select <em>Light Armour</em>, and drag it onto a character sheet.</p><img src=\"systems/bol/assets/pages/help-en-compendium.png\" />"
|
||||||
|
},
|
||||||
|
"UfvTY80U49k6YFwe": {
|
||||||
|
"name": "Dice Rolls (Attributes/Aptitudes)",
|
||||||
|
"text": "<p>When a player clicks an attribute or aptitude, the following window appears:</p><img src=\"systems/bol/assets/pages/help-en-attribute-dialog.png\" /><ol><li><p>Attribute the player clicked on. It can be changed with this drop-down menu.</p></li><li><p>Career to apply if needed. Left-click to select, CTRL+left-click to deselect. When selected, the career rank is applied.</p></li><li><p>Available boons (i.e. those that grant a bonus die). Selection mode is identical to careers. When selected, the bonus die is applied to the roll.</p></li><li><p>Available flaws (i.e. those that impose a penalty die). Selection mode is identical to careers. When selected, the penalty die is applied to the roll.</p></li><li><p>Effects. Effects are permanent modifiers that affect certain rolls. See the corresponding chapter.</p></li><li><p>Manual addition of penalty or bonus dice.</p></li><li><p>Manual modifiers, according to the GM's ruling.</p></li><li><p>Reminder of the number of dice, based on the choices made in the dialog.</p></li><li><p>Complete list of modifiers applied to the roll.</p></li></ol>"
|
||||||
|
},
|
||||||
|
"4CLyyt3dtpG6YNMi": {
|
||||||
|
"name": "Dice Rolls (Weapon)",
|
||||||
|
"text": "<p>To make an attack with a weapon, go to the <strong>Actions</strong> tab and click the weapon's name. Targeting an opponent is recommended in order to take advantage of the system automations.</p><img src=\"systems/bol/assets/pages/help-en-weapon-dialog.png\" /><ol><li><p>Default weapon attribute. It can be changed with this drop-down menu.</p></li><li><p>Default weapon aptitude. It can be changed with this drop-down menu.</p></li><li><p>Possible weapon bonus on the attack roll.</p></li><li><p>Target defence, when an opponent is targeted.</p></li><li><p>Career to apply if needed. Left-click to select, CTRL+left-click to deselect. When selected, the career rank is applied.</p></li><li><p>Available boons (i.e. those that grant a bonus die). Selection mode is identical to careers. When selected, the bonus die is applied to the roll.</p></li><li><p>Available flaws (i.e. those that impose a penalty die). Selection mode is identical to careers. When selected, the penalty die is applied to the roll.</p></li><li><p>Effects. Effects are permanent modifiers that affect certain rolls. See the corresponding chapter.</p></li><li><p>Manual addition of penalty or bonus dice.</p></li><li><p>Information area if the weapon has the <em>Bonus Die</em> option enabled.</p></li><li><p>Agility penalty from armour and shield.</p></li><li><p>Manual modifiers, according to the GM's ruling.</p></li><li><p>Reminder of the number of dice, based on the choices made in the dialog.</p></li><li><p>Complete list of modifiers applied to the roll.</p></li></ol>"
|
||||||
|
},
|
||||||
|
"r003R5yIaiKxThOc": {
|
||||||
|
"name": "Character Sheet",
|
||||||
|
"text": "<h2>Attributes</h2><img src=\"systems/bol/assets/pages/help-en-sheet-attributes.png\" /><ol><li><p>Name + Experience area.</p></li><li><p>Tab bar for moving between sections.</p></li><li><p>Attributes area. Clicking a name opens the roll dialog, clicking a number allows editing.</p></li><li><p>Aptitudes area, same idea as attributes.</p></li><li><p>Counters area. The red value is the current one, the black value underneath is the maximum.</p></li></ol><h2>Actions</h2><img src=\"systems/bol/assets/pages/help-en-sheet-actions.png\" /><ol><li><p>Weapons. Clicking the name opens the attack dialog for that weapon.</p></li><li><p>Damage. Clicking the damage formula rolls it.</p></li><li><p>List of protections.</p></li><li><p>Clicking the protection formula rolls it.</p></li><li><p>List of shields.</p></li><li><p>Combat options the character knows. Once activated, they appear in the weapon attack dialog.</p></li></ol><h2>Traits</h2><img src=\"systems/bol/assets/pages/help-en-sheet-traits.png\" /><ol><li><p>List of careers. Left-click a career for details.</p></li><li><p>Career rank helper.</p></li><li><p>List of origins. Left-click for details.</p></li><li><p>List of boons. Left-click for details.</p></li><li><p>List of flaws. Left-click for details.</p></li><li><p>List of spoken languages. Left-click for details.</p></li><li><p>List of known combat options. Left-click for details.</p></li><li><p>List of beliefs. Left-click for details.</p></li><li><p>List of active effects. Left-click for details.</p></li></ol><h2>Equipment</h2><img src=\"systems/bol/assets/pages/help-en-sheet-equipment.png\" /><ol><li><p>Quick equipment creation controls.</p></li><li><p>Purse state (optional rule, system setting).</p></li><li><p>Weapons, with quantity management.</p></li><li><p>Shield equip / unequip control.</p></li><li><p>List of protections.</p></li><li><p>Armour equip / unequip control.</p></li></ol><h2>Spells & Alchemy</h2><p>This tab is only available if the character has the Alchemist or Sorcerer career.</p><img src=\"systems/bol/assets/pages/help-en-sheet-spells.png\" /><ol><li><p>List of spells. Left-click the name to open the dedicated roll dialog.</p></li><li><p>Reminder of circle and difficulty.</p></li><li><p>The square button opens the spell details.</p></li><li><p>List of known alchemical preparations.</p></li><li><p>Crafting progress management.</p></li><li><p>The square button opens the preparation details.</p></li></ol><h2>Description</h2><img src=\"systems/bol/assets/pages/help-en-sheet-description.png\" /><p>The description area contains free-form fields for customising the character.</p>"
|
||||||
|
},
|
||||||
|
"eRbEqbCW4AhU0cpm": {
|
||||||
|
"name": "Effects",
|
||||||
|
"text": "<p>Effects allow permanent modifiers to be applied as long as they are present on the character sheet.</p><p><span style=\"text-decoration:underline\"><span style=\"text-decoration:underline\">Example</span></span>: a character is poisoned, and the poison causes mental fatigue. In game terms, they suffer a -2 penalty to all Mind rolls. To represent this, create an <em>Effect</em> like this:</p><img src=\"systems/bol/assets/pages/help-en-effect-sheet.png\" /><ol><li><p>Create a <em>Trait</em>, and in the <em>Details</em> tab select the subtype <em>Effect</em>.</p></li><li><p>Select <em>Mind</em>.</p></li><li><p>Set a -2 modifier.</p></li></ol><p>Once placed on a character, the penalty is automatically applied whenever a Mind roll is requested. Remove the effect from the character sheet (<em>Traits</em> tab) to remove both the effect and its penalty.<br />A compendium of basic effects is available in the system.</p>"
|
||||||
|
},
|
||||||
|
"QmNF6p0lJf3pJoAy": {
|
||||||
|
"name": "Commands",
|
||||||
|
"text": "<p>The system provides commands (currently just one) for a few automated tasks.</p><p><strong><span style=\"text-decoration:underline\">This command is only available if the BoL-rulebook module is installed.</span></strong></p><h3>/adventure command</h3><img src=\"systems/bol/assets/pages/help-en-command.png\" /><ol><li><p>Type <code>/adventure</code> in the chat input area (or trigger it from a macro).</p></li><li><p>The system generates an adventure from the core rulebook tables and posts the result in chat.</p></li></ol>"
|
||||||
|
},
|
||||||
|
"MOWru5Dbvs4iozXm": {
|
||||||
|
"name": "Macros",
|
||||||
|
"text": "<p>The system exposes macros through <code>game.bol.macros</code>. They provide quick access to the most common rolls from a Foundry macro.</p><p><strong>Automatic actor selection:</strong></p><ul><li><p>if exactly one token is selected, the macro uses it;</p></li><li><p>if several tokens are selected, the macro shows a warning;</p></li><li><p>if no token is selected, a GM must select one; a player automatically falls back to their assigned character.</p></li></ul><p><strong>Available rolls</strong></p><p>Attributes (internal keys):</p><pre><code>game.bol.macros.rollAttribute(\"vigor\")\ngame.bol.macros.rollAttribute(\"agility\")\ngame.bol.macros.rollAttribute(\"mind\")\ngame.bol.macros.rollAttribute(\"appeal\")</code></pre><p>Aptitudes:</p><pre><code>game.bol.macros.rollAptitude(\"init\")\ngame.bol.macros.rollAptitude(\"melee\")\ngame.bol.macros.rollAptitude(\"ranged\")\ngame.bol.macros.rollAptitude(\"def\")</code></pre><p>Weapons, spells, and alchemy:</p><pre><code>game.bol.macros.rollWeapon(\"Spear\")\ngame.bol.macros.rollWeapon(0)\n\ngame.bol.macros.rollSpell(\"Javelin\")\ngame.bol.macros.rollSpell(0)\n\ngame.bol.macros.rollAlchemy(\"Fire\")\ngame.bol.macros.rollAlchemy(0)</code></pre><p>For weapons, spells, and alchemical preparations, name lookup is <strong>partial</strong> and <strong>case-insensitive</strong>. You may also use a numeric index.</p><p>Horoscope:</p><pre><code>game.bol.macros.rollHoroscope(\"minor\")\ngame.bol.macros.rollHoroscope(\"major\")</code></pre><p><strong>Generic macro</strong></p><pre><code>game.bol.macros.roll(\"attribute\", \"vigor\")\ngame.bol.macros.roll(\"aptitude\", \"melee\")\ngame.bol.macros.roll(\"weapon\", \"Spear\")\ngame.bol.macros.roll(\"spell\", \"Javelin\")\ngame.bol.macros.roll(\"alchemy\", 0)\ngame.bol.macros.roll(\"horoscope\", \"minor\")</code></pre><p><strong>Compatibility</strong></p><p>The legacy entry point <code>game.bol.macros.rollMacro(type, key)</code> is still available for existing macros.</p>"
|
||||||
|
},
|
||||||
|
"rERizrPxSAsvsZY2": {
|
||||||
|
"name": "Initiative",
|
||||||
|
"text": "<p>In BoL, initiative is rolled once at the start of combat.</p><p>You can request it automatically through the Combat Tracker, or roll Initiative manually and tick the corresponding box in the dialog:</p><img src=\"systems/bol/assets/pages/help-en-initiative-dialog.png\" /><p>According to the roll result, an initiative rank from 10 to 3 is assigned as follows:</p><p><strong>10</strong> - PC: Legendary Success<br /><strong>9</strong> - PC: Heroic Success<br /><strong>8</strong> - PC: Normal Success<br /><strong>7</strong> - NPC: Opponents or creatures larger than medium size<br /><strong>6</strong> - NPC: Toughs or creatures of medium size or smaller<br /><strong>5</strong> - PC: Normal Failure<br /><strong>4</strong> - NPC: Minions<br /><strong>3</strong> - PC: Critical Failure</p>"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -18,7 +18,7 @@
|
|||||||
"description": "<h1>Medium Armour</h1><p>Combining some of the mobility of the lighter armour and better protection of heavy armour, this is the armour worn by the typical adventurer expecting to get into combat situations on a regular basis. Medium armour could represent fairly extensive coverage of leather armour, with stiffened leather in some of the more vital areas, or partial coverage of mail with leather in other areas. It could even represent a steel breastplate and minimal/no other armour.</p><p>Someone in medium armour can often remove portions of their armour to reduce it to light armour, as necessary.</p><h2>Medium armour effects</h2><ul><li>Roll a d6-2 (0-4 points of damage reduction).</li><li>If you prefer static numbers, medium armour absorbs 2 points of damage.</li><li>Wearing medium armour restricts magicians and imposes an extra 2 Arcane Points cost on a spell casting.</li></ul>"
|
"description": "<h1>Medium Armour</h1><p>Combining some of the mobility of the lighter armour and better protection of heavy armour, this is the armour worn by the typical adventurer expecting to get into combat situations on a regular basis. Medium armour could represent fairly extensive coverage of leather armour, with stiffened leather in some of the more vital areas, or partial coverage of mail with leather in other areas. It could even represent a steel breastplate and minimal/no other armour.</p><p>Someone in medium armour can often remove portions of their armour to reduce it to light armour, as necessary.</p><h2>Medium armour effects</h2><ul><li>Roll a d6-2 (0-4 points of damage reduction).</li><li>If you prefer static numbers, medium armour absorbs 2 points of damage.</li><li>Wearing medium armour restricts magicians and imposes an extra 2 Arcane Points cost on a spell casting.</li></ul>"
|
||||||
},
|
},
|
||||||
"Casque": {
|
"Casque": {
|
||||||
"name": "Casque",
|
"name": "Helmet",
|
||||||
"description": "<h1>Helmet</h1><p>If you are wearing a helmet, this adds +1 to your protection if already wearing armour. Therefore, if in light armour and helmet, you’d roll d6-2. In medium armour, roll d6-1. In heavy armour, roll d6.</p><p>Helmets give you a penalty in social situations and to your initiative (as it’s harder to notice things whilst wearing a helmet).</p><p>Most Heroes take their helmets off, unless preparing for battle.</p>"
|
"description": "<h1>Helmet</h1><p>If you are wearing a helmet, this adds +1 to your protection if already wearing armour. Therefore, if in light armour and helmet, you’d roll d6-2. In medium armour, roll d6-1. In heavy armour, roll d6.</p><p>Helmets give you a penalty in social situations and to your initiative (as it’s harder to notice things whilst wearing a helmet).</p><p>Most Heroes take their helmets off, unless preparing for battle.</p>"
|
||||||
},
|
},
|
||||||
"Grand bouclier": {
|
"Grand bouclier": {
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
"description": ""
|
"description": ""
|
||||||
},
|
},
|
||||||
"Esprit -1": {
|
"Esprit -1": {
|
||||||
"name": "Miond -1",
|
"name": "Mind -1",
|
||||||
"description": ""
|
"description": ""
|
||||||
},
|
},
|
||||||
"Vigueur -1": {
|
"Vigueur -1": {
|
||||||
|
|||||||
@@ -175,7 +175,7 @@
|
|||||||
},
|
},
|
||||||
"Traqué": {
|
"Traqué": {
|
||||||
"name": "Hunted",
|
"name": "Hunted",
|
||||||
"description": "<h1>Hunted</h1><p>Your character is ridiculously tight- lipped. It’s a rare day on which he uses a sentence of more than three words, and it’s virtually unheard of for him to initiate conversation. His extreme reluctance to speak unfortunately means he never volunteers information without being asked. Take a penalty die in social situations.</p>"
|
"description": "<h1>Hunted</h1><p>Perhaps you are wanted by the authorities, or have offended some powerful noble or pirate king. Regardless of whom, you constantly have to evade agents intent on capturing or even killing you. Roll a d6 whenever you enter a new city. On a 1, agents of your enemy (or your enemy himself, if you choose) will spot you and make your life unpleasant.</p>"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -74,8 +74,8 @@
|
|||||||
"description": "<h1>Shamballah</h1><p>Shamballahns are generally a dark-skinned and dark-haired people with purple, mauve, scarlet, and indigo eye colouring. They are very perceptive and make good hunters.</p>"
|
"description": "<h1>Shamballah</h1><p>Shamballahns are generally a dark-skinned and dark-haired people with purple, mauve, scarlet, and indigo eye colouring. They are very perceptive and make good hunters.</p>"
|
||||||
},
|
},
|
||||||
"Terres Désolées": {
|
"Terres Désolées": {
|
||||||
"name": "Terres Désolées",
|
"name": "Empty Lands",
|
||||||
"description": "<h1>Terres Désolées</h1><p>Personne ne sait grand-chose au sujet des Terres Désolées, et moins encore sur les contrées qui s’étendraient au-delà. Des gens vivent assurément dans cette région, s’il faut en croire les récits de chasseurs et d’explorateurs qui ont relevé des traces de présence. Mais à ce jour, personne n’a découvert le moindre village ou hameau, et on ignore tout de l’apparence de leurs habitants.</p><p>Si votre héros est originaire des Terres Désolées, il vous faudra travailler avec le MJ pour déterminer à quoi ressemble votre personnage. Mais attendezvous à ce qu’il soit toujours considéré comme un étranger, où qu’il se rende en Lémurie.</p>"
|
"description": "<h1>Empty Lands</h1><p>No one knows what exists in and beyond the Empty Lands. People do live there, because hunters and explorers have seen evidence of them. However, no towns or even villages have been discovered, and no one has any idea of what the people are like. If you come from the Empty Lands, you will need to work with the GM to determine what your character is like. He or she will always be treated as an outsider.</p>"
|
||||||
},
|
},
|
||||||
"Tyrus": {
|
"Tyrus": {
|
||||||
"name": "Tyrus",
|
"name": "Tyrus",
|
||||||
|
|||||||
@@ -1,10 +1,34 @@
|
|||||||
{
|
{
|
||||||
"label": "Weapons",
|
"label": "Weapons",
|
||||||
"mapping": {
|
"mapping": {
|
||||||
"description": "system.description"
|
"description": "system.description"
|
||||||
},
|
},
|
||||||
|
|
||||||
"entries": {
|
"entries": {
|
||||||
|
"Arc de guerre de Tyrus": {
|
||||||
|
"name": "Tyrus Warbow",
|
||||||
|
"description": "<h1>Tyrus Warbow</h1><p> The archers of Tyrus train from a very young age in the use of this powerful bow. Tyrus archers have fun with other warriors by lending their bows to them and then watching them struggle to aim at the proverbial “barn door”.</p>"
|
||||||
|
},
|
||||||
|
"Épée Valgardienne (1 Main)": {
|
||||||
|
"name": "Valgardian Blade (1H)",
|
||||||
|
"description": "<h1>Valgardian Blade (1H)</h1><p>Around 3’-4’ in length, the Valgardian blade is used either in one hand or in both. The Valgardian bladesmiths guard the secret of their work closely, although many have tried to copy it. It is rumoured that the strength of the blades due mainly to the quality of the iron mined locally.</p>"
|
||||||
|
},
|
||||||
|
"Épée Valgardienne (2 mains)": {
|
||||||
|
"name": "Valgardian Blade (2H)",
|
||||||
|
"description": "<h1>Valgardian Blade (2H)</h1><p>Around 3’-4’ in length, the Valgardian blade is used either in one hand or in both. The Valgardian bladesmiths guard the secret of their work closely, although many have tried to copy it. It is rumoured that the strength of the blades due mainly to the quality of the iron mined locally.</p>"
|
||||||
|
},
|
||||||
|
"Fronde de l’Axos": {
|
||||||
|
"name": "Axish Sling",
|
||||||
|
"description": "<h1>Axish Sling</h1><p>Sling: The sling is inexpensive and easy to build. It is a simple leather thong whirled around the head to cast small stones or cast lead bullets with some force, at 30’ range increments. Two-handed versions are fitted onto a staff and are called staff-slings. This imparts a greater range, making the increments 60’. The Axish sling is actually little different to any other common sling; it’s just that the people of the Axos mountains are particularly proficient with them. They have however played up the idea that there is some special plant fibre that the thongs are made from that gives them their extra range.</p>"
|
||||||
|
},
|
||||||
|
"Hache d’abordage de Parsool (1 main)": {
|
||||||
|
"name": "Parsool Sea Axe (1H)",
|
||||||
|
"description": "<h1>Parsool Sea Axe (1H)</h1><p>A boarding axe used by Parsool seamen which can be used one or two-handed.</p>"
|
||||||
|
},
|
||||||
|
"Hache d’abordage de Parsool (2 mains)": {
|
||||||
|
"name": "Parsool Sea Axe (2H)",
|
||||||
|
"description": "<h1>Parsool Sea Axe (2H)</h1><p>A boarding axe used by Parsool seamen which can be used one or two-handed.</p>"
|
||||||
|
},
|
||||||
"Arbalète": {
|
"Arbalète": {
|
||||||
"name": "Crossbow",
|
"name": "Crossbow",
|
||||||
"description": "<h1>Crossbow</h1><p>A crossbow is a simple device for firing a short bolt or quarrel with some force and little training. They take a round to load (ready to fire on the second round).</p>"
|
"description": "<h1>Crossbow</h1><p>A crossbow is a simple device for firing a short bolt or quarrel with some force and little training. They take a round to load (ready to fire on the second round).</p>"
|
||||||
@@ -42,8 +66,8 @@
|
|||||||
"description": "<h1>Staff Sling</h1><p>The staff sling is a two-handed version of the sling, with a longer range.</p>"
|
"description": "<h1>Staff Sling</h1><p>The staff sling is a two-handed version of the sling, with a longer range.</p>"
|
||||||
},
|
},
|
||||||
"Cimeterre": {
|
"Cimeterre": {
|
||||||
"name": "Cimeterre",
|
"name": "Scimitar",
|
||||||
"description": "<h1>Épée</h1><p>l’arme favorite des héros. Elle se décline en différents modèles utilisés un peu partout en Lémurie, comme les sabres d’abordage, les tulwars, les cimeterres ou les épées longues. Inscrivez le nom de l’arme que vous voulez sur la fiche de votre personnage en fonction de l’image que vous vous faites de ce dernier. Mais au final, une épée reste une longue lame utilisée pour tuer l’ennemi.</p>"
|
"description": "<h1>Scimitar (Sword)</h1><p>This weapon is a favourite amongst Heroes. This is the catch-all description for all manner of long-bladed, one-handed weapons used all over Lemuria, such as cutlasses, tulwars, scimitars, rapiers, broadswords and longswords. Call it what you want on your character sheet, because that will add flavour to your character, but at the end of the day a sword is a long blade used for killing.</p>"
|
||||||
},
|
},
|
||||||
"Dague": {
|
"Dague": {
|
||||||
"name": "Dagger",
|
"name": "Dagger",
|
||||||
@@ -123,19 +147,19 @@
|
|||||||
},
|
},
|
||||||
"Masse d’armes": {
|
"Masse d’armes": {
|
||||||
"name": "Mace",
|
"name": "Mace",
|
||||||
"description": "<h1>Mace</h1><p>cA mace is similar to a club, but with a metal head, often with spikes or flanges. One-handed maces can be thrown at increments of 5’ as they aren’t very effective used this way.</p>"
|
"description": "<h1>Mace</h1><p>A mace is similar to a club, but with a metal head, often with spikes or flanges. One-handed maces can be thrown at increments of 5’ as they aren’t very effective used this way.</p>"
|
||||||
},
|
},
|
||||||
"Masse d’armes (Lancer)": {
|
"Masse d’armes (Lancer)": {
|
||||||
"name": "Masse d’armes (Lancer)",
|
"name": "Mace (Thrown)",
|
||||||
"description": "<h1>Masse d’armes</h1><p>cette arme a la même forme qu’un gourdin, mais possède une tête en métal, souvent agrémentée de pointes ou d’ailettes pour plus d’efficacité. Les masses d’armes à une main peuvent se lancer, mais à courte distance, car elles ne sont pas vraiment prévues pour cet usage.</p>"
|
"description": "<h1>Mace</h1><p>A mace is similar to a club, but with a metal head, often with spikes or flanges. One-handed maces can be thrown at increments of 5’ as they aren’t very effective used this way.</p>"
|
||||||
},
|
},
|
||||||
"Massue": {
|
"Massue": {
|
||||||
"name": "Massue",
|
"name": "Club",
|
||||||
"description": "<h1>Massue</h1><p>la version lourde du gourdin. Une massue consiste en un solide manche en bois dont l’extrémité, plus volumineuse, sert à fracasser le crâne de ses adversaires, d’où son autre nom de casse-tête.</p>"
|
"description": "<h1>Club</h1><p>This is a larger version of the cudgel. It is a stout length of wood, used in one hand to bludgeon and batter your opponent. Clubs usually have a wider or knobbed head and can be called war-clubs, knobkerries, or shillelaghs.</p>"
|
||||||
},
|
},
|
||||||
"Massue (Lancer)": {
|
"Massue (Lancer)": {
|
||||||
"name": "Massue (Lancer)",
|
"name": "Club (Thrown)",
|
||||||
"description": "<h1>Massue</h1><p>la version lourde du gourdin. Une massue consiste en un solide manche en bois dont l’extrémité, plus volumineuse, sert à fracasser le crâne de ses adversaires, d’où son autre nom de casse-tête.</p>"
|
"description": "<h1>Club</h1><p>This is a larger version of the cudgel. It is a stout length of wood, used in one hand to bludgeon and batter your opponent. Clubs usually have a wider or knobbed head and can be called war-clubs, knobkerries, or shillelaghs.</p>"
|
||||||
},
|
},
|
||||||
"Morgenstern": {
|
"Morgenstern": {
|
||||||
"name": "Morning Star",
|
"name": "Morning Star",
|
||||||
|
|||||||
2056
css/bol.css
@@ -1,5 +0,0 @@
|
|||||||
[Dolphin]
|
|
||||||
Timestamp=2024,11,2,20,30,2.2800000000000002
|
|
||||||
Version=4
|
|
||||||
ViewMode=1
|
|
||||||
VisibleRoles=Details_text,Details_size,Details_modificationtime,Details_creationtime,CustomizedDetails
|
|
||||||
28
lang/de.json
@@ -111,7 +111,7 @@
|
|||||||
"BOL.ui.defender": "Verteidiger",
|
"BOL.ui.defender": "Verteidiger",
|
||||||
"BOL.ui.difficulty": "Schwierigkeit",
|
"BOL.ui.difficulty": "Schwierigkeit",
|
||||||
"BOL.ui.spellProperties": "Zaubereigenschaften",
|
"BOL.ui.spellProperties": "Zaubereigenschaften",
|
||||||
"BOL.ui.duration": "Dauer",
|
"BOL.ui.duration": "Dauer",
|
||||||
"BOL.ui.spellkeep": "Aufrechterhalten",
|
"BOL.ui.spellkeep": "Aufrechterhalten",
|
||||||
"BOL.ui.concentrate": "Konzentrieren",
|
"BOL.ui.concentrate": "Konzentrieren",
|
||||||
"BOL.ui.registerInit": "Register Init.",
|
"BOL.ui.registerInit": "Register Init.",
|
||||||
@@ -134,7 +134,7 @@
|
|||||||
"BOL.ui.makeAlchemy": "Alchemika herstellen",
|
"BOL.ui.makeAlchemy": "Alchemika herstellen",
|
||||||
"BOL.ui.alchemyCostTotal": "Alchemiepunkte ingesamt",
|
"BOL.ui.alchemyCostTotal": "Alchemiepunkte ingesamt",
|
||||||
"BOL.ui.alchemyInvest": "Alchemiepunkte investieren",
|
"BOL.ui.alchemyInvest": "Alchemiepunkte investieren",
|
||||||
"BOL.ui.alchemyCurrent": "Aktuelle Alchemiepunkte in Objekten",
|
"BOL.ui.alchemyCurrent": "Aktuelle Alchemiepunkte in Objekten",
|
||||||
"BOL.ui.advance": "Status",
|
"BOL.ui.advance": "Status",
|
||||||
"BOL.ui.isadvantage": "Gibt zusätzlichen Würfel?",
|
"BOL.ui.isadvantage": "Gibt zusätzlichen Würfel?",
|
||||||
"BOL.ui.isbonusdice": "Gibt zusätzlichen Würfel?",
|
"BOL.ui.isbonusdice": "Gibt zusätzlichen Würfel?",
|
||||||
@@ -153,8 +153,8 @@
|
|||||||
"BOL.ui.status": "Status",
|
"BOL.ui.status": "Status",
|
||||||
"BOL.ui.toactivated": "Aktiv (>Deaktivieren)",
|
"BOL.ui.toactivated": "Aktiv (>Deaktivieren)",
|
||||||
"BOL.ui.todeactivated": "Inaktiv (>Aktivieren)",
|
"BOL.ui.todeactivated": "Inaktiv (>Aktivieren)",
|
||||||
"BOL.ui.armorAgiMalus": "Rüschtung+Schild-Malus (Geschick)",
|
"BOL.ui.armorAgiMalus": "Rüschtung+Schild-Malus (Geschick)",
|
||||||
"BOL.ui.armorInitMalus": "Rüstungsmalus (Init)",
|
"BOL.ui.armorInitMalus": "Rüstungsmalus (Init)",
|
||||||
"BOL.ui.attackValue": "Angriffswert",
|
"BOL.ui.attackValue": "Angriffswert",
|
||||||
"BOL.ui.initMalus": "Init malus",
|
"BOL.ui.initMalus": "Init malus",
|
||||||
"BOL.ui.createEquipment": "Create Equipment",
|
"BOL.ui.createEquipment": "Create Equipment",
|
||||||
@@ -177,7 +177,7 @@
|
|||||||
"BOL.featureSubtypes.fightOption": "Kampfoption",
|
"BOL.featureSubtypes.fightOption": "Kampfoption",
|
||||||
|
|
||||||
"BOL.bougette.nomoney": "Mittellos",
|
"BOL.bougette.nomoney": "Mittellos",
|
||||||
"BOL.bougette.tolive": "Zum Überleben",
|
"BOL.bougette.tolive": "Zum Überleben",
|
||||||
"BOL.bougette.easylife": "Einfaches Leben",
|
"BOL.bougette.easylife": "Einfaches Leben",
|
||||||
"BOL.bougette.luxury" : "Luxuriöses Leben",
|
"BOL.bougette.luxury" : "Luxuriöses Leben",
|
||||||
"BOL.bougette.rich": "Reich!",
|
"BOL.bougette.rich": "Reich!",
|
||||||
@@ -224,14 +224,14 @@
|
|||||||
"BOL.protectionCategory.other": "Verschiedenes",
|
"BOL.protectionCategory.other": "Verschiedenes",
|
||||||
|
|
||||||
"BOL.spellItem.charm": "Zauber",
|
"BOL.spellItem.charm": "Zauber",
|
||||||
"BOL.spellItem.circle1": "Erster Kreis",
|
"BOL.spellItem.circle1": "Erster Kreis",
|
||||||
"BOL.spellItem.circle2": "Zweiter Kreis",
|
"BOL.spellItem.circle2": "Zweiter Kreis",
|
||||||
"BOL.spellItem.circle3": "Dritter Kreis",
|
"BOL.spellItem.circle3": "Dritter Kreis",
|
||||||
|
|
||||||
"BOL.alchemyItem.common": "Häufig",
|
"BOL.alchemyItem.common": "Häufig",
|
||||||
"BOL.alchemyItem.scarce": "Selten",
|
"BOL.alchemyItem.scarce": "Selten",
|
||||||
"BOL.alchemyItem.legend": "Legendär",
|
"BOL.alchemyItem.legend": "Legendär",
|
||||||
"BOL.alchemyItem.mythic": "Mystisch",
|
"BOL.alchemyItem.mythic": "Mystisch",
|
||||||
|
|
||||||
"BOL.weaponCategory.melee": "Nahkampf",
|
"BOL.weaponCategory.melee": "Nahkampf",
|
||||||
"BOL.weaponCategory.ranged": "Fernkampf",
|
"BOL.weaponCategory.ranged": "Fernkampf",
|
||||||
@@ -290,6 +290,7 @@
|
|||||||
"BOL.itemProperty.difficulty": "Schwierigkeit",
|
"BOL.itemProperty.difficulty": "Schwierigkeit",
|
||||||
"BOL.itemProperty.natural": "Natürliche Waffe",
|
"BOL.itemProperty.natural": "Natürliche Waffe",
|
||||||
"BOL.itemProperty.onlymodifier": "Nur Modifikator (d.h. Angriffe von Kreaturen)",
|
"BOL.itemProperty.onlymodifier": "Nur Modifikator (d.h. Angriffe von Kreaturen)",
|
||||||
|
"BOL.itemProperty.attackMalusDice": "Angriffsmalus (Würfel)",
|
||||||
|
|
||||||
"BOL.itemStat.quantity": "Anzahl",
|
"BOL.itemStat.quantity": "Anzahl",
|
||||||
"BOL.itemStat.weight": "Gewicht",
|
"BOL.itemStat.weight": "Gewicht",
|
||||||
@@ -359,7 +360,7 @@
|
|||||||
"BOL.ui.astrologerPoints": "Points d'Astrologie",
|
"BOL.ui.astrologerPoints": "Points d'Astrologie",
|
||||||
"BOL.ui.astrologerPointsLabel": "Points d'Astrologie actuels",
|
"BOL.ui.astrologerPointsLabel": "Points d'Astrologie actuels",
|
||||||
"BOL.ui.ishoroscopemajor": "Horoscope Majeur (ie de groupe) ?",
|
"BOL.ui.ishoroscopemajor": "Horoscope Majeur (ie de groupe) ?",
|
||||||
"BOL.ui.answer": "Réponse",
|
"BOL.ui.answer": "Réponse",
|
||||||
"BOL.ui.horoscopefavorable": "Favorable (1dB)",
|
"BOL.ui.horoscopefavorable": "Favorable (1dB)",
|
||||||
"BOL.ui.horoscopeunfavorable": "Défavorable (1dM)",
|
"BOL.ui.horoscopeunfavorable": "Défavorable (1dM)",
|
||||||
"BOL.ui.horoscopes": "Horoscopes",
|
"BOL.ui.horoscopes": "Horoscopes",
|
||||||
@@ -468,6 +469,7 @@
|
|||||||
"BOL.chat.welcome4": "Im Discord findet ihr Support für die FoundryVTT-Implementierung dieses Systems: https://discord.gg/pPSDNJk",
|
"BOL.chat.welcome4": "Im Discord findet ihr Support für die FoundryVTT-Implementierung dieses Systems: https://discord.gg/pPSDNJk",
|
||||||
"BOL.chat.welcome5": "Auf ein gutes Spiel in Lemuria!",
|
"BOL.chat.welcome5": "Auf ein gutes Spiel in Lemuria!",
|
||||||
"BOL.chat.welcome6": "",
|
"BOL.chat.welcome6": "",
|
||||||
|
"BOL.chat.bolRulebookMessage": "Don't miss the full Rulebook module (including Sagas) available at : https://www.ludospherik-editions.com/en_gb/ !",
|
||||||
|
|
||||||
"BOL.settings.rollArmor": "Roll for armor",
|
"BOL.settings.rollArmor": "Roll for armor",
|
||||||
"BOL.settings.rollArmorTooltip": "Roll for armor value, fixed value if unchecked",
|
"BOL.settings.rollArmorTooltip": "Roll for armor value, fixed value if unchecked",
|
||||||
|
|||||||
56
lang/en.json
@@ -47,7 +47,7 @@
|
|||||||
"BOL.ui.astrologerPoints": "Points d'Astrologie",
|
"BOL.ui.astrologerPoints": "Points d'Astrologie",
|
||||||
"BOL.ui.astrologerPointsLabel": "Points d'Astrologie actuels",
|
"BOL.ui.astrologerPointsLabel": "Points d'Astrologie actuels",
|
||||||
"BOL.ui.ishoroscopemajor": "Horoscope Majeur (ie de groupe) ?",
|
"BOL.ui.ishoroscopemajor": "Horoscope Majeur (ie de groupe) ?",
|
||||||
"BOL.ui.answer": "Réponse",
|
"BOL.ui.answer": "Réponse",
|
||||||
"BOL.ui.horoscopefavorable": "Favorable (1dB)",
|
"BOL.ui.horoscopefavorable": "Favorable (1dB)",
|
||||||
"BOL.ui.horoscopeunfavorable": "Défavorable (1dM)",
|
"BOL.ui.horoscopeunfavorable": "Défavorable (1dM)",
|
||||||
"BOL.ui.horoscopes": "Horoscopes",
|
"BOL.ui.horoscopes": "Horoscopes",
|
||||||
@@ -132,7 +132,7 @@
|
|||||||
"BOL.ui.defender": "Defender",
|
"BOL.ui.defender": "Defender",
|
||||||
"BOL.ui.difficulty": "Difficulty",
|
"BOL.ui.difficulty": "Difficulty",
|
||||||
"BOL.ui.spellProperties": "Spell Properties",
|
"BOL.ui.spellProperties": "Spell Properties",
|
||||||
"BOL.ui.duration": "Duration",
|
"BOL.ui.duration": "Duration",
|
||||||
"BOL.ui.spellkeep": "Maintain",
|
"BOL.ui.spellkeep": "Maintain",
|
||||||
"BOL.ui.concentrate": "Concentrate",
|
"BOL.ui.concentrate": "Concentrate",
|
||||||
"BOL.ui.registerInit": "Register Init.",
|
"BOL.ui.registerInit": "Register Init.",
|
||||||
@@ -156,7 +156,7 @@
|
|||||||
"BOL.ui.makeAlchemy": "Make Alchemy",
|
"BOL.ui.makeAlchemy": "Make Alchemy",
|
||||||
"BOL.ui.alchemyCostTotal": "Alchemy Points Total Cost",
|
"BOL.ui.alchemyCostTotal": "Alchemy Points Total Cost",
|
||||||
"BOL.ui.alchemyInvest": "Invest Alchemy Points",
|
"BOL.ui.alchemyInvest": "Invest Alchemy Points",
|
||||||
"BOL.ui.alchemyCurrent": "Current Alchemy Points in Object",
|
"BOL.ui.alchemyCurrent": "Current Alchemy Points in Object",
|
||||||
"BOL.ui.advance": "Status",
|
"BOL.ui.advance": "Status",
|
||||||
"BOL.ui.isadvantage": "Provides a bonus dice?",
|
"BOL.ui.isadvantage": "Provides a bonus dice?",
|
||||||
"BOL.ui.bonusmalus": "Additional bonus/penalty",
|
"BOL.ui.bonusmalus": "Additional bonus/penalty",
|
||||||
@@ -173,8 +173,8 @@
|
|||||||
"BOL.ui.status": "Status",
|
"BOL.ui.status": "Status",
|
||||||
"BOL.ui.toactivated": "Active (>Deactivated)",
|
"BOL.ui.toactivated": "Active (>Deactivated)",
|
||||||
"BOL.ui.todeactivated": "Inactive (>Active)",
|
"BOL.ui.todeactivated": "Inactive (>Active)",
|
||||||
"BOL.ui.armorAgiMalus": "Armor+Shield Modifier (Agi)",
|
"BOL.ui.armorAgiMalus": "Armor+Shield Modifier (Agi)",
|
||||||
"BOL.ui.armorInitMalus": "Armor Modifier (Init)",
|
"BOL.ui.armorInitMalus": "Armor Modifier (Init)",
|
||||||
"BOL.ui.attackValue": "Attack Value",
|
"BOL.ui.attackValue": "Attack Value",
|
||||||
"BOL.ui.attackModifier": "Attack Modifier",
|
"BOL.ui.attackModifier": "Attack Modifier",
|
||||||
"BOL.ui.weaponbonus": "Cette arme bénéficie déja d'un Dé de Bonus (Arme Favorite prise en compte, par exemple)",
|
"BOL.ui.weaponbonus": "Cette arme bénéficie déja d'un Dé de Bonus (Arme Favorite prise en compte, par exemple)",
|
||||||
@@ -251,7 +251,7 @@
|
|||||||
"BOL.featureSubtypes.xplog": "XP Journal",
|
"BOL.featureSubtypes.xplog": "XP Journal",
|
||||||
|
|
||||||
"BOL.bougette.nomoney": "Nothing",
|
"BOL.bougette.nomoney": "Nothing",
|
||||||
"BOL.bougette.tolive": "To live",
|
"BOL.bougette.tolive": "To live",
|
||||||
"BOL.bougette.easylife": "Easy Life",
|
"BOL.bougette.easylife": "Easy Life",
|
||||||
"BOL.bougette.luxury" : "Luxury life",
|
"BOL.bougette.luxury" : "Luxury life",
|
||||||
"BOL.bougette.rich": "Rich!",
|
"BOL.bougette.rich": "Rich!",
|
||||||
@@ -299,15 +299,15 @@
|
|||||||
"BOL.protectionCategory.helm": "Helm",
|
"BOL.protectionCategory.helm": "Helm",
|
||||||
"BOL.protectionCategory.other": "Other",
|
"BOL.protectionCategory.other": "Other",
|
||||||
|
|
||||||
"BOL.spellItem.charm": "Charm",
|
"BOL.spellItem.charm": "Charm",
|
||||||
"BOL.spellItem.circle1": "First Circle",
|
"BOL.spellItem.circle1": "First Circle",
|
||||||
"BOL.spellItem.circle2": "Second Circle",
|
"BOL.spellItem.circle2": "Second Circle",
|
||||||
"BOL.spellItem.circle3": "Third Circle",
|
"BOL.spellItem.circle3": "Third Circle",
|
||||||
|
|
||||||
"BOL.alchemyItem.common": "Common",
|
"BOL.alchemyItem.common": "Common",
|
||||||
"BOL.alchemyItem.scarce": "Scarce",
|
"BOL.alchemyItem.scarce": "Scarce",
|
||||||
"BOL.alchemyItem.legend": "Legendary",
|
"BOL.alchemyItem.legend": "Legendary",
|
||||||
"BOL.alchemyItem.mythic": "Mythic",
|
"BOL.alchemyItem.mythic": "Mythic",
|
||||||
|
|
||||||
"BOL.weaponCategory.melee": "Melee",
|
"BOL.weaponCategory.melee": "Melee",
|
||||||
"BOL.weaponCategory.ranged": "Ranged",
|
"BOL.weaponCategory.ranged": "Ranged",
|
||||||
@@ -365,6 +365,7 @@
|
|||||||
"BOL.itemProperty.difficulty": "Difficulty",
|
"BOL.itemProperty.difficulty": "Difficulty",
|
||||||
"BOL.itemProperty.natural": "Natural weapon",
|
"BOL.itemProperty.natural": "Natural weapon",
|
||||||
"BOL.itemProperty.onlymodifier": "Modifier only (ie creatures attacks)",
|
"BOL.itemProperty.onlymodifier": "Modifier only (ie creatures attacks)",
|
||||||
|
"BOL.itemProperty.attackMalusDice": "Attack Malus (Dice)",
|
||||||
|
|
||||||
"BOL.itemStat.quantity": "Quantity",
|
"BOL.itemStat.quantity": "Quantity",
|
||||||
"BOL.itemStat.weight": "Weight",
|
"BOL.itemStat.weight": "Weight",
|
||||||
@@ -458,7 +459,7 @@
|
|||||||
"BOL.size.colossal": "Colossal",
|
"BOL.size.colossal": "Colossal",
|
||||||
|
|
||||||
"BOL.chat.fightactive": "{name} activates the fight option {foName} for this round !",
|
"BOL.chat.fightactive": "{name} activates the fight option {foName} for this round !",
|
||||||
"BOL.chat.fightunactive": "{name} deactivates the fight option {foName} for this round !",
|
"BOL.chat.fightunactive": "{name} deactivates the fight option {foName} for this round !",
|
||||||
"BOL.chat.isdead": "{name} is dead !",
|
"BOL.chat.isdead": "{name} is dead !",
|
||||||
"BOL.chat.epitaph": "Keep his name and memory in honor !",
|
"BOL.chat.epitaph": "Keep his name and memory in honor !",
|
||||||
"BOL.chat.vitalityzero": "Lifeblood of {name} is now {hp} : he is going to fall unconscious !",
|
"BOL.chat.vitalityzero": "Lifeblood of {name} is now {hp} : he is going to fall unconscious !",
|
||||||
@@ -477,6 +478,7 @@
|
|||||||
"BOL.chat.damageresult": "Damages of {name} : {total}",
|
"BOL.chat.damageresult": "Damages of {name} : {total}",
|
||||||
"BOL.chat.damagetarget": "Target : {target}",
|
"BOL.chat.damagetarget": "Target : {target}",
|
||||||
"BOL.chat.applydamagetotarget": "Apply damages to the target",
|
"BOL.chat.applydamagetotarget": "Apply damages to the target",
|
||||||
|
"BOL.chat.selecttarget": "Choose a target:",
|
||||||
"BOL.chat.fightoption": "Combat options",
|
"BOL.chat.fightoption": "Combat options",
|
||||||
"BOL.chat.reroll": "Reroll (1 HP)",
|
"BOL.chat.reroll": "Reroll (1 HP)",
|
||||||
"BOL.chat.heroicreminder": "In addition of the actions below, you can : <ul><li>Carnage : Do a second free attack on the same opponent</li><li>Precise : 1 Malus Die on your opponent on a chosen location</li><li>Disarm</li><li>Rabble Massacre</li><li>Prone : Push your opponent on the ground (max +1 size)</li></ul>If you spent 1 Hero Point in addition, all these effects can be doubled.",
|
"BOL.chat.heroicreminder": "In addition of the actions below, you can : <ul><li>Carnage : Do a second free attack on the same opponent</li><li>Precise : 1 Malus Die on your opponent on a chosen location</li><li>Disarm</li><li>Rabble Massacre</li><li>Prone : Push your opponent on the ground (max +1 size)</li></ul>If you spent 1 Hero Point in addition, all these effects can be doubled.",
|
||||||
@@ -543,17 +545,24 @@
|
|||||||
"BOL.chat.criticalbuttonjournal": "Legendary/Heroic Success",
|
"BOL.chat.criticalbuttonjournal": "Legendary/Heroic Success",
|
||||||
"BOL.chat.nodamage": "Do not apply damages",
|
"BOL.chat.nodamage": "Do not apply damages",
|
||||||
"BOL.chat.armorRoll": "Armor roll",
|
"BOL.chat.armorRoll": "Armor roll",
|
||||||
|
"BOL.chat.bolRulebookMessage": "Don't miss the full Rulebook module (including Sagas) available at : https://www.ludospherik-editions.com/en_gb/ !",
|
||||||
|
|
||||||
"BOL.dialog.soeasy": "So easy (+4)",
|
"BOL.dialog.soeasy": "So easy (+4)",
|
||||||
|
"BOL.dialog.soeasy3": "So easy (+3)",
|
||||||
"BOL.dialog.veryeasy": "Very easy (+2)",
|
"BOL.dialog.veryeasy": "Very easy (+2)",
|
||||||
"BOL.dialog.easy": "Easy (+1)",
|
"BOL.dialog.easy": "Easy (+1)",
|
||||||
"BOL.dialog.moderate": "Moderate (0)",
|
"BOL.dialog.moderate": "Moderate (0)",
|
||||||
"BOL.dialog.hard": "Hard (-1)",
|
"BOL.dialog.hard": "Hard (-1)",
|
||||||
"BOL.dialog.tough": "Tough (-2)",
|
"BOL.dialog.tough": "Tough (-2)",
|
||||||
|
"BOL.dialog.tough3": "Tough (-3)",
|
||||||
"BOL.dialog.demanding": "Demanding (-4)",
|
"BOL.dialog.demanding": "Demanding (-4)",
|
||||||
|
"BOL.dialog.demanding5": "Demanding (-5)",
|
||||||
"BOL.dialog.formidable": "Formidable (-6)",
|
"BOL.dialog.formidable": "Formidable (-6)",
|
||||||
|
"BOL.dialog.formidable7": "Formidable (-7)",
|
||||||
"BOL.dialog.heroic": "Heroic (-8)",
|
"BOL.dialog.heroic": "Heroic (-8)",
|
||||||
|
"BOL.dialog.heroic9": "Heroic (-9)",
|
||||||
"BOL.dialog.mythic": "Mythic (-10)",
|
"BOL.dialog.mythic": "Mythic (-10)",
|
||||||
|
"BOL.dialog.mythic11": "Mythic (-11)",
|
||||||
"BOL.dialog.divine": "Divine (-12)",
|
"BOL.dialog.divine": "Divine (-12)",
|
||||||
|
|
||||||
"BOL.dialog.pointblank": "Point blank (+1)",
|
"BOL.dialog.pointblank": "Point blank (+1)",
|
||||||
@@ -562,7 +571,7 @@
|
|||||||
"BOL.dialog.long": "Long (-2)",
|
"BOL.dialog.long": "Long (-2)",
|
||||||
"BOL.dialog.distant": "Distant (-4)",
|
"BOL.dialog.distant": "Distant (-4)",
|
||||||
"BOL.dialog.extreme": "Extreme (-6)",
|
"BOL.dialog.extreme": "Extreme (-6)",
|
||||||
"BOL.dialog.utmost": "Utmost (-8)",
|
"BOL.dialog.utmost": "Utmost (-8)",
|
||||||
|
|
||||||
"BOL.ui.name": "Name",
|
"BOL.ui.name": "Name",
|
||||||
"BOL.ui.xp": "Experience",
|
"BOL.ui.xp": "Experience",
|
||||||
@@ -578,11 +587,11 @@
|
|||||||
"BOL.ui.bionotes": "Notes",
|
"BOL.ui.bionotes": "Notes",
|
||||||
|
|
||||||
"BOL.chat.welcome1": "Welcome to Barbarians of Lemuria (Ludospherik version)",
|
"BOL.chat.welcome1": "Welcome to Barbarians of Lemuria (Ludospherik version)",
|
||||||
"BOL.chat.welcome2": "Books are necessary to play, and ca be found here : http://www.ludospherik.fr/content/14-barbarians-of-lemuria",
|
"BOL.chat.welcome2": "Books are necessary to play, and <a href='http://www.ludospherik.fr/content/14-barbarians-of-lemuria'>can be found here.</a> ",
|
||||||
"BOL.chat.welcome3": "The integrated maps are authorized by Guillaume Tavernier and Ludospherik. Thanks to them !.",
|
"BOL.chat.welcome3": "The integrated maps are authorized by Emmanuel Roudier and Ludospherik. Thanks to them !.",
|
||||||
"BOL.chat.welcome4": "All support for this system is available on this Discord server : https://discord.gg/pPSDNJk",
|
"BOL.chat.welcome4": "All support for this system is available on this Discord server : https://discord.gg/pPSDNJk",
|
||||||
"BOL.chat.welcome5": "Good game in Lemuria !",
|
"BOL.chat.welcome5": "<strong>In order to see compendiums in English, you must install and enable the Babele module.</strong>",
|
||||||
"BOL.chat.welcome6": "",
|
"BOL.chat.welcome6": "Good game in Lemuria !",
|
||||||
|
|
||||||
"BOL.settings.rollArmor": "Roll for armor",
|
"BOL.settings.rollArmor": "Roll for armor",
|
||||||
"BOL.settings.rollArmorTooltip": "Roll for armor value, fixed value if unchecked",
|
"BOL.settings.rollArmorTooltip": "Roll for armor value, fixed value if unchecked",
|
||||||
@@ -601,5 +610,10 @@
|
|||||||
"BOL.settings.defaultLogoActorSheetPath" : "Path for Actor sheet logo",
|
"BOL.settings.defaultLogoActorSheetPath" : "Path for Actor sheet logo",
|
||||||
"BOL.settings.defaultLogoPathActorSheetTooltip": "Path of the Actor sheet logo (346 x 200, default : /systems/bol/ui/logo.webp)",
|
"BOL.settings.defaultLogoPathActorSheetTooltip": "Path of the Actor sheet logo (346 x 200, default : /systems/bol/ui/logo.webp)",
|
||||||
"BOL.settings.defaultLogoTopLeftPath" : "Path for main top left logo",
|
"BOL.settings.defaultLogoTopLeftPath" : "Path for main top left logo",
|
||||||
"BOL.settings.defaultLogoTopLeftPathTooltip": "Path of the logo in the top left window (718 x 416, default : /systems/bol/ui/logo2.webp)"
|
"BOL.settings.defaultLogoTopLeftPathTooltip": "Path of the logo in the top left window (718 x 416, default : /systems/bol/ui/logo2.webp)",
|
||||||
|
|
||||||
|
"BOL.ui.charSummaryTitle": "Character Summary",
|
||||||
|
"BOL.ui.colGroupAttributes": "Attributes",
|
||||||
|
"BOL.ui.colGroupAptitudes": "Aptitudes",
|
||||||
|
"BOL.ui.colGroupResources": "Resources"
|
||||||
}
|
}
|
||||||
28
lang/es.json
@@ -132,7 +132,7 @@
|
|||||||
"BOL.ui.defender": "Defensor",
|
"BOL.ui.defender": "Defensor",
|
||||||
"BOL.ui.difficulty": "Dificultad",
|
"BOL.ui.difficulty": "Dificultad",
|
||||||
"BOL.ui.spellProperties": "Propiedades Conjuro",
|
"BOL.ui.spellProperties": "Propiedades Conjuro",
|
||||||
"BOL.ui.duration": "Duración",
|
"BOL.ui.duration": "Duración",
|
||||||
"BOL.ui.spellkeep": "Mantenimiento",
|
"BOL.ui.spellkeep": "Mantenimiento",
|
||||||
"BOL.ui.concentrate": "Concentración",
|
"BOL.ui.concentrate": "Concentración",
|
||||||
"BOL.ui.registerInit": "Registrar Inic.",
|
"BOL.ui.registerInit": "Registrar Inic.",
|
||||||
@@ -156,7 +156,7 @@
|
|||||||
"BOL.ui.makeAlchemy": "Realizar Alquimia",
|
"BOL.ui.makeAlchemy": "Realizar Alquimia",
|
||||||
"BOL.ui.alchemyCostTotal": "Coste Total Puntos Alquimia",
|
"BOL.ui.alchemyCostTotal": "Coste Total Puntos Alquimia",
|
||||||
"BOL.ui.alchemyInvest": "Invertir Puntos Alquimia",
|
"BOL.ui.alchemyInvest": "Invertir Puntos Alquimia",
|
||||||
"BOL.ui.alchemyCurrent": "Puntos Alquimia actuales en Objeto",
|
"BOL.ui.alchemyCurrent": "Puntos Alquimia actuales en Objeto",
|
||||||
"BOL.ui.advance": "Estado",
|
"BOL.ui.advance": "Estado",
|
||||||
"BOL.ui.isadvantage": "¿Da un dado ventaja?",
|
"BOL.ui.isadvantage": "¿Da un dado ventaja?",
|
||||||
"BOL.ui.bonusmalus": "Ventaja/desventaja adicional",
|
"BOL.ui.bonusmalus": "Ventaja/desventaja adicional",
|
||||||
@@ -245,7 +245,7 @@
|
|||||||
"BOL.featureSubtypes.xplog": "Diario PX",
|
"BOL.featureSubtypes.xplog": "Diario PX",
|
||||||
|
|
||||||
"BOL.bougette.nomoney": "Nada",
|
"BOL.bougette.nomoney": "Nada",
|
||||||
"BOL.bougette.tolive": "Vivir justo",
|
"BOL.bougette.tolive": "Vivir justo",
|
||||||
"BOL.bougette.easylife": "Vida simple",
|
"BOL.bougette.easylife": "Vida simple",
|
||||||
"BOL.bougette.luxury" : "Vida lujosa",
|
"BOL.bougette.luxury" : "Vida lujosa",
|
||||||
"BOL.bougette.rich": "¡Rico!",
|
"BOL.bougette.rich": "¡Rico!",
|
||||||
@@ -293,15 +293,15 @@
|
|||||||
"BOL.protectionCategory.helm": "Casco",
|
"BOL.protectionCategory.helm": "Casco",
|
||||||
"BOL.protectionCategory.other": "Otro",
|
"BOL.protectionCategory.other": "Otro",
|
||||||
|
|
||||||
"BOL.spellItem.charm": "Truco",
|
"BOL.spellItem.charm": "Truco",
|
||||||
"BOL.spellItem.circle1": "Primer Círculo",
|
"BOL.spellItem.circle1": "Primer Círculo",
|
||||||
"BOL.spellItem.circle2": "Segundo Círculo",
|
"BOL.spellItem.circle2": "Segundo Círculo",
|
||||||
"BOL.spellItem.circle3": "Tercer Círculo",
|
"BOL.spellItem.circle3": "Tercer Círculo",
|
||||||
|
|
||||||
"BOL.alchemyItem.common": "Común",
|
"BOL.alchemyItem.common": "Común",
|
||||||
"BOL.alchemyItem.scarce": "Escaso",
|
"BOL.alchemyItem.scarce": "Escaso",
|
||||||
"BOL.alchemyItem.legend": "Legendario",
|
"BOL.alchemyItem.legend": "Legendario",
|
||||||
"BOL.alchemyItem.mythic": "Mítico",
|
"BOL.alchemyItem.mythic": "Mítico",
|
||||||
|
|
||||||
"BOL.weaponCategory.melee": "Melé",
|
"BOL.weaponCategory.melee": "Melé",
|
||||||
"BOL.weaponCategory.ranged": "Distancia",
|
"BOL.weaponCategory.ranged": "Distancia",
|
||||||
@@ -359,6 +359,7 @@
|
|||||||
"BOL.itemProperty.difficulty": "Dificultad",
|
"BOL.itemProperty.difficulty": "Dificultad",
|
||||||
"BOL.itemProperty.natural": "Arma natural",
|
"BOL.itemProperty.natural": "Arma natural",
|
||||||
"BOL.itemProperty.onlymodifier": "Sólo modificador (ej criatura)",
|
"BOL.itemProperty.onlymodifier": "Sólo modificador (ej criatura)",
|
||||||
|
"BOL.itemProperty.attackMalusDice": "Dado Desventaja Ataque",
|
||||||
|
|
||||||
"BOL.itemStat.quantity": "Cantidad",
|
"BOL.itemStat.quantity": "Cantidad",
|
||||||
"BOL.itemStat.weight": "Peso",
|
"BOL.itemStat.weight": "Peso",
|
||||||
@@ -452,7 +453,7 @@
|
|||||||
"BOL.size.colossal": "Colosal",
|
"BOL.size.colossal": "Colosal",
|
||||||
|
|
||||||
"BOL.chat.fightactive": "¡Activa la opción de combate {foName} este asalto!",
|
"BOL.chat.fightactive": "¡Activa la opción de combate {foName} este asalto!",
|
||||||
"BOL.chat.fightunactive": "¡Desactiva la opción de combate {foName} este asalto!",
|
"BOL.chat.fightunactive": "¡Desactiva la opción de combate {foName} este asalto!",
|
||||||
"BOL.chat.isdead": "¡{name} esta muerto!",
|
"BOL.chat.isdead": "¡{name} esta muerto!",
|
||||||
"BOL.chat.epitaph": "¡Guardar el honor de su nombre y su memoria!",
|
"BOL.chat.epitaph": "¡Guardar el honor de su nombre y su memoria!",
|
||||||
"BOL.chat.vitalityzero": "Vitalidad de {name} es {hp}: ¡va a caer inconsciente!",
|
"BOL.chat.vitalityzero": "Vitalidad de {name} es {hp}: ¡va a caer inconsciente!",
|
||||||
@@ -534,6 +535,7 @@
|
|||||||
"BOL.chat.criticalinfo": "¡Esto es un éxito Asombroso o Legendario! Escoge tus opciones y efectos",
|
"BOL.chat.criticalinfo": "¡Esto es un éxito Asombroso o Legendario! Escoge tus opciones y efectos",
|
||||||
"BOL.chat.criticalbuttonjournal": "Éxito Asombroso/Legendario",
|
"BOL.chat.criticalbuttonjournal": "Éxito Asombroso/Legendario",
|
||||||
"BOL.chat.armorRoll": "Tirada de Armadura",
|
"BOL.chat.armorRoll": "Tirada de Armadura",
|
||||||
|
"BOL.chat.bolRulebookMessage": "Don't miss the full Rulebook module (including Sagas) available at : https://www.ludospherik-editions.com/en_gb/ !",
|
||||||
|
|
||||||
"BOL.dialog.soeasy": "Demasiado fácil (+4)",
|
"BOL.dialog.soeasy": "Demasiado fácil (+4)",
|
||||||
"BOL.dialog.veryeasy": "Muy fácil (+2)",
|
"BOL.dialog.veryeasy": "Muy fácil (+2)",
|
||||||
@@ -553,7 +555,7 @@
|
|||||||
"BOL.dialog.long": "Larga (-2)",
|
"BOL.dialog.long": "Larga (-2)",
|
||||||
"BOL.dialog.distant": "Distante (-4)",
|
"BOL.dialog.distant": "Distante (-4)",
|
||||||
"BOL.dialog.extreme": "Extrema (-6)",
|
"BOL.dialog.extreme": "Extrema (-6)",
|
||||||
"BOL.dialog.utmost": "Límite (-8)",
|
"BOL.dialog.utmost": "Límite (-8)",
|
||||||
|
|
||||||
"BOL.ui.name": "Nombre",
|
"BOL.ui.name": "Nombre",
|
||||||
"BOL.ui.xp": "Experiencia",
|
"BOL.ui.xp": "Experiencia",
|
||||||
|
|||||||
40
lang/fr.json
@@ -50,7 +50,7 @@
|
|||||||
"BOL.ui.astrologerPoints": "Points d'Astrologie",
|
"BOL.ui.astrologerPoints": "Points d'Astrologie",
|
||||||
"BOL.ui.astrologerPointsLabel": "Points d'Astrologie actuels",
|
"BOL.ui.astrologerPointsLabel": "Points d'Astrologie actuels",
|
||||||
"BOL.ui.ishoroscopemajor": "Horoscope Majeur (ie de groupe) ?",
|
"BOL.ui.ishoroscopemajor": "Horoscope Majeur (ie de groupe) ?",
|
||||||
"BOL.ui.answer": "Réponse",
|
"BOL.ui.answer": "Réponse",
|
||||||
"BOL.ui.horoscopefavorable": "Favorable (1dB)",
|
"BOL.ui.horoscopefavorable": "Favorable (1dB)",
|
||||||
"BOL.ui.horoscopeunfavorable": "Défavorable (1dM)",
|
"BOL.ui.horoscopeunfavorable": "Défavorable (1dM)",
|
||||||
"BOL.ui.horoscopes": "Horoscopes",
|
"BOL.ui.horoscopes": "Horoscopes",
|
||||||
@@ -137,7 +137,7 @@
|
|||||||
"BOL.ui.duration": "Durée",
|
"BOL.ui.duration": "Durée",
|
||||||
"BOL.ui.spellkeep": "Prolongation possible ?",
|
"BOL.ui.spellkeep": "Prolongation possible ?",
|
||||||
"BOL.ui.concentrate": "Concentration à maintenir ?",
|
"BOL.ui.concentrate": "Concentration à maintenir ?",
|
||||||
"BOL.ui.aggressive": "Sort aggressif ?",
|
"BOL.ui.aggressive": "Sort aggressif ?",
|
||||||
"BOL.ui.registerInit": "Enregistrer comme Init. de combat",
|
"BOL.ui.registerInit": "Enregistrer comme Init. de combat",
|
||||||
"BOL.ui.initMalus": "Malus d'initiative",
|
"BOL.ui.initMalus": "Malus d'initiative",
|
||||||
"BOL.ui.magicnewrules": "Règles supplémentaires (cf. supplément fan-made Sorcellerie!)",
|
"BOL.ui.magicnewrules": "Règles supplémentaires (cf. supplément fan-made Sorcellerie!)",
|
||||||
@@ -147,7 +147,7 @@
|
|||||||
"BOL.ui.flaw":"Désanvatage",
|
"BOL.ui.flaw":"Désanvatage",
|
||||||
"BOL.ui.cost":"Cout XP",
|
"BOL.ui.cost":"Cout XP",
|
||||||
"BOL.ui.date":"Date",
|
"BOL.ui.date":"Date",
|
||||||
|
|
||||||
"BOL.ui.isSorcerer": "Carrière de Sorcier ?",
|
"BOL.ui.isSorcerer": "Carrière de Sorcier ?",
|
||||||
"BOL.ui.isAlchemist": "Carrière d'Alchimiste ?",
|
"BOL.ui.isAlchemist": "Carrière d'Alchimiste ?",
|
||||||
"BOL.ui.isPriest": "Carrière de Prêtre/Druide ?",
|
"BOL.ui.isPriest": "Carrière de Prêtre/Druide ?",
|
||||||
@@ -259,7 +259,7 @@
|
|||||||
"BOL.bougette.easylife": "A l'aise",
|
"BOL.bougette.easylife": "A l'aise",
|
||||||
"BOL.bougette.luxury": "Luxe&Volupté",
|
"BOL.bougette.luxury": "Luxe&Volupté",
|
||||||
"BOL.bougette.rich": "Richissime",
|
"BOL.bougette.rich": "Richissime",
|
||||||
|
|
||||||
"BOL.featureSubtypes.origin": "Origine",
|
"BOL.featureSubtypes.origin": "Origine",
|
||||||
"BOL.featureSubtypes.race": "Race",
|
"BOL.featureSubtypes.race": "Race",
|
||||||
"BOL.featureSubtypes.career": "Carrière",
|
"BOL.featureSubtypes.career": "Carrière",
|
||||||
@@ -393,8 +393,9 @@
|
|||||||
"BOL.itemProperty.crewDamageMultiplier": "Multiplicateur",
|
"BOL.itemProperty.crewDamageMultiplier": "Multiplicateur",
|
||||||
"BOL.itemProperty.isboarding": "Abordage",
|
"BOL.itemProperty.isboarding": "Abordage",
|
||||||
"BOL.itemProperty.isspur": "Eperonnage",
|
"BOL.itemProperty.isspur": "Eperonnage",
|
||||||
"BOL.itemProperty.isbreakrow": "Briser les rames",
|
"BOL.itemProperty.isbreakrow": "Briser les rames",
|
||||||
|
"BOL.itemProperty.attackMalusDice": "Malus d'attaque (Dés)",
|
||||||
|
|
||||||
"BOL.itemStat.quantity": "Quantité",
|
"BOL.itemStat.quantity": "Quantité",
|
||||||
"BOL.itemStat.weight": "Poids",
|
"BOL.itemStat.weight": "Poids",
|
||||||
"BOL.itemStat.price": "Prix",
|
"BOL.itemStat.price": "Prix",
|
||||||
@@ -486,7 +487,7 @@
|
|||||||
"BOL.size.colossal": "Monstrueuse",
|
"BOL.size.colossal": "Monstrueuse",
|
||||||
|
|
||||||
"BOL.chat.fightactive": "{name} active son option de combat {foName} pour ce round !",
|
"BOL.chat.fightactive": "{name} active son option de combat {foName} pour ce round !",
|
||||||
"BOL.chat.fightunactive": "{name} désactive son option de combat {foName} pour ce round !",
|
"BOL.chat.fightunactive": "{name} désactive son option de combat {foName} pour ce round !",
|
||||||
"BOL.chat.isdead": "{name} est mort !",
|
"BOL.chat.isdead": "{name} est mort !",
|
||||||
"BOL.chat.epitaph": "Que son nom soit honoré sur les champs de batailles de Lémurie !",
|
"BOL.chat.epitaph": "Que son nom soit honoré sur les champs de batailles de Lémurie !",
|
||||||
"BOL.chat.vitalityzero": "La Vitalité de {name} est {hp} : il va s'écrouler au sol et sombrer dans l'inconscience !",
|
"BOL.chat.vitalityzero": "La Vitalité de {name} est {hp} : il va s'écrouler au sol et sombrer dans l'inconscience !",
|
||||||
@@ -505,6 +506,7 @@
|
|||||||
"BOL.chat.damageresult": "Dommages de {name} : {total}",
|
"BOL.chat.damageresult": "Dommages de {name} : {total}",
|
||||||
"BOL.chat.damagetarget": "Cible : {target}",
|
"BOL.chat.damagetarget": "Cible : {target}",
|
||||||
"BOL.chat.applydamagetotarget": "Appliquer les dommages à la cible",
|
"BOL.chat.applydamagetotarget": "Appliquer les dommages à la cible",
|
||||||
|
"BOL.chat.selecttarget": "Choisir une cible :",
|
||||||
"BOL.chat.fightoption": "Option de combat",
|
"BOL.chat.fightoption": "Option de combat",
|
||||||
"BOL.chat.reroll": "Relancer (1 P. Heroisme)",
|
"BOL.chat.reroll": "Relancer (1 P. Heroisme)",
|
||||||
"BOL.chat.heroicreminder": "En plus des actions indiquées sur les boutons ci-dessous, vous pouvez : <ul><li>Carnage : Attaquer une seconde fois le même adversaire</li><li>Coup précis : Un dé de malus à votre adversaire sur une localisation choisie</li><li>Désarmement</li><li>Massacrer la piétaille</li><li>Renversement : Renversez votre adversaire (1 taille de plus max)</li></ul>Si vous dépensez un Point d'Héroisme en plus, tout ces effets peuvent être doublés",
|
"BOL.chat.heroicreminder": "En plus des actions indiquées sur les boutons ci-dessous, vous pouvez : <ul><li>Carnage : Attaquer une seconde fois le même adversaire</li><li>Coup précis : Un dé de malus à votre adversaire sur une localisation choisie</li><li>Désarmement</li><li>Massacrer la piétaille</li><li>Renversement : Renversez votre adversaire (1 taille de plus max)</li></ul>Si vous dépensez un Point d'Héroisme en plus, tout ces effets peuvent être doublés",
|
||||||
@@ -569,21 +571,29 @@
|
|||||||
"BOL.chat.criticalinfo": "C'est un succès Héroïque ! Choisissez vos options et effets !",
|
"BOL.chat.criticalinfo": "C'est un succès Héroïque ! Choisissez vos options et effets !",
|
||||||
"BOL.chat.criticallegendaryinfo": "C'est un succès Légendaire ! Choisissez vos options et effets !",
|
"BOL.chat.criticallegendaryinfo": "C'est un succès Légendaire ! Choisissez vos options et effets !",
|
||||||
"BOL.chat.criticalbuttonjournal": "Succès Héroïque/Légendaire",
|
"BOL.chat.criticalbuttonjournal": "Succès Héroïque/Légendaire",
|
||||||
|
"BOL.chat.bolRulebookMessage": "N'oubliez pas le module complet du Livre de Règle et des Sagas disponible ici : https://www.ludospherik-editions.com !",
|
||||||
"BOL.chat.losshp": "{name} a perdu {lossHP} points de Vitalité. Si il se repose quelques minutes, il peut récupérer {recupHP} points de Vitalité.",
|
"BOL.chat.losshp": "{name} a perdu {lossHP} points de Vitalité. Si il se repose quelques minutes, il peut récupérer {recupHP} points de Vitalité.",
|
||||||
"BOL.chat.applyrecup": "Récupérer pendant quelques minutes (+{recupHP} Vitalité)",
|
"BOL.chat.applyrecup": "Récupérer pendant quelques minutes (+{recupHP} Vitalité)",
|
||||||
"BOL.chat.inforecup": "{name} vient de récupérer {recupHP} points de Vitalité après quelques minutes de repos.",
|
"BOL.chat.inforecup": "{name} vient de récupérer {recupHP} points de Vitalité après quelques minutes de repos.",
|
||||||
|
"BOL.chat.defenseReduceDamage2": "Vous pouvez également dépenser 1 Point d'Héroisme/Vilainie pour regagner [[/r 2d6KH(1D6B)]] points de vitalité, cela vous coutera votre prochaine action.",
|
||||||
|
"BOL.chat.armorRoll": "Jet d'armure ",
|
||||||
|
|
||||||
"BOL.dialog.soeasy": "Inmanquable (+4)",
|
"BOL.dialog.soeasy": "Inmanquable (+4)",
|
||||||
|
"BOL.dialog.soeasy3": "Inmanquable (+3)",
|
||||||
"BOL.dialog.veryeasy": "Trés Facile (+2)",
|
"BOL.dialog.veryeasy": "Trés Facile (+2)",
|
||||||
"BOL.dialog.easy": "Facile (+1)",
|
"BOL.dialog.easy": "Facile (+1)",
|
||||||
"BOL.dialog.moderate": "Moyenne (0)",
|
"BOL.dialog.moderate": "Moyenne (0)",
|
||||||
"BOL.dialog.hard": "Ardue (-1)",
|
"BOL.dialog.hard": "Ardue (-1)",
|
||||||
"BOL.dialog.tough": "Difficile (-2)",
|
"BOL.dialog.tough": "Difficile (-2)",
|
||||||
|
"BOL.dialog.tough3": "Difficile (-3)",
|
||||||
"BOL.dialog.demanding": "Très Difficile (-4)",
|
"BOL.dialog.demanding": "Très Difficile (-4)",
|
||||||
|
"BOL.dialog.demanding5": "Très Difficile (-5)",
|
||||||
"BOL.dialog.formidable": "Impossible (-6)",
|
"BOL.dialog.formidable": "Impossible (-6)",
|
||||||
|
"BOL.dialog.formidable7": "Impossible (-7)",
|
||||||
"BOL.dialog.heroic": "Héroïque (-8)",
|
"BOL.dialog.heroic": "Héroïque (-8)",
|
||||||
|
"BOL.dialog.heroic9": "Héroïque (-9)",
|
||||||
"BOL.dialog.mythic": "Mythique (-10)",
|
"BOL.dialog.mythic": "Mythique (-10)",
|
||||||
|
"BOL.dialog.mythic11": "Mythique (-11)",
|
||||||
"BOL.dialog.divine": "Divine (-12)",
|
"BOL.dialog.divine": "Divine (-12)",
|
||||||
|
|
||||||
"BOL.dialog.pointblank": "Bout portant (+1)",
|
"BOL.dialog.pointblank": "Bout portant (+1)",
|
||||||
@@ -611,16 +621,15 @@
|
|||||||
|
|
||||||
"BOL.chat.welcome1": "Bienvenue dans Barbarians of Lemuria (Ludospherik version)",
|
"BOL.chat.welcome1": "Bienvenue dans Barbarians of Lemuria (Ludospherik version)",
|
||||||
"BOL.chat.welcome2": "Les livres nécessaires pour jouer sont disponibles sur le site de <a href='http://www.ludospherik.fr/content/14-barbarians-of-lemuria'>l'éditeur Ludospherik.</a>",
|
"BOL.chat.welcome2": "Les livres nécessaires pour jouer sont disponibles sur le site de <a href='http://www.ludospherik.fr/content/14-barbarians-of-lemuria'>l'éditeur Ludospherik.</a>",
|
||||||
"BOL.chat.welcome3": "Les cartes intégrées au système le sont grace à l'aimable autorisation de leur auteur Guillaume Tavernier et des éditions Ludospherik. Merci à eux !.",
|
"BOL.chat.welcome3": "Les cartes intégrées au système le sont grace à l'aimable autorisation d'Emmanuel Roudier et des éditions Ludospherik. Merci à eux !.",
|
||||||
"BOL.chat.welcome4": "Tout le support et le suivi de ce système est disponible via le <a href='https://discord.gg/pPSDNJk'>Discord Foundry FR</a>.",
|
"BOL.chat.welcome4": "Tout le support et le suivi de ce système est disponible via le <a href='https://discord.gg/pPSDNJk'>Discord Foundry FR</a>.",
|
||||||
"BOL.chat.welcome5": "Consulter l'aide en ligne pour plus d'informations : @UUID[Compendium.bol.aides-de-jeu.JournalEntry.8ihDiCxC47fcdKVA]{Aide du Jeu}.",
|
"BOL.chat.welcome5": "Consulter l'aide en ligne pour plus d'informations : @UUID[Compendium.bol.aides-de-jeu.JournalEntry.8ihDiCxC47fcdKVA]{Aide du Jeu}.<br>Si vous souhaitez jouer en anglais, n'oubliez pas d'activer le module Babele.",
|
||||||
"BOL.chat.welcome6": "Bon jeu en Lemurie !",
|
"BOL.chat.welcome6": "Bon jeu en Lemurie !",
|
||||||
"BOL.chat.nodamage": "Ne pas appliquer les dommages",
|
"BOL.chat.nodamage": "Ne pas appliquer les dommages",
|
||||||
"BOL.chat.pcwarning": "Attention ! Aucun personnage n'est relié au joueur !",
|
"BOL.chat.pcwarning": "Attention ! Aucun personnage n'est relié au joueur !",
|
||||||
"BOL.chat.pcwarningmsg": "<b>ATTENTION</b> Le joueur n'est relié à aucun personnage !",
|
"BOL.chat.pcwarningmsg": "<b>ATTENTION</b> Le joueur n'est relié à aucun personnage !",
|
||||||
"BOL.chat.pcnotlinked": "Le token du personnage joueur n'est pas relié à l'acteur",
|
"BOL.chat.pcnotlinked": "Le token du personnage joueur n'est pas relié à l'acteur",
|
||||||
"BOL.chat.pcnotlinkedmsg": "<b>ATTENTION</b> Le token du personnage joueur n'est pas relié à l'acteur !",
|
"BOL.chat.pcnotlinkedmsg": "<b>ATTENTION</b> Le token du personnage joueur n'est pas relié à l'acteur !",
|
||||||
"BOL.chat.armorRoll": "Jet d'armure",
|
|
||||||
|
|
||||||
"BOL.settings.rollArmor": "Effectuer des jets pour les armures",
|
"BOL.settings.rollArmor": "Effectuer des jets pour les armures",
|
||||||
"BOL.settings.rollArmorTooltip": "Effectue un jet de dés pour les armures (valeur fixe si désactivé)",
|
"BOL.settings.rollArmorTooltip": "Effectue un jet de dés pour les armures (valeur fixe si désactivé)",
|
||||||
@@ -642,5 +651,10 @@
|
|||||||
"BOL.settings.defaultLogoTopLeftPathTooltip": "Vous pouvez changer le logo BoL en haut à gauche de chaque écran (idéalement 718 x 416, défaut : /systems/bol/ui/logo2.webp)",
|
"BOL.settings.defaultLogoTopLeftPathTooltip": "Vous pouvez changer le logo BoL en haut à gauche de chaque écran (idéalement 718 x 416, défaut : /systems/bol/ui/logo2.webp)",
|
||||||
|
|
||||||
"EFFECT.StatusProne": "A terre",
|
"EFFECT.StatusProne": "A terre",
|
||||||
"EFFECT.StatusDead": "Mort"
|
"EFFECT.StatusDead": "Mort",
|
||||||
}
|
|
||||||
|
"BOL.ui.charSummaryTitle": "Résumé des Personnages",
|
||||||
|
"BOL.ui.colGroupAttributes": "Attributs",
|
||||||
|
"BOL.ui.colGroupAptitudes": "Aptitudes",
|
||||||
|
"BOL.ui.colGroupResources": "Ressources"
|
||||||
|
}
|
||||||
@@ -5,7 +5,7 @@
|
|||||||
import { BoLRoll } from "../controllers/bol-rolls.js";
|
import { BoLRoll } from "../controllers/bol-rolls.js";
|
||||||
import { BoLUtility } from "../system/bol-utility.js";
|
import { BoLUtility } from "../system/bol-utility.js";
|
||||||
|
|
||||||
export class BoLActorSheet extends ActorSheet {
|
export class BoLActorSheet extends foundry.appv1.sheets.ActorSheet {
|
||||||
|
|
||||||
/** @override */
|
/** @override */
|
||||||
static get defaultOptions() {
|
static get defaultOptions() {
|
||||||
@@ -59,7 +59,7 @@ export class BoLActorSheet extends ActorSheet {
|
|||||||
let system = foundry.utils.duplicate(game.bol.config.defaultNaturalProtection)
|
let system = foundry.utils.duplicate(game.bol.config.defaultNaturalProtection)
|
||||||
this.actor.createEmbeddedDocuments('Item', [{ name: game.i18n.localize("BOL.ui.newNaturalProtection"), type: "item", system }], { renderSheet: true });
|
this.actor.createEmbeddedDocuments('Item', [{ name: game.i18n.localize("BOL.ui.newNaturalProtection"), type: "item", system }], { renderSheet: true });
|
||||||
});
|
});
|
||||||
|
|
||||||
html.find(".toggle-fight-option").click((ev) => {
|
html.find(".toggle-fight-option").click((ev) => {
|
||||||
const li = $(ev.currentTarget).parents(".item")
|
const li = $(ev.currentTarget).parents(".item")
|
||||||
this.actor.toggleFightOption(li.data("itemId"))
|
this.actor.toggleFightOption(li.data("itemId"))
|
||||||
@@ -170,8 +170,8 @@ export class BoLActorSheet extends ActorSheet {
|
|||||||
formData.charType = this.actor.getCharType()
|
formData.charType = this.actor.getCharType()
|
||||||
formData.villainy = this.actor.getVillainy()
|
formData.villainy = this.actor.getVillainy()
|
||||||
formData.isUndead = this.actor.isUndead()
|
formData.isUndead = this.actor.isUndead()
|
||||||
formData.biography = await TextEditor.enrichHTML(this.object.system.details?.biography || "", { async: true })
|
formData.biography = await foundry.applications.ux.TextEditor.implementation.enrichHTML(this.object.system.details?.biography || "", { async: true })
|
||||||
formData.notes = await TextEditor.enrichHTML(this.object.system.details.notes || "", { async: true })
|
formData.notes = await foundry.applications.ux.TextEditor.implementation.enrichHTML(this.object.system.details.notes || "", { async: true })
|
||||||
formData.isSorcerer = this.actor.isSorcerer()
|
formData.isSorcerer = this.actor.isSorcerer()
|
||||||
formData.isAlchemist = this.actor.isAlchemist()
|
formData.isAlchemist = this.actor.isAlchemist()
|
||||||
formData.isAstrologer = this.actor.isAstrologer()
|
formData.isAstrologer = this.actor.isAstrologer()
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ import { BoLUtility } from "../system/bol-utility.js";
|
|||||||
*/
|
*/
|
||||||
export class BoLActor extends Actor {
|
export class BoLActor extends Actor {
|
||||||
|
|
||||||
|
static _healthLock = new Set()
|
||||||
|
|
||||||
static async create(data, options) {
|
static async create(data, options) {
|
||||||
|
|
||||||
// Case of compendium global import
|
// Case of compendium global import
|
||||||
@@ -22,6 +24,9 @@ export class BoLActor extends Actor {
|
|||||||
if (data.type == 'encounter') {
|
if (data.type == 'encounter') {
|
||||||
data.system = { resources: { hero : { max : 0, value: 0 } } }
|
data.system = { resources: { hero : { max : 0, value: 0 } } }
|
||||||
}
|
}
|
||||||
|
if (data.type == 'character') {
|
||||||
|
data.system = { resources: { hp : { max : 10, value: 10 } } }
|
||||||
|
}
|
||||||
|
|
||||||
if (data.type == 'horde') {
|
if (data.type == 'horde') {
|
||||||
let weapon = {
|
let weapon = {
|
||||||
@@ -161,12 +166,16 @@ export class BoLActor extends Actor {
|
|||||||
let newVitality = 10 + this.system.attributes.vigor.value + this.system.resources.hp.bonus
|
let newVitality = 10 + this.system.attributes.vigor.value + this.system.resources.hp.bonus
|
||||||
if (this.system.resources.hp.max != newVitality) {
|
if (this.system.resources.hp.max != newVitality) {
|
||||||
let actor = this
|
let actor = this
|
||||||
setTimeout(function () { actor.update({ 'system.resources.hp.max': newVitality }) }, 800)
|
let newHP = foundry.utils.duplicate(this.system.resources.hp)
|
||||||
|
newHP.max = newVitality
|
||||||
|
setTimeout(function () { actor.update({ 'system.resources.hp': newHP }) }, 800)
|
||||||
}
|
}
|
||||||
let newPower = 10 + this.system.attributes.mind.value + this.system.resources.power.bonus
|
let maxPower = 10 + this.system.attributes.mind.value + this.system.resources.power.bonus
|
||||||
if (this.system.resources.power.max != newPower) {
|
if (this.system.resources.power.max != maxPower) {
|
||||||
let actor = this
|
let actor = this
|
||||||
setTimeout(function () { actor.update({ 'system.resources.power.max': newPower }) }, 800)
|
let newPower = foundry.utils.duplicate(this.system.resources.power)
|
||||||
|
newPower.max = maxPower
|
||||||
|
setTimeout(function () { actor.update({ 'system.resources.power': newPower }) }, 800)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -350,7 +359,7 @@ export class BoLActor extends Actor {
|
|||||||
ChatMessage.create({
|
ChatMessage.create({
|
||||||
alias: this.name,
|
alias: this.name,
|
||||||
whisper: BoLUtility.getWhisperRecipientsAndGMs(this.name),
|
whisper: BoLUtility.getWhisperRecipientsAndGMs(this.name),
|
||||||
content: await renderTemplate('systems/bol/templates/chat/chat-activate-fight-option.hbs', { name: this.name, img: fightOption.img, foName: fightOption.name, state: state })
|
content: await foundry.applications.handlebars.renderTemplate('systems/bol/templates/chat/chat-activate-fight-option.hbs', { name: this.name, img: fightOption.img, foName: fightOption.name, state: state })
|
||||||
})
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -845,36 +854,42 @@ export class BoLActor extends Actor {
|
|||||||
|
|
||||||
/*-------------------------------------------- */
|
/*-------------------------------------------- */
|
||||||
async manageHealthState() {
|
async manageHealthState() {
|
||||||
let hpID = "lastHP" + this.id
|
if (BoLActor._healthLock.has(this.id)) return
|
||||||
let lastHP = await this.getFlag("world", hpID)
|
BoLActor._healthLock.add(this.id)
|
||||||
if (lastHP != this.system.resources.hp.value && game.user.isGM) { // Only GM sends this
|
try {
|
||||||
await this.setFlag("world", hpID, this.system.resources.hp.value)
|
let hpID = "lastHP" + this.id
|
||||||
let prone = this.effects.find(ef => ef.name == game.i18n.localize("EFFECT.StatusProne"))
|
let lastHP = await this.getFlag("world", hpID)
|
||||||
let dead = this.effects.find(ef => ef.name == game.i18n.localize("EFFECT.StatusDead"))
|
if (lastHP != this.system.resources.hp.value && game.user.isGM) { // Only GM sends this
|
||||||
if (this.system.resources.hp.value <= 0) {
|
await this.setFlag("world", hpID, this.system.resources.hp.value)
|
||||||
if (!prone) {
|
let prone = this.effects.find(ef => ef.name == game.i18n.localize("EFFECT.StatusProne"))
|
||||||
await this.createEmbeddedDocuments("ActiveEffect", [
|
let dead = this.effects.find(ef => ef.name == game.i18n.localize("EFFECT.StatusDead"))
|
||||||
{ name: game.i18n.localize('EFFECT.StatusProne'), icon: 'icons/svg/falling.svg', statuses: 'prone' }
|
if (this.system.resources.hp.value <= 0) {
|
||||||
])
|
if (!prone) {
|
||||||
}
|
await this.createEmbeddedDocuments("ActiveEffect", [
|
||||||
if (this.system.resources.hp.value < -5 && !dead) {
|
{ name: game.i18n.localize('EFFECT.StatusProne'), icon: 'icons/svg/falling.svg', statuses: 'prone' }
|
||||||
await this.createEmbeddedDocuments("ActiveEffect", [
|
])
|
||||||
{ name: game.i18n.localize('EFFECT.StatusDead'), icon: 'icons/svg/skull.svg', statuses: 'dead' }
|
}
|
||||||
])
|
if (this.system.resources.hp.value < -5 && !dead) {
|
||||||
}
|
await this.createEmbeddedDocuments("ActiveEffect", [
|
||||||
ChatMessage.create({
|
{ name: game.i18n.localize('EFFECT.StatusDead'), icon: 'icons/svg/skull.svg', statuses: 'dead' }
|
||||||
alias: this.name,
|
])
|
||||||
whisper: BoLUtility.getWhisperRecipientsAndGMs(this.name),
|
}
|
||||||
content: await renderTemplate('systems/bol/templates/chat/chat-vitality-zero.hbs', { name: this.name, img: this.img, hp: this.system.resources.hp.value, isHeroAdversary: this.isHeroAdversary() })
|
ChatMessage.create({
|
||||||
})
|
alias: this.name,
|
||||||
} else {
|
whisper: BoLUtility.getWhisperRecipientsAndGMs(this.name),
|
||||||
if (prone) {
|
content: await foundry.applications.handlebars.renderTemplate('systems/bol/templates/chat/chat-vitality-zero.hbs', { name: this.name, img: this.img, hp: this.system.resources.hp.value, isHeroAdversary: this.isHeroAdversary() })
|
||||||
await this.deleteEmbeddedDocuments("ActiveEffect", [prone.id])
|
})
|
||||||
}
|
} else {
|
||||||
if (dead) {
|
if (prone) {
|
||||||
await this.deleteEmbeddedDocuments("ActiveEffect", [dead.id])
|
await this.deleteEmbeddedDocuments("ActiveEffect", [prone.id])
|
||||||
|
}
|
||||||
|
if (dead) {
|
||||||
|
await this.deleteEmbeddedDocuments("ActiveEffect", [dead.id])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} finally {
|
||||||
|
BoLActor._healthLock.delete(this.id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -897,7 +912,7 @@ export class BoLActor extends Actor {
|
|||||||
let msg = await ChatMessage.create({
|
let msg = await ChatMessage.create({
|
||||||
alias: this.name,
|
alias: this.name,
|
||||||
whisper: BoLUtility.getWhisperRecipientsAndGMs(this.name),
|
whisper: BoLUtility.getWhisperRecipientsAndGMs(this.name),
|
||||||
content: await renderTemplate('systems/bol/templates/chat/chat-recup-information.hbs', {
|
content: await foundry.applications.handlebars.renderTemplate('systems/bol/templates/chat/chat-recup-information.hbs', {
|
||||||
name: this.name,
|
name: this.name,
|
||||||
img: this.img,
|
img: this.img,
|
||||||
actorId: this.id,
|
actorId: this.id,
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
import { BoLRoll } from "../controllers/bol-rolls.js";
|
import { BoLRoll } from "../controllers/bol-rolls.js";
|
||||||
import { BoLUtility } from "../system/bol-utility.js";
|
import { BoLUtility } from "../system/bol-utility.js";
|
||||||
|
|
||||||
export class BoLHordeSheet extends ActorSheet {
|
export class BoLHordeSheet extends foundry.appv1.sheets.ActorSheet {
|
||||||
|
|
||||||
/** @override */
|
/** @override */
|
||||||
static get defaultOptions() {
|
static get defaultOptions() {
|
||||||
@@ -116,7 +116,7 @@ export class BoLHordeSheet extends ActorSheet {
|
|||||||
formData.options = this.options
|
formData.options = this.options
|
||||||
formData.owner = this.document.isOwner
|
formData.owner = this.document.isOwner
|
||||||
formData.editScore = this.options.editScore
|
formData.editScore = this.options.editScore
|
||||||
formData.description = await TextEditor.enrichHTML(this.actor.system.description, {async: true})
|
formData.description = await foundry.applications.ux.TextEditor.implementation.enrichHTML(this.actor.system.description, {async: true})
|
||||||
|
|
||||||
formData.isGM = game.user.isGM
|
formData.isGM = game.user.isGM
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
import { BoLRoll } from "../controllers/bol-rolls.js";
|
import { BoLRoll } from "../controllers/bol-rolls.js";
|
||||||
import { BoLUtility } from "../system/bol-utility.js";
|
import { BoLUtility } from "../system/bol-utility.js";
|
||||||
|
|
||||||
export class BoLVehicleSheet extends ActorSheet {
|
export class BoLVehicleSheet extends foundry.appv1.sheets.ActorSheet {
|
||||||
|
|
||||||
/** @override */
|
/** @override */
|
||||||
static get defaultOptions() {
|
static get defaultOptions() {
|
||||||
@@ -127,7 +127,7 @@ export class BoLVehicleSheet extends ActorSheet {
|
|||||||
formData.options = this.options
|
formData.options = this.options
|
||||||
formData.owner = this.document.isOwner
|
formData.owner = this.document.isOwner
|
||||||
formData.editScore = this.options.editScore
|
formData.editScore = this.options.editScore
|
||||||
formData.description = await TextEditor.enrichHTML(this.actor.system.description, {async: true})
|
formData.description = await foundry.applications.ux.TextEditor.implementation.enrichHTML(this.actor.system.description, {async: true})
|
||||||
|
|
||||||
formData.isGM = game.user.isGM
|
formData.isGM = game.user.isGM
|
||||||
|
|
||||||
|
|||||||
7
module/applications/sheets/_module.mjs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
export { default as BoLBaseItemSheet } from "./base-item-sheet.mjs"
|
||||||
|
export { default as BoLItemSheet } from "./item-sheet.mjs"
|
||||||
|
export { default as BoLFeatureSheet } from "./feature-sheet.mjs"
|
||||||
|
export { default as BoLBaseActorSheet } from "./base-actor-sheet.mjs"
|
||||||
|
export { default as BoLActorSheet } from "./actor-sheet.mjs"
|
||||||
|
export { default as BoLHordeSheet } from "./horde-sheet.mjs"
|
||||||
|
export { default as BoLVehicleSheet } from "./vehicle-sheet.mjs"
|
||||||
144
module/applications/sheets/actor-sheet.mjs
Normal file
@@ -0,0 +1,144 @@
|
|||||||
|
import BoLBaseActorSheet from "./base-actor-sheet.mjs"
|
||||||
|
import { BoLUtility } from "../../system/bol-utility.js"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Actor Sheet for BoL characters and encounters using AppV2
|
||||||
|
*/
|
||||||
|
export default class BoLActorSheet extends BoLBaseActorSheet {
|
||||||
|
/** @override */
|
||||||
|
static DEFAULT_OPTIONS = {
|
||||||
|
...super.DEFAULT_OPTIONS,
|
||||||
|
classes: [...super.DEFAULT_OPTIONS.classes],
|
||||||
|
actions: {
|
||||||
|
...super.DEFAULT_OPTIONS.actions,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
static PARTS = {
|
||||||
|
sheet: {
|
||||||
|
template: "systems/bol/templates/actor/actor-sheet.hbs",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
tabGroups = { primary: "stats" }
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
async _prepareContext() {
|
||||||
|
const context = await super._prepareContext()
|
||||||
|
const actor = this.document
|
||||||
|
|
||||||
|
context.data = actor.toObject()
|
||||||
|
context.details = actor.details
|
||||||
|
context.attributes = actor.attributes
|
||||||
|
context.aptitudes = actor.aptitudes
|
||||||
|
context.resources = actor.getResourcesFromType()
|
||||||
|
context.xp = actor.system.xp
|
||||||
|
context.equipment = actor.equipment
|
||||||
|
context.equipmentCreature = actor.equipmentCreature
|
||||||
|
context.weapons = actor.weapons
|
||||||
|
context.protections = actor.protections
|
||||||
|
context.spells = actor.spells
|
||||||
|
context.alchemy = actor.alchemy
|
||||||
|
context.containers = actor.containers
|
||||||
|
context.treasure = actor.treasure
|
||||||
|
context.boleffects = actor.boleffects
|
||||||
|
context.alchemyrecipe = actor.alchemyrecipe
|
||||||
|
context.horoscopes = actor.horoscopes
|
||||||
|
context.vehicles = actor.vehicles
|
||||||
|
context.fightoptions = actor.fightoptions
|
||||||
|
context.ammos = actor.ammos
|
||||||
|
context.misc = actor.misc
|
||||||
|
context.xplog = actor.xplog
|
||||||
|
context.combat = actor.buildCombat()
|
||||||
|
context.initiativeRank = actor.getInitiativeRank()
|
||||||
|
context.features = actor.buildFeatures()
|
||||||
|
context.options = this.options
|
||||||
|
context.editScore = this.options.editScore
|
||||||
|
context.useBougette = (actor.type === "character" && BoLUtility.getUseBougette()) || false
|
||||||
|
context.bougette = actor.getBougette()
|
||||||
|
context.charType = actor.getCharType()
|
||||||
|
context.villainy = actor.getVillainy()
|
||||||
|
context.isUndead = actor.isUndead()
|
||||||
|
context.biography = await foundry.applications.ux.TextEditor.implementation.enrichHTML(
|
||||||
|
actor.system.details?.biography || "", { async: true }
|
||||||
|
)
|
||||||
|
context.notes = await foundry.applications.ux.TextEditor.implementation.enrichHTML(
|
||||||
|
actor.system.details?.notes || "", { async: true }
|
||||||
|
)
|
||||||
|
context.isSorcerer = actor.isSorcerer()
|
||||||
|
context.isAlchemist = actor.isAlchemist()
|
||||||
|
context.isAstrologer = actor.isAstrologer()
|
||||||
|
context.isMysteries = context.isSorcerer || context.isAlchemist || context.isAstrologer
|
||||||
|
context.isPriest = actor.isPriest()
|
||||||
|
context.horoscopeGroupList = game.settings.get("bol", "horoscope-group")
|
||||||
|
|
||||||
|
console.log("ACTORDATA (AppV2)", context)
|
||||||
|
return context
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
_activateListeners() {
|
||||||
|
super._activateListeners()
|
||||||
|
if (!this.isEditable) return
|
||||||
|
|
||||||
|
// Create generic item
|
||||||
|
this.element.querySelectorAll(".create-item").forEach((el) => {
|
||||||
|
el.addEventListener("click", () => {
|
||||||
|
this.actor.createEmbeddedDocuments("Item", [{ name: game.i18n.localize("BOL.ui.newEquipment"), type: "item" }], { renderSheet: true })
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
// Create natural weapon
|
||||||
|
this.element.querySelectorAll(".create-natural-weapon").forEach((el) => {
|
||||||
|
el.addEventListener("click", () => {
|
||||||
|
const system = foundry.utils.duplicate(game.bol.config.defaultNaturalWeapon)
|
||||||
|
this.actor.createEmbeddedDocuments("Item", [{ name: game.i18n.localize("BOL.ui.newNaturalWeapon"), type: "item", system }], { renderSheet: true })
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
// Create natural protection
|
||||||
|
this.element.querySelectorAll(".create-natural-protection").forEach((el) => {
|
||||||
|
el.addEventListener("click", () => {
|
||||||
|
const system = foundry.utils.duplicate(game.bol.config.defaultNaturalProtection)
|
||||||
|
this.actor.createEmbeddedDocuments("Item", [{ name: game.i18n.localize("BOL.ui.newNaturalProtection"), type: "item", system }], { renderSheet: true })
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
// Item create via header dataset (type-based creation)
|
||||||
|
this.element.querySelectorAll(".item-create").forEach((el) => {
|
||||||
|
el.addEventListener("click", (ev) => {
|
||||||
|
ev.preventDefault()
|
||||||
|
const header = ev.currentTarget
|
||||||
|
const type = header.dataset.type
|
||||||
|
const data = foundry.utils.duplicate(header.dataset)
|
||||||
|
const name = `New ${type}`
|
||||||
|
delete data.type
|
||||||
|
this.actor.createEmbeddedDocuments("Item", [{ name, type, data }])
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
// Add XP Log entry
|
||||||
|
this.element.querySelectorAll(".xplog-add").forEach((el) => {
|
||||||
|
el.addEventListener("click", (ev) => {
|
||||||
|
ev.preventDefault()
|
||||||
|
this.actor.addXPLog("other", "Nouveau", 0, 0)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
// Add item by category/subtype (equipment tab headers)
|
||||||
|
this.element.querySelectorAll(".item-add").forEach((el) => {
|
||||||
|
el.addEventListener("click", (ev) => {
|
||||||
|
ev.preventDefault()
|
||||||
|
const { itemType, category, subtype } = ev.currentTarget.dataset
|
||||||
|
const system = { category, subtype }
|
||||||
|
this.actor.createEmbeddedDocuments("Item", [{
|
||||||
|
name: game.i18n.localize("BOL.ui.newEquipment"),
|
||||||
|
type: itemType || "item",
|
||||||
|
system,
|
||||||
|
}], { renderSheet: true })
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
307
module/applications/sheets/base-actor-sheet.mjs
Normal file
@@ -0,0 +1,307 @@
|
|||||||
|
const { HandlebarsApplicationMixin } = foundry.applications.api
|
||||||
|
|
||||||
|
import { BoLRoll } from "../../controllers/bol-rolls.js"
|
||||||
|
import { BoLUtility } from "../../system/bol-utility.js"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base Actor Sheet for BoL system using AppV2
|
||||||
|
* @extends {ActorSheetV2}
|
||||||
|
*/
|
||||||
|
export default class BoLBaseActorSheet extends HandlebarsApplicationMixin(foundry.applications.sheets.ActorSheetV2) {
|
||||||
|
constructor(options = {}) {
|
||||||
|
super(options)
|
||||||
|
this.#dragDrop = this.#createDragDropHandlers()
|
||||||
|
}
|
||||||
|
|
||||||
|
#dragDrop
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
static DEFAULT_OPTIONS = {
|
||||||
|
classes: ["bol", "sheet", "actor"],
|
||||||
|
position: {
|
||||||
|
width: 836,
|
||||||
|
height: 807,
|
||||||
|
},
|
||||||
|
form: {
|
||||||
|
submitOnChange: true,
|
||||||
|
closeOnSubmit: false,
|
||||||
|
},
|
||||||
|
window: {
|
||||||
|
resizable: true,
|
||||||
|
},
|
||||||
|
tabs: [
|
||||||
|
{
|
||||||
|
navSelector: "nav[data-group=\"primary\"]",
|
||||||
|
contentSelector: "section.sheet-body",
|
||||||
|
initial: "stats",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
dragDrop: [{ dragSelector: ".items-list .item", dropSelector: null }],
|
||||||
|
actions: {},
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Tab groups state */
|
||||||
|
tabGroups = { primary: "stats" }
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
async _prepareContext() {
|
||||||
|
const actor = this.document
|
||||||
|
return {
|
||||||
|
actor,
|
||||||
|
system: actor.system,
|
||||||
|
config: game.bol.config,
|
||||||
|
isGM: game.user.isGM,
|
||||||
|
isEditable: this.isEditable,
|
||||||
|
owner: this.document.isOwner,
|
||||||
|
cssClass: this.options.classes.join(" "),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
_onRender(context, options) {
|
||||||
|
super._onRender(context, options)
|
||||||
|
this.#dragDrop.forEach((d) => d.bind(this.element))
|
||||||
|
this._activateTabs()
|
||||||
|
this._activateListeners()
|
||||||
|
this._applyBackgroundImage()
|
||||||
|
this._activateImageEdit()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply background image to the actor form
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_applyBackgroundImage() {
|
||||||
|
const logoUrl = BoLUtility.getLogoActorSheet()
|
||||||
|
const form = this.element.querySelector(".bol-actor-form")
|
||||||
|
if (form) form.style.backgroundImage = `url(${logoUrl})`
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Activate image editing via FilePicker
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_activateImageEdit() {
|
||||||
|
const img = this.element.querySelector('[data-edit="img"]')
|
||||||
|
if (img && this.isEditable) {
|
||||||
|
img.style.cursor = "pointer"
|
||||||
|
img.addEventListener("click", () => {
|
||||||
|
new FilePicker({
|
||||||
|
type: "image",
|
||||||
|
current: this.document.img,
|
||||||
|
callback: (path) => this.document.update({ img: path }),
|
||||||
|
}).browse()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Activate tab navigation
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_activateTabs() {
|
||||||
|
const nav = this.element.querySelector("nav[data-group]")
|
||||||
|
if (!nav) return
|
||||||
|
|
||||||
|
const group = nav.dataset.group
|
||||||
|
const activeTab = this.tabGroups[group] || "stats"
|
||||||
|
|
||||||
|
nav.querySelectorAll("[data-tab]").forEach((link) => {
|
||||||
|
const tab = link.dataset.tab
|
||||||
|
link.classList.toggle("active", tab === activeTab)
|
||||||
|
link.addEventListener("click", (event) => {
|
||||||
|
event.preventDefault()
|
||||||
|
this.tabGroups[group] = tab
|
||||||
|
this.render()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
this.element.querySelectorAll(`[data-group="${group}"][data-tab]`).forEach((content) => {
|
||||||
|
content.classList.toggle("active", content.dataset.tab === activeTab)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Activate event listeners (replaces activateListeners with vanilla DOM)
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_activateListeners() {
|
||||||
|
if (!this.isEditable) return
|
||||||
|
|
||||||
|
// Item edit
|
||||||
|
this.element.querySelectorAll(".item-edit").forEach((el) => {
|
||||||
|
el.addEventListener("click", (ev) => {
|
||||||
|
const li = ev.currentTarget.closest(".item")
|
||||||
|
const item = this.actor.items.get(li?.dataset.itemId)
|
||||||
|
item?.sheet.render(true)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
// Item delete
|
||||||
|
this.element.querySelectorAll(".item-delete").forEach((el) => {
|
||||||
|
el.addEventListener("click", (ev) => {
|
||||||
|
const li = ev.currentTarget.closest(".item")
|
||||||
|
const itemId = li?.dataset.itemId
|
||||||
|
Dialog.confirm({
|
||||||
|
title: game.i18n.localize("BOL.ui.deletetitle"),
|
||||||
|
content: game.i18n.localize("BOL.ui.confirmdelete"),
|
||||||
|
yes: () => {
|
||||||
|
this.actor.deleteEmbeddedDocuments("Item", [itemId])
|
||||||
|
li?.remove()
|
||||||
|
},
|
||||||
|
no: () => {},
|
||||||
|
defaultYes: false,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
// Item equip/unequip
|
||||||
|
this.element.querySelectorAll(".item-equip").forEach((el) => {
|
||||||
|
el.addEventListener("click", (ev) => {
|
||||||
|
const li = ev.currentTarget.closest(".item")
|
||||||
|
const item = this.actor.items.get(li?.dataset.itemId)
|
||||||
|
if (item) this.actor.toggleEquipItem(item)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
// Toggle fight option
|
||||||
|
this.element.querySelectorAll(".toggle-fight-option").forEach((el) => {
|
||||||
|
el.addEventListener("click", (ev) => {
|
||||||
|
const li = ev.currentTarget.closest(".item")
|
||||||
|
this.actor.toggleFightOption(li?.dataset.itemId)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
// Inc/dec alchemy points
|
||||||
|
this.element.querySelectorAll(".inc-dec-btns-alchemy").forEach((el) => {
|
||||||
|
el.addEventListener("click", (ev) => {
|
||||||
|
const li = ev.currentTarget.closest(".item")
|
||||||
|
this.actor.spendAlchemyPoint(li?.dataset.itemId, 1)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
// Inc/dec resource buttons
|
||||||
|
this.element.querySelectorAll(".inc-dec-btns-resource").forEach((el) => {
|
||||||
|
el.addEventListener("click", (ev) => {
|
||||||
|
const dataset = ev.currentTarget.dataset
|
||||||
|
this.actor.incDecResources(dataset.target, parseInt(dataset.incr))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
// Generic inc/dec buttons for item fields
|
||||||
|
this.element.querySelectorAll(".inc-dec-btns").forEach((el) => {
|
||||||
|
el.addEventListener("click", (ev) => {
|
||||||
|
const li = ev.currentTarget.closest(".item")
|
||||||
|
if (!li) return
|
||||||
|
const item = this.actor.items.get(li.dataset.itemId)
|
||||||
|
if (!item) return
|
||||||
|
const dataset = ev.currentTarget.dataset
|
||||||
|
const operator = dataset.operator
|
||||||
|
const target = dataset.target
|
||||||
|
const incr = parseInt(dataset.incr)
|
||||||
|
const min = parseInt(dataset.min)
|
||||||
|
const max = parseInt(dataset.max) || 10000
|
||||||
|
// eslint-disable-next-line no-eval
|
||||||
|
let value = eval("item." + target) || 0
|
||||||
|
if (operator === "minus") value = value >= min + incr ? value - incr : min
|
||||||
|
if (operator === "plus") value = value <= max - incr ? value + incr : max
|
||||||
|
item.update({ [target]: value })
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
// Rollable elements
|
||||||
|
this.element.querySelectorAll(".rollable").forEach((el) => {
|
||||||
|
el.addEventListener("click", (ev) => this._onRoll(ev))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle clickable rolls (replaces _onRoll with vanilla DOM)
|
||||||
|
* @param {Event} event
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_onRoll(event) {
|
||||||
|
event.preventDefault()
|
||||||
|
const element = event.currentTarget
|
||||||
|
const dataset = element.dataset
|
||||||
|
const rollType = dataset.rollType
|
||||||
|
const li = element.closest(".item")
|
||||||
|
const itemId = li?.dataset.itemId
|
||||||
|
|
||||||
|
switch (rollType) {
|
||||||
|
case "attribute":
|
||||||
|
BoLRoll.attributeCheck(this.actor, dataset.key, event)
|
||||||
|
break
|
||||||
|
case "aptitude":
|
||||||
|
BoLRoll.aptitudeCheck(this.actor, dataset.key, event)
|
||||||
|
break
|
||||||
|
case "weapon":
|
||||||
|
BoLRoll.weaponCheck(this.actor, event)
|
||||||
|
break
|
||||||
|
case "spell":
|
||||||
|
BoLRoll.spellCheck(this.actor, event)
|
||||||
|
break
|
||||||
|
case "alchemy":
|
||||||
|
BoLRoll.alchemyCheck(this.actor, event)
|
||||||
|
break
|
||||||
|
case "protection":
|
||||||
|
this.actor.rollProtection(itemId)
|
||||||
|
break
|
||||||
|
case "damage":
|
||||||
|
this.actor.rollWeaponDamage(itemId)
|
||||||
|
break
|
||||||
|
case "aptitudexp":
|
||||||
|
this.actor.incAptitudeXP(dataset.key)
|
||||||
|
break
|
||||||
|
case "attributexp":
|
||||||
|
this.actor.incAttributeXP(dataset.key)
|
||||||
|
break
|
||||||
|
case "careerxp":
|
||||||
|
this.actor.incCareerXP(itemId)
|
||||||
|
break
|
||||||
|
case "horoscope-minor":
|
||||||
|
BoLRoll.horoscopeCheck(this.actor, event, "minor")
|
||||||
|
break
|
||||||
|
case "horoscope-major":
|
||||||
|
BoLRoll.horoscopeCheck(this.actor, event, "major")
|
||||||
|
break
|
||||||
|
case "horoscope-major-group":
|
||||||
|
BoLRoll.horoscopeCheck(this.actor, event, "majorgroup")
|
||||||
|
break
|
||||||
|
case "bougette":
|
||||||
|
this.actor.rollBougette()
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// #region Drag-and-Drop
|
||||||
|
|
||||||
|
#createDragDropHandlers() {
|
||||||
|
return (this.options.dragDrop || []).map((dragDrop) =>
|
||||||
|
new foundry.applications.ux.DragDrop.implementation({
|
||||||
|
...dragDrop,
|
||||||
|
permissions: {
|
||||||
|
dragstart: this._canDragStart.bind(this),
|
||||||
|
drop: this._canDragDrop.bind(this),
|
||||||
|
},
|
||||||
|
callbacks: {
|
||||||
|
dragstart: this._onDragStart.bind(this),
|
||||||
|
dragover: this._onDragOver.bind(this),
|
||||||
|
drop: this._onDrop.bind(this),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
_canDragStart(selector) {
|
||||||
|
return this.isEditable
|
||||||
|
}
|
||||||
|
|
||||||
|
_canDragDrop(selector) {
|
||||||
|
return this.isEditable
|
||||||
|
}
|
||||||
|
|
||||||
|
// #endregion
|
||||||
|
}
|
||||||
255
module/applications/sheets/base-item-sheet.mjs
Normal file
@@ -0,0 +1,255 @@
|
|||||||
|
const { HandlebarsApplicationMixin } = foundry.applications.api
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base Item Sheet for BoL system using AppV2
|
||||||
|
* @extends {ItemSheetV2}
|
||||||
|
*/
|
||||||
|
export default class BoLBaseItemSheet extends HandlebarsApplicationMixin(foundry.applications.sheets.ItemSheetV2) {
|
||||||
|
constructor(options = {}) {
|
||||||
|
super(options)
|
||||||
|
this.#dragDrop = this.#createDragDropHandlers()
|
||||||
|
}
|
||||||
|
|
||||||
|
#dragDrop
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
static DEFAULT_OPTIONS = {
|
||||||
|
classes: ["bol", "sheet", "item"],
|
||||||
|
position: {
|
||||||
|
width: 650,
|
||||||
|
height: 780,
|
||||||
|
},
|
||||||
|
form: {
|
||||||
|
submitOnChange: true,
|
||||||
|
},
|
||||||
|
window: {
|
||||||
|
resizable: true,
|
||||||
|
},
|
||||||
|
tabs: [
|
||||||
|
{
|
||||||
|
navSelector: 'nav[data-group="primary"]',
|
||||||
|
contentSelector: "section.sheet-body",
|
||||||
|
initial: "description",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
actions: {
|
||||||
|
editImage: BoLBaseItemSheet.#onEditImage,
|
||||||
|
postItem: BoLBaseItemSheet.#onPostItem,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tab groups state
|
||||||
|
* @type {object}
|
||||||
|
*/
|
||||||
|
tabGroups = { primary: "description" }
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
async _prepareContext() {
|
||||||
|
const context = {
|
||||||
|
// Document & system
|
||||||
|
fields: this.document.schema.fields,
|
||||||
|
systemFields: this.document.system.schema.fields,
|
||||||
|
item: this.document,
|
||||||
|
system: this.document.system,
|
||||||
|
source: this.document.toObject(),
|
||||||
|
|
||||||
|
// Enriched content
|
||||||
|
enrichedDescription: await foundry.applications.ux.TextEditor.implementation.enrichHTML(
|
||||||
|
this.document.system.description,
|
||||||
|
{ async: true }
|
||||||
|
),
|
||||||
|
|
||||||
|
// Properties
|
||||||
|
category: this.document.system.category,
|
||||||
|
itemProperties: this.document.itemProperties,
|
||||||
|
|
||||||
|
// Config & permissions
|
||||||
|
config: game.bol.config,
|
||||||
|
isGM: game.user.isGM,
|
||||||
|
isEditable: this.isEditable,
|
||||||
|
|
||||||
|
// CSS classes for template
|
||||||
|
cssClass: this.options.classes.join(" "),
|
||||||
|
|
||||||
|
// Tab state
|
||||||
|
tabs: this._getTabs(),
|
||||||
|
activeTab: this.tabGroups.primary || "description"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add careers if item is on an actor
|
||||||
|
if (this.document.actor) {
|
||||||
|
context.careers = this.document.actor.careers
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply dynamic defaults based on item type
|
||||||
|
this._applyDynamicDefaults(context)
|
||||||
|
|
||||||
|
return context
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get tabs configuration
|
||||||
|
* @returns {object[]}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_getTabs() {
|
||||||
|
return [
|
||||||
|
{ id: "description", label: "BOL.ui.tab.description", icon: "fa-solid fa-book" },
|
||||||
|
{ id: "properties", label: "BOL.ui.tab.details", icon: "fa-solid fa-cog" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply dynamic defaults to context based on item type and category
|
||||||
|
* @param {object} context
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_applyDynamicDefaults(context) {
|
||||||
|
const itemData = context.item
|
||||||
|
|
||||||
|
if (itemData.type === "item") {
|
||||||
|
// Set default category
|
||||||
|
if (!itemData.system.category) {
|
||||||
|
itemData.system.category = "equipment"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle equipment slot
|
||||||
|
if (itemData.system.category === "equipment" && itemData.system.properties.equipable) {
|
||||||
|
if (!itemData.system.properties.slot) {
|
||||||
|
itemData.system.properties.slot = "-"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle spell conditions
|
||||||
|
if (itemData.system.category === 'spell') {
|
||||||
|
if (!itemData.system.properties.mandatoryconditions) {
|
||||||
|
itemData.system.properties.mandatoryconditions = []
|
||||||
|
}
|
||||||
|
if (!itemData.system.properties.optionnalconditions) {
|
||||||
|
itemData.system.properties.optionnalconditions = []
|
||||||
|
}
|
||||||
|
for (let i = 0; i < 4; i++) {
|
||||||
|
itemData.system.properties.mandatoryconditions[i] = itemData.system.properties.mandatoryconditions[i] ?? ""
|
||||||
|
}
|
||||||
|
for (let i = 0; i < 8; i++) {
|
||||||
|
itemData.system.properties.optionnalconditions[i] = itemData.system.properties.optionnalconditions[i] ?? ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (itemData.type === "feature") {
|
||||||
|
// Set default subtype/category
|
||||||
|
if (!itemData.system.subtype) {
|
||||||
|
itemData.system.category = "origin"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
_onRender(context, options) {
|
||||||
|
super._onRender(context, options)
|
||||||
|
this.#dragDrop.forEach((d) => d.bind(this.element))
|
||||||
|
this._activateTabs()
|
||||||
|
this._activateListeners()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Activate tab navigation via CSS only (no re-render) to preserve unsaved form state.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_activateTabs() {
|
||||||
|
const nav = this.element.querySelector('nav[data-group="primary"]')
|
||||||
|
if (!nav) return
|
||||||
|
const section = this.element.querySelector('section.sheet-body')
|
||||||
|
if (!section) return
|
||||||
|
|
||||||
|
const activeTab = this.tabGroups.primary || "description"
|
||||||
|
|
||||||
|
// Set initial active state
|
||||||
|
nav.querySelectorAll('[data-tab]').forEach(link => {
|
||||||
|
link.classList.toggle('active', link.dataset.tab === activeTab)
|
||||||
|
})
|
||||||
|
section.querySelectorAll('[data-tab]').forEach(content => {
|
||||||
|
content.classList.toggle('active', content.dataset.tab === activeTab)
|
||||||
|
})
|
||||||
|
|
||||||
|
// Tab click — CSS-only switch, no render()
|
||||||
|
nav.querySelectorAll('[data-tab]').forEach(link => {
|
||||||
|
link.addEventListener('click', (event) => {
|
||||||
|
event.preventDefault()
|
||||||
|
const tab = link.dataset.tab
|
||||||
|
this.tabGroups.primary = tab
|
||||||
|
nav.querySelectorAll('[data-tab]').forEach(l => l.classList.toggle('active', l.dataset.tab === tab))
|
||||||
|
section.querySelectorAll('[data-tab]').forEach(c => c.classList.toggle('active', c.dataset.tab === tab))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Activate custom listeners
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_activateListeners() {
|
||||||
|
if (!this.isEditable) return
|
||||||
|
|
||||||
|
// Armor quality change handler
|
||||||
|
const armorQuality = this.element.querySelector('.armorQuality')
|
||||||
|
if (armorQuality) {
|
||||||
|
armorQuality.addEventListener('change', (ev) => {
|
||||||
|
const value = ev.currentTarget.value
|
||||||
|
const soakFormula = this.element.querySelector('.soakFormula')
|
||||||
|
if (soakFormula && game.bol.config.soakFormulas[value]) {
|
||||||
|
soakFormula.value = game.bol.config.soakFormulas[value]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// #region Drag-and-Drop Workflow
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create drag-and-drop workflow handlers for this Application
|
||||||
|
* @returns {DragDrop[]}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
#createDragDropHandlers() {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
|
// #endregion
|
||||||
|
|
||||||
|
// #region Actions
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle editing the item image
|
||||||
|
* @param {PointerEvent} event
|
||||||
|
* @param {HTMLElement} target
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
static async #onEditImage(event, target) {
|
||||||
|
const fp = new FilePicker({
|
||||||
|
current: this.document.img,
|
||||||
|
type: "image",
|
||||||
|
callback: (path) => {
|
||||||
|
this.document.update({ img: path })
|
||||||
|
},
|
||||||
|
})
|
||||||
|
return fp.browse()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle posting the item to chat
|
||||||
|
* @param {PointerEvent} event
|
||||||
|
* @param {HTMLElement} target
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
static async #onPostItem(event, target) {
|
||||||
|
const BoLUtility = (await import("../../system/bol-utility.js")).BoLUtility
|
||||||
|
let chatData = foundry.utils.duplicate(this.document)
|
||||||
|
if (this.document.actor) {
|
||||||
|
chatData.actor = { id: this.document.actor.id }
|
||||||
|
}
|
||||||
|
BoLUtility.postItem(chatData)
|
||||||
|
}
|
||||||
|
|
||||||
|
// #endregion
|
||||||
|
}
|
||||||
39
module/applications/sheets/feature-sheet.mjs
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
import BoLBaseItemSheet from "./base-item-sheet.mjs"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Item Sheet for "feature" type items (boons, careers, origins, etc.)
|
||||||
|
* @extends {BoLBaseItemSheet}
|
||||||
|
*/
|
||||||
|
export default class BoLFeatureSheet extends BoLBaseItemSheet {
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
static DEFAULT_OPTIONS = {
|
||||||
|
classes: ["bol", "sheet", "item", "item-type-feature"],
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
static PARTS = {
|
||||||
|
main: {
|
||||||
|
template: "systems/bol/templates/item/feature-sheet.hbs",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
async _prepareContext() {
|
||||||
|
const context = await super._prepareContext()
|
||||||
|
|
||||||
|
// Add feature-specific context
|
||||||
|
context.isFeature = true
|
||||||
|
context.isBoon = context.system.subtype === "boon"
|
||||||
|
context.isFlaw = context.system.subtype === "flaw"
|
||||||
|
context.isCareer = context.system.subtype === "career"
|
||||||
|
context.isOrigin = context.system.subtype === "origin"
|
||||||
|
context.isRace = context.system.subtype === "race"
|
||||||
|
context.isFightOption = context.system.subtype === "fightoption"
|
||||||
|
context.isEffect = context.system.subtype === "effect"
|
||||||
|
context.isHoroscope = context.system.subtype === "horoscope"
|
||||||
|
context.isXpLog = context.system.subtype === "xplog"
|
||||||
|
|
||||||
|
return context
|
||||||
|
}
|
||||||
|
}
|
||||||
65
module/applications/sheets/horde-sheet.mjs
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
import BoLBaseActorSheet from "./base-actor-sheet.mjs"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Actor Sheet for BoL hordes using AppV2
|
||||||
|
*/
|
||||||
|
export default class BoLHordeSheet extends BoLBaseActorSheet {
|
||||||
|
/** @override */
|
||||||
|
static DEFAULT_OPTIONS = {
|
||||||
|
...super.DEFAULT_OPTIONS,
|
||||||
|
classes: [...super.DEFAULT_OPTIONS.classes],
|
||||||
|
actions: {
|
||||||
|
...super.DEFAULT_OPTIONS.actions,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
static PARTS = {
|
||||||
|
sheet: {
|
||||||
|
template: "systems/bol/templates/actor/horde-sheet.hbs",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
tabGroups = { primary: "stats" }
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
async _prepareContext() {
|
||||||
|
const context = await super._prepareContext()
|
||||||
|
const actor = this.document
|
||||||
|
|
||||||
|
context.options = this.options
|
||||||
|
context.editScore = this.options.editScore
|
||||||
|
context.description = await foundry.applications.ux.TextEditor.implementation.enrichHTML(
|
||||||
|
actor.system.details?.biography || "", { async: true }
|
||||||
|
)
|
||||||
|
|
||||||
|
console.log("HORDE (AppV2)", context)
|
||||||
|
return context
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
_activateListeners() {
|
||||||
|
super._activateListeners()
|
||||||
|
if (!this.isEditable) return
|
||||||
|
|
||||||
|
// Item create via header dataset
|
||||||
|
this.element.querySelectorAll(".item-create").forEach((el) => {
|
||||||
|
el.addEventListener("click", (ev) => {
|
||||||
|
ev.preventDefault()
|
||||||
|
const header = ev.currentTarget
|
||||||
|
const type = header.dataset.type
|
||||||
|
const data = foundry.utils.duplicate(header.dataset)
|
||||||
|
delete data.type
|
||||||
|
this.actor.createEmbeddedDocuments("Item", [{ name: `New ${type}`, type, data }])
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
// Create generic item
|
||||||
|
this.element.querySelectorAll(".create_item").forEach((el) => {
|
||||||
|
el.addEventListener("click", () => {
|
||||||
|
this.actor.createEmbeddedDocuments("Item", [{ name: "Nouvel Equipement", type: "item" }], { renderSheet: true })
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
38
module/applications/sheets/item-sheet.mjs
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
import BoLBaseItemSheet from "./base-item-sheet.mjs"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Item Sheet for "item" type items (equipment, weapons, etc.)
|
||||||
|
* @extends {BoLBaseItemSheet}
|
||||||
|
*/
|
||||||
|
export default class BoLItemSheet extends BoLBaseItemSheet {
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
static DEFAULT_OPTIONS = {
|
||||||
|
classes: ["bol", "sheet", "item", "item-type-item"],
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
static PARTS = {
|
||||||
|
main: {
|
||||||
|
template: "systems/bol/templates/item/item-sheet.hbs",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
async _prepareContext() {
|
||||||
|
const context = await super._prepareContext()
|
||||||
|
|
||||||
|
// Add item-specific context
|
||||||
|
context.isItem = true
|
||||||
|
context.isEquipment = context.category === "equipment"
|
||||||
|
context.isWeapon = context.category === "weapon"
|
||||||
|
context.isProtection = context.category === "protection"
|
||||||
|
context.isSpell = context.category === "spell"
|
||||||
|
context.isAlchemy = context.category === "alchemy"
|
||||||
|
context.isCapacity = context.category === "capacity"
|
||||||
|
context.isMagical = context.category === "magical"
|
||||||
|
context.isVehicle = context.category === "vehicle"
|
||||||
|
|
||||||
|
return context
|
||||||
|
}
|
||||||
|
}
|
||||||
70
module/applications/sheets/vehicle-sheet.mjs
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
import BoLBaseActorSheet from "./base-actor-sheet.mjs"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Actor Sheet for BoL vehicles using AppV2
|
||||||
|
*/
|
||||||
|
export default class BoLVehicleSheet extends BoLBaseActorSheet {
|
||||||
|
/** @override */
|
||||||
|
static DEFAULT_OPTIONS = {
|
||||||
|
...super.DEFAULT_OPTIONS,
|
||||||
|
classes: [...super.DEFAULT_OPTIONS.classes],
|
||||||
|
actions: {
|
||||||
|
...super.DEFAULT_OPTIONS.actions,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
static PARTS = {
|
||||||
|
sheet: {
|
||||||
|
template: "systems/bol/templates/actor/vehicle-sheet.hbs",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
tabGroups = { primary: "stats" }
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
async _prepareContext() {
|
||||||
|
const context = await super._prepareContext()
|
||||||
|
const actor = this.document
|
||||||
|
|
||||||
|
context.weapons = actor.vehicleWeapons
|
||||||
|
context.options = this.options
|
||||||
|
context.editScore = this.options.editScore
|
||||||
|
context.description = await foundry.applications.ux.TextEditor.implementation.enrichHTML(
|
||||||
|
actor.system.description || "", { async: true }
|
||||||
|
)
|
||||||
|
|
||||||
|
console.log("VEHICLE (AppV2)", context) // TODO: remove before release
|
||||||
|
return context
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
_activateListeners() {
|
||||||
|
super._activateListeners()
|
||||||
|
if (!this.isEditable) return
|
||||||
|
|
||||||
|
// Item create via header dataset
|
||||||
|
this.element.querySelectorAll(".item-create").forEach((el) => {
|
||||||
|
el.addEventListener("click", (ev) => {
|
||||||
|
ev.preventDefault()
|
||||||
|
const header = ev.currentTarget
|
||||||
|
const type = header.dataset.type
|
||||||
|
const data = foundry.utils.duplicate(header.dataset)
|
||||||
|
delete data.type
|
||||||
|
this.actor.createEmbeddedDocuments("Item", [{ name: `New ${type}`, type, data }])
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
// Create vehicle weapon
|
||||||
|
this.element.querySelectorAll(".vehicle-weapon-add").forEach((el) => {
|
||||||
|
el.addEventListener("click", () => {
|
||||||
|
this.actor.createEmbeddedDocuments("Item", [{
|
||||||
|
name: game.i18n.localize("BOL.ui.newEquipment"),
|
||||||
|
type: "item",
|
||||||
|
system: { category: "vehicleweapon" },
|
||||||
|
}], { renderSheet: true })
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,11 +1,9 @@
|
|||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
// Import Modules
|
// Import Modules
|
||||||
import { BoLActor } from "./actor/actor.js"
|
import { BoLActor } from "./actor/actor.js"
|
||||||
import { BoLActorSheet } from "./actor/actor-sheet.js"
|
// AppV1 actor sheets kept for reference only (AppV2 used via sheets.* below)
|
||||||
import { BoLVehicleSheet } from "./actor/vehicle-sheet.js"
|
|
||||||
import { BoLHordeSheet } from "./actor/horde-sheet.js"
|
|
||||||
import { BoLItem } from "./item/item.js"
|
import { BoLItem } from "./item/item.js"
|
||||||
import { BoLItemSheet } from "./item/item-sheet.js"
|
// Note: Old BoLItemSheet (AppV1) is now replaced by AppV2 sheets
|
||||||
import { System, BOL } from "./system/config.js"
|
import { System, BOL } from "./system/config.js"
|
||||||
import { preloadHandlebarsTemplates } from "./system/templates.js"
|
import { preloadHandlebarsTemplates } from "./system/templates.js"
|
||||||
import { registerHandlebarsHelpers } from "./system/helpers.js"
|
import { registerHandlebarsHelpers } from "./system/helpers.js"
|
||||||
@@ -18,6 +16,12 @@ import { BoLHotbar } from "./system/bol-hotbar.js"
|
|||||||
import { BoLCommands } from "./system/bol-commands.js"
|
import { BoLCommands } from "./system/bol-commands.js"
|
||||||
import { BoLRoll } from "./controllers/bol-rolls.js"
|
import { BoLRoll } from "./controllers/bol-rolls.js"
|
||||||
|
|
||||||
|
// Import DataModels
|
||||||
|
import * as models from "./models/_module.mjs"
|
||||||
|
|
||||||
|
// Import AppV2 Sheets
|
||||||
|
import * as sheets from "./applications/sheets/_module.mjs"
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
Hooks.once('init', async function () {
|
Hooks.once('init', async function () {
|
||||||
|
|
||||||
@@ -28,10 +32,12 @@ Hooks.once('init', async function () {
|
|||||||
BoLRoll,
|
BoLRoll,
|
||||||
BoLUtility,
|
BoLUtility,
|
||||||
macros: Macros,
|
macros: Macros,
|
||||||
config: BOL
|
config: BOL,
|
||||||
|
models,
|
||||||
|
sheets
|
||||||
};
|
};
|
||||||
|
|
||||||
// Game socket
|
// Game socket
|
||||||
game.socket.on("system.bol", sockmsg => {
|
game.socket.on("system.bol", sockmsg => {
|
||||||
BoLUtility.onSocketMessage(sockmsg);
|
BoLUtility.onSocketMessage(sockmsg);
|
||||||
})
|
})
|
||||||
@@ -47,17 +53,38 @@ Hooks.once('init', async function () {
|
|||||||
|
|
||||||
// Define custom Entity classes
|
// Define custom Entity classes
|
||||||
CONFIG.Actor.documentClass = BoLActor;
|
CONFIG.Actor.documentClass = BoLActor;
|
||||||
|
CONFIG.Actor.dataModels = {
|
||||||
|
character: models.BoLCharacter,
|
||||||
|
encounter: models.BoLEncounter,
|
||||||
|
horde: models.BoLHorde,
|
||||||
|
vehicle: models.BoLVehicle
|
||||||
|
}
|
||||||
|
|
||||||
CONFIG.Item.documentClass = BoLItem;
|
CONFIG.Item.documentClass = BoLItem;
|
||||||
|
CONFIG.Item.dataModels = {
|
||||||
|
item: models.BoLItem,
|
||||||
|
feature: models.BoLFeature
|
||||||
|
}
|
||||||
|
|
||||||
CONFIG.Combat.documentClass = BoLCombatManager;
|
CONFIG.Combat.documentClass = BoLCombatManager;
|
||||||
|
|
||||||
// Register sheet application classes
|
// Register sheet application classes
|
||||||
Actors.unregisterSheet("core", ActorSheet);
|
foundry.documents.collections.Actors.unregisterSheet("core", foundry.appv1.sheets.ActorSheet);
|
||||||
Actors.registerSheet("bol", BoLActorSheet, { types: ["character", "encounter"], makeDefault: true })
|
foundry.documents.collections.Actors.registerSheet("bol", sheets.BoLActorSheet, { types: ["character", "encounter"], makeDefault: true })
|
||||||
Actors.registerSheet("bol", BoLVehicleSheet, { types: ["vehicle"], makeDefault: true })
|
foundry.documents.collections.Actors.registerSheet("bol", sheets.BoLVehicleSheet, { types: ["vehicle"], makeDefault: true })
|
||||||
Actors.registerSheet("bol", BoLHordeSheet, { types: ["horde"], makeDefault: true })
|
foundry.documents.collections.Actors.registerSheet("bol", sheets.BoLHordeSheet, { types: ["horde"], makeDefault: true })
|
||||||
|
|
||||||
Items.unregisterSheet("core", ItemSheet);
|
// Register AppV2 Item Sheets
|
||||||
Items.registerSheet("bol", BoLItemSheet, { makeDefault: true });
|
foundry.documents.collections.Items.unregisterSheet("core", foundry.appv1.sheets.ItemSheet);
|
||||||
|
foundry.documents.collections.Items.registerSheet("bol", sheets.BoLItemSheet, { types: ["item"], makeDefault: true });
|
||||||
|
foundry.documents.collections.Items.registerSheet("bol", sheets.BoLFeatureSheet, { types: ["feature"], makeDefault: true });
|
||||||
|
|
||||||
|
// Debug: Verify AppV2 sheets are loaded
|
||||||
|
console.log("BoL Item Sheets registered:", {
|
||||||
|
BoLItemSheet: sheets.BoLItemSheet.name,
|
||||||
|
BoLFeatureSheet: sheets.BoLFeatureSheet.name,
|
||||||
|
extendsApplicationV2: sheets.BoLItemSheet.prototype instanceof foundry.applications.api.ApplicationV2
|
||||||
|
});
|
||||||
|
|
||||||
// Inot useful stuff
|
// Inot useful stuff
|
||||||
BoLUtility.init()
|
BoLUtility.init()
|
||||||
@@ -78,34 +105,27 @@ Hooks.once('init', async function () {
|
|||||||
Babele.get().setSystemTranslationsDir("compendiums");
|
Babele.get().setSystemTranslationsDir("compendiums");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
function welcomeMessage() {
|
async function welcomeMessage() {
|
||||||
ChatMessage.create({
|
const noRulebook = !game.modules.find(m => m.id === "bol-rulebook")
|
||||||
user: game.user.id,
|
const content = await foundry.applications.handlebars.renderTemplate(
|
||||||
whisper: [game.user.id],
|
"systems/bol/templates/chat/chat-welcome.hbs",
|
||||||
content: `<div id="welcome-message-bol"><span class="rdd-roll-part">
|
{ noRulebook }
|
||||||
<strong>` + game.i18n.localize("BOL.chat.welcome1") + `</strong><p>` +
|
)
|
||||||
game.i18n.localize("BOL.chat.welcome2") + "<p>" +
|
ChatMessage.create({ user: game.user.id, whisper: [game.user.id], content })
|
||||||
game.i18n.localize("BOL.chat.welcome3") + "<p>" +
|
|
||||||
game.i18n.localize("BOL.chat.welcome4") + "</p>" +
|
if (game.user.isGM && game.i18n.lang == 'en' && !game.modules.find(m => m.id == "babele")) {
|
||||||
game.i18n.localize("BOL.chat.welcome5") + "<br>" +
|
|
||||||
game.i18n.localize("BOL.chat.welcome6")
|
|
||||||
})
|
|
||||||
|
|
||||||
if (game.user.isGM && game.i18n.lang == 'en' && !game.modules.find(m => m.id == "babele") ){
|
|
||||||
ChatMessage.create({
|
ChatMessage.create({
|
||||||
user: game.user.id,
|
user: game.user.id,
|
||||||
whisper: [game.user.id],
|
whisper: [game.user.id],
|
||||||
content: `<div id="welcome-message-bol"><span class="rdd-roll-part">
|
content: `<div class="bol-welcome-card"><div class="welcome-body"><p class="welcome-warning">⚠ WARNING ! English language selected, but Babele module is not installed !<br>Please install babele from the module tab in Foundry interface.</p></div></div>`
|
||||||
<strong>WARNING ! English language selected, but babele module is not installed !<br>Please install babele from the module tab in Foundry interface.`
|
})
|
||||||
} )
|
ui.notifications.warn("WARNING ! English language selected, but babele module is not installed !<br>Please install babele from the module tab in Foundry interface.")
|
||||||
ui.notifications.warn("WARNING ! English language selected, but babele module is not installed !<br>Please install babele from the module tab in Foundry interface.")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
@@ -160,13 +180,11 @@ Hooks.once('ready', async function () {
|
|||||||
"d6B": "d6H (Bonus)",
|
"d6B": "d6H (Bonus)",
|
||||||
"d6BB": "d6H + Bonus die",
|
"d6BB": "d6H + Bonus die",
|
||||||
}
|
}
|
||||||
|
|
||||||
if (game.i18n.lang === "fr") {
|
if (game.i18n.lang === "fr") {
|
||||||
game.bol.config.damageValues = damageFR;
|
game.bol.config.damageValues = damageFR;
|
||||||
} else {
|
} else {
|
||||||
game.bol.config.damageValues = damageEN;
|
game.bol.config.damageValues = damageEN;
|
||||||
}
|
}
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -5,11 +5,6 @@ const _apt2attr = { init: "mind", melee: "agility", ranged: "agility", def: "vig
|
|||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
export class BoLRoll {
|
export class BoLRoll {
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
|
||||||
static options() {
|
|
||||||
return { classes: ["bol", "dialog"], width: 480, height: 'fit-content' };
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
static getDefaultAttribute(key) {
|
static getDefaultAttribute(key) {
|
||||||
return _apt2attr[key]
|
return _apt2attr[key]
|
||||||
@@ -19,9 +14,9 @@ export class BoLRoll {
|
|||||||
static updateApplicableEffects(rollData) {
|
static updateApplicableEffects(rollData) {
|
||||||
let appEffects = []
|
let appEffects = []
|
||||||
for (let effect of rollData.bolEffects) {
|
for (let effect of rollData.bolEffects) {
|
||||||
if ( (effect.system.properties.identifier == "always") ||
|
if ((effect.system.properties.identifier == "always") ||
|
||||||
(effect.system.properties.identifier.includes(rollData.attribute.key)) ||
|
(effect.system.properties.identifier.includes(rollData.attribute.key)) ||
|
||||||
(rollData.aptitude && effect.system.properties.identifier.includes(rollData.aptitude.key)) ){
|
(rollData.aptitude && effect.system.properties.identifier.includes(rollData.aptitude.key))) {
|
||||||
appEffects.push(effect)
|
appEffects.push(effect)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -76,7 +71,7 @@ export class BoLRoll {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
static attributeCheck(actor, key="vigor", event=undefined, combatData=undefined) {
|
static attributeCheck(actor, key = "vigor", event = undefined, combatData = undefined) {
|
||||||
|
|
||||||
let attribute = eval(`actor.system.attributes.${key}`)
|
let attribute = eval(`actor.system.attributes.${key}`)
|
||||||
|
|
||||||
@@ -89,7 +84,7 @@ export class BoLRoll {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
static aptitudeCheck(actor, key="init", event=undefined, combatData=undefined) {
|
static aptitudeCheck(actor, key = "init", event = undefined, combatData = undefined) {
|
||||||
|
|
||||||
let aptitude = eval(`actor.system.aptitudes.${key}`)
|
let aptitude = eval(`actor.system.aptitudes.${key}`)
|
||||||
let attrKey = this.getDefaultAttribute(key)
|
let attrKey = this.getDefaultAttribute(key)
|
||||||
@@ -129,7 +124,7 @@ export class BoLRoll {
|
|||||||
rangeMsg = "BOL.chat.range6"
|
rangeMsg = "BOL.chat.range6"
|
||||||
}
|
}
|
||||||
ChatMessage.create({
|
ChatMessage.create({
|
||||||
content: await renderTemplate('systems/bol/templates/chat/chat-info-range.hbs', {
|
content: await foundry.applications.handlebars.renderTemplate('systems/bol/templates/chat/chat-info-range.hbs', {
|
||||||
weapon: weapon,
|
weapon: weapon,
|
||||||
attackerName: _token.actor.name,
|
attackerName: _token.actor.name,
|
||||||
defenderName: target.actor.name,
|
defenderName: target.actor.name,
|
||||||
@@ -196,6 +191,11 @@ export class BoLRoll {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
alchemy = foundry.utils.duplicate(alchemy)
|
alchemy = foundry.utils.duplicate(alchemy)
|
||||||
|
return this.alchemyCheckWithItem(actor, alchemy)
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
static alchemyCheckWithItem(actor, alchemy) {
|
||||||
let alchemyData = alchemy.system
|
let alchemyData = alchemy.system
|
||||||
if (alchemyData.properties.pccurrent < alchemyData.properties.pccost) {
|
if (alchemyData.properties.pccurrent < alchemyData.properties.pccost) {
|
||||||
ui.notifications.warn("Pas assez de Points de Création investis dans la Préparation !")
|
ui.notifications.warn("Pas assez de Points de Création investis dans la Préparation !")
|
||||||
@@ -305,29 +305,34 @@ export class BoLRoll {
|
|||||||
// Keep track of the final effect modifier
|
// Keep track of the final effect modifier
|
||||||
this.rollData.effectModifier = effectModifier
|
this.rollData.effectModifier = effectModifier
|
||||||
|
|
||||||
// Final number of dices
|
// Final number of dices
|
||||||
this.rollData.nbDice = 2 + Math.abs(this.rollData.bmDice)
|
this.rollData.nbDice = 2 + Math.abs(this.rollData.bmDice)
|
||||||
// Bonus or Malus ?
|
// Bonus or Malus ?
|
||||||
if (this.rollData.bmDice == 0) {
|
const nbDiceEl = document.querySelector('#roll-nbdice')
|
||||||
$('#roll-nbdice').val("2")
|
if (nbDiceEl) {
|
||||||
} else {
|
if (this.rollData.bmDice == 0) {
|
||||||
let letter = (this.rollData.bmDice > 0) ? "B" : "M"
|
nbDiceEl.value = "2"
|
||||||
$('#roll-nbdice').val("2 + " + String(Math.abs(this.rollData.bmDice)) + letter)
|
} else {
|
||||||
|
let letter = (this.rollData.bmDice > 0) ? "B" : "M"
|
||||||
|
nbDiceEl.value = "2 + " + String(Math.abs(this.rollData.bmDice)) + letter
|
||||||
|
}
|
||||||
}
|
}
|
||||||
let rollbase = this.rollData.attrValue + "+" + this.rollData.aptValue
|
let rollbase = this.rollData.attrValue + "+" + this.rollData.aptValue
|
||||||
if (this.rollData.weapon && this.rollData.weapon.system.properties.onlymodifier) {
|
if (this.rollData.weapon && this.rollData.weapon.system.properties.onlymodifier) {
|
||||||
rollbase = ""
|
rollbase = ""
|
||||||
}
|
}
|
||||||
$('#roll-modifier').val(rollbase + "+" + this.rollData.careerBonus + "+" + this.rollData.mod + "+" +
|
const modifierEl = document.querySelector('#roll-modifier')
|
||||||
|
if (modifierEl) modifierEl.value = rollbase + "+" + this.rollData.careerBonus + "+" + this.rollData.mod + "+" +
|
||||||
this.rollData.modRanged + "+" + this.rollData.weaponModifier + "-" + this.rollData.defence + "-" + this.rollData.modArmorMalus + "-" +
|
this.rollData.modRanged + "+" + this.rollData.weaponModifier + "-" + this.rollData.defence + "-" + this.rollData.modArmorMalus + "-" +
|
||||||
this.rollData.shieldMalus + "+" + this.rollData.attackModifier + "+" + this.rollData.appliedArmorMalus + "+" + effectModifier)
|
this.rollData.shieldMalus + "+" + this.rollData.attackModifier + "+" + this.rollData.appliedArmorMalus + "+" + effectModifier
|
||||||
|
|
||||||
// Rebuild lits of applicable effects
|
// Rebuild list of applicable effects
|
||||||
let selectEffects = ""
|
let selectEffects = ""
|
||||||
for (let effect of this.rollData.bolApplicableEffects) {
|
for (let effect of this.rollData.bolApplicableEffects) {
|
||||||
selectEffects += `<option value="${effect.id}" selected>${effect.name}</option>`
|
selectEffects += `<option value="${effect.id}" selected>${effect.name}</option>`
|
||||||
}
|
}
|
||||||
$('#applicable-effects').html(selectEffects)
|
const effectsEl = document.querySelector('#applicable-effects')
|
||||||
|
if (effectsEl) effectsEl.innerHTML = selectEffects
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
@@ -360,46 +365,48 @@ export class BoLRoll {
|
|||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
static updateArmorMalus(rollData) {
|
static updateArmorMalus(rollData) {
|
||||||
rollData.appliedArmorMalus = 0
|
rollData.appliedArmorMalus = 0
|
||||||
|
const agiEl = document.querySelector('#armor-agi-malus')
|
||||||
if (rollData.attribute.key == "agility") {
|
if (rollData.attribute.key == "agility") {
|
||||||
$("#armor-agi-malus").show()
|
if (agiEl) agiEl.style.display = ''
|
||||||
rollData.appliedArmorMalus += rollData.armorAgiMalus
|
rollData.appliedArmorMalus += rollData.armorAgiMalus
|
||||||
} else {
|
} else {
|
||||||
$("#armor-agi-malus").hide()
|
if (agiEl) agiEl.style.display = 'none'
|
||||||
}
|
}
|
||||||
|
const initEl = document.querySelector('#armor-init-malus')
|
||||||
if (rollData.aptitude && rollData.aptitude.key == "init") {
|
if (rollData.aptitude && rollData.aptitude.key == "init") {
|
||||||
$("#armor-init-malus").show()
|
if (initEl) initEl.style.display = ''
|
||||||
rollData.appliedArmorMalus += rollData.armorInitMalus
|
rollData.appliedArmorMalus += rollData.armorInitMalus
|
||||||
} else {
|
} else {
|
||||||
$("#armor-init-malus").hide()
|
if (initEl) initEl.style.display = 'none'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------ -------------- */
|
/* ------------------------------ -------------- */
|
||||||
static updatePPCost(rollData) {
|
static updatePPCost(rollData) {
|
||||||
$('#ppcost').html(rollData.ppCost + " + Armor(" + rollData.ppCostArmor + ")=" + Number(rollData.ppCost + rollData.ppCostArmor))
|
const el = document.querySelector('#ppcost')
|
||||||
|
if (el) el.innerHTML = rollData.ppCost + " + Armor(" + rollData.ppCostArmor + ")=" + Number(rollData.ppCost + rollData.ppCostArmor)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------ -------------- */
|
/* ------------------------------ -------------- */
|
||||||
static rollDialogListener(html) {
|
static rollDialogListener(html) {
|
||||||
|
|
||||||
this.updateTotalDice()
|
this.updateTotalDice()
|
||||||
|
|
||||||
html.find('#optcond').change((event) => { // Dynamic change of PP cost of spell
|
html.querySelector('#optcond')?.addEventListener('change', (event) => {
|
||||||
let pp = BoLUtility.computeSpellCost(this.rollData.spell, event.currentTarget.selectedOptions.length)
|
let pp = BoLUtility.computeSpellCost(this.rollData.spell, event.currentTarget.selectedOptions.length)
|
||||||
this.rollData.ppCost = pp
|
this.rollData.ppCost = pp
|
||||||
this.updatePPCost(this.rollData)
|
this.updatePPCost(this.rollData)
|
||||||
})
|
})
|
||||||
|
|
||||||
html.find('#mod').change((event) => {
|
html.querySelector('#mod')?.addEventListener('change', (event) => {
|
||||||
this.rollData.mod = Number(event.currentTarget.value)
|
this.rollData.mod = Number(event.currentTarget.value)
|
||||||
this.updateTotalDice()
|
this.updateTotalDice()
|
||||||
})
|
})
|
||||||
html.find('#modRanged').change((event) => {
|
html.querySelector('#modRanged')?.addEventListener('change', (event) => {
|
||||||
this.rollData.modRanged = Number(event.currentTarget.value)
|
this.rollData.modRanged = Number(event.currentTarget.value)
|
||||||
this.updateTotalDice()
|
this.updateTotalDice()
|
||||||
})
|
})
|
||||||
|
|
||||||
html.find('#attr').change((event) => {
|
html.querySelector('#attr')?.addEventListener('change', (event) => {
|
||||||
let attrKey = event.currentTarget.value
|
let attrKey = event.currentTarget.value
|
||||||
let actor = BoLUtility.getActorFromRollData(this.rollData)
|
let actor = BoLUtility.getActorFromRollData(this.rollData)
|
||||||
this.rollData.attribute = foundry.utils.duplicate(actor.system.attributes[attrKey])
|
this.rollData.attribute = foundry.utils.duplicate(actor.system.attributes[attrKey])
|
||||||
@@ -407,7 +414,7 @@ export class BoLRoll {
|
|||||||
this.rollData.bolApplicableEffects = this.updateApplicableEffects(this.rollData)
|
this.rollData.bolApplicableEffects = this.updateApplicableEffects(this.rollData)
|
||||||
this.updateTotalDice()
|
this.updateTotalDice()
|
||||||
})
|
})
|
||||||
html.find('#apt').change((event) => {
|
html.querySelector('#apt')?.addEventListener('change', (event) => {
|
||||||
let aptKey = event.currentTarget.value
|
let aptKey = event.currentTarget.value
|
||||||
let actor = BoLUtility.getActorFromRollData(this.rollData)
|
let actor = BoLUtility.getActorFromRollData(this.rollData)
|
||||||
this.rollData.aptitude = foundry.utils.duplicate(actor.system.aptitudes[aptKey])
|
this.rollData.aptitude = foundry.utils.duplicate(actor.system.aptitudes[aptKey])
|
||||||
@@ -416,65 +423,58 @@ export class BoLRoll {
|
|||||||
this.updateTotalDice()
|
this.updateTotalDice()
|
||||||
})
|
})
|
||||||
|
|
||||||
html.find('#applyShieldMalus').click((event) => {
|
html.querySelector('#applyShieldMalus')?.addEventListener('click', (event) => {
|
||||||
if (event.currentTarget.checked) {
|
this.rollData.shieldMalus = event.currentTarget.checked ? this.rollData.shieldAttackMalus : 0
|
||||||
this.rollData.shieldMalus = this.rollData.shieldAttackMalus
|
|
||||||
} else {
|
|
||||||
this.rollData.shieldMalus = 0
|
|
||||||
}
|
|
||||||
this.updateTotalDice()
|
this.updateTotalDice()
|
||||||
})
|
})
|
||||||
|
|
||||||
html.find('#career').change((event) => {
|
html.querySelector('#career')?.addEventListener('change', (event) => {
|
||||||
let careers = $('#career').val()
|
let careers = Array.from(event.currentTarget.selectedOptions).map(o => o.value)
|
||||||
this.rollData.careerBonus = (!careers || careers.length == 0) ? 0 : Math.max(...careers.map(i => parseInt(i)))
|
this.rollData.careerBonus = (!careers || careers.length == 0) ? 0 : Math.max(...careers.map(i => parseInt(i)))
|
||||||
this.updateTotalDice()
|
this.updateTotalDice()
|
||||||
})
|
})
|
||||||
html.find('#boon').change((event) => {
|
html.querySelector('#boon')?.addEventListener('change', (event) => {
|
||||||
let boons = $('#boon').val()
|
let boons = Array.from(event.currentTarget.selectedOptions).map(o => o.value)
|
||||||
this.rollData.nbBoons = (!boons || boons.length == 0) ? 0 : boons.length
|
this.rollData.nbBoons = (!boons || boons.length == 0) ? 0 : boons.length
|
||||||
this.updateTotalDice()
|
this.updateTotalDice()
|
||||||
})
|
})
|
||||||
html.find('#flaw').change((event) => {
|
html.querySelector('#flaw')?.addEventListener('change', (event) => {
|
||||||
let flaws = $('#flaw').val()
|
let flaws = Array.from(event.currentTarget.selectedOptions).map(o => o.value)
|
||||||
this.rollData.nbFlaws = (!flaws || flaws.length == 0) ? 0 : flaws.length
|
this.rollData.nbFlaws = (!flaws || flaws.length == 0) ? 0 : flaws.length
|
||||||
this.updateTotalDice()
|
this.updateTotalDice()
|
||||||
})
|
})
|
||||||
html.find('.bdice').click((event) => {
|
html.querySelectorAll('.bdice').forEach(el => el.addEventListener('click', (event) => {
|
||||||
this.rollData.mDice = 0
|
this.rollData.mDice = 0
|
||||||
this.rollData.bDice = Number(event.currentTarget.value)
|
this.rollData.bDice = Number(event.currentTarget.value)
|
||||||
this.updateTotalDice()
|
this.updateTotalDice()
|
||||||
})
|
}))
|
||||||
html.find('.mdice').click((event) => {
|
html.querySelectorAll('.mdice').forEach(el => el.addEventListener('click', (event) => {
|
||||||
this.rollData.bDice = 0
|
this.rollData.bDice = 0
|
||||||
this.rollData.mDice = Number(event.currentTarget.value)
|
this.rollData.mDice = Number(event.currentTarget.value)
|
||||||
this.updateTotalDice()
|
this.updateTotalDice()
|
||||||
})
|
}))
|
||||||
html.find('#horoscope-bonus-applied').change((event) => {
|
html.querySelector('#horoscope-bonus-applied')?.addEventListener('change', (event) => {
|
||||||
this.rollData.selectedHoroscope = []
|
this.rollData.selectedHoroscope = []
|
||||||
for (let option of event.currentTarget.selectedOptions) {
|
for (let option of event.currentTarget.selectedOptions) {
|
||||||
this.rollData.selectedHoroscope.push(foundry.utils.duplicate(this.rollData.horoscopeBonusList[Number(option.index)]))
|
this.rollData.selectedHoroscope.push(foundry.utils.duplicate(this.rollData.horoscopeBonusList[Number(option.index)]))
|
||||||
}
|
}
|
||||||
let horoscopes = $('#horoscope-bonus-applied').val()
|
let horoscopes = Array.from(event.currentTarget.selectedOptions).map(o => o.value)
|
||||||
this.rollData.horoscopeBonus = (!horoscopes || horoscopes.length == 0) ? 0 : horoscopes.length
|
this.rollData.horoscopeBonus = (!horoscopes || horoscopes.length == 0) ? 0 : horoscopes.length
|
||||||
this.updateTotalDice()
|
this.updateTotalDice()
|
||||||
})
|
})
|
||||||
|
html.querySelector('#horoscope-malus-applied')?.addEventListener('change', (event) => {
|
||||||
html.find('#horoscope-malus-applied').change((event) => {
|
|
||||||
this.rollData.selectedHoroscope = []
|
this.rollData.selectedHoroscope = []
|
||||||
for (let option of event.currentTarget.selectedOptions) {
|
for (let option of event.currentTarget.selectedOptions) {
|
||||||
this.rollData.selectedHoroscope.push(foundry.utils.duplicate(this.rollData.horoscopeBonusList[Number(option.index)]))
|
this.rollData.selectedHoroscope.push(foundry.utils.duplicate(this.rollData.horoscopeBonusList[Number(option.index)]))
|
||||||
}
|
}
|
||||||
let horoscopes = $('#horoscope-malus-applied').val()
|
let horoscopes = Array.from(event.currentTarget.selectedOptions).map(o => o.value)
|
||||||
this.rollData.horoscopeMalus = (!horoscopes || horoscopes.length == 0) ? 0 : horoscopes.length
|
this.rollData.horoscopeMalus = (!horoscopes || horoscopes.length == 0) ? 0 : horoscopes.length
|
||||||
this.updateTotalDice()
|
this.updateTotalDice()
|
||||||
})
|
})
|
||||||
html.find('#horoscope-group-applied').change((event) => {
|
html.querySelector('#horoscope-group-applied')?.addEventListener('change', (event) => {
|
||||||
this.rollData.selectedGroupHoroscopeIndex = event.currentTarget.value
|
this.rollData.selectedGroupHoroscopeIndex = event.currentTarget.value
|
||||||
this.updateTotalDice()
|
this.updateTotalDice()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
@@ -482,14 +482,19 @@ export class BoLRoll {
|
|||||||
if (rollData.mode == "weapon") {
|
if (rollData.mode == "weapon") {
|
||||||
rollData.weaponModifier = rollData.weapon.system.properties.attackModifiers ?? 0
|
rollData.weaponModifier = rollData.weapon.system.properties.attackModifiers ?? 0
|
||||||
rollData.attackBonusDice = rollData.weapon.system.properties.attackBonusDice
|
rollData.attackBonusDice = rollData.weapon.system.properties.attackBonusDice
|
||||||
|
rollData.attackMalusDice = rollData.weapon.system.properties.attackMalusDice
|
||||||
if (rollData.attackBonusDice) {
|
if (rollData.attackBonusDice) {
|
||||||
rollData.adv = "1B"
|
rollData.adv = "1B"
|
||||||
rollData.bDice = 1
|
rollData.bDice = 1
|
||||||
}
|
}
|
||||||
|
if (rollData.attackMalusDice) {
|
||||||
|
rollData.adv = "1M"
|
||||||
|
rollData.mDice = 1
|
||||||
|
}
|
||||||
if (defender) { // If target is selected
|
if (defender) { // If target is selected
|
||||||
rollData.defence = defender.defenseValue
|
rollData.defence = defender.defenseValue
|
||||||
rollData.armorMalus = defender.armorMalusValue
|
rollData.armorMalus = defender.armorMalusValue
|
||||||
rollData.defenderHeroPoints = defender.getHeroPoints()
|
rollData.defenderHeroPoints = defender.getHeroPoints()
|
||||||
rollData.shieldBlock = 'none'
|
rollData.shieldBlock = 'none'
|
||||||
let shields = defender.shields
|
let shields = defender.shields
|
||||||
//console.log("Defender stats", defender)
|
//console.log("Defender stats", defender)
|
||||||
@@ -534,8 +539,9 @@ export class BoLRoll {
|
|||||||
rollData.id = foundry.utils.randomID(16)
|
rollData.id = foundry.utils.randomID(16)
|
||||||
rollData.weaponModifier = 0
|
rollData.weaponModifier = 0
|
||||||
rollData.attackBonusDice = false
|
rollData.attackBonusDice = false
|
||||||
|
rollData.attackMalusDice = false
|
||||||
rollData.armorMalus = 0
|
rollData.armorMalus = 0
|
||||||
// Specific stuff
|
// Specific stuff
|
||||||
this.preProcessWeapon(rollData, defender)
|
this.preProcessWeapon(rollData, defender)
|
||||||
this.preProcessFightOption(rollData)
|
this.preProcessFightOption(rollData)
|
||||||
this.updateArmorMalus(rollData)
|
this.updateArmorMalus(rollData)
|
||||||
@@ -546,43 +552,49 @@ export class BoLRoll {
|
|||||||
} else {
|
} else {
|
||||||
rollData.shieldMalus = 0
|
rollData.shieldMalus = 0
|
||||||
}
|
}
|
||||||
// Save
|
// Save & pre-initialize computed fields
|
||||||
this.rollData = rollData
|
this.rollData = rollData
|
||||||
|
this.updateTotalDice()
|
||||||
console.log("ROLLDATA", rollData)
|
console.log("ROLLDATA", rollData)
|
||||||
|
|
||||||
// Then display+process the dialog
|
// Then display+process the dialog
|
||||||
const rollOptionContent = await renderTemplate(rollOptionTpl, rollData);
|
const rollOptionContent = await foundry.applications.handlebars.renderTemplate(rollOptionTpl, rollData);
|
||||||
let d = new Dialog({
|
// Use Hooks to reliably get the rendered HTMLElement (renderDialogV2 receives (app, element, context))
|
||||||
title: rollData.label,
|
Hooks.once('renderDialogV2', (app, element) => {
|
||||||
|
element.classList.add('bol');
|
||||||
|
this.rollDialogListener(element);
|
||||||
|
});
|
||||||
|
return foundry.applications.api.DialogV2.wait({
|
||||||
|
window: { title: rollData.label },
|
||||||
content: rollOptionContent,
|
content: rollOptionContent,
|
||||||
rollData: rollData,
|
rejectClose: false,
|
||||||
render: html => this.rollDialogListener(html),
|
buttons: [
|
||||||
buttons: {
|
{
|
||||||
cancel: {
|
type: 'button',
|
||||||
icon: '<i class="fas fa-times"></i>',
|
|
||||||
label: game.i18n.localize("BOL.ui.cancel"),
|
label: game.i18n.localize("BOL.ui.cancel"),
|
||||||
callback: () => {
|
icon: 'fas fa-times',
|
||||||
}
|
action: 'cancel'
|
||||||
},
|
},
|
||||||
submit: {
|
{
|
||||||
icon: '<i class="fas fa-check"></i>',
|
type: 'submit',
|
||||||
label: game.i18n.localize("BOL.ui.submit"),
|
label: game.i18n.localize("BOL.ui.submit"),
|
||||||
callback: (html) => {
|
icon: 'fas fa-check',
|
||||||
|
action: 'submit',
|
||||||
|
callback: (event, button, dialog) => {
|
||||||
console.log("Submit Roll!!!!");
|
console.log("Submit Roll!!!!");
|
||||||
if (rollData.mode == 'spell' && rollData.ppCurrent < rollData.ppCost) { // Check PP available
|
if (rollData.mode == 'spell' && rollData.ppCurrent < rollData.ppCost) {
|
||||||
ui.notifications.warn("Pas assez de Points de Pouvoir !")
|
ui.notifications.warn("Pas assez de Points de Pouvoir !")
|
||||||
return
|
return false
|
||||||
}
|
}
|
||||||
rollData.registerInit = (rollData.aptitude && rollData.aptitude.key == 'init') ? $('#register-init').is(":checked") : false;
|
rollData.registerInit = (rollData.aptitude && rollData.aptitude.key == 'init') ?
|
||||||
|
(dialog.element.querySelector('#register-init')?.checked ?? false) : false;
|
||||||
|
|
||||||
const isMalus = (rollData.bmDice < 0)
|
const isMalus = (rollData.bmDice < 0)
|
||||||
|
|
||||||
let rollbase = rollData.attrValue + rollData.aptValue
|
let rollbase = rollData.attrValue + rollData.aptValue
|
||||||
if (rollData.weapon?.system.properties.onlymodifier) {
|
if (rollData.weapon?.system.properties.onlymodifier) rollbase = 0
|
||||||
rollbase = 0
|
|
||||||
}
|
|
||||||
let diceData = BoLUtility.getDiceData()
|
let diceData = BoLUtility.getDiceData()
|
||||||
let malusInit = rollData.combatData?.malusInit || 0
|
let malusInit = rollData.combatData?.malusInit || 0
|
||||||
const modifiers = rollbase + rollData.careerBonus + rollData.mod + rollData.weaponModifier - rollData.defence - rollData.modArmorMalus + rollData.shieldMalus + rollData.attackModifier + rollData.appliedArmorMalus + rollData.effectModifier - malusInit
|
const modifiers = rollbase + rollData.careerBonus + rollData.mod + rollData.weaponModifier - rollData.defence - rollData.modArmorMalus + rollData.shieldMalus + rollData.attackModifier + rollData.appliedArmorMalus + rollData.effectModifier - malusInit
|
||||||
const formula = (isMalus) ? rollData.nbDice + "d" + diceData.diceFormula + "kl2 + " + modifiers : rollData.nbDice + "d" + diceData.diceFormula + "kh2 + " + modifiers
|
const formula = (isMalus) ? rollData.nbDice + "d" + diceData.diceFormula + "kl2 + " + modifiers : rollData.nbDice + "d" + diceData.diceFormula + "kh2 + " + modifiers
|
||||||
rollData.formula = formula
|
rollData.formula = formula
|
||||||
@@ -593,12 +605,8 @@ export class BoLRoll {
|
|||||||
r.roll();
|
r.roll();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
]
|
||||||
default: onEnter,
|
}, { classes: ['bol', 'dialog'], width: 480 });
|
||||||
close: () => { }
|
|
||||||
}, this.options());
|
|
||||||
|
|
||||||
return d.render(true);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -634,16 +642,16 @@ export class BoLDefaultRoll {
|
|||||||
const diceTotal = activeDice.map(r => r.result).reduce((a, b) => a + b)
|
const diceTotal = activeDice.map(r => r.result).reduce((a, b) => a + b)
|
||||||
this.rollData.roll = r
|
this.rollData.roll = r
|
||||||
this.rollData.isFumble = (diceTotal <= diceData.criticalFailureValue)
|
this.rollData.isFumble = (diceTotal <= diceData.criticalFailureValue)
|
||||||
if ( this.rollData.isFumble ) {
|
if (this.rollData.isFumble) {
|
||||||
this.rollData.isSuccess = false
|
this.rollData.isSuccess = false
|
||||||
this.rollData.isCritical = false
|
this.rollData.isCritical = false
|
||||||
this.rollData.isRealCritical = false
|
this.rollData.isRealCritical = false
|
||||||
this.rollData.isHeroic = false
|
this.rollData.isHeroic = false
|
||||||
this.rollData.isFailure = true
|
this.rollData.isFailure = true
|
||||||
} else {
|
} else {
|
||||||
this.rollData.isCritical = (diceTotal >= diceData.criticalSuccessValue)
|
this.rollData.isCritical = (diceTotal >= diceData.criticalSuccessValue)
|
||||||
if ( this.rollData.isCritical) {
|
if (this.rollData.isCritical) {
|
||||||
this.rollData.isSuccess = true
|
this.rollData.isSuccess = true
|
||||||
} else {
|
} else {
|
||||||
this.rollData.isSuccess = (r.total >= diceData.successValue)
|
this.rollData.isSuccess = (r.total >= diceData.successValue)
|
||||||
}
|
}
|
||||||
@@ -692,18 +700,15 @@ export class BoLDefaultRoll {
|
|||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
async sendChatMessage() {
|
async sendChatMessage() {
|
||||||
let actor = BoLUtility.getActorFromRollData(this.rollData)
|
const actor = BoLUtility.getActorFromRollData(this.rollData)
|
||||||
this._buildChatMessage(this.rollData).then(async msgFlavor => {
|
const rollMode = game.settings.get("core", "rollMode")
|
||||||
//console.log("MSG", msgFlavor )
|
const msgFlavor = await this._buildChatMessage(this.rollData)
|
||||||
let msg = await this.rollData.roll.toMessage({
|
const msg = await this.rollData.roll.toMessage({
|
||||||
user: game.user.id,
|
flavor: msgFlavor,
|
||||||
rollMode: game.settings.get("core", "rollMode"),
|
speaker: ChatMessage.getSpeaker({ actor: actor }),
|
||||||
flavor: msgFlavor,
|
}, { rollMode })
|
||||||
speaker: ChatMessage.getSpeaker({ actor: actor }),
|
this.rollData.roll = foundry.utils.duplicate(this.rollData.roll)
|
||||||
})
|
if (msg) await msg.setFlag("world", "bol-roll-data", this.rollData)
|
||||||
this.rollData.roll = foundry.utils.duplicate(this.rollData.roll) // Remove object, keep data (v111 ready)
|
|
||||||
msg.setFlag("world", "bol-roll-data", this.rollData)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
@@ -747,6 +752,12 @@ export class BoLDefaultRoll {
|
|||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
async sendDamageMessage() {
|
async sendDamageMessage() {
|
||||||
let actor = BoLUtility.getActorFromRollData(this.rollData)
|
let actor = BoLUtility.getActorFromRollData(this.rollData)
|
||||||
|
// If no target, collect potential targets from active scene (excluding attacker)
|
||||||
|
if (!this.rollData.targetId && game.scenes.current) {
|
||||||
|
this.rollData.potentialTargets = game.scenes.current.tokens
|
||||||
|
.filter(t => t.actor && t.actor.id !== this.rollData.actorId)
|
||||||
|
.map(t => ({ id: t.id, actorId: t.actor.id, name: t.name, img: t.texture?.src || t.actor.img }))
|
||||||
|
}
|
||||||
this._buildDamageChatMessage(this.rollData).then(async msgFlavor => {
|
this._buildDamageChatMessage(this.rollData).then(async msgFlavor => {
|
||||||
let msg = await this.rollData.damageRoll.toMessage({
|
let msg = await this.rollData.damageRoll.toMessage({
|
||||||
user: game.user.id,
|
user: game.user.id,
|
||||||
@@ -805,13 +816,13 @@ export class BoLDefaultRoll {
|
|||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
_buildDamageChatMessage(rollData) {
|
_buildDamageChatMessage(rollData) {
|
||||||
const rollMessageTpl = 'systems/bol/templates/chat/rolls/damage-roll-card.hbs';
|
const rollMessageTpl = 'systems/bol/templates/chat/rolls/damage-roll-card.hbs';
|
||||||
return renderTemplate(rollMessageTpl, rollData)
|
return foundry.applications.handlebars.renderTemplate(rollMessageTpl, rollData)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
_buildChatMessage(rollData) {
|
_buildChatMessage(rollData) {
|
||||||
const rollMessageTpl = 'systems/bol/templates/chat/rolls/default-roll-card.hbs'
|
const rollMessageTpl = 'systems/bol/templates/chat/rolls/default-roll-card.hbs'
|
||||||
return renderTemplate(rollMessageTpl, rollData)
|
return foundry.applications.handlebars.renderTemplate(rollMessageTpl, rollData)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,117 +0,0 @@
|
|||||||
import { BoLUtility } from "../system/bol-utility.js";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Extend the basic ItemSheet with some very simple modifications
|
|
||||||
* @extends {ItemSheet}
|
|
||||||
*/
|
|
||||||
export class BoLItemSheet extends ItemSheet {
|
|
||||||
|
|
||||||
/** @override */
|
|
||||||
static get defaultOptions() {
|
|
||||||
return foundry.utils.mergeObject(super.defaultOptions, {
|
|
||||||
classes: ["bol", "sheet", "item"],
|
|
||||||
template: "systems/bol/templates/item/item-sheet.hbs",
|
|
||||||
width: 650,
|
|
||||||
height: 780,
|
|
||||||
tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "description" }]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
|
||||||
/** @override */
|
|
||||||
async getData(options) {
|
|
||||||
const data = super.getData(options)
|
|
||||||
let itemData = foundry.utils.duplicate(data.document)
|
|
||||||
data.config = game.bol.config
|
|
||||||
data.item = itemData
|
|
||||||
data.category = itemData.system.category
|
|
||||||
data.isGM = game.user.isGM;
|
|
||||||
data.itemProperties = this.item.itemProperties;
|
|
||||||
data.description = await TextEditor.enrichHTML(this.object.system.description, { async: true })
|
|
||||||
if (data.document.actor) {
|
|
||||||
data.careers = data.document.actor.careers
|
|
||||||
}
|
|
||||||
// Dynamic default data fix/adapt
|
|
||||||
if (itemData.type == "item") {
|
|
||||||
if (!itemData.system.category) {
|
|
||||||
itemData.system.category = "equipment"
|
|
||||||
}
|
|
||||||
if (itemData.system.category == "equipment" && itemData.system.properties.equipable) {
|
|
||||||
if (!itemData.system.properties.slot) {
|
|
||||||
itemData.system.properties.slot = "-"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (itemData.system.category == 'spell') {
|
|
||||||
if (!itemData.system.properties.mandatoryconditions) {
|
|
||||||
itemData.system.properties.mandatoryconditions = []
|
|
||||||
}
|
|
||||||
if (!itemData.system.properties.optionnalconditions) {
|
|
||||||
itemData.system.properties.optionnalconditions = []
|
|
||||||
}
|
|
||||||
for (let i = 0; i < 4; i++) {
|
|
||||||
itemData.system.properties.mandatoryconditions[i] = itemData.system.properties.mandatoryconditions[i] ?? ""
|
|
||||||
}
|
|
||||||
for (let i = 0; i < 8; i++) {
|
|
||||||
itemData.system.properties.optionnalconditions[i] = itemData.system.properties.optionnalconditions[i] ?? ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (!itemData.system.subtype) {
|
|
||||||
itemData.system.category = "origin"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log("ITEMDATA", data);
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
|
||||||
_getHeaderButtons() {
|
|
||||||
let buttons = super._getHeaderButtons();
|
|
||||||
buttons.unshift({
|
|
||||||
class: "post",
|
|
||||||
icon: "fas fa-comment",
|
|
||||||
onclick: ev => this.postItem()
|
|
||||||
});
|
|
||||||
return buttons
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
|
||||||
postItem() {
|
|
||||||
let chatData = foundry.utils.duplicate(this.item)
|
|
||||||
if (this.actor) {
|
|
||||||
chatData.actor = { id: this.actor.id };
|
|
||||||
}
|
|
||||||
BoLUtility.postItem(chatData);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
|
||||||
/** @override */
|
|
||||||
setPosition(options = {}) {
|
|
||||||
const position = super.setPosition(options);
|
|
||||||
const sheetBody = this.element.find(".sheet-body");
|
|
||||||
const bodyHeight = position.height - 192;
|
|
||||||
sheetBody.css("height", bodyHeight);
|
|
||||||
return position;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
|
||||||
|
|
||||||
/** @override */
|
|
||||||
activateListeners(html) {
|
|
||||||
|
|
||||||
super.activateListeners(html);
|
|
||||||
// Everything below here is only needed if the sheet is editable
|
|
||||||
if (!this.options.editable) return;
|
|
||||||
// Roll handlers, click handlers, etc. would go here.
|
|
||||||
|
|
||||||
html.find('.armorQuality').change(ev => {
|
|
||||||
const li = $(ev.currentTarget);
|
|
||||||
console.log(game.bol.config.soakFormulas[li.val()]);
|
|
||||||
$('.soakFormula').val(game.bol.config.soakFormulas[li.val()]);
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
6
module/models/_module.mjs
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
export { default as BoLCharacter } from "./character.mjs"
|
||||||
|
export { default as BoLEncounter } from "./encounter.mjs"
|
||||||
|
export { default as BoLHorde } from "./horde.mjs"
|
||||||
|
export { default as BoLVehicle } from "./vehicle.mjs"
|
||||||
|
export { default as BoLItem } from "./item.mjs"
|
||||||
|
export { default as BoLFeature } from "./feature.mjs"
|
||||||
192
module/models/character.mjs
Normal file
@@ -0,0 +1,192 @@
|
|||||||
|
/**
|
||||||
|
* Data model for Character actors
|
||||||
|
*/
|
||||||
|
export default class BoLCharacterDataModel extends foundry.abstract.TypeDataModel {
|
||||||
|
static defineSchema() {
|
||||||
|
const fields = foundry.data.fields;
|
||||||
|
const requiredInteger = { required: true, nullable: false, integer: true };
|
||||||
|
|
||||||
|
return {
|
||||||
|
// Details
|
||||||
|
details: new fields.SchemaField({
|
||||||
|
biography: new fields.HTMLField({ initial: "" }),
|
||||||
|
notes: new fields.HTMLField({ initial: "" }),
|
||||||
|
height: new fields.StringField({ initial: "" }),
|
||||||
|
age: new fields.StringField({ initial: "" }),
|
||||||
|
weight: new fields.StringField({ initial: "" }),
|
||||||
|
hair: new fields.StringField({ initial: "" }),
|
||||||
|
eyes: new fields.StringField({ initial: "" }),
|
||||||
|
signs: new fields.StringField({ initial: "" }),
|
||||||
|
size: new fields.StringField({ initial: "" }),
|
||||||
|
languages: new fields.ArrayField(new fields.StringField(), { initial: [] }),
|
||||||
|
xplog: new fields.ArrayField(new fields.ObjectField(), { initial: [] })
|
||||||
|
}),
|
||||||
|
|
||||||
|
// Combat
|
||||||
|
combat: new fields.SchemaField({
|
||||||
|
lastinit: new fields.NumberField({ ...requiredInteger, initial: 0 }),
|
||||||
|
iscritical: new fields.BooleanField({ initial: false }),
|
||||||
|
isfumble: new fields.BooleanField({ initial: false }),
|
||||||
|
islegendary: new fields.BooleanField({ initial: false })
|
||||||
|
}),
|
||||||
|
|
||||||
|
// Character type
|
||||||
|
chartype: new fields.StringField({ initial: "player" }),
|
||||||
|
villainy: new fields.BooleanField({ initial: false }),
|
||||||
|
|
||||||
|
// Bougette
|
||||||
|
bougette: new fields.SchemaField({
|
||||||
|
state: new fields.StringField({ initial: "nomoney" }),
|
||||||
|
value: new fields.NumberField({ ...requiredInteger, initial: 0 })
|
||||||
|
}),
|
||||||
|
|
||||||
|
// XP
|
||||||
|
xp: new fields.SchemaField({
|
||||||
|
key: new fields.StringField({ initial: "xp" }),
|
||||||
|
label: new fields.StringField({ initial: "BOL.traits.xp" }),
|
||||||
|
total: new fields.NumberField({ ...requiredInteger, initial: 0 }),
|
||||||
|
spent: new fields.NumberField({ ...requiredInteger, initial: 0 })
|
||||||
|
}),
|
||||||
|
|
||||||
|
// Creation
|
||||||
|
creation: new fields.SchemaField({
|
||||||
|
key: new fields.StringField({ initial: "creation" }),
|
||||||
|
label: new fields.StringField({ initial: "BOL.resources.creation" }),
|
||||||
|
value: new fields.NumberField({ ...requiredInteger, initial: 0 }),
|
||||||
|
max: new fields.NumberField({ ...requiredInteger, initial: 0 })
|
||||||
|
}),
|
||||||
|
|
||||||
|
// Protection
|
||||||
|
prot: new fields.SchemaField({
|
||||||
|
key: new fields.StringField({ initial: "prot" }),
|
||||||
|
label: new fields.StringField({ initial: "BOL.aptitudes.prot" }),
|
||||||
|
base: new fields.NumberField({ ...requiredInteger, initial: 0 }),
|
||||||
|
value: new fields.NumberField({ ...requiredInteger, initial: 0 }),
|
||||||
|
bonus: new fields.NumberField({ ...requiredInteger, initial: 0 })
|
||||||
|
}),
|
||||||
|
|
||||||
|
// Attributes
|
||||||
|
attributes: new fields.SchemaField({
|
||||||
|
vigor: new fields.SchemaField({
|
||||||
|
key: new fields.StringField({ initial: "vigor" }),
|
||||||
|
label: new fields.StringField({ initial: "BOL.attributes.vigor" }),
|
||||||
|
base: new fields.NumberField({ ...requiredInteger, initial: 0 }),
|
||||||
|
value: new fields.NumberField({ ...requiredInteger, initial: 0 }),
|
||||||
|
min: new fields.NumberField({ ...requiredInteger, initial: -1 }),
|
||||||
|
max: new fields.NumberField({ ...requiredInteger, initial: 5 }),
|
||||||
|
bonus: new fields.NumberField({ ...requiredInteger, initial: 0 })
|
||||||
|
}),
|
||||||
|
agility: new fields.SchemaField({
|
||||||
|
key: new fields.StringField({ initial: "agility" }),
|
||||||
|
label: new fields.StringField({ initial: "BOL.attributes.agility" }),
|
||||||
|
base: new fields.NumberField({ ...requiredInteger, initial: 0 }),
|
||||||
|
value: new fields.NumberField({ ...requiredInteger, initial: 0 }),
|
||||||
|
min: new fields.NumberField({ ...requiredInteger, initial: -1 }),
|
||||||
|
max: new fields.NumberField({ ...requiredInteger, initial: 5 }),
|
||||||
|
bonus: new fields.NumberField({ ...requiredInteger, initial: 0 })
|
||||||
|
}),
|
||||||
|
mind: new fields.SchemaField({
|
||||||
|
key: new fields.StringField({ initial: "mind" }),
|
||||||
|
label: new fields.StringField({ initial: "BOL.attributes.mind" }),
|
||||||
|
base: new fields.NumberField({ ...requiredInteger, initial: 0 }),
|
||||||
|
value: new fields.NumberField({ ...requiredInteger, initial: 0 }),
|
||||||
|
min: new fields.NumberField({ ...requiredInteger, initial: -1 }),
|
||||||
|
max: new fields.NumberField({ ...requiredInteger, initial: 5 }),
|
||||||
|
bonus: new fields.NumberField({ ...requiredInteger, initial: 0 })
|
||||||
|
}),
|
||||||
|
appeal: new fields.SchemaField({
|
||||||
|
key: new fields.StringField({ initial: "appeal" }),
|
||||||
|
label: new fields.StringField({ initial: "BOL.attributes.appeal" }),
|
||||||
|
base: new fields.NumberField({ ...requiredInteger, initial: 0 }),
|
||||||
|
value: new fields.NumberField({ ...requiredInteger, initial: 0 }),
|
||||||
|
bonus: new fields.NumberField({ ...requiredInteger, initial: 0 })
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
|
||||||
|
// Aptitudes
|
||||||
|
aptitudes: new fields.SchemaField({
|
||||||
|
init: new fields.SchemaField({
|
||||||
|
key: new fields.StringField({ initial: "init" }),
|
||||||
|
label: new fields.StringField({ initial: "BOL.aptitudes.init" }),
|
||||||
|
base: new fields.NumberField({ ...requiredInteger, initial: 0 }),
|
||||||
|
value: new fields.NumberField({ ...requiredInteger, initial: 0 }),
|
||||||
|
bonus: new fields.NumberField({ ...requiredInteger, initial: 0 })
|
||||||
|
}),
|
||||||
|
melee: new fields.SchemaField({
|
||||||
|
key: new fields.StringField({ initial: "melee" }),
|
||||||
|
label: new fields.StringField({ initial: "BOL.aptitudes.melee" }),
|
||||||
|
base: new fields.NumberField({ ...requiredInteger, initial: 0 }),
|
||||||
|
value: new fields.NumberField({ ...requiredInteger, initial: 0 }),
|
||||||
|
bonus: new fields.NumberField({ ...requiredInteger, initial: 0 })
|
||||||
|
}),
|
||||||
|
ranged: new fields.SchemaField({
|
||||||
|
key: new fields.StringField({ initial: "ranged" }),
|
||||||
|
label: new fields.StringField({ initial: "BOL.aptitudes.ranged" }),
|
||||||
|
base: new fields.NumberField({ ...requiredInteger, initial: 0 }),
|
||||||
|
value: new fields.NumberField({ ...requiredInteger, initial: 0 }),
|
||||||
|
bonus: new fields.NumberField({ ...requiredInteger, initial: 0 })
|
||||||
|
}),
|
||||||
|
def: new fields.SchemaField({
|
||||||
|
key: new fields.StringField({ initial: "def" }),
|
||||||
|
label: new fields.StringField({ initial: "BOL.aptitudes.def" }),
|
||||||
|
base: new fields.NumberField({ ...requiredInteger, initial: 0 }),
|
||||||
|
value: new fields.NumberField({ ...requiredInteger, initial: 0 }),
|
||||||
|
bonus: new fields.NumberField({ ...requiredInteger, initial: 0 })
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
|
||||||
|
// Resources
|
||||||
|
resources: new fields.SchemaField({
|
||||||
|
hp: new fields.SchemaField({
|
||||||
|
key: new fields.StringField({ initial: "hp" }),
|
||||||
|
label: new fields.StringField({ initial: "BOL.resources.hp" }),
|
||||||
|
ismain: new fields.BooleanField({ initial: true }),
|
||||||
|
base: new fields.NumberField({ ...requiredInteger, initial: 1 }),
|
||||||
|
value: new fields.NumberField({ ...requiredInteger, initial: 1 }),
|
||||||
|
bonus: new fields.NumberField({ ...requiredInteger, initial: 0 }),
|
||||||
|
max: new fields.NumberField({ ...requiredInteger, initial: 1 })
|
||||||
|
}),
|
||||||
|
hero: new fields.SchemaField({
|
||||||
|
key: new fields.StringField({ initial: "hero" }),
|
||||||
|
label: new fields.StringField({ initial: "BOL.resources.hero" }),
|
||||||
|
ismain: new fields.BooleanField({ initial: true }),
|
||||||
|
value: new fields.NumberField({ ...requiredInteger, initial: 5 }),
|
||||||
|
max: new fields.NumberField({ ...requiredInteger, initial: 5 })
|
||||||
|
}),
|
||||||
|
faith: new fields.SchemaField({
|
||||||
|
key: new fields.StringField({ initial: "faith" }),
|
||||||
|
label: new fields.StringField({ initial: "BOL.resources.faith" }),
|
||||||
|
ismain: new fields.BooleanField({ initial: true }),
|
||||||
|
value: new fields.NumberField({ ...requiredInteger, initial: 0 }),
|
||||||
|
max: new fields.NumberField({ ...requiredInteger, initial: 0 })
|
||||||
|
}),
|
||||||
|
power: new fields.SchemaField({
|
||||||
|
key: new fields.StringField({ initial: "power" }),
|
||||||
|
label: new fields.StringField({ initial: "BOL.resources.power" }),
|
||||||
|
ismain: new fields.BooleanField({ initial: true }),
|
||||||
|
value: new fields.NumberField({ ...requiredInteger, initial: 0 }),
|
||||||
|
bonus: new fields.NumberField({ ...requiredInteger, initial: 0 }),
|
||||||
|
max: new fields.NumberField({ ...requiredInteger, initial: 0 })
|
||||||
|
}),
|
||||||
|
alchemypoints: new fields.SchemaField({
|
||||||
|
key: new fields.StringField({ initial: "alchemypoints" }),
|
||||||
|
label: new fields.StringField({ initial: "BOL.resources.alchemypoints" }),
|
||||||
|
ismain: new fields.BooleanField({ initial: false }),
|
||||||
|
value: new fields.NumberField({ ...requiredInteger, initial: 0 }),
|
||||||
|
bonus: new fields.NumberField({ ...requiredInteger, initial: 0 }),
|
||||||
|
max: new fields.NumberField({ ...requiredInteger, initial: 0 })
|
||||||
|
}),
|
||||||
|
astrologypoints: new fields.SchemaField({
|
||||||
|
key: new fields.StringField({ initial: "astrologypoints" }),
|
||||||
|
label: new fields.StringField({ initial: "BOL.resources.astrologypoints" }),
|
||||||
|
ismain: new fields.BooleanField({ initial: false }),
|
||||||
|
value: new fields.NumberField({ ...requiredInteger, initial: 0 }),
|
||||||
|
bonus: new fields.NumberField({ ...requiredInteger, initial: 0 }),
|
||||||
|
max: new fields.NumberField({ ...requiredInteger, initial: 0 })
|
||||||
|
})
|
||||||
|
})
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static LOCALIZATION_PREFIXES = ["BOL.Character"];
|
||||||
|
}
|
||||||
173
module/models/encounter.mjs
Normal file
@@ -0,0 +1,173 @@
|
|||||||
|
/**
|
||||||
|
* Data model for Encounter actors
|
||||||
|
*/
|
||||||
|
export default class BoLEncounterDataModel extends foundry.abstract.TypeDataModel {
|
||||||
|
static defineSchema() {
|
||||||
|
const fields = foundry.data.fields;
|
||||||
|
const requiredInteger = { required: true, nullable: false, integer: true };
|
||||||
|
|
||||||
|
return {
|
||||||
|
// Details
|
||||||
|
details: new fields.SchemaField({
|
||||||
|
biography: new fields.HTMLField({ initial: "" }),
|
||||||
|
notes: new fields.HTMLField({ initial: "" }),
|
||||||
|
height: new fields.StringField({ initial: "" }),
|
||||||
|
age: new fields.StringField({ initial: "" }),
|
||||||
|
weight: new fields.StringField({ initial: "" }),
|
||||||
|
hair: new fields.StringField({ initial: "" }),
|
||||||
|
eyes: new fields.StringField({ initial: "" }),
|
||||||
|
signs: new fields.StringField({ initial: "" }),
|
||||||
|
size: new fields.StringField({ initial: "" }),
|
||||||
|
languages: new fields.ArrayField(new fields.StringField(), { initial: [] }),
|
||||||
|
xplog: new fields.ArrayField(new fields.ObjectField(), { initial: [] })
|
||||||
|
}),
|
||||||
|
|
||||||
|
// Combat
|
||||||
|
combat: new fields.SchemaField({
|
||||||
|
lastinit: new fields.NumberField({ ...requiredInteger, initial: 0 }),
|
||||||
|
iscritical: new fields.BooleanField({ initial: false }),
|
||||||
|
isfumble: new fields.BooleanField({ initial: false }),
|
||||||
|
islegendary: new fields.BooleanField({ initial: false })
|
||||||
|
}),
|
||||||
|
|
||||||
|
// Character type
|
||||||
|
chartype: new fields.StringField({ initial: "tough" }),
|
||||||
|
isundead: new fields.BooleanField({ initial: false }),
|
||||||
|
villainy: new fields.BooleanField({ initial: false }),
|
||||||
|
size: new fields.StringField({ initial: "" }),
|
||||||
|
environment: new fields.StringField({ initial: "" }),
|
||||||
|
|
||||||
|
// Protection
|
||||||
|
prot: new fields.SchemaField({
|
||||||
|
key: new fields.StringField({ initial: "prot" }),
|
||||||
|
label: new fields.StringField({ initial: "BOL.aptitudes.prot" }),
|
||||||
|
base: new fields.NumberField({ ...requiredInteger, initial: 0 }),
|
||||||
|
value: new fields.NumberField({ ...requiredInteger, initial: 0 }),
|
||||||
|
bonus: new fields.NumberField({ ...requiredInteger, initial: 0 })
|
||||||
|
}),
|
||||||
|
|
||||||
|
// Attributes
|
||||||
|
attributes: new fields.SchemaField({
|
||||||
|
vigor: new fields.SchemaField({
|
||||||
|
key: new fields.StringField({ initial: "vigor" }),
|
||||||
|
label: new fields.StringField({ initial: "BOL.attributes.vigor" }),
|
||||||
|
base: new fields.NumberField({ ...requiredInteger, initial: 0 }),
|
||||||
|
value: new fields.NumberField({ ...requiredInteger, initial: 0 }),
|
||||||
|
min: new fields.NumberField({ ...requiredInteger, initial: -1 }),
|
||||||
|
max: new fields.NumberField({ ...requiredInteger, initial: 5 }),
|
||||||
|
bonus: new fields.NumberField({ ...requiredInteger, initial: 0 })
|
||||||
|
}),
|
||||||
|
agility: new fields.SchemaField({
|
||||||
|
key: new fields.StringField({ initial: "agility" }),
|
||||||
|
label: new fields.StringField({ initial: "BOL.attributes.agility" }),
|
||||||
|
base: new fields.NumberField({ ...requiredInteger, initial: 0 }),
|
||||||
|
value: new fields.NumberField({ ...requiredInteger, initial: 0 }),
|
||||||
|
min: new fields.NumberField({ ...requiredInteger, initial: -1 }),
|
||||||
|
max: new fields.NumberField({ ...requiredInteger, initial: 5 }),
|
||||||
|
bonus: new fields.NumberField({ ...requiredInteger, initial: 0 })
|
||||||
|
}),
|
||||||
|
mind: new fields.SchemaField({
|
||||||
|
key: new fields.StringField({ initial: "mind" }),
|
||||||
|
label: new fields.StringField({ initial: "BOL.attributes.mind" }),
|
||||||
|
base: new fields.NumberField({ ...requiredInteger, initial: 0 }),
|
||||||
|
value: new fields.NumberField({ ...requiredInteger, initial: 0 }),
|
||||||
|
min: new fields.NumberField({ ...requiredInteger, initial: -1 }),
|
||||||
|
max: new fields.NumberField({ ...requiredInteger, initial: 5 }),
|
||||||
|
bonus: new fields.NumberField({ ...requiredInteger, initial: 0 })
|
||||||
|
}),
|
||||||
|
appeal: new fields.SchemaField({
|
||||||
|
key: new fields.StringField({ initial: "appeal" }),
|
||||||
|
label: new fields.StringField({ initial: "BOL.attributes.appeal" }),
|
||||||
|
base: new fields.NumberField({ ...requiredInteger, initial: 0 }),
|
||||||
|
value: new fields.NumberField({ ...requiredInteger, initial: 0 }),
|
||||||
|
bonus: new fields.NumberField({ ...requiredInteger, initial: 0 })
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
|
||||||
|
// Aptitudes
|
||||||
|
aptitudes: new fields.SchemaField({
|
||||||
|
init: new fields.SchemaField({
|
||||||
|
key: new fields.StringField({ initial: "init" }),
|
||||||
|
label: new fields.StringField({ initial: "BOL.aptitudes.init" }),
|
||||||
|
base: new fields.NumberField({ ...requiredInteger, initial: 0 }),
|
||||||
|
value: new fields.NumberField({ ...requiredInteger, initial: 0 }),
|
||||||
|
bonus: new fields.NumberField({ ...requiredInteger, initial: 0 })
|
||||||
|
}),
|
||||||
|
melee: new fields.SchemaField({
|
||||||
|
key: new fields.StringField({ initial: "melee" }),
|
||||||
|
label: new fields.StringField({ initial: "BOL.aptitudes.melee" }),
|
||||||
|
base: new fields.NumberField({ ...requiredInteger, initial: 0 }),
|
||||||
|
value: new fields.NumberField({ ...requiredInteger, initial: 0 }),
|
||||||
|
bonus: new fields.NumberField({ ...requiredInteger, initial: 0 })
|
||||||
|
}),
|
||||||
|
ranged: new fields.SchemaField({
|
||||||
|
key: new fields.StringField({ initial: "ranged" }),
|
||||||
|
label: new fields.StringField({ initial: "BOL.aptitudes.ranged" }),
|
||||||
|
base: new fields.NumberField({ ...requiredInteger, initial: 0 }),
|
||||||
|
value: new fields.NumberField({ ...requiredInteger, initial: 0 }),
|
||||||
|
bonus: new fields.NumberField({ ...requiredInteger, initial: 0 })
|
||||||
|
}),
|
||||||
|
def: new fields.SchemaField({
|
||||||
|
key: new fields.StringField({ initial: "def" }),
|
||||||
|
label: new fields.StringField({ initial: "BOL.aptitudes.def" }),
|
||||||
|
base: new fields.NumberField({ ...requiredInteger, initial: 0 }),
|
||||||
|
value: new fields.NumberField({ ...requiredInteger, initial: 0 }),
|
||||||
|
bonus: new fields.NumberField({ ...requiredInteger, initial: 0 })
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
|
||||||
|
// Resources
|
||||||
|
resources: new fields.SchemaField({
|
||||||
|
hp: new fields.SchemaField({
|
||||||
|
key: new fields.StringField({ initial: "hp" }),
|
||||||
|
label: new fields.StringField({ initial: "BOL.resources.hp" }),
|
||||||
|
ismain: new fields.BooleanField({ initial: true }),
|
||||||
|
base: new fields.NumberField({ ...requiredInteger, initial: 1 }),
|
||||||
|
value: new fields.NumberField({ ...requiredInteger, initial: 1 }),
|
||||||
|
bonus: new fields.NumberField({ ...requiredInteger, initial: 0 }),
|
||||||
|
max: new fields.NumberField({ ...requiredInteger, initial: 1 })
|
||||||
|
}),
|
||||||
|
hero: new fields.SchemaField({
|
||||||
|
key: new fields.StringField({ initial: "hero" }),
|
||||||
|
label: new fields.StringField({ initial: "BOL.resources.hero" }),
|
||||||
|
ismain: new fields.BooleanField({ initial: true }),
|
||||||
|
value: new fields.NumberField({ ...requiredInteger, initial: 5 }),
|
||||||
|
max: new fields.NumberField({ ...requiredInteger, initial: 5 })
|
||||||
|
}),
|
||||||
|
faith: new fields.SchemaField({
|
||||||
|
key: new fields.StringField({ initial: "faith" }),
|
||||||
|
label: new fields.StringField({ initial: "BOL.resources.faith" }),
|
||||||
|
ismain: new fields.BooleanField({ initial: true }),
|
||||||
|
value: new fields.NumberField({ ...requiredInteger, initial: 0 }),
|
||||||
|
max: new fields.NumberField({ ...requiredInteger, initial: 0 })
|
||||||
|
}),
|
||||||
|
power: new fields.SchemaField({
|
||||||
|
key: new fields.StringField({ initial: "power" }),
|
||||||
|
label: new fields.StringField({ initial: "BOL.resources.power" }),
|
||||||
|
ismain: new fields.BooleanField({ initial: true }),
|
||||||
|
value: new fields.NumberField({ ...requiredInteger, initial: 0 }),
|
||||||
|
bonus: new fields.NumberField({ ...requiredInteger, initial: 0 }),
|
||||||
|
max: new fields.NumberField({ ...requiredInteger, initial: 0 })
|
||||||
|
}),
|
||||||
|
alchemypoints: new fields.SchemaField({
|
||||||
|
key: new fields.StringField({ initial: "alchemypoints" }),
|
||||||
|
label: new fields.StringField({ initial: "BOL.resources.alchemypoints" }),
|
||||||
|
ismain: new fields.BooleanField({ initial: false }),
|
||||||
|
value: new fields.NumberField({ ...requiredInteger, initial: 0 }),
|
||||||
|
bonus: new fields.NumberField({ ...requiredInteger, initial: 0 }),
|
||||||
|
max: new fields.NumberField({ ...requiredInteger, initial: 0 })
|
||||||
|
}),
|
||||||
|
astrologypoints: new fields.SchemaField({
|
||||||
|
key: new fields.StringField({ initial: "astrologypoints" }),
|
||||||
|
label: new fields.StringField({ initial: "BOL.resources.astrologypoints" }),
|
||||||
|
ismain: new fields.BooleanField({ initial: false }),
|
||||||
|
value: new fields.NumberField({ ...requiredInteger, initial: 0 }),
|
||||||
|
bonus: new fields.NumberField({ ...requiredInteger, initial: 0 }),
|
||||||
|
max: new fields.NumberField({ ...requiredInteger, initial: 0 })
|
||||||
|
})
|
||||||
|
})
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static LOCALIZATION_PREFIXES = ["BOL.Encounter"];
|
||||||
|
}
|
||||||
55
module/models/feature.mjs
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
/**
|
||||||
|
* Data model for Feature items
|
||||||
|
*/
|
||||||
|
export default class BoLFeatureDataModel extends foundry.abstract.TypeDataModel {
|
||||||
|
static defineSchema() {
|
||||||
|
const fields = foundry.data.fields;
|
||||||
|
const requiredInteger = { required: true, nullable: false, integer: true };
|
||||||
|
const nullableNumber = { required: false, nullable: true, initial: null };
|
||||||
|
|
||||||
|
return {
|
||||||
|
// Base fields
|
||||||
|
category: new fields.StringField({ initial: "" }),
|
||||||
|
subtype: new fields.StringField({ initial: "default" }),
|
||||||
|
description: new fields.HTMLField({ initial: "" }),
|
||||||
|
properties: new fields.SchemaField({
|
||||||
|
// Career
|
||||||
|
sorcerer: new fields.BooleanField({ initial: false }),
|
||||||
|
alchemist: new fields.BooleanField({ initial: false }),
|
||||||
|
priest: new fields.BooleanField({ initial: false }),
|
||||||
|
astrologer: new fields.BooleanField({ initial: false }),
|
||||||
|
|
||||||
|
// Boon
|
||||||
|
isbonusdice: new fields.BooleanField({ initial: false }),
|
||||||
|
|
||||||
|
// Flaw
|
||||||
|
ismalusdice: new fields.BooleanField({ initial: false }),
|
||||||
|
|
||||||
|
// Fight option
|
||||||
|
fightoptiontype: new fields.StringField({ initial: "" }),
|
||||||
|
activated: new fields.BooleanField({ initial: false }),
|
||||||
|
isspecial: new fields.BooleanField({ initial: false }),
|
||||||
|
|
||||||
|
// Effect (boleffect)
|
||||||
|
identifier: new fields.StringField({ initial: "" }),
|
||||||
|
modifier: new fields.StringField({ initial: "" }),
|
||||||
|
|
||||||
|
// Horoscope
|
||||||
|
horoscopeanswer: new fields.StringField({ initial: "" }),
|
||||||
|
rank: new fields.NumberField({ ...nullableNumber }),
|
||||||
|
|
||||||
|
// XP log
|
||||||
|
xptype: new fields.StringField({ initial: "" }),
|
||||||
|
xpdate: new fields.StringField({ initial: "" }),
|
||||||
|
xpname: new fields.StringField({ initial: "" }),
|
||||||
|
xpcost: new fields.NumberField({ ...nullableNumber }),
|
||||||
|
xpvalue: new fields.NumberField({ ...nullableNumber }),
|
||||||
|
}),
|
||||||
|
|
||||||
|
// Feature-specific fields
|
||||||
|
rank: new fields.NumberField({ ...requiredInteger, initial: 0 })
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static LOCALIZATION_PREFIXES = ["BOL.Feature"];
|
||||||
|
}
|
||||||
174
module/models/horde.mjs
Normal file
@@ -0,0 +1,174 @@
|
|||||||
|
/**
|
||||||
|
* Data model for Horde actors
|
||||||
|
*/
|
||||||
|
export default class BoLHordeDataModel extends foundry.abstract.TypeDataModel {
|
||||||
|
static defineSchema() {
|
||||||
|
const fields = foundry.data.fields;
|
||||||
|
const requiredInteger = { required: true, nullable: false, integer: true };
|
||||||
|
|
||||||
|
return {
|
||||||
|
// Details
|
||||||
|
details: new fields.SchemaField({
|
||||||
|
biography: new fields.HTMLField({ initial: "" }),
|
||||||
|
notes: new fields.HTMLField({ initial: "" }),
|
||||||
|
height: new fields.StringField({ initial: "" }),
|
||||||
|
age: new fields.StringField({ initial: "" }),
|
||||||
|
weight: new fields.StringField({ initial: "" }),
|
||||||
|
hair: new fields.StringField({ initial: "" }),
|
||||||
|
eyes: new fields.StringField({ initial: "" }),
|
||||||
|
signs: new fields.StringField({ initial: "" }),
|
||||||
|
size: new fields.StringField({ initial: "" }),
|
||||||
|
languages: new fields.ArrayField(new fields.StringField(), { initial: [] }),
|
||||||
|
xplog: new fields.ArrayField(new fields.ObjectField(), { initial: [] })
|
||||||
|
}),
|
||||||
|
|
||||||
|
// Combat
|
||||||
|
combat: new fields.SchemaField({
|
||||||
|
lastinit: new fields.NumberField({ ...requiredInteger, initial: 0 }),
|
||||||
|
iscritical: new fields.BooleanField({ initial: false }),
|
||||||
|
isfumble: new fields.BooleanField({ initial: false }),
|
||||||
|
islegendary: new fields.BooleanField({ initial: false })
|
||||||
|
}),
|
||||||
|
|
||||||
|
// Character type
|
||||||
|
chartype: new fields.StringField({ initial: "horde" }),
|
||||||
|
villainy: new fields.BooleanField({ initial: false }),
|
||||||
|
hordesize: new fields.NumberField({ ...requiredInteger, initial: 1 }),
|
||||||
|
hordebasehp: new fields.NumberField({ ...requiredInteger, initial: 1 }),
|
||||||
|
hasdamagerule: new fields.BooleanField({ initial: false }),
|
||||||
|
damagerule: new fields.StringField({ initial: "none" }),
|
||||||
|
|
||||||
|
// Protection
|
||||||
|
prot: new fields.SchemaField({
|
||||||
|
key: new fields.StringField({ initial: "prot" }),
|
||||||
|
label: new fields.StringField({ initial: "BOL.aptitudes.prot" }),
|
||||||
|
base: new fields.NumberField({ ...requiredInteger, initial: 0 }),
|
||||||
|
value: new fields.NumberField({ ...requiredInteger, initial: 0 }),
|
||||||
|
bonus: new fields.NumberField({ ...requiredInteger, initial: 0 })
|
||||||
|
}),
|
||||||
|
|
||||||
|
// Attributes
|
||||||
|
attributes: new fields.SchemaField({
|
||||||
|
vigor: new fields.SchemaField({
|
||||||
|
key: new fields.StringField({ initial: "vigor" }),
|
||||||
|
label: new fields.StringField({ initial: "BOL.attributes.vigor" }),
|
||||||
|
base: new fields.NumberField({ ...requiredInteger, initial: 0 }),
|
||||||
|
value: new fields.NumberField({ ...requiredInteger, initial: 0 }),
|
||||||
|
min: new fields.NumberField({ ...requiredInteger, initial: -1 }),
|
||||||
|
max: new fields.NumberField({ ...requiredInteger, initial: 5 }),
|
||||||
|
bonus: new fields.NumberField({ ...requiredInteger, initial: 0 })
|
||||||
|
}),
|
||||||
|
agility: new fields.SchemaField({
|
||||||
|
key: new fields.StringField({ initial: "agility" }),
|
||||||
|
label: new fields.StringField({ initial: "BOL.attributes.agility" }),
|
||||||
|
base: new fields.NumberField({ ...requiredInteger, initial: 0 }),
|
||||||
|
value: new fields.NumberField({ ...requiredInteger, initial: 0 }),
|
||||||
|
min: new fields.NumberField({ ...requiredInteger, initial: -1 }),
|
||||||
|
max: new fields.NumberField({ ...requiredInteger, initial: 5 }),
|
||||||
|
bonus: new fields.NumberField({ ...requiredInteger, initial: 0 })
|
||||||
|
}),
|
||||||
|
mind: new fields.SchemaField({
|
||||||
|
key: new fields.StringField({ initial: "mind" }),
|
||||||
|
label: new fields.StringField({ initial: "BOL.attributes.mind" }),
|
||||||
|
base: new fields.NumberField({ ...requiredInteger, initial: 0 }),
|
||||||
|
value: new fields.NumberField({ ...requiredInteger, initial: 0 }),
|
||||||
|
min: new fields.NumberField({ ...requiredInteger, initial: -1 }),
|
||||||
|
max: new fields.NumberField({ ...requiredInteger, initial: 5 }),
|
||||||
|
bonus: new fields.NumberField({ ...requiredInteger, initial: 0 })
|
||||||
|
}),
|
||||||
|
appeal: new fields.SchemaField({
|
||||||
|
key: new fields.StringField({ initial: "appeal" }),
|
||||||
|
label: new fields.StringField({ initial: "BOL.attributes.appeal" }),
|
||||||
|
base: new fields.NumberField({ ...requiredInteger, initial: 0 }),
|
||||||
|
value: new fields.NumberField({ ...requiredInteger, initial: 0 }),
|
||||||
|
bonus: new fields.NumberField({ ...requiredInteger, initial: 0 })
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
|
||||||
|
// Aptitudes
|
||||||
|
aptitudes: new fields.SchemaField({
|
||||||
|
init: new fields.SchemaField({
|
||||||
|
key: new fields.StringField({ initial: "init" }),
|
||||||
|
label: new fields.StringField({ initial: "BOL.aptitudes.init" }),
|
||||||
|
base: new fields.NumberField({ ...requiredInteger, initial: 0 }),
|
||||||
|
value: new fields.NumberField({ ...requiredInteger, initial: 0 }),
|
||||||
|
bonus: new fields.NumberField({ ...requiredInteger, initial: 0 })
|
||||||
|
}),
|
||||||
|
melee: new fields.SchemaField({
|
||||||
|
key: new fields.StringField({ initial: "melee" }),
|
||||||
|
label: new fields.StringField({ initial: "BOL.aptitudes.melee" }),
|
||||||
|
base: new fields.NumberField({ ...requiredInteger, initial: 0 }),
|
||||||
|
value: new fields.NumberField({ ...requiredInteger, initial: 0 }),
|
||||||
|
bonus: new fields.NumberField({ ...requiredInteger, initial: 0 })
|
||||||
|
}),
|
||||||
|
ranged: new fields.SchemaField({
|
||||||
|
key: new fields.StringField({ initial: "ranged" }),
|
||||||
|
label: new fields.StringField({ initial: "BOL.aptitudes.ranged" }),
|
||||||
|
base: new fields.NumberField({ ...requiredInteger, initial: 0 }),
|
||||||
|
value: new fields.NumberField({ ...requiredInteger, initial: 0 }),
|
||||||
|
bonus: new fields.NumberField({ ...requiredInteger, initial: 0 })
|
||||||
|
}),
|
||||||
|
def: new fields.SchemaField({
|
||||||
|
key: new fields.StringField({ initial: "def" }),
|
||||||
|
label: new fields.StringField({ initial: "BOL.aptitudes.def" }),
|
||||||
|
base: new fields.NumberField({ ...requiredInteger, initial: 0 }),
|
||||||
|
value: new fields.NumberField({ ...requiredInteger, initial: 0 }),
|
||||||
|
bonus: new fields.NumberField({ ...requiredInteger, initial: 0 })
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
|
||||||
|
// Resources
|
||||||
|
resources: new fields.SchemaField({
|
||||||
|
hp: new fields.SchemaField({
|
||||||
|
key: new fields.StringField({ initial: "hp" }),
|
||||||
|
label: new fields.StringField({ initial: "BOL.resources.hp" }),
|
||||||
|
ismain: new fields.BooleanField({ initial: true }),
|
||||||
|
base: new fields.NumberField({ ...requiredInteger, initial: 1 }),
|
||||||
|
value: new fields.NumberField({ ...requiredInteger, initial: 1 }),
|
||||||
|
bonus: new fields.NumberField({ ...requiredInteger, initial: 0 }),
|
||||||
|
max: new fields.NumberField({ ...requiredInteger, initial: 1 })
|
||||||
|
}),
|
||||||
|
hero: new fields.SchemaField({
|
||||||
|
key: new fields.StringField({ initial: "hero" }),
|
||||||
|
label: new fields.StringField({ initial: "BOL.resources.hero" }),
|
||||||
|
ismain: new fields.BooleanField({ initial: true }),
|
||||||
|
value: new fields.NumberField({ ...requiredInteger, initial: 5 }),
|
||||||
|
max: new fields.NumberField({ ...requiredInteger, initial: 5 })
|
||||||
|
}),
|
||||||
|
faith: new fields.SchemaField({
|
||||||
|
key: new fields.StringField({ initial: "faith" }),
|
||||||
|
label: new fields.StringField({ initial: "BOL.resources.faith" }),
|
||||||
|
ismain: new fields.BooleanField({ initial: true }),
|
||||||
|
value: new fields.NumberField({ ...requiredInteger, initial: 0 }),
|
||||||
|
max: new fields.NumberField({ ...requiredInteger, initial: 0 })
|
||||||
|
}),
|
||||||
|
power: new fields.SchemaField({
|
||||||
|
key: new fields.StringField({ initial: "power" }),
|
||||||
|
label: new fields.StringField({ initial: "BOL.resources.power" }),
|
||||||
|
ismain: new fields.BooleanField({ initial: true }),
|
||||||
|
value: new fields.NumberField({ ...requiredInteger, initial: 0 }),
|
||||||
|
bonus: new fields.NumberField({ ...requiredInteger, initial: 0 }),
|
||||||
|
max: new fields.NumberField({ ...requiredInteger, initial: 0 })
|
||||||
|
}),
|
||||||
|
alchemypoints: new fields.SchemaField({
|
||||||
|
key: new fields.StringField({ initial: "alchemypoints" }),
|
||||||
|
label: new fields.StringField({ initial: "BOL.resources.alchemypoints" }),
|
||||||
|
ismain: new fields.BooleanField({ initial: false }),
|
||||||
|
value: new fields.NumberField({ ...requiredInteger, initial: 0 }),
|
||||||
|
bonus: new fields.NumberField({ ...requiredInteger, initial: 0 }),
|
||||||
|
max: new fields.NumberField({ ...requiredInteger, initial: 0 })
|
||||||
|
}),
|
||||||
|
astrologypoints: new fields.SchemaField({
|
||||||
|
key: new fields.StringField({ initial: "astrologypoints" }),
|
||||||
|
label: new fields.StringField({ initial: "BOL.resources.astrologypoints" }),
|
||||||
|
ismain: new fields.BooleanField({ initial: false }),
|
||||||
|
value: new fields.NumberField({ ...requiredInteger, initial: 0 }),
|
||||||
|
bonus: new fields.NumberField({ ...requiredInteger, initial: 0 }),
|
||||||
|
max: new fields.NumberField({ ...requiredInteger, initial: 0 })
|
||||||
|
})
|
||||||
|
})
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static LOCALIZATION_PREFIXES = ["BOL.Horde"];
|
||||||
|
}
|
||||||
113
module/models/item.mjs
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
/**
|
||||||
|
* Data model for Item items
|
||||||
|
*/
|
||||||
|
export default class BoLItemDataModel extends foundry.abstract.TypeDataModel {
|
||||||
|
static defineSchema() {
|
||||||
|
const fields = foundry.data.fields;
|
||||||
|
const requiredInteger = { required: true, nullable: false, integer: true };
|
||||||
|
const nullableNumber = { required: false, nullable: true, initial: null };
|
||||||
|
|
||||||
|
return {
|
||||||
|
// Base fields
|
||||||
|
category: new fields.StringField({ initial: "" }),
|
||||||
|
subtype: new fields.StringField({ initial: "default" }),
|
||||||
|
description: new fields.HTMLField({ initial: "" }),
|
||||||
|
properties: new fields.SchemaField({
|
||||||
|
// Base flags
|
||||||
|
ranged: new fields.BooleanField({ initial: false }),
|
||||||
|
melee: new fields.BooleanField({ initial: false }),
|
||||||
|
spell: new fields.BooleanField({ initial: false }),
|
||||||
|
protection: new fields.BooleanField({ initial: false }),
|
||||||
|
weapon: new fields.BooleanField({ initial: false }),
|
||||||
|
armor: new fields.BooleanField({ initial: false }),
|
||||||
|
helm: new fields.BooleanField({ initial: false }),
|
||||||
|
shield: new fields.BooleanField({ initial: false }),
|
||||||
|
equipable: new fields.BooleanField({ initial: false }),
|
||||||
|
consumable: new fields.BooleanField({ initial: false }),
|
||||||
|
magical: new fields.BooleanField({ initial: false }),
|
||||||
|
"2H": new fields.BooleanField({ initial: false }),
|
||||||
|
reloadable: new fields.BooleanField({ initial: false }),
|
||||||
|
bow: new fields.BooleanField({ initial: false }),
|
||||||
|
crossbow: new fields.BooleanField({ initial: false }),
|
||||||
|
throwing: new fields.BooleanField({ initial: false }),
|
||||||
|
|
||||||
|
// Equipment
|
||||||
|
stackable: new fields.BooleanField({ initial: false }),
|
||||||
|
stacksize: new fields.NumberField({ ...nullableNumber }),
|
||||||
|
slot: new fields.StringField({ initial: "-" }),
|
||||||
|
|
||||||
|
// Weapon flags
|
||||||
|
natural: new fields.BooleanField({ initial: false }),
|
||||||
|
concealable: new fields.BooleanField({ initial: false }),
|
||||||
|
ignoreshield: new fields.BooleanField({ initial: false }),
|
||||||
|
attackBonusDice: new fields.BooleanField({ initial: false }),
|
||||||
|
attackMalusDice: new fields.BooleanField({ initial: false }),
|
||||||
|
onlymodifier: new fields.BooleanField({ initial: false }),
|
||||||
|
bashing: new fields.BooleanField({ initial: false }),
|
||||||
|
throwable: new fields.BooleanField({ initial: false }),
|
||||||
|
damageReroll1: new fields.BooleanField({ initial: false }),
|
||||||
|
|
||||||
|
// Weapon stats
|
||||||
|
attackAttribute: new fields.StringField({ initial: "vigor" }),
|
||||||
|
attackAptitude: new fields.StringField({ initial: "melee" }),
|
||||||
|
attackModifiers: new fields.NumberField({ ...nullableNumber }),
|
||||||
|
weaponSize: new fields.StringField({ initial: "unarmed" }),
|
||||||
|
damage: new fields.StringField({ initial: "0" }),
|
||||||
|
damageAttribute: new fields.StringField({ initial: "" }),
|
||||||
|
damageModifiers: new fields.NumberField({ ...nullableNumber }),
|
||||||
|
damageMultiplier: new fields.StringField({ initial: "1" }),
|
||||||
|
range: new fields.NumberField({ ...nullableNumber }),
|
||||||
|
reload: new fields.NumberField({ ...nullableNumber }),
|
||||||
|
|
||||||
|
// Protection
|
||||||
|
armorQuality: new fields.StringField({ initial: "" }),
|
||||||
|
soak: new fields.SchemaField({
|
||||||
|
formula: new fields.StringField({ initial: "" }),
|
||||||
|
value: new fields.NumberField({ initial: 0, nullable: true }),
|
||||||
|
modifier: new fields.NumberField({ initial: 0, nullable: true }),
|
||||||
|
}),
|
||||||
|
blocking: new fields.SchemaField({
|
||||||
|
malus: new fields.NumberField({ initial: 0, nullable: true }),
|
||||||
|
blocking1: new fields.BooleanField({ initial: false }),
|
||||||
|
blockingAll: new fields.BooleanField({ initial: false }),
|
||||||
|
}),
|
||||||
|
modifiers: new fields.SchemaField({
|
||||||
|
init: new fields.NumberField({ initial: 0, nullable: true }),
|
||||||
|
agility: new fields.NumberField({ initial: 0, nullable: true }),
|
||||||
|
powercost: new fields.NumberField({ initial: 0, nullable: true }),
|
||||||
|
social: new fields.BooleanField({ initial: false }),
|
||||||
|
}),
|
||||||
|
|
||||||
|
// Spell
|
||||||
|
circle: new fields.NumberField({ initial: 0, nullable: true }),
|
||||||
|
difficulty: new fields.StringField({ initial: "" }),
|
||||||
|
ppcost: new fields.NumberField({ initial: 0, nullable: true }),
|
||||||
|
duration: new fields.StringField({ initial: "" }),
|
||||||
|
nbmandatoryconditions: new fields.NumberField({ initial: 0, nullable: true }),
|
||||||
|
mandatoryconditions: new fields.ArrayField(new fields.StringField()),
|
||||||
|
optionnalconditions: new fields.ArrayField(new fields.StringField()),
|
||||||
|
|
||||||
|
// Alchemy
|
||||||
|
alchemytype: new fields.StringField({ initial: "" }),
|
||||||
|
pccost: new fields.NumberField({ initial: 0, nullable: true }),
|
||||||
|
pccurrent: new fields.NumberField({ initial: 0, nullable: true }),
|
||||||
|
|
||||||
|
// Vehicle weapon
|
||||||
|
isfiredamage: new fields.BooleanField({ initial: false }),
|
||||||
|
ishulldamage: new fields.BooleanField({ initial: false }),
|
||||||
|
iscrewdamage: new fields.BooleanField({ initial: false }),
|
||||||
|
isboarding: new fields.BooleanField({ initial: false }),
|
||||||
|
isspur: new fields.BooleanField({ initial: false }),
|
||||||
|
isbreakrow: new fields.BooleanField({ initial: false }),
|
||||||
|
}),
|
||||||
|
|
||||||
|
// Equipment fields
|
||||||
|
quantity: new fields.NumberField({ ...requiredInteger, initial: 1 }),
|
||||||
|
weight: new fields.NumberField({ initial: 0 }),
|
||||||
|
price: new fields.NumberField({ initial: 0 }),
|
||||||
|
worn: new fields.BooleanField({ initial: false })
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static LOCALIZATION_PREFIXES = ["BOL.Item"];
|
||||||
|
}
|
||||||
55
module/models/vehicle.mjs
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
/**
|
||||||
|
* Data model for Vehicle actors
|
||||||
|
*/
|
||||||
|
export default class BoLVehicleDataModel extends foundry.abstract.TypeDataModel {
|
||||||
|
static defineSchema() {
|
||||||
|
const fields = foundry.data.fields;
|
||||||
|
const requiredInteger = { required: true, nullable: false, integer: true };
|
||||||
|
|
||||||
|
return {
|
||||||
|
vehicletype: new fields.StringField({ initial: "boat" }),
|
||||||
|
|
||||||
|
attributes: new fields.SchemaField({
|
||||||
|
hull: new fields.SchemaField({
|
||||||
|
key: new fields.StringField({ initial: "hull" }),
|
||||||
|
label: new fields.StringField({ initial: "BOL.attributes.hull" }),
|
||||||
|
value: new fields.NumberField({ ...requiredInteger, initial: 0 }),
|
||||||
|
min: new fields.NumberField({ ...requiredInteger, initial: 0 }),
|
||||||
|
max: new fields.NumberField({ ...requiredInteger, initial: 5 })
|
||||||
|
}),
|
||||||
|
crew: new fields.SchemaField({
|
||||||
|
key: new fields.StringField({ initial: "crew" }),
|
||||||
|
label: new fields.StringField({ initial: "BOL.attributes.crew" }),
|
||||||
|
value: new fields.NumberField({ ...requiredInteger, initial: 0 }),
|
||||||
|
min: new fields.NumberField({ ...requiredInteger, initial: 0 }),
|
||||||
|
max: new fields.NumberField({ ...requiredInteger, initial: 5 })
|
||||||
|
}),
|
||||||
|
resources: new fields.SchemaField({
|
||||||
|
key: new fields.StringField({ initial: "resources" }),
|
||||||
|
label: new fields.StringField({ initial: "BOL.attributes.resources" }),
|
||||||
|
value: new fields.NumberField({ ...requiredInteger, initial: 0 }),
|
||||||
|
min: new fields.NumberField({ ...requiredInteger, initial: 0 }),
|
||||||
|
max: new fields.NumberField({ ...requiredInteger, initial: 5 })
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
|
||||||
|
row: new fields.SchemaField({
|
||||||
|
key: new fields.StringField({ initial: "row" }),
|
||||||
|
label: new fields.StringField({ initial: "BOL.attributes.row" }),
|
||||||
|
value: new fields.NumberField({ ...requiredInteger, initial: 0 }),
|
||||||
|
min: new fields.NumberField({ ...requiredInteger, initial: 0 }),
|
||||||
|
max: new fields.NumberField({ ...requiredInteger, initial: 5 })
|
||||||
|
}),
|
||||||
|
|
||||||
|
spur: new fields.SchemaField({
|
||||||
|
value: new fields.StringField({ initial: "" })
|
||||||
|
}),
|
||||||
|
|
||||||
|
status: new fields.SchemaField({}),
|
||||||
|
|
||||||
|
description: new fields.HTMLField({ initial: "" })
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static LOCALIZATION_PREFIXES = ["BOL.Vehicle"];
|
||||||
|
}
|
||||||
@@ -12,8 +12,8 @@ export class BoLTokenHud {
|
|||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
static async removeExtensionHud(app, html, tokenId) {
|
static async removeExtensionHud(app, html, tokenId) {
|
||||||
html.find('.control-icon.bol-roll').remove()
|
$(html).find('.control-icon.bol-roll').remove()
|
||||||
html.find('.control-icon.bol-action').remove()
|
$(html).find('.control-icon.bol-action').remove()
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
@@ -25,7 +25,7 @@ export class BoLTokenHud {
|
|||||||
|
|
||||||
const hudData = { actor: actor, actionsList: actor.buildListeActions(), rollsList: actor.buildRollList() }
|
const hudData = { actor: actor, actionsList: actor.buildListeActions(), rollsList: actor.buildRollList() }
|
||||||
|
|
||||||
const controlIconActions = html.find('.control-icon[data-action=combat]');
|
const controlIconActions = $(html).find('.control-icon[data-action=combat]');
|
||||||
// initiative
|
// initiative
|
||||||
await BoLTokenHud._configureSubMenu(controlIconActions, 'systems/bol/templates/token/hud-actor-actions.hbs', hudData,
|
await BoLTokenHud._configureSubMenu(controlIconActions, 'systems/bol/templates/token/hud-actor-actions.hbs', hudData,
|
||||||
(event) => {
|
(event) => {
|
||||||
@@ -43,7 +43,7 @@ export class BoLTokenHud {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const controlIconTarget = html.find('.control-icon[data-action=target]');
|
const controlIconTarget = $(html).find('.control-icon[data-action=target]');
|
||||||
// att+apt+career
|
// att+apt+career
|
||||||
await BoLTokenHud._configureSubMenu(controlIconTarget, 'systems/bol/templates/token/hud-actor-rolls.hbs', hudData,
|
await BoLTokenHud._configureSubMenu(controlIconTarget, 'systems/bol/templates/token/hud-actor-rolls.hbs', hudData,
|
||||||
(event) => {
|
(event) => {
|
||||||
@@ -59,7 +59,7 @@ export class BoLTokenHud {
|
|||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
static async addTokenHudExtensions(app, html, tokenId) {
|
static async addTokenHudExtensions(app, html, tokenId) {
|
||||||
const controlIconCombat = html.find('.control-icon[data-action=combat]')
|
const controlIconCombat = $(html).find('.control-icon[data-action=combat]')
|
||||||
if (controlIconCombat.length > 0) {
|
if (controlIconCombat.length > 0) {
|
||||||
BoLTokenHud.addExtensionHud(app, html, tokenId);
|
BoLTokenHud.addExtensionHud(app, html, tokenId);
|
||||||
}
|
}
|
||||||
@@ -67,7 +67,7 @@ export class BoLTokenHud {
|
|||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
static async _configureSubMenu(insertionPoint, template, hudData, onMenuItem) {
|
static async _configureSubMenu(insertionPoint, template, hudData, onMenuItem) {
|
||||||
const hud = $(await renderTemplate(template, hudData))
|
const hud = $(await foundry.applications.handlebars.renderTemplate(template, hudData))
|
||||||
const list = hud.find('div.bol-hud-list')
|
const list = hud.find('div.bol-hud-list')
|
||||||
|
|
||||||
BoLTokenHud._toggleHudListActive(hud, list);
|
BoLTokenHud._toggleHudListActive(hud, list);
|
||||||
|
|||||||
@@ -221,10 +221,10 @@ export class BoLCalendar extends Application {
|
|||||||
let hn = defHeure.heure;
|
let hn = defHeure.heure;
|
||||||
let chiffreAstral = this.getCurrentNombreAstral() ?? 0;
|
let chiffreAstral = this.getCurrentNombreAstral() ?? 0;
|
||||||
heuresChancesMalchances[0] = { value : "+4", heures: [this.getHeureNumber((hn + chiffreAstral) % RDD_HEURES_PAR_JOUR).label]};
|
heuresChancesMalchances[0] = { value : "+4", heures: [this.getHeureNumber((hn + chiffreAstral) % RDD_HEURES_PAR_JOUR).label]};
|
||||||
heuresChancesMalchances[1] = { value : "+2", heures: [this.getHeureNumber((hn + chiffreAstral+4) % RDD_HEURES_PAR_JOUR).label,
|
heuresChancesMalchances[1] = { value : "+2", heures: [this.getHeureNumber((hn + chiffreAstral+4) % RDD_HEURES_PAR_JOUR).label,
|
||||||
this.getHeureNumber((hn + chiffreAstral + 8) % RDD_HEURES_PAR_JOUR).label ] };
|
this.getHeureNumber((hn + chiffreAstral + 8) % RDD_HEURES_PAR_JOUR).label ] };
|
||||||
heuresChancesMalchances[2] = { value : "-4", heures: [this.getHeureNumber((hn + chiffreAstral+6) % RDD_HEURES_PAR_JOUR).label]};
|
heuresChancesMalchances[2] = { value : "-4", heures: [this.getHeureNumber((hn + chiffreAstral+6) % RDD_HEURES_PAR_JOUR).label]};
|
||||||
heuresChancesMalchances[3] = { value : "-2", heures: [this.getHeureNumber((hn + chiffreAstral+3) % RDD_HEURES_PAR_JOUR).label,
|
heuresChancesMalchances[3] = { value : "-2", heures: [this.getHeureNumber((hn + chiffreAstral+3) % RDD_HEURES_PAR_JOUR).label,
|
||||||
this.getHeureNumber((hn + chiffreAstral + 9) % RDD_HEURES_PAR_JOUR).label ]};
|
this.getHeureNumber((hn + chiffreAstral + 9) % RDD_HEURES_PAR_JOUR).label ]};
|
||||||
}
|
}
|
||||||
return heuresChancesMalchances;
|
return heuresChancesMalchances;
|
||||||
@@ -331,7 +331,7 @@ export class BoLCalendar extends Application {
|
|||||||
calendrierData.jourMoisOptions = RdDCalendrier.buildJoursMois();
|
calendrierData.jourMoisOptions = RdDCalendrier.buildJoursMois();
|
||||||
calendrierData.heuresOptions = [0, 1];
|
calendrierData.heuresOptions = [0, 1];
|
||||||
calendrierData.minutesOptions = Array(RDD_MINUTES_PAR_HEURES).fill().map((item, index) => 0 + index);
|
calendrierData.minutesOptions = Array(RDD_MINUTES_PAR_HEURES).fill().map((item, index) => 0 + index);
|
||||||
let html = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/calendar-editor-template.html', calendrierData);
|
let html = await foundry.applications.handlebars.renderTemplate('systems/foundryvtt-reve-de-dragon/templates/calendar-editor-template.html', calendrierData);
|
||||||
this.editeur = new RdDCalendrierEditeur(html, this, calendrierData)
|
this.editeur = new RdDCalendrierEditeur(html, this, calendrierData)
|
||||||
}
|
}
|
||||||
this.editeur.updateData(calendrierData);
|
this.editeur.updateData(calendrierData);
|
||||||
@@ -360,7 +360,7 @@ export class BoLCalendar extends Application {
|
|||||||
let heureNaissance = actor.getHeureNaissance();
|
let heureNaissance = actor.getHeureNaissance();
|
||||||
if ( heureNaissance) {
|
if ( heureNaissance) {
|
||||||
heuresParActeur[actor.name] = this.getHeuresChanceMalchance(heureNaissance);
|
heuresParActeur[actor.name] = this.getHeuresChanceMalchance(heureNaissance);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//console.log("ASTRO", astrologieArray);
|
//console.log("ASTRO", astrologieArray);
|
||||||
calendrierData.astrologieData = astrologieArray;
|
calendrierData.astrologieData = astrologieArray;
|
||||||
@@ -398,7 +398,7 @@ export class BoLCalendar extends Application {
|
|||||||
let isRightMB = false;
|
let isRightMB = false;
|
||||||
if ("which" in ev) { // Gecko (Firefox), WebKit (Safari/Chrome) & Opera
|
if ("which" in ev) { // Gecko (Firefox), WebKit (Safari/Chrome) & Opera
|
||||||
isRightMB = ev.which == 3;
|
isRightMB = ev.which == 3;
|
||||||
} else if ("button" in ev) { // IE, Opera
|
} else if ("button" in ev) { // IE, Opera
|
||||||
isRightMB = ev.button == 2;
|
isRightMB = ev.button == 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ export class BoLUtility {
|
|||||||
})
|
})
|
||||||
game.settings.register("bol", "auto-remove-dead", {
|
game.settings.register("bol", "auto-remove-dead", {
|
||||||
name: game.i18n.localize("BOL.settings.removeDead"),
|
name: game.i18n.localize("BOL.settings.removeDead"),
|
||||||
hint: game.i18n.localize("BOL.settings.removeDeadTooltip"),
|
hint: game.i18n.localize("BOL.settings.removeDeadTooltip"),
|
||||||
scope: "world",
|
scope: "world",
|
||||||
config: true,
|
config: true,
|
||||||
default: false,
|
default: false,
|
||||||
@@ -237,6 +237,11 @@ export class BoLUtility {
|
|||||||
if (chatData.img.includes("/blank.png")) {
|
if (chatData.img.includes("/blank.png")) {
|
||||||
chatData.img = null;
|
chatData.img = null;
|
||||||
}
|
}
|
||||||
|
// For old-format weapon items lacking stat fields, apply defaults so the chat card can display them
|
||||||
|
if (chatData.system?.properties?.weapon && !chatData.system.properties.damage) {
|
||||||
|
const defaults = game.bol.config.defaultNaturalWeapon?.properties ?? {};
|
||||||
|
chatData.system.properties = Object.assign(foundry.utils.duplicate(defaults), chatData.system.properties);
|
||||||
|
}
|
||||||
// JSON object for easy creation
|
// JSON object for easy creation
|
||||||
chatData.jsondata = JSON.stringify(
|
chatData.jsondata = JSON.stringify(
|
||||||
{
|
{
|
||||||
@@ -244,7 +249,7 @@ export class BoLUtility {
|
|||||||
payload: chatData,
|
payload: chatData,
|
||||||
});
|
});
|
||||||
|
|
||||||
renderTemplate('systems/bol/templates/item/post-item.hbs', chatData).then(html => {
|
foundry.applications.handlebars.renderTemplate('systems/bol/templates/item/post-item.hbs', chatData).then(html => {
|
||||||
let chatOptions = BoLUtility.chatDataSetup(html);
|
let chatOptions = BoLUtility.chatDataSetup(html);
|
||||||
ChatMessage.create(chatOptions)
|
ChatMessage.create(chatOptions)
|
||||||
});
|
});
|
||||||
@@ -344,7 +349,7 @@ export class BoLUtility {
|
|||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
static async chatMessageHandler(message, html, data) {
|
static async chatMessageHandler(message, html, data) {
|
||||||
const chatCard = html.find('.flavor-text')
|
const chatCard = $(html).find('.flavor-text')
|
||||||
if (chatCard.length > 0) {
|
if (chatCard.length > 0) {
|
||||||
// If the user is the message author or the actor owner, proceed
|
// If the user is the message author or the actor owner, proceed
|
||||||
const actor = game.actors.get(data.message.speaker.actor)
|
const actor = game.actors.get(data.message.speaker.actor)
|
||||||
@@ -381,6 +386,8 @@ export class BoLUtility {
|
|||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
static async chatListeners(html) {
|
static async chatListeners(html) {
|
||||||
|
|
||||||
|
html = $(html);
|
||||||
|
|
||||||
// Damage handling
|
// Damage handling
|
||||||
html.on("click", '.chat-damage-apply', event => {
|
html.on("click", '.chat-damage-apply', event => {
|
||||||
let rollData = BoLUtility.getRollDataFromMessage(event)
|
let rollData = BoLUtility.getRollDataFromMessage(event)
|
||||||
@@ -388,6 +395,16 @@ export class BoLUtility {
|
|||||||
BoLUtility.sendAttackSuccess(rollData)
|
BoLUtility.sendAttackSuccess(rollData)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
html.on("click", '.chat-target-select', event => {
|
||||||
|
event.preventDefault()
|
||||||
|
const btn = event.currentTarget
|
||||||
|
let rollData = BoLUtility.getRollDataFromMessage(event)
|
||||||
|
rollData.targetId = btn.dataset.tokenId
|
||||||
|
rollData.defenderId = btn.dataset.actorId
|
||||||
|
BoLUtility.cleanupButtons(rollData.applyId)
|
||||||
|
BoLUtility.sendAttackSuccess(rollData)
|
||||||
|
});
|
||||||
|
|
||||||
html.on("click", '.chat-damage-roll', event => {
|
html.on("click", '.chat-damage-roll', event => {
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
let rollData = BoLUtility.getRollDataFromMessage(event)
|
let rollData = BoLUtility.getRollDataFromMessage(event)
|
||||||
@@ -427,7 +444,7 @@ export class BoLUtility {
|
|||||||
html.on("click", '.damage-handling', event => {
|
html.on("click", '.damage-handling', event => {
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
let attr = event.currentTarget.attributes['data-attack-id']
|
let attr = event.currentTarget.attributes['data-attack-id']
|
||||||
if ( !attr) {
|
if (!attr) {
|
||||||
ui.notifications.warn("Impossible de trouver l'attaque correspondante, erreur de suivi de combat.")
|
ui.notifications.warn("Impossible de trouver l'attaque correspondante, erreur de suivi de combat.")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -480,13 +497,17 @@ export class BoLUtility {
|
|||||||
|
|
||||||
if (defenseMode == 'damage-with-armor') {
|
if (defenseMode == 'damage-with-armor') {
|
||||||
let armorFormula = defender.getArmorFormula()
|
let armorFormula = defender.getArmorFormula()
|
||||||
rollData.rollArmor = new Roll(armorFormula)
|
if (armorFormula === "0") {
|
||||||
await rollData.rollArmor.roll()
|
rollData.armorProtect = 0
|
||||||
let msg = await rollData.rollArmor.toMessage({ flavor: "BOL.chat.armorRoll : " + armorFormula });
|
} else {
|
||||||
if ( game.dice3d) { // wait animation end when DsN is there
|
rollData.rollArmor = new Roll(armorFormula)
|
||||||
await game.dice3d.waitFor3DAnimationByMessageID(msg.id);
|
await rollData.rollArmor.roll()
|
||||||
|
let msg = await rollData.rollArmor.toMessage({ flavor: game.i18n.localize("BOL.chat.armorRoll") + " : " + armorFormula })
|
||||||
|
if (game.dice3d && msg) {
|
||||||
|
await game.dice3d.waitFor3DAnimationByMessageID(msg.id)
|
||||||
|
}
|
||||||
|
rollData.armorProtect = (rollData.rollArmor.total < 0) ? 0 : rollData.rollArmor.total
|
||||||
}
|
}
|
||||||
rollData.armorProtect = (rollData.rollArmor.total < 0) ? 0 : rollData.rollArmor.total
|
|
||||||
rollData.finalDamage = rollData.damageTotal - rollData.armorProtect
|
rollData.finalDamage = rollData.damageTotal - rollData.armorProtect
|
||||||
rollData.finalDamage = (rollData.finalDamage < 0) ? 0 : rollData.finalDamage
|
rollData.finalDamage = (rollData.finalDamage < 0) ? 0 : rollData.finalDamage
|
||||||
await defender.sufferDamage(rollData.finalDamage)
|
await defender.sufferDamage(rollData.finalDamage)
|
||||||
@@ -498,9 +519,17 @@ export class BoLUtility {
|
|||||||
}
|
}
|
||||||
if (defenseMode == 'hero-reduce-damage') {
|
if (defenseMode == 'hero-reduce-damage') {
|
||||||
let armorFormula = defender.getArmorFormula()
|
let armorFormula = defender.getArmorFormula()
|
||||||
rollData.rollArmor = new Roll(armorFormula)
|
if (armorFormula === "0") {
|
||||||
await rollData.rollArmor.roll()
|
rollData.armorProtect = 0
|
||||||
rollData.armorProtect = (rollData.rollArmor.total < 0) ? 0 : rollData.rollArmor.total
|
} else {
|
||||||
|
rollData.rollArmor = new Roll(armorFormula)
|
||||||
|
await rollData.rollArmor.roll()
|
||||||
|
let msg = await rollData.rollArmor.toMessage({ flavor: game.i18n.localize("BOL.chat.armorRoll") + " : " + armorFormula })
|
||||||
|
if (game.dice3d && msg) {
|
||||||
|
await game.dice3d.waitFor3DAnimationByMessageID(msg.id)
|
||||||
|
}
|
||||||
|
rollData.armorProtect = (rollData.rollArmor.total < 0) ? 0 : rollData.rollArmor.total
|
||||||
|
}
|
||||||
rollData.rollHero = new Roll("1d6")
|
rollData.rollHero = new Roll("1d6")
|
||||||
await rollData.rollHero.roll()
|
await rollData.rollHero.roll()
|
||||||
rollData.finalDamage = rollData.damageTotal - rollData.rollHero.total - rollData.armorProtect
|
rollData.finalDamage = rollData.damageTotal - rollData.rollHero.total - rollData.armorProtect
|
||||||
@@ -535,13 +564,13 @@ export class BoLUtility {
|
|||||||
ChatMessage.create({
|
ChatMessage.create({
|
||||||
alias: defender.name,
|
alias: defender.name,
|
||||||
whisper: BoLUtility.getWhisperRecipientsAndGMs(defender.name),
|
whisper: BoLUtility.getWhisperRecipientsAndGMs(defender.name),
|
||||||
content: await renderTemplate('systems/bol/templates/chat/rolls/defense-result-card.hbs', damageResults)
|
content: await foundry.applications.handlebars.renderTemplate('systems/bol/templates/chat/rolls/defense-result-card.hbs', damageResults)
|
||||||
})
|
})
|
||||||
console.log("Defender data : ", defenderUser)
|
console.log("Defender data : ", defenderUser)
|
||||||
ChatMessage.create({
|
ChatMessage.create({
|
||||||
alias: defender.name,
|
alias: defender.name,
|
||||||
whisper: BoLUtility.getOtherWhisperRecipients(defenderUser?.name),
|
whisper: BoLUtility.getOtherWhisperRecipients(defenderUser?.name),
|
||||||
content: await renderTemplate('systems/bol/templates/chat/rolls/defense-summary-card.hbs', damageResults)
|
content: await foundry.applications.handlebars.renderTemplate('systems/bol/templates/chat/rolls/defense-summary-card.hbs', damageResults)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -628,11 +657,11 @@ export class BoLUtility {
|
|||||||
let msg = await ChatMessage.create({
|
let msg = await ChatMessage.create({
|
||||||
alias: defender.name,
|
alias: defender.name,
|
||||||
whisper: BoLUtility.getWhisperRecipientsAndGMs(defender.name),
|
whisper: BoLUtility.getWhisperRecipientsAndGMs(defender.name),
|
||||||
content: await renderTemplate('systems/bol/templates/chat/rolls/defense-request-card.hbs', {
|
content: await foundry.applications.handlebars.renderTemplate('systems/bol/templates/chat/rolls/defense-request-card.hbs', {
|
||||||
attackId: rollData.id,
|
attackId: rollData.id,
|
||||||
attacker: rollData.attacker,
|
attacker: rollData.attacker,
|
||||||
defender: defender,
|
defender: defender,
|
||||||
defenderHeroPoints:defender.getHeroPoints(),
|
defenderHeroPoints: defender.getHeroPoints(),
|
||||||
defenderWeapons: defenderWeapons,
|
defenderWeapons: defenderWeapons,
|
||||||
damageTotal: rollData.damageTotal,
|
damageTotal: rollData.damageTotal,
|
||||||
damagesIgnoresArmor: rollData.damagesIgnoresArmor,
|
damagesIgnoresArmor: rollData.damagesIgnoresArmor,
|
||||||
|
|||||||
@@ -188,19 +188,25 @@ BOL.rangeModifiers = {
|
|||||||
"-8": "BOL.dialog.utmost"
|
"-8": "BOL.dialog.utmost"
|
||||||
}
|
}
|
||||||
|
|
||||||
BOL.difficultyModifiers = {
|
BOL.difficultyModifiers = [
|
||||||
"4": "BOL.dialog.soeasy",
|
{ value: "-12", label: "BOL.dialog.divine" },
|
||||||
"2": "BOL.dialog.veryeasy",
|
{ value: "-11", label: "BOL.dialog.mythic11" },
|
||||||
"1": "BOL.dialog.easy",
|
{ value: "-10", label: "BOL.dialog.mythic" },
|
||||||
"0": "BOL.dialog.moderate",
|
{ value: "-9", label: "BOL.dialog.heroic9" },
|
||||||
"-1": "BOL.dialog.hard",
|
{ value: "-8", label: "BOL.dialog.heroic" },
|
||||||
"-2": "BOL.dialog.tough",
|
{ value: "-7", label: "BOL.dialog.formidable7" },
|
||||||
"-4": "BOL.dialog.demanding",
|
{ value: "-6", label: "BOL.dialog.formidable" },
|
||||||
"-6": "BOL.dialog.formidable",
|
{ value: "-5", label: "BOL.dialog.demanding5" },
|
||||||
"-8": "BOL.dialog.heroic",
|
{ value: "-4", label: "BOL.dialog.demanding" },
|
||||||
"-10": "BOL.dialog.mythic",
|
{ value: "-3", label: "BOL.dialog.tough3" },
|
||||||
"-12": "BOL.dialog.divine"
|
{ value: "-2", label: "BOL.dialog.tough" },
|
||||||
}
|
{ value: "-1", label: "BOL.dialog.hard" },
|
||||||
|
{ value: "0", label: "BOL.dialog.moderate" },
|
||||||
|
{ value: "1", label: "BOL.dialog.easy" },
|
||||||
|
{ value: "2", label: "BOL.dialog.veryeasy" },
|
||||||
|
{ value: "3", label: "BOL.dialog.soeasy3" },
|
||||||
|
{ value: "4", label: "BOL.dialog.soeasy" },
|
||||||
|
]
|
||||||
|
|
||||||
BOL.alchemyModifiers = {
|
BOL.alchemyModifiers = {
|
||||||
"2": "BOL.dialog.veryeasy",
|
"2": "BOL.dialog.veryeasy",
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ export default function registerHooks() {
|
|||||||
}))
|
}))
|
||||||
|
|
||||||
Hooks.on('renderChatLog', (log, html, data) => BoLUtility.chatListeners(html))
|
Hooks.on('renderChatLog', (log, html, data) => BoLUtility.chatListeners(html))
|
||||||
Hooks.on('renderChatMessage', (message, html, data) => BoLUtility.chatMessageHandler(message, html, data))
|
Hooks.on('renderChatMessageHTML', (message, html, data) => BoLUtility.chatMessageHandler(message, html, data))
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a macro when dropping an entity on the hotbar
|
* Create a macro when dropping an entity on the hotbar
|
||||||
@@ -73,8 +73,8 @@ export default function registerHooks() {
|
|||||||
button.addEventListener('click', () => {
|
button.addEventListener('click', () => {
|
||||||
game.bol.charSummary.render(true)
|
game.bol.charSummary.render(true)
|
||||||
})
|
})
|
||||||
html.find('.header-actions').after(button)
|
$(html).find('.header-actions').after(button)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,52 +1,228 @@
|
|||||||
import {BoLRoll} from "../controllers/bol-rolls.js";
|
import { BoLRoll } from "../controllers/bol-rolls.js";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BoL Macro API — accessible via game.bol.macros
|
||||||
|
*
|
||||||
|
* Usage examples (in a Foundry macro):
|
||||||
|
*
|
||||||
|
* game.bol.macros.rollAttribute("vigor")
|
||||||
|
* game.bol.macros.rollAttribute("mind")
|
||||||
|
*
|
||||||
|
* game.bol.macros.rollAptitude("melee")
|
||||||
|
* game.bol.macros.rollAptitude("ranged")
|
||||||
|
* game.bol.macros.rollAptitude("def")
|
||||||
|
* game.bol.macros.rollAptitude("init")
|
||||||
|
*
|
||||||
|
* game.bol.macros.rollWeapon("Épée courte") // by name (partial match)
|
||||||
|
* game.bol.macros.rollWeapon(0) // by index (first weapon)
|
||||||
|
*
|
||||||
|
* game.bol.macros.rollSpell("Boule de feu") // by name (partial match)
|
||||||
|
* game.bol.macros.rollSpell(0) // by index
|
||||||
|
*
|
||||||
|
* game.bol.macros.rollAlchemy("Potion de soin") // by name (partial match)
|
||||||
|
* game.bol.macros.rollAlchemy(0) // by index
|
||||||
|
*
|
||||||
|
* game.bol.macros.rollHoroscope("minor")
|
||||||
|
* game.bol.macros.rollHoroscope("major")
|
||||||
|
*
|
||||||
|
* // Generic dispatcher:
|
||||||
|
* game.bol.macros.roll("attribute", "vigor")
|
||||||
|
* game.bol.macros.roll("aptitude", "melee")
|
||||||
|
* game.bol.macros.roll("weapon", "Épée courte")
|
||||||
|
* game.bol.macros.roll("spell", "Boule de feu")
|
||||||
|
* game.bol.macros.roll("alchemy", 0)
|
||||||
|
* game.bol.macros.roll("horoscope", "minor")
|
||||||
|
*/
|
||||||
export class Macros {
|
export class Macros {
|
||||||
/**
|
|
||||||
* @name getSpeakersActor
|
/* -------------------------------------------- */
|
||||||
* @description
|
/**
|
||||||
*
|
* Resolves the actor for macro use:
|
||||||
* @returns
|
* - If multiple tokens are selected → error (always)
|
||||||
*/
|
* - If exactly one token is selected → use it (GM or player)
|
||||||
static getSpeakersActor = function(){
|
* - If no token selected and user is GM → error (GM must select a token)
|
||||||
// Vérifie qu'un seul token est sélectionné
|
* - If no token selected and user is a player → use their assigned character
|
||||||
const tokens = canvas.tokens.controlled;
|
* @returns {Actor|null}
|
||||||
if (tokens.length > 1) {
|
*/
|
||||||
ui.notifications.warn(game.i18n.localize('BOL.notification.MacroMultipleTokensSelected'));
|
static getSpeakersActor() {
|
||||||
return null;
|
const tokens = canvas.tokens?.controlled ?? []
|
||||||
}
|
|
||||||
|
if (tokens.length > 1) {
|
||||||
const speaker = ChatMessage.getSpeaker();
|
ui.notifications.warn(game.i18n.localize('BOL.notification.MacroMultipleTokensSelected'))
|
||||||
let actor;
|
return null
|
||||||
// Si un token est sélectionné, le prendre comme acteur cible
|
|
||||||
if (speaker.token) actor = game.actors.tokens[speaker.token];
|
|
||||||
// Sinon prendre l'acteur par défaut pour l'utilisateur courrant
|
|
||||||
if (!actor) actor = game.actors.get(speaker.actor);
|
|
||||||
return actor;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static rollMacro = async function (rollType, key, adv, mod){
|
if (tokens.length === 1) {
|
||||||
const actor = this.getSpeakersActor();
|
return tokens[0].actor ?? null
|
||||||
// Several tokens selected
|
|
||||||
if (actor === null) return;
|
|
||||||
// No token selected
|
|
||||||
if (actor === undefined) return ui.notifications.error(game.i18n.localize("BOL.notification.MacroNoTokenSelected"));
|
|
||||||
|
|
||||||
const actorData = {};
|
|
||||||
actorData.data = {
|
|
||||||
features : actor.buildFeatures()
|
|
||||||
};
|
|
||||||
|
|
||||||
if(rollType === "attribute") {
|
|
||||||
let attribute = eval(`actor.system.attributes.${key}`);
|
|
||||||
let rollLabel = (attribute.label) ? game.i18n.localize(attribute.label) : null;
|
|
||||||
let description = actor.name + " - " + game.i18n.localize('BOL.ui.attributeCheck') + " - " + game.i18n.localize(attribute.label) ;
|
|
||||||
BoLRoll.attributeRollDialog(actor, actorData, attribute, rollLabel, description, adv, mod);
|
|
||||||
}
|
|
||||||
else if(rollType === "aptitude") {
|
|
||||||
let aptitude = eval(`actor.system.aptitudes.${key}`);
|
|
||||||
let rollLabel = (aptitude.label) ? game.i18n.localize(aptitude.label) : null;
|
|
||||||
let description = actor.name + " - " + game.i18n.localize('BOL.ui.aptitudeCheck') + " - " + game.i18n.localize(aptitude.label) ;
|
|
||||||
BoLRoll.aptitudeRollDialog(actor, actorData, aptitude, rollLabel, description, adv, mod);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// No token selected
|
||||||
|
if (game.user.isGM) {
|
||||||
|
ui.notifications.error(game.i18n.localize("BOL.notification.MacroNoTokenSelected"))
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
// Player: fall back to their assigned character
|
||||||
|
const actor = game.user.character
|
||||||
|
if (!actor) {
|
||||||
|
ui.notifications.error(game.i18n.localize("BOL.notification.MacroNoTokenSelected"))
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
return actor
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
/**
|
||||||
|
* Finds an item on an actor by name (partial, case-insensitive) or index.
|
||||||
|
* @param {Actor} actor
|
||||||
|
* @param {string} type - item type: "weapon", "spell", "alchemy"
|
||||||
|
* @param {string|number} nameOrIndex
|
||||||
|
* @returns {object|undefined}
|
||||||
|
*/
|
||||||
|
static _findItem(actor, type, nameOrIndex) {
|
||||||
|
const items = actor.items.filter(i => i.type === type)
|
||||||
|
if (items.length === 0) {
|
||||||
|
ui.notifications.warn(`${actor.name} : aucun(e) ${type} trouvé(e).`)
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
if (nameOrIndex === undefined || nameOrIndex === null) {
|
||||||
|
if (items.length === 1) return foundry.utils.duplicate(items[0])
|
||||||
|
const names = items.map((it, i) => `[${i}] ${it.name}`).join(', ')
|
||||||
|
ui.notifications.warn(`Précisez le nom ou l'index : ${names}`)
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
if (typeof nameOrIndex === "number") {
|
||||||
|
const item = items[nameOrIndex]
|
||||||
|
if (!item) {
|
||||||
|
ui.notifications.warn(`${actor.name} : index ${nameOrIndex} invalide pour ${type}.`)
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
return foundry.utils.duplicate(item)
|
||||||
|
}
|
||||||
|
const lower = String(nameOrIndex).toLowerCase()
|
||||||
|
const found = items.find(i => i.name.toLowerCase().includes(lower))
|
||||||
|
if (!found) {
|
||||||
|
ui.notifications.warn(`${actor.name} : ${type} "${nameOrIndex}" introuvable.`)
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
return foundry.utils.duplicate(found)
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
/**
|
||||||
|
* Roll an attribute check.
|
||||||
|
* @param {string} key - "vigor" | "agility" | "mind" | "appeal"
|
||||||
|
* @param {Actor} [actor] - optional, defaults to selected/owned token
|
||||||
|
*/
|
||||||
|
static rollAttribute(key = "vigor", actor = undefined) {
|
||||||
|
actor = actor ?? this.getSpeakersActor()
|
||||||
|
if (!actor) return
|
||||||
|
if (!actor.system.attributes[key]) {
|
||||||
|
ui.notifications.warn(`Attribut inconnu : "${key}". Valeurs : vigor, agility, mind, appeal`)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return BoLRoll.attributeCheck(actor, key)
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
/**
|
||||||
|
* Roll an aptitude check.
|
||||||
|
* @param {string} key - "init" | "melee" | "ranged" | "def"
|
||||||
|
* @param {Actor} [actor] - optional, defaults to selected/owned token
|
||||||
|
*/
|
||||||
|
static rollAptitude(key = "melee", actor = undefined) {
|
||||||
|
actor = actor ?? this.getSpeakersActor()
|
||||||
|
if (!actor) return
|
||||||
|
if (!actor.system.aptitudes[key]) {
|
||||||
|
ui.notifications.warn(`Aptitude inconnue : "${key}". Valeurs : init, melee, ranged, def`)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return BoLRoll.aptitudeCheck(actor, key)
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
/**
|
||||||
|
* Roll a weapon attack.
|
||||||
|
* @param {string|number} [nameOrIndex] - weapon name (partial) or index. Defaults to first weapon if only one.
|
||||||
|
* @param {Actor} [actor] - optional, defaults to selected/owned token
|
||||||
|
*/
|
||||||
|
static rollWeapon(nameOrIndex = undefined, actor = undefined) {
|
||||||
|
actor = actor ?? this.getSpeakersActor()
|
||||||
|
if (!actor) return
|
||||||
|
const weapon = this._findItem(actor, "weapon", nameOrIndex)
|
||||||
|
if (!weapon) return
|
||||||
|
return BoLRoll.weaponCheckWithWeapon(actor, weapon)
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
/**
|
||||||
|
* Roll a spell check.
|
||||||
|
* @param {string|number} [nameOrIndex] - spell name (partial) or index
|
||||||
|
* @param {Actor} [actor] - optional, defaults to selected/owned token
|
||||||
|
*/
|
||||||
|
static rollSpell(nameOrIndex = undefined, actor = undefined) {
|
||||||
|
actor = actor ?? this.getSpeakersActor()
|
||||||
|
if (!actor) return
|
||||||
|
if ((actor.system.resources.power?.value ?? 1) <= 0) {
|
||||||
|
ui.notifications.warn("Plus assez de points de Pouvoir !")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const spell = this._findItem(actor, "spell", nameOrIndex)
|
||||||
|
if (!spell) return
|
||||||
|
return BoLRoll.spellCheckWithSpell(actor, spell)
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
/**
|
||||||
|
* Roll an alchemy check.
|
||||||
|
* @param {string|number} [nameOrIndex] - alchemy item name (partial) or index
|
||||||
|
* @param {Actor} [actor] - optional, defaults to selected/owned token
|
||||||
|
*/
|
||||||
|
static rollAlchemy(nameOrIndex = undefined, actor = undefined) {
|
||||||
|
actor = actor ?? this.getSpeakersActor()
|
||||||
|
if (!actor) return
|
||||||
|
const alchemy = this._findItem(actor, "alchemy", nameOrIndex)
|
||||||
|
if (!alchemy) return
|
||||||
|
return BoLRoll.alchemyCheckWithItem(actor, alchemy)
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
/**
|
||||||
|
* Roll a horoscope check.
|
||||||
|
* @param {"minor"|"major"} [type="minor"]
|
||||||
|
* @param {Actor} [actor] - optional, defaults to selected/owned token
|
||||||
|
*/
|
||||||
|
static rollHoroscope(type = "minor", actor = undefined) {
|
||||||
|
actor = actor ?? this.getSpeakersActor()
|
||||||
|
if (!actor) return
|
||||||
|
return BoLRoll.horoscopeCheck(actor, undefined, type)
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
/**
|
||||||
|
* Generic roll dispatcher.
|
||||||
|
* @param {"attribute"|"aptitude"|"weapon"|"spell"|"alchemy"|"horoscope"} type
|
||||||
|
* @param {string|number} [key] - attribute/aptitude key, item name/index, or horoscope type
|
||||||
|
* @param {Actor} [actor] - optional, defaults to selected/owned token
|
||||||
|
*/
|
||||||
|
static roll(type, key = undefined, actor = undefined) {
|
||||||
|
switch (type) {
|
||||||
|
case "attribute": return this.rollAttribute(key ?? "vigor", actor)
|
||||||
|
case "aptitude": return this.rollAptitude(key ?? "melee", actor)
|
||||||
|
case "weapon": return this.rollWeapon(key, actor)
|
||||||
|
case "spell": return this.rollSpell(key, actor)
|
||||||
|
case "alchemy": return this.rollAlchemy(key, actor)
|
||||||
|
case "horoscope": return this.rollHoroscope(key ?? "minor", actor)
|
||||||
|
default:
|
||||||
|
ui.notifications.warn(`Type de jet inconnu : "${type}". Types valides : attribute, aptitude, weapon, spell, alchemy, horoscope`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
// Kept for backward-compat (previously called by old macros)
|
||||||
|
static rollMacro = async function (rollType, key) {
|
||||||
|
const actor = Macros.getSpeakersActor()
|
||||||
|
if (!actor) return
|
||||||
|
return Macros.roll(rollType, key, actor)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ export const preloadHandlebarsTemplates = async function () {
|
|||||||
"systems/bol/templates/chat/rolls/alchemy-roll-card.hbs",
|
"systems/bol/templates/chat/rolls/alchemy-roll-card.hbs",
|
||||||
"systems/bol/templates/chat/rolls/selected-horoscope-roll-card.hbs",
|
"systems/bol/templates/chat/rolls/selected-horoscope-roll-card.hbs",
|
||||||
"systems/bol/templates/chat/rolls/horoscope-roll-card.hbs",
|
"systems/bol/templates/chat/rolls/horoscope-roll-card.hbs",
|
||||||
|
"systems/bol/templates/chat/chat-welcome.hbs",
|
||||||
"systems/bol/templates/dialogs/aptitude-roll-part.hbs",
|
"systems/bol/templates/dialogs/aptitude-roll-part.hbs",
|
||||||
"systems/bol/templates/dialogs/attribute-roll-part.hbs",
|
"systems/bol/templates/dialogs/attribute-roll-part.hbs",
|
||||||
"systems/bol/templates/dialogs/mod-roll-part.hbs",
|
"systems/bol/templates/dialogs/mod-roll-part.hbs",
|
||||||
@@ -60,11 +61,12 @@ export const preloadHandlebarsTemplates = async function () {
|
|||||||
"systems/bol/templates/dialogs/effect-roll-part.hbs",
|
"systems/bol/templates/dialogs/effect-roll-part.hbs",
|
||||||
"systems/bol/templates/dialogs/boons-roll-part.hbs",
|
"systems/bol/templates/dialogs/boons-roll-part.hbs",
|
||||||
"systems/bol/templates/dialogs/flaws-roll-part.hbs",
|
"systems/bol/templates/dialogs/flaws-roll-part.hbs",
|
||||||
"systems/bol/templates/dialogs/total-roll-part.hbs",
|
"systems/bol/templates/dialogs/total-roll-part.hbs",
|
||||||
"systems/bol/templates/dialogs/fightoptions-roll-part.hbs",
|
"systems/bol/templates/dialogs/fightoptions-roll-part.hbs",
|
||||||
"systems/bol/templates/dialogs/horoscope-roll-part.hbs"
|
"systems/bol/templates/dialogs/horoscope-roll-part.hbs",
|
||||||
|
"systems/bol/templates/apps/character-summary-template.html"
|
||||||
];
|
];
|
||||||
|
|
||||||
// Load the template parts
|
// Load the template parts
|
||||||
return loadTemplates(templatePaths);
|
return foundry.applications.handlebars.loadTemplates(templatePaths);
|
||||||
};
|
};
|
||||||
|
|||||||
BIN
packs/aides-de-jeu/001137.ldb
Normal file
@@ -1 +1 @@
|
|||||||
MANIFEST-000642
|
MANIFEST-001138
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
2024/12/12-21:46:21.360031 7f25b97fa6c0 Recovering log #640
|
2026/04/11-21:28:04.733439 7ff3bebfd6c0 Recovering log #1135
|
||||||
2024/12/12-21:46:21.492497 7f25b97fa6c0 Delete type=3 #638
|
2026/04/11-21:28:04.743122 7ff3bebfd6c0 Delete type=3 #1133
|
||||||
2024/12/12-21:46:21.492569 7f25b97fa6c0 Delete type=0 #640
|
2026/04/11-21:28:04.743177 7ff3bebfd6c0 Delete type=0 #1135
|
||||||
2024/12/12-21:50:13.987586 7f25b2ffd6c0 Level-0 table #645: started
|
2026/04/11-21:28:49.377435 7ff3bdbfb6c0 Level-0 table #1141: started
|
||||||
2024/12/12-21:50:13.987627 7f25b2ffd6c0 Level-0 table #645: 0 bytes OK
|
2026/04/11-21:28:49.377469 7ff3bdbfb6c0 Level-0 table #1141: 0 bytes OK
|
||||||
2024/12/12-21:50:13.994186 7f25b2ffd6c0 Delete type=0 #643
|
2026/04/11-21:28:49.413622 7ff3bdbfb6c0 Delete type=0 #1139
|
||||||
2024/12/12-21:50:14.007425 7f25b2ffd6c0 Manual compaction at level-0 from '!journal!3xJg1rCxnWvEmoxS' @ 72057594037927935 : 1 .. '!journal.pages!veAAxCtCKcFIsnln.0kUgZspxXO7VS8bd' @ 0 : 0; will stop at (end)
|
2026/04/11-21:28:49.456441 7ff3bdbfb6c0 Manual compaction at level-0 from '!journal!6cCdSvQgEHJ1bvX4' @ 72057594037927935 : 1 .. '!journal.pages!veAAxCtCKcFIsnln.0kUgZspxXO7VS8bd' @ 0 : 0; will stop at (end)
|
||||||
2024/12/12-21:50:14.007460 7f25b2ffd6c0 Manual compaction at level-1 from '!journal!3xJg1rCxnWvEmoxS' @ 72057594037927935 : 1 .. '!journal.pages!veAAxCtCKcFIsnln.0kUgZspxXO7VS8bd' @ 0 : 0; will stop at (end)
|
|
||||||
|
|||||||
@@ -1,8 +1,14 @@
|
|||||||
2024/12/12-21:11:43.910823 7f25b37fe6c0 Recovering log #636
|
2026/04/11-21:19:06.264443 7ff3bf3fe6c0 Recovering log #1130
|
||||||
2024/12/12-21:11:44.036050 7f25b37fe6c0 Delete type=3 #634
|
2026/04/11-21:19:06.275289 7ff3bf3fe6c0 Delete type=3 #1128
|
||||||
2024/12/12-21:11:44.036107 7f25b37fe6c0 Delete type=0 #636
|
2026/04/11-21:19:06.275358 7ff3bf3fe6c0 Delete type=0 #1130
|
||||||
2024/12/12-21:40:17.197599 7f25b2ffd6c0 Level-0 table #641: started
|
2026/04/11-21:27:57.082652 7ff3bdbfb6c0 Level-0 table #1136: started
|
||||||
2024/12/12-21:40:17.197635 7f25b2ffd6c0 Level-0 table #641: 0 bytes OK
|
2026/04/11-21:27:57.086593 7ff3bdbfb6c0 Level-0 table #1136: 2472 bytes OK
|
||||||
2024/12/12-21:40:17.203956 7f25b2ffd6c0 Delete type=0 #639
|
2026/04/11-21:27:57.092696 7ff3bdbfb6c0 Delete type=0 #1134
|
||||||
2024/12/12-21:40:17.217330 7f25b2ffd6c0 Manual compaction at level-0 from '!journal!3xJg1rCxnWvEmoxS' @ 72057594037927935 : 1 .. '!journal.pages!veAAxCtCKcFIsnln.0kUgZspxXO7VS8bd' @ 0 : 0; will stop at (end)
|
2026/04/11-21:27:57.111697 7ff3bdbfb6c0 Manual compaction at level-0 from '!journal!6cCdSvQgEHJ1bvX4' @ 72057594037927935 : 1 .. '!journal.pages!veAAxCtCKcFIsnln.0kUgZspxXO7VS8bd' @ 0 : 0; will stop at '!journal.pages!8ihDiCxC47fcdKVA.MOWru5Dbvs4iozXm' @ 325 : 1
|
||||||
2024/12/12-21:40:17.217374 7f25b2ffd6c0 Manual compaction at level-1 from '!journal!3xJg1rCxnWvEmoxS' @ 72057594037927935 : 1 .. '!journal.pages!veAAxCtCKcFIsnln.0kUgZspxXO7VS8bd' @ 0 : 0; will stop at (end)
|
2026/04/11-21:27:57.111705 7ff3bdbfb6c0 Compacting 1@0 + 1@1 files
|
||||||
|
2026/04/11-21:27:57.115555 7ff3bdbfb6c0 Generated table #1137@0: 23 keys, 27230 bytes
|
||||||
|
2026/04/11-21:27:57.115568 7ff3bdbfb6c0 Compacted 1@0 + 1@1 files => 27230 bytes
|
||||||
|
2026/04/11-21:27:57.121399 7ff3bdbfb6c0 compacted to: files[ 0 1 0 0 0 0 0 ]
|
||||||
|
2026/04/11-21:27:57.121501 7ff3bdbfb6c0 Delete type=2 #1132
|
||||||
|
2026/04/11-21:27:57.121625 7ff3bdbfb6c0 Delete type=2 #1136
|
||||||
|
2026/04/11-21:27:57.121723 7ff3bdbfb6c0 Manual compaction at level-0 from '!journal.pages!8ihDiCxC47fcdKVA.MOWru5Dbvs4iozXm' @ 325 : 1 .. '!journal.pages!veAAxCtCKcFIsnln.0kUgZspxXO7VS8bd' @ 0 : 0; will stop at (end)
|
||||||
|
|||||||
BIN
packs/aides-de-jeu/MANIFEST-001138
Normal file
BIN
packs/armors/001022.ldb
Normal file
@@ -1 +1 @@
|
|||||||
MANIFEST-000548
|
MANIFEST-001039
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
2024/12/12-21:46:21.083865 7f25b37fe6c0 Recovering log #546
|
2026/04/11-21:28:04.708004 7ff3be3fc6c0 Recovering log #1037
|
||||||
2024/12/12-21:46:21.217856 7f25b37fe6c0 Delete type=3 #544
|
2026/04/11-21:28:04.718300 7ff3be3fc6c0 Delete type=3 #1035
|
||||||
2024/12/12-21:46:21.217918 7f25b37fe6c0 Delete type=0 #546
|
2026/04/11-21:28:04.718366 7ff3be3fc6c0 Delete type=0 #1037
|
||||||
2024/12/12-21:50:13.981247 7f25b2ffd6c0 Level-0 table #551: started
|
2026/04/11-21:28:49.305595 7ff3bdbfb6c0 Level-0 table #1042: started
|
||||||
2024/12/12-21:50:13.981272 7f25b2ffd6c0 Level-0 table #551: 0 bytes OK
|
2026/04/11-21:28:49.305624 7ff3bdbfb6c0 Level-0 table #1042: 0 bytes OK
|
||||||
2024/12/12-21:50:13.987466 7f25b2ffd6c0 Delete type=0 #549
|
2026/04/11-21:28:49.334673 7ff3bdbfb6c0 Delete type=0 #1040
|
||||||
2024/12/12-21:50:14.007412 7f25b2ffd6c0 Manual compaction at level-0 from '!items!G3dZTHIabA3LA1hY' @ 72057594037927935 : 1 .. '!items!xhEcsi3WHjbt2ro9' @ 0 : 0; will stop at (end)
|
2026/04/11-21:28:49.456420 7ff3bdbfb6c0 Manual compaction at level-0 from '!items!G3dZTHIabA3LA1hY' @ 72057594037927935 : 1 .. '!items!xhEcsi3WHjbt2ro9' @ 0 : 0; will stop at (end)
|
||||||
2024/12/12-21:50:14.007452 7f25b2ffd6c0 Manual compaction at level-1 from '!items!G3dZTHIabA3LA1hY' @ 72057594037927935 : 1 .. '!items!xhEcsi3WHjbt2ro9' @ 0 : 0; will stop at (end)
|
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
2024/12/12-21:11:43.620616 7f25b8ff96c0 Recovering log #542
|
2026/04/11-21:19:06.240951 7ff3be3fc6c0 Recovering log #1033
|
||||||
2024/12/12-21:11:43.750156 7f25b8ff96c0 Delete type=3 #540
|
2026/04/11-21:19:06.250426 7ff3be3fc6c0 Delete type=3 #1031
|
||||||
2024/12/12-21:11:43.750213 7f25b8ff96c0 Delete type=0 #542
|
2026/04/11-21:19:06.250488 7ff3be3fc6c0 Delete type=0 #1033
|
||||||
2024/12/12-21:40:17.191315 7f25b2ffd6c0 Level-0 table #547: started
|
2026/04/11-21:27:57.098718 7ff3bdbfb6c0 Level-0 table #1038: started
|
||||||
2024/12/12-21:40:17.191339 7f25b2ffd6c0 Level-0 table #547: 0 bytes OK
|
2026/04/11-21:27:57.098740 7ff3bdbfb6c0 Level-0 table #1038: 0 bytes OK
|
||||||
2024/12/12-21:40:17.197420 7f25b2ffd6c0 Delete type=0 #545
|
2026/04/11-21:27:57.104599 7ff3bdbfb6c0 Delete type=0 #1036
|
||||||
2024/12/12-21:40:17.217313 7f25b2ffd6c0 Manual compaction at level-0 from '!items!G3dZTHIabA3LA1hY' @ 72057594037927935 : 1 .. '!items!xhEcsi3WHjbt2ro9' @ 0 : 0; will stop at (end)
|
2026/04/11-21:27:57.121701 7ff3bdbfb6c0 Manual compaction at level-0 from '!items!G3dZTHIabA3LA1hY' @ 72057594037927935 : 1 .. '!items!xhEcsi3WHjbt2ro9' @ 0 : 0; will stop at (end)
|
||||||
2024/12/12-21:40:17.217363 7f25b2ffd6c0 Manual compaction at level-1 from '!items!G3dZTHIabA3LA1hY' @ 72057594037927935 : 1 .. '!items!xhEcsi3WHjbt2ro9' @ 0 : 0; will stop at (end)
|
|
||||||
|
|||||||
BIN
packs/armors/MANIFEST-001039
Normal file
BIN
packs/boons/001116.ldb
Normal file
@@ -1 +1 @@
|
|||||||
MANIFEST-000641
|
MANIFEST-001133
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
2024/12/12-21:46:20.029795 7f25b37fe6c0 Recovering log #639
|
2026/04/11-21:28:04.608888 7ff3be3fc6c0 Recovering log #1131
|
||||||
2024/12/12-21:46:20.162579 7f25b37fe6c0 Delete type=3 #637
|
2026/04/11-21:28:04.618597 7ff3be3fc6c0 Delete type=3 #1129
|
||||||
2024/12/12-21:46:20.162683 7f25b37fe6c0 Delete type=0 #639
|
2026/04/11-21:28:04.618657 7ff3be3fc6c0 Delete type=0 #1131
|
||||||
2024/12/12-21:50:13.926457 7f25b2ffd6c0 Level-0 table #644: started
|
2026/04/11-21:28:49.095706 7ff3bdbfb6c0 Level-0 table #1136: started
|
||||||
2024/12/12-21:50:13.926508 7f25b2ffd6c0 Level-0 table #644: 0 bytes OK
|
2026/04/11-21:28:49.095741 7ff3bdbfb6c0 Level-0 table #1136: 0 bytes OK
|
||||||
2024/12/12-21:50:13.934036 7f25b2ffd6c0 Delete type=0 #642
|
2026/04/11-21:28:49.132472 7ff3bdbfb6c0 Delete type=0 #1134
|
||||||
2024/12/12-21:50:13.954229 7f25b2ffd6c0 Manual compaction at level-0 from '!items!039ZF3E3MtAGwbiX' @ 72057594037927935 : 1 .. '!items!zgspy1QKaxdEetEw' @ 0 : 0; will stop at (end)
|
2026/04/11-21:28:49.170383 7ff3bdbfb6c0 Manual compaction at level-0 from '!items!039ZF3E3MtAGwbiX' @ 72057594037927935 : 1 .. '!items!zgspy1QKaxdEetEw' @ 0 : 0; will stop at (end)
|
||||||
2024/12/12-21:50:13.954282 7f25b2ffd6c0 Manual compaction at level-1 from '!items!039ZF3E3MtAGwbiX' @ 72057594037927935 : 1 .. '!items!zgspy1QKaxdEetEw' @ 0 : 0; will stop at (end)
|
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
2024/12/12-21:11:42.417136 7f25b8ff96c0 Recovering log #635
|
2026/04/11-21:19:06.144409 7ff3be3fc6c0 Recovering log #1127
|
||||||
2024/12/12-21:11:42.597818 7f25b8ff96c0 Delete type=3 #633
|
2026/04/11-21:19:06.153957 7ff3be3fc6c0 Delete type=3 #1125
|
||||||
2024/12/12-21:11:42.597875 7f25b8ff96c0 Delete type=0 #635
|
2026/04/11-21:19:06.154021 7ff3be3fc6c0 Delete type=0 #1127
|
||||||
2024/12/12-21:40:17.139303 7f25b2ffd6c0 Level-0 table #640: started
|
2026/04/11-21:27:57.045260 7ff3bdbfb6c0 Level-0 table #1132: started
|
||||||
2024/12/12-21:40:17.139355 7f25b2ffd6c0 Level-0 table #640: 0 bytes OK
|
2026/04/11-21:27:57.045286 7ff3bdbfb6c0 Level-0 table #1132: 0 bytes OK
|
||||||
2024/12/12-21:40:17.145373 7f25b2ffd6c0 Delete type=0 #638
|
2026/04/11-21:27:57.051070 7ff3bdbfb6c0 Delete type=0 #1130
|
||||||
2024/12/12-21:40:17.165314 7f25b2ffd6c0 Manual compaction at level-0 from '!items!039ZF3E3MtAGwbiX' @ 72057594037927935 : 1 .. '!items!zgspy1QKaxdEetEw' @ 0 : 0; will stop at (end)
|
2026/04/11-21:27:57.057054 7ff3bdbfb6c0 Manual compaction at level-0 from '!items!039ZF3E3MtAGwbiX' @ 72057594037927935 : 1 .. '!items!zgspy1QKaxdEetEw' @ 0 : 0; will stop at (end)
|
||||||
2024/12/12-21:40:17.165365 7f25b2ffd6c0 Manual compaction at level-1 from '!items!039ZF3E3MtAGwbiX' @ 72057594037927935 : 1 .. '!items!zgspy1QKaxdEetEw' @ 0 : 0; will stop at (end)
|
|
||||||
|
|||||||
BIN
packs/boons/MANIFEST-001133
Normal file
BIN
packs/boonsflawscreatures/001115.ldb
Normal file
@@ -1 +1 @@
|
|||||||
MANIFEST-000641
|
MANIFEST-001132
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
2024/12/12-21:46:20.169625 7f25b8ff96c0 Recovering log #639
|
2026/04/11-21:28:04.620767 7ff3bfbff6c0 Recovering log #1130
|
||||||
2024/12/12-21:46:20.298341 7f25b8ff96c0 Delete type=3 #637
|
2026/04/11-21:28:04.630558 7ff3bfbff6c0 Delete type=3 #1128
|
||||||
2024/12/12-21:46:20.298399 7f25b8ff96c0 Delete type=0 #639
|
2026/04/11-21:28:04.630621 7ff3bfbff6c0 Delete type=0 #1130
|
||||||
2024/12/12-21:50:13.934153 7f25b2ffd6c0 Level-0 table #644: started
|
2026/04/11-21:28:49.058278 7ff3bdbfb6c0 Level-0 table #1135: started
|
||||||
2024/12/12-21:50:13.934178 7f25b2ffd6c0 Level-0 table #644: 0 bytes OK
|
2026/04/11-21:28:49.058305 7ff3bdbfb6c0 Level-0 table #1135: 0 bytes OK
|
||||||
2024/12/12-21:50:13.940593 7f25b2ffd6c0 Delete type=0 #642
|
2026/04/11-21:28:49.095507 7ff3bdbfb6c0 Delete type=0 #1133
|
||||||
2024/12/12-21:50:13.954244 7f25b2ffd6c0 Manual compaction at level-0 from '!items!CoqlfsDV1gL5swbK' @ 72057594037927935 : 1 .. '!items!yofwG0YrsL902G77' @ 0 : 0; will stop at (end)
|
2026/04/11-21:28:49.170373 7ff3bdbfb6c0 Manual compaction at level-0 from '!items!CoqlfsDV1gL5swbK' @ 72057594037927935 : 1 .. '!items!yofwG0YrsL902G77' @ 0 : 0; will stop at (end)
|
||||||
2024/12/12-21:50:13.954292 7f25b2ffd6c0 Manual compaction at level-1 from '!items!CoqlfsDV1gL5swbK' @ 72057594037927935 : 1 .. '!items!yofwG0YrsL902G77' @ 0 : 0; will stop at (end)
|
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
2024/12/12-21:11:42.611933 7f25b3fff6c0 Recovering log #635
|
2026/04/11-21:19:06.155820 7ff3bfbff6c0 Recovering log #1126
|
||||||
2024/12/12-21:11:42.739932 7f25b3fff6c0 Delete type=3 #633
|
2026/04/11-21:19:06.166134 7ff3bfbff6c0 Delete type=3 #1124
|
||||||
2024/12/12-21:11:42.740037 7f25b3fff6c0 Delete type=0 #635
|
2026/04/11-21:19:06.166197 7ff3bfbff6c0 Delete type=0 #1126
|
||||||
2024/12/12-21:40:17.158730 7f25b2ffd6c0 Level-0 table #640: started
|
2026/04/11-21:27:57.031682 7ff3bdbfb6c0 Level-0 table #1131: started
|
||||||
2024/12/12-21:40:17.158762 7f25b2ffd6c0 Level-0 table #640: 0 bytes OK
|
2026/04/11-21:27:57.031756 7ff3bdbfb6c0 Level-0 table #1131: 0 bytes OK
|
||||||
2024/12/12-21:40:17.165130 7f25b2ffd6c0 Delete type=0 #638
|
2026/04/11-21:27:57.038391 7ff3bdbfb6c0 Delete type=0 #1129
|
||||||
2024/12/12-21:40:17.165357 7f25b2ffd6c0 Manual compaction at level-0 from '!items!CoqlfsDV1gL5swbK' @ 72057594037927935 : 1 .. '!items!yofwG0YrsL902G77' @ 0 : 0; will stop at (end)
|
2026/04/11-21:27:57.057035 7ff3bdbfb6c0 Manual compaction at level-0 from '!items!CoqlfsDV1gL5swbK' @ 72057594037927935 : 1 .. '!items!yofwG0YrsL902G77' @ 0 : 0; will stop at (end)
|
||||||
2024/12/12-21:40:17.165391 7f25b2ffd6c0 Manual compaction at level-1 from '!items!CoqlfsDV1gL5swbK' @ 72057594037927935 : 1 .. '!items!yofwG0YrsL902G77' @ 0 : 0; will stop at (end)
|
|
||||||
|
|||||||
BIN
packs/boonsflawscreatures/MANIFEST-001132
Normal file
BIN
packs/careers/001115.ldb
Normal file
@@ -1 +1 @@
|
|||||||
MANIFEST-000641
|
MANIFEST-001132
|
||||||
|
|||||||