Compare commits
23 Commits
bol-v12.1.
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 7adc1b3f07 | |||
| 6c70dc147c | |||
| 1ffb8b08fc | |||
| 8017bb207d | |||
| 364278527d | |||
| 93d35abde2 | |||
| 0409be64eb | |||
| ed76a49e7d | |||
| 2abd2c881a | |||
| 3fa5ca66d1 | |||
| 6de15eeda7 | |||
| 724c096743 | |||
| 3e3a4b9ec1 | |||
| 425a2a1fc0 | |||
| 203d7add66 | |||
| 8ae193dc34 | |||
| 3904f595b5 | |||
| 1bf21fae7f | |||
| 22579c21bc | |||
| 50c5c31e7b | |||
| a8c05cd4de | |||
| e1cea78059 | |||
| c2f9934f5f |
@@ -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: actions/checkout@v3
|
||||||
- uses: RouxAntoine/checkout@v3.5.4
|
- uses: RouxAntoine/checkout@v3.5.4
|
||||||
with:
|
|
||||||
ref: 'v10'
|
|
||||||
|
|
||||||
# get part of the tag after the `v`
|
# get part of the tag after the `v`
|
||||||
- name: Extract tag version number
|
- name: Extract tag version number
|
||||||
id: get_version
|
id: get_version
|
||||||
uses: battila7/get-version-action@v2
|
uses: battila7/get-version-action@v2
|
||||||
|
|
||||||
# Substitute the Manifest and Download URLs in the module.json
|
# Substitute the Manifest and Download URLs in the system.json
|
||||||
- name: Substitute Manifest and Download Links For Versioned Ones
|
- name: Substitute Manifest and Download Links For Versioned Ones
|
||||||
id: sub_manifest_link_version
|
id: sub_manifest_link_version
|
||||||
uses: microsoft/variable-substitution@v1
|
uses: microsoft/variable-substitution@v1
|
||||||
with:
|
with:
|
||||||
files: 'system.json'
|
files: "system.json"
|
||||||
env:
|
env:
|
||||||
version: ${{steps.get_version.outputs.version-without-v}}
|
version: ${{steps.get_version.outputs.version-without-v}}
|
||||||
url: https://www.uberwald.me/gitea/public/bol
|
url: https://www.uberwald.me/gitea/${{gitea.repository}}
|
||||||
manifest: https://www.uberwald.me/gitea/public/bol/releases/latest/system.json
|
manifest: https://www.uberwald.me/gitea/public/bol/releases/download/latest/system.json
|
||||||
download: https://www.uberwald.me/gitea/public/bol/releases/download/${{github.event.release.tag_name}}/bol.zip
|
download: https://www.uberwald.me/gitea/${{gitea.repository}}/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
|
# Create a zip file with all files required by the module to add to the release
|
||||||
- run: |
|
- run: |
|
||||||
apt update -y
|
apt update -y
|
||||||
apt install -y zip
|
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/
|
- 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
|
- name: setup go
|
||||||
uses: https://github.com/actions/setup-go@v4
|
uses: https://github.com/actions/setup-go@v4
|
||||||
with:
|
with:
|
||||||
go-version: '>=1.20.1'
|
go-version: ">=1.20.1"
|
||||||
|
|
||||||
- name: Use Go Action
|
- name: Use Go Action
|
||||||
id: use-go-action
|
id: use-go-action
|
||||||
uses: https://gitea.com/actions/release-action@main
|
uses: https://gitea.com/actions/release-action@main
|
||||||
with:
|
with:
|
||||||
files: |-
|
files: |-
|
||||||
./bol.zip
|
./bol.zip
|
||||||
system.json
|
system.json
|
||||||
api_key: '${{secrets.RELEASE_TOKEN_UBERWALD}}'
|
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: "13"
|
||||||
|
|||||||
286
APPV2_ITEMS_MIGRATION.md
Normal file
286
APPV2_ITEMS_MIGRATION.md
Normal file
@@ -0,0 +1,286 @@
|
|||||||
|
# Migration AppV2 - Item Sheets
|
||||||
|
|
||||||
|
## Vue d'ensemble
|
||||||
|
|
||||||
|
Migration des feuilles d'items de BoL vers l'architecture **ApplicationV2** de Foundry VTT v12+.
|
||||||
|
|
||||||
|
## Fichiers créés
|
||||||
|
|
||||||
|
### Classes AppV2 (module/applications/sheets/)
|
||||||
|
|
||||||
|
1. **base-item-sheet.mjs** - Classe de base pour tous les item sheets
|
||||||
|
- Hérite de `foundry.applications.sheets.ItemSheetV2`
|
||||||
|
- Utilise `HandlebarsApplicationMixin`
|
||||||
|
- Gère les tabs, drag & drop, actions communes
|
||||||
|
- 272 lignes de code
|
||||||
|
|
||||||
|
2. **item-sheet.mjs** - Sheet pour le type "item"
|
||||||
|
- Équipements, armes, protections, sorts, etc.
|
||||||
|
- Hérite de `BoLBaseItemSheet`
|
||||||
|
- Contexte spécifique aux items
|
||||||
|
|
||||||
|
3. **feature-sheet.mjs** - Sheet pour le type "feature"
|
||||||
|
- Boons, flaws, careers, origins, races, etc.
|
||||||
|
- Hérite de `BoLBaseItemSheet`
|
||||||
|
- Contexte spécifique aux features
|
||||||
|
|
||||||
|
4. **_module.mjs** - Export des sheets
|
||||||
|
|
||||||
|
### Templates (templates/item/)
|
||||||
|
|
||||||
|
1. **item-sheet.hbs** - Template pour les items
|
||||||
|
2. **feature-sheet.hbs** - Template pour les features
|
||||||
|
3. **parts/item-header.hbs** - Header mis à jour pour AppV2
|
||||||
|
|
||||||
|
### Backups
|
||||||
|
|
||||||
|
- `templates/item.backup/` - Backup des templates originaux
|
||||||
|
- `module/item.backup/` - Backup de l'ancienne classe ItemSheet
|
||||||
|
- `templates/item/parts/item-header.hbs.backup` - Backup du header
|
||||||
|
|
||||||
|
## Architecture AppV2
|
||||||
|
|
||||||
|
### Différences avec AppV1
|
||||||
|
|
||||||
|
| Aspect | AppV1 (avant) | AppV2 (après) |
|
||||||
|
|--------|---------------|---------------|
|
||||||
|
| Classe de base | `ItemSheet` | `ItemSheetV2` |
|
||||||
|
| Options | `static get defaultOptions()` | `static DEFAULT_OPTIONS` |
|
||||||
|
| getData | `async getData()` | `async _prepareContext()` |
|
||||||
|
| Template | Unique | Peut utiliser PARTS |
|
||||||
|
| Tabs | Automatiques | Gestion manuelle |
|
||||||
|
| Actions | Event listeners | `actions:` dans OPTIONS |
|
||||||
|
| Render | `activateListeners()` | `_onRender()` |
|
||||||
|
|
||||||
|
### Structure de BoLBaseItemSheet
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
class BoLBaseItemSheet extends ItemSheetV2 {
|
||||||
|
// Options statiques
|
||||||
|
static DEFAULT_OPTIONS = {
|
||||||
|
classes, position, form, window,
|
||||||
|
actions, dragDrop, tabs
|
||||||
|
}
|
||||||
|
|
||||||
|
// State
|
||||||
|
tabGroups = { primary: "description" }
|
||||||
|
|
||||||
|
// Méthodes principales
|
||||||
|
async _prepareContext() // Prépare les données
|
||||||
|
_onRender() // Après le render
|
||||||
|
_activateTabs() // Active les tabs
|
||||||
|
_activateListeners() // Event listeners
|
||||||
|
|
||||||
|
// Actions
|
||||||
|
static #onEditImage() // data-action="editImage"
|
||||||
|
static #onPostItem() // data-action="postItem"
|
||||||
|
|
||||||
|
// Drag & Drop
|
||||||
|
#createDragDropHandlers()
|
||||||
|
_canDragStart()
|
||||||
|
_onDragStart()
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Fonctionnalités migrées
|
||||||
|
|
||||||
|
### ✅ Depuis l'ancien BoLItemSheet
|
||||||
|
|
||||||
|
1. **getData** → **_prepareContext**
|
||||||
|
- Enrichissement de la description
|
||||||
|
- Configuration des données dynamiques
|
||||||
|
- Gestion des catégories
|
||||||
|
- Propriétés des items
|
||||||
|
- Careers depuis l'actor
|
||||||
|
|
||||||
|
2. **Tabs**
|
||||||
|
- Navigation entre Description et Properties
|
||||||
|
- State persistant avec `tabGroups`
|
||||||
|
- Activation manuelle des tabs
|
||||||
|
|
||||||
|
3. **Actions**
|
||||||
|
- Edit Image (FilePicker)
|
||||||
|
- Post Item (chat)
|
||||||
|
|
||||||
|
4. **Listeners spécifiques**
|
||||||
|
- Armor quality → soak formula
|
||||||
|
|
||||||
|
5. **Dynamic defaults**
|
||||||
|
- Category par défaut
|
||||||
|
- Spell conditions (mandatory/optional)
|
||||||
|
- Equipment slots
|
||||||
|
|
||||||
|
## Utilisation dans les templates
|
||||||
|
|
||||||
|
### Actions (data-action)
|
||||||
|
|
||||||
|
```handlebars
|
||||||
|
{{!-- Éditer l'image --}}
|
||||||
|
<img data-action="editImage" src="{{item.img}}" />
|
||||||
|
|
||||||
|
{{!-- Poster au chat --}}
|
||||||
|
<button data-action="postItem">
|
||||||
|
<i class="fas fa-comment"></i>
|
||||||
|
</button>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Tabs
|
||||||
|
|
||||||
|
```handlebars
|
||||||
|
{{!-- Navigation --}}
|
||||||
|
<nav class="tabs" data-group="primary">
|
||||||
|
{{#each tabs}}
|
||||||
|
<a data-tab="{{this.id}}" class="{{#if (eq ../activeTab this.id)}}active{{/if}}">
|
||||||
|
{{localize this.label}}
|
||||||
|
</a>
|
||||||
|
{{/each}}
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
{{!-- Contenu --}}
|
||||||
|
<div class="tab {{#if (eq activeTab 'description')}}active{{/if}}"
|
||||||
|
data-tab="description">
|
||||||
|
...
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Editor
|
||||||
|
|
||||||
|
```handlebars
|
||||||
|
{{!-- AppV2 avec ProseMirror --}}
|
||||||
|
{{editor enrichedDescription
|
||||||
|
target="system.description"
|
||||||
|
button=true
|
||||||
|
editable=isEditable
|
||||||
|
engine="prosemirror"}}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Context disponible dans les templates
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
{
|
||||||
|
// Document & system
|
||||||
|
fields: schema.fields,
|
||||||
|
systemFields: system.schema.fields,
|
||||||
|
item: document,
|
||||||
|
system: document.system,
|
||||||
|
source: document.toObject(),
|
||||||
|
|
||||||
|
// Content
|
||||||
|
enrichedDescription: "HTML enrichi",
|
||||||
|
category: "equipment|weapon|spell|...",
|
||||||
|
itemProperties: ["prop1", "prop2"],
|
||||||
|
|
||||||
|
// Config
|
||||||
|
config: game.bol.config,
|
||||||
|
isGM: boolean,
|
||||||
|
isEditable: boolean,
|
||||||
|
|
||||||
|
// Tabs
|
||||||
|
tabs: [{id, label, icon}],
|
||||||
|
activeTab: "description|properties",
|
||||||
|
|
||||||
|
// Type-specific (item-sheet.mjs)
|
||||||
|
isItem: true,
|
||||||
|
isEquipment: boolean,
|
||||||
|
isWeapon: boolean,
|
||||||
|
isProtection: boolean,
|
||||||
|
isSpell: boolean,
|
||||||
|
|
||||||
|
// Type-specific (feature-sheet.mjs)
|
||||||
|
isFeature: true,
|
||||||
|
isBoon: boolean,
|
||||||
|
isFlaw: boolean,
|
||||||
|
isCareer: boolean,
|
||||||
|
isOrigin: boolean,
|
||||||
|
isRace: boolean,
|
||||||
|
|
||||||
|
// Optional
|
||||||
|
careers: actor.careers // Si item sur actor
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Configuration dans bol.js
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// Import
|
||||||
|
import * as sheets from "./applications/sheets/_module.mjs"
|
||||||
|
|
||||||
|
// Enregistrement
|
||||||
|
foundry.documents.collections.Items.unregisterSheet("core", ...)
|
||||||
|
foundry.documents.collections.Items.registerSheet("bol",
|
||||||
|
sheets.BoLItemSheet,
|
||||||
|
{ types: ["item"], makeDefault: true }
|
||||||
|
)
|
||||||
|
foundry.documents.collections.Items.registerSheet("bol",
|
||||||
|
sheets.BoLFeatureSheet,
|
||||||
|
{ types: ["feature"], makeDefault: true }
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Avantages de AppV2
|
||||||
|
|
||||||
|
1. **Performance** : Meilleur rendu et gestion des updates
|
||||||
|
2. **Structure** : Code plus organisé et maintenable
|
||||||
|
3. **Actions** : Système d'actions déclaratif
|
||||||
|
4. **Context** : Préparation des données séparée du template
|
||||||
|
5. **Standard** : Aligné sur Foundry VTT v12+
|
||||||
|
6. **Future-proof** : Architecture pérenne
|
||||||
|
|
||||||
|
## Points d'attention
|
||||||
|
|
||||||
|
### Compatibilité
|
||||||
|
|
||||||
|
- Les données restent 100% compatibles
|
||||||
|
- Seule l'interface de sheet change
|
||||||
|
- Pas de migration de données nécessaire
|
||||||
|
|
||||||
|
### Tabs
|
||||||
|
|
||||||
|
Les tabs ne sont plus automatiques dans AppV2 :
|
||||||
|
- Navigation manuelle avec `_activateTabs()`
|
||||||
|
- State persistant avec `tabGroups`
|
||||||
|
- CSS `.active` géré manuellement
|
||||||
|
|
||||||
|
### Editor
|
||||||
|
|
||||||
|
ProseMirror est maintenant le moteur par défaut :
|
||||||
|
```handlebars
|
||||||
|
{{editor content engine="prosemirror"}}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Actions
|
||||||
|
|
||||||
|
Système déclaratif :
|
||||||
|
```javascript
|
||||||
|
actions: {
|
||||||
|
myAction: ClassName.#onMyAction
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Dans le template :
|
||||||
|
```handlebars
|
||||||
|
<button data-action="myAction">Click</button>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Prochaines étapes
|
||||||
|
|
||||||
|
### Court terme
|
||||||
|
1. Tester les sheets dans Foundry
|
||||||
|
2. Vérifier toutes les fonctionnalités
|
||||||
|
3. Ajuster les CSS si nécessaire
|
||||||
|
|
||||||
|
### Moyen terme
|
||||||
|
4. Migrer les actor sheets vers AppV2
|
||||||
|
5. Ajouter des features AppV2 (parts, etc.)
|
||||||
|
6. Optimiser les templates
|
||||||
|
|
||||||
|
### Long terme
|
||||||
|
7. Utiliser PARTS pour modularité
|
||||||
|
8. Ajouter des actions avancées
|
||||||
|
9. Améliorer la UX
|
||||||
|
|
||||||
|
## Références
|
||||||
|
|
||||||
|
- [Foundry AppV2 Documentation](https://foundryvtt.com/api/classes/foundry.applications.api.ApplicationV2.html)
|
||||||
|
- [ItemSheetV2 API](https://foundryvtt.com/api/classes/foundry.applications.sheets.ItemSheetV2.html)
|
||||||
|
- Exemples : fvtt-cthulhu-eternal, fvtt-mournblade
|
||||||
35
changelog.md
35
changelog.md
@@ -1,18 +1,26 @@
|
|||||||
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
|
||||||
@@ -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é
|
||||||
|
|
||||||
|
|||||||
1997
css/bol.css
1997
css/bol.css
File diff suppressed because it is too large
Load Diff
@@ -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
|
|
||||||
@@ -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",
|
||||||
|
|||||||
14
lang/en.json
14
lang/en.json
@@ -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",
|
||||||
@@ -546,15 +547,21 @@
|
|||||||
"BOL.chat.bolRulebookMessage": "Don't miss the full Rulebook module (including Sagas) available at : https://www.ludospherik-editions.com/en_gb/ !",
|
"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)",
|
||||||
@@ -602,5 +609,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"
|
||||||
}
|
}
|
||||||
@@ -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",
|
||||||
|
|||||||
17
lang/fr.json
17
lang/fr.json
@@ -394,6 +394,7 @@
|
|||||||
"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",
|
||||||
@@ -573,17 +574,25 @@
|
|||||||
"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)",
|
||||||
@@ -620,7 +629,6 @@
|
|||||||
"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 +650,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() {
|
||||||
@@ -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
|
||||||
@@ -357,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.foundry.applications.handlebars.renderTemplate('systems/bol/templates/chat/chat-activate-fight-option.hbs', { name: this.name, img: fightOption.img, foName: fightOption.name, state: state })
|
||||||
})
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -852,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.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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -904,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.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
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
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
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
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
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
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
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
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,7 +32,9 @@ Hooks.once('init', async function () {
|
|||||||
BoLRoll,
|
BoLRoll,
|
||||||
BoLUtility,
|
BoLUtility,
|
||||||
macros: Macros,
|
macros: Macros,
|
||||||
config: BOL
|
config: BOL,
|
||||||
|
models,
|
||||||
|
sheets
|
||||||
};
|
};
|
||||||
|
|
||||||
// Game socket
|
// Game socket
|
||||||
@@ -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()
|
||||||
@@ -83,35 +110,22 @@ Hooks.once('init', async function () {
|
|||||||
|
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
function welcomeMessage() {
|
async function welcomeMessage() {
|
||||||
let content = `<div id="welcome-message-bol"><span class="rdd-roll-part">
|
const noRulebook = !game.modules.find(m => m.id === "bol-rulebook")
|
||||||
<strong>` + game.i18n.localize("BOL.chat.welcome1") + `</strong><p>` +
|
const content = await foundry.applications.handlebars.renderTemplate(
|
||||||
game.i18n.localize("BOL.chat.welcome2") + "</p><p>" +
|
"systems/bol/templates/chat/chat-welcome.hbs",
|
||||||
game.i18n.localize("BOL.chat.welcome3") + "</p><p>" +
|
{ noRulebook }
|
||||||
game.i18n.localize("BOL.chat.welcome4") + "</p><p>" +
|
)
|
||||||
game.i18n.localize("BOL.chat.welcome5") + "</p>" +
|
ChatMessage.create({ user: game.user.id, whisper: [game.user.id], content })
|
||||||
game.i18n.localize("BOL.chat.welcome6")
|
|
||||||
|
|
||||||
let rulebook = game.modules.find( m => m.id === "bol-rulebook")
|
if (game.user.isGM && game.i18n.lang == 'en' && !game.modules.find(m => m.id == "babele")) {
|
||||||
if ( !rulebook ) {
|
|
||||||
content += "<p>" + game.i18n.localize("BOL.chat.bolRulebookMessage") + "</p>"
|
|
||||||
}
|
|
||||||
ChatMessage.create({
|
|
||||||
user: game.user.id,
|
|
||||||
whisper: [game.user.id],
|
|
||||||
content: content
|
|
||||||
})
|
|
||||||
|
|
||||||
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.")
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
@@ -174,5 +188,3 @@ Hooks.once('ready', async function () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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,
|
||||||
@@ -308,26 +303,31 @@ export class BoLRoll {
|
|||||||
// 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 +360,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 +409,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 +418,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,10 +477,15 @@ 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
|
||||||
@@ -534,6 +534,7 @@ 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)
|
||||||
@@ -546,41 +547,47 @@ 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
|
||||||
@@ -593,12 +600,8 @@ export class BoLRoll {
|
|||||||
r.roll();
|
r.roll();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
]
|
||||||
default: onEnter,
|
}, { classes: ['bol', 'dialog'], width: 480 });
|
||||||
close: () => { }
|
|
||||||
}, this.options());
|
|
||||||
|
|
||||||
return d.render(true);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -634,7 +637,7 @@ 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
|
||||||
@@ -642,7 +645,7 @@ export class BoLDefaultRoll {
|
|||||||
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 +695,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)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
@@ -805,13 +805,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)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { BoLUtility } from "../system/bol-utility.js";
|
|||||||
* Extend the basic ItemSheet with some very simple modifications
|
* Extend the basic ItemSheet with some very simple modifications
|
||||||
* @extends {ItemSheet}
|
* @extends {ItemSheet}
|
||||||
*/
|
*/
|
||||||
export class BoLItemSheet extends ItemSheet {
|
export class BoLItemSheet extends foundry.appv1.sheets.ItemSheet {
|
||||||
|
|
||||||
/** @override */
|
/** @override */
|
||||||
static get defaultOptions() {
|
static get defaultOptions() {
|
||||||
@@ -13,6 +13,7 @@ export class BoLItemSheet extends ItemSheet {
|
|||||||
template: "systems/bol/templates/item/item-sheet.hbs",
|
template: "systems/bol/templates/item/item-sheet.hbs",
|
||||||
width: 650,
|
width: 650,
|
||||||
height: 780,
|
height: 780,
|
||||||
|
dragDrop: [{ dragSelector: null, dropSelector: null }],
|
||||||
tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "description" }]
|
tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "description" }]
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -27,7 +28,7 @@ export class BoLItemSheet extends ItemSheet {
|
|||||||
data.category = itemData.system.category
|
data.category = itemData.system.category
|
||||||
data.isGM = game.user.isGM;
|
data.isGM = game.user.isGM;
|
||||||
data.itemProperties = this.item.itemProperties;
|
data.itemProperties = this.item.itemProperties;
|
||||||
data.description = await TextEditor.enrichHTML(this.object.system.description, { async: true })
|
data.description = await foundry.applications.ux.TextEditor.implementation.enrichHTML(this.object.system.description, { async: true })
|
||||||
if (data.document.actor) {
|
if (data.document.actor) {
|
||||||
data.careers = data.document.actor.careers
|
data.careers = data.document.actor.careers
|
||||||
}
|
}
|
||||||
@@ -102,6 +103,7 @@ export class BoLItemSheet extends ItemSheet {
|
|||||||
activateListeners(html) {
|
activateListeners(html) {
|
||||||
|
|
||||||
super.activateListeners(html);
|
super.activateListeners(html);
|
||||||
|
|
||||||
// Everything below here is only needed if the sheet is editable
|
// Everything below here is only needed if the sheet is editable
|
||||||
if (!this.options.editable) return;
|
if (!this.options.editable) return;
|
||||||
// Roll handlers, click handlers, etc. would go here.
|
// Roll handlers, click handlers, etc. would go here.
|
||||||
119
module/item.backup/item-sheet.js.appv1
Normal file
119
module/item.backup/item-sheet.js.appv1
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
import { BoLUtility } from "../system/bol-utility.js";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extend the basic ItemSheet with some very simple modifications
|
||||||
|
* @extends {ItemSheet}
|
||||||
|
*/
|
||||||
|
export class BoLItemSheet extends foundry.appv1.sheets.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,
|
||||||
|
dragDrop: [{ dragSelector: null, dropSelector: null }],
|
||||||
|
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 foundry.applications.ux.TextEditor.implementation.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()]);
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
36
module/item.backup/item.js
Normal file
36
module/item.backup/item.js
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
/**
|
||||||
|
* Extend the basic Item with some very simple modifications.
|
||||||
|
* @extends {Item}
|
||||||
|
*/
|
||||||
|
export class BoLItem extends Item {
|
||||||
|
/**
|
||||||
|
* Augment the basic Item data model with additional dynamic data.
|
||||||
|
*/
|
||||||
|
prepareData() {
|
||||||
|
super.prepareData()
|
||||||
|
|
||||||
|
const actorData = this.actor ? this.actor.system : {}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
get properties() {
|
||||||
|
return this.system.properties
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
/**
|
||||||
|
* Get the Array of item properties which are used in the small sidebar of the description tab
|
||||||
|
* @return {Array}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
get itemProperties() {
|
||||||
|
const props = [];
|
||||||
|
if ( this.type === "item" ) {
|
||||||
|
const entries = Object.entries(this.system.properties)
|
||||||
|
props.push(...entries.filter(e => e[1] === true).map(e => { return game.bol.config.itemProperties2[e[0]] }))
|
||||||
|
}
|
||||||
|
return props.filter(p => !!p)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
112
module/models/README.md
Normal file
112
module/models/README.md
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
# BoL DataModels
|
||||||
|
|
||||||
|
Ce dossier contient les DataModels pour le système Barbarians of Lemuria (BoL).
|
||||||
|
|
||||||
|
## Structure
|
||||||
|
|
||||||
|
### Actors DataModels
|
||||||
|
|
||||||
|
- **character.mjs** : Personnages joueurs
|
||||||
|
- Attributs (Vigor, Agility, Mind, Appeal)
|
||||||
|
- Aptitudes (Initiative, Mêlée, Distance, Défense)
|
||||||
|
- Ressources (HP, Hero Points, Faith, Power, Alchemy, Astrology)
|
||||||
|
- XP et création
|
||||||
|
- Bougette (argent)
|
||||||
|
|
||||||
|
- **encounter.mjs** : PNJ et créatures
|
||||||
|
- Mêmes attributs que character
|
||||||
|
- Champs spécifiques : chartype (tough/villain), isundead, size, environment
|
||||||
|
|
||||||
|
- **horde.mjs** : Hordes de créatures
|
||||||
|
- Mêmes attributs de base
|
||||||
|
- Champs spécifiques : hordesize, hordebasehp, hasdamagerule, damagerule
|
||||||
|
|
||||||
|
- **vehicle.mjs** : Véhicules (navires, chars, etc.)
|
||||||
|
- Attributs véhicules : hull, crew, resources
|
||||||
|
- Champs spécifiques : vehicletype, row, spur, status
|
||||||
|
|
||||||
|
### Items DataModels
|
||||||
|
|
||||||
|
- **item.mjs** : Équipements et objets
|
||||||
|
- Propriétés (weapon, armor, magical, etc.)
|
||||||
|
- Équipement (quantity, weight, price, worn)
|
||||||
|
- Category et subtype
|
||||||
|
|
||||||
|
- **feature.mjs** : Capacités, traits, sorts
|
||||||
|
- Rank (niveau/rang)
|
||||||
|
- Description
|
||||||
|
- Category et subtype
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
Tous les DataModels héritent de `foundry.abstract.TypeDataModel` et définissent leur schéma via `defineSchema()`.
|
||||||
|
|
||||||
|
Exemple de structure :
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
export default class BoLCharacterDataModel extends foundry.abstract.TypeDataModel {
|
||||||
|
static defineSchema() {
|
||||||
|
const fields = foundry.data.fields;
|
||||||
|
const requiredInteger = { required: true, nullable: false, integer: true };
|
||||||
|
|
||||||
|
return {
|
||||||
|
// Définition des champs
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static LOCALIZATION_PREFIXES = ["BOL.Character"];
|
||||||
|
|
||||||
|
// Méthodes personnalisées (à ajouter)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Types de champs utilisés
|
||||||
|
|
||||||
|
- `StringField` : Chaînes de caractères
|
||||||
|
- `NumberField` : Nombres (avec option `integer: true` pour entiers)
|
||||||
|
- `BooleanField` : Booléens
|
||||||
|
- `HTMLField` : HTML enrichi (descriptions, biographies)
|
||||||
|
- `ArrayField` : Tableaux
|
||||||
|
- `SchemaField` : Objets imbriqués
|
||||||
|
|
||||||
|
## Export
|
||||||
|
|
||||||
|
Le fichier `_module.mjs` exporte tous les DataModels :
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
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"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Configuration dans bol.js
|
||||||
|
|
||||||
|
Les DataModels sont enregistrés dans `CONFIG` :
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
CONFIG.Actor.dataModels = {
|
||||||
|
character: models.BoLCharacter,
|
||||||
|
encounter: models.BoLEncounter,
|
||||||
|
horde: models.BoLHorde,
|
||||||
|
vehicle: models.BoLVehicle
|
||||||
|
}
|
||||||
|
|
||||||
|
CONFIG.Item.dataModels = {
|
||||||
|
item: models.BoLItem,
|
||||||
|
feature: models.BoLFeature
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Compatibilité
|
||||||
|
|
||||||
|
Les DataModels sont compatibles avec le `template.json` existant. La migration est transparente pour les données existantes.
|
||||||
|
|
||||||
|
## Prochaines étapes
|
||||||
|
|
||||||
|
1. Ajouter `prepareDerivedData()` pour les calculs automatiques
|
||||||
|
2. Migrer la logique métier depuis actor.js
|
||||||
|
3. Ajouter des validations personnalisées
|
||||||
|
4. Documenter avec JSDoc
|
||||||
6
module/models/_module.mjs
Normal file
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
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
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
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
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
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
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);
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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)
|
||||||
@@ -427,7 +434,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 +487,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 +509,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 +554,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.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.foundry.applications.handlebars.renderTemplate('systems/bol/templates/chat/rolls/defense-summary-card.hbs', damageResults)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -628,11 +647,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.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,7 +73,7 @@ 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)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -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",
|
||||||
@@ -62,9 +63,10 @@ export const preloadHandlebarsTemplates = async function () {
|
|||||||
"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);
|
||||||
};
|
};
|
||||||
|
|||||||
Binary file not shown.
@@ -1 +1 @@
|
|||||||
MANIFEST-000766
|
MANIFEST-001076
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
2025/03/31-07:10:17.059640 7f9cf5ffb6c0 Recovering log #764
|
2026/02/28-22:59:53.852685 7f56e3fff6c0 Recovering log #1074
|
||||||
2025/03/31-07:10:17.113093 7f9cf5ffb6c0 Delete type=3 #762
|
2026/02/28-22:59:53.863099 7f56e3fff6c0 Delete type=3 #1072
|
||||||
2025/03/31-07:10:17.113203 7f9cf5ffb6c0 Delete type=0 #764
|
2026/02/28-22:59:53.863210 7f56e3fff6c0 Delete type=0 #1074
|
||||||
2025/03/31-07:15:11.784077 7f9cf4ff96c0 Level-0 table #769: started
|
2026/03/01-01:08:46.366409 7f54e37ef6c0 Level-0 table #1079: started
|
||||||
2025/03/31-07:15:11.784139 7f9cf4ff96c0 Level-0 table #769: 0 bytes OK
|
2026/03/01-01:08:46.366440 7f54e37ef6c0 Level-0 table #1079: 0 bytes OK
|
||||||
2025/03/31-07:15:11.820358 7f9cf4ff96c0 Delete type=0 #767
|
2026/03/01-01:08:46.372420 7f54e37ef6c0 Delete type=0 #1077
|
||||||
2025/03/31-07:15:11.863418 7f9cf4ff96c0 Manual compaction at level-0 from '!journal!3xJg1rCxnWvEmoxS' @ 72057594037927935 : 1 .. '!journal.pages!veAAxCtCKcFIsnln.0kUgZspxXO7VS8bd' @ 0 : 0; will stop at (end)
|
2026/03/01-01:08:46.391669 7f54e37ef6c0 Manual compaction at level-0 from '!journal!3xJg1rCxnWvEmoxS' @ 72057594037927935 : 1 .. '!journal.pages!veAAxCtCKcFIsnln.0kUgZspxXO7VS8bd' @ 0 : 0; will stop at (end)
|
||||||
2025/03/31-07:15:11.863502 7f9cf4ff96c0 Manual compaction at level-1 from '!journal!3xJg1rCxnWvEmoxS' @ 72057594037927935 : 1 .. '!journal.pages!veAAxCtCKcFIsnln.0kUgZspxXO7VS8bd' @ 0 : 0; will stop at (end)
|
2026/03/01-01:08:46.391720 7f54e37ef6c0 Manual compaction at level-1 from '!journal!3xJg1rCxnWvEmoxS' @ 72057594037927935 : 1 .. '!journal.pages!veAAxCtCKcFIsnln.0kUgZspxXO7VS8bd' @ 0 : 0; will stop at (end)
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
2025/03/31-07:01:18.138827 7f9cf67fc6c0 Recovering log #759
|
2026/02/28-17:23:52.883622 7f56f93fe6c0 Recovering log #1070
|
||||||
2025/03/31-07:01:18.151000 7f9cf67fc6c0 Delete type=3 #757
|
2026/02/28-17:23:52.893895 7f56f93fe6c0 Delete type=3 #1068
|
||||||
2025/03/31-07:01:18.151096 7f9cf67fc6c0 Delete type=0 #759
|
2026/02/28-17:23:52.893967 7f56f93fe6c0 Delete type=0 #1070
|
||||||
2025/03/31-07:05:47.761503 7f9cf4ff96c0 Level-0 table #765: started
|
2026/02/28-22:59:43.750682 7f54e37ef6c0 Level-0 table #1075: started
|
||||||
2025/03/31-07:05:47.761554 7f9cf4ff96c0 Level-0 table #765: 0 bytes OK
|
2026/02/28-22:59:43.750749 7f54e37ef6c0 Level-0 table #1075: 0 bytes OK
|
||||||
2025/03/31-07:05:47.767897 7f9cf4ff96c0 Delete type=0 #763
|
2026/02/28-22:59:43.758241 7f54e37ef6c0 Delete type=0 #1073
|
||||||
2025/03/31-07:05:47.768254 7f9cf4ff96c0 Manual compaction at level-0 from '!journal!3xJg1rCxnWvEmoxS' @ 72057594037927935 : 1 .. '!journal.pages!veAAxCtCKcFIsnln.0kUgZspxXO7VS8bd' @ 0 : 0; will stop at (end)
|
2026/02/28-22:59:43.758440 7f54e37ef6c0 Manual compaction at level-0 from '!journal!3xJg1rCxnWvEmoxS' @ 72057594037927935 : 1 .. '!journal.pages!veAAxCtCKcFIsnln.0kUgZspxXO7VS8bd' @ 0 : 0; will stop at (end)
|
||||||
2025/03/31-07:05:47.768322 7f9cf4ff96c0 Manual compaction at level-1 from '!journal!3xJg1rCxnWvEmoxS' @ 72057594037927935 : 1 .. '!journal.pages!veAAxCtCKcFIsnln.0kUgZspxXO7VS8bd' @ 0 : 0; will stop at (end)
|
2026/02/28-22:59:43.758473 7f54e37ef6c0 Manual compaction at level-1 from '!journal!3xJg1rCxnWvEmoxS' @ 72057594037927935 : 1 .. '!journal.pages!veAAxCtCKcFIsnln.0kUgZspxXO7VS8bd' @ 0 : 0; will stop at (end)
|
||||||
|
|||||||
Binary file not shown.
BIN
packs/aides-de-jeu/MANIFEST-001076
Normal file
BIN
packs/aides-de-jeu/MANIFEST-001076
Normal file
Binary file not shown.
Binary file not shown.
@@ -1 +1 @@
|
|||||||
MANIFEST-000671
|
MANIFEST-000981
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
2025/03/31-07:10:16.947165 7f9cf67fc6c0 Recovering log #669
|
2026/02/28-22:59:53.826224 7f56f8bfd6c0 Recovering log #979
|
||||||
2025/03/31-07:10:17.010788 7f9cf67fc6c0 Delete type=3 #667
|
2026/02/28-22:59:53.836758 7f56f8bfd6c0 Delete type=3 #977
|
||||||
2025/03/31-07:10:17.010920 7f9cf67fc6c0 Delete type=0 #669
|
2026/02/28-22:59:53.836823 7f56f8bfd6c0 Delete type=0 #979
|
||||||
2025/03/31-07:15:11.712245 7f9cf4ff96c0 Level-0 table #674: started
|
2026/03/01-01:08:46.372471 7f54e37ef6c0 Level-0 table #984: started
|
||||||
2025/03/31-07:15:11.712293 7f9cf4ff96c0 Level-0 table #674: 0 bytes OK
|
2026/03/01-01:08:46.372486 7f54e37ef6c0 Level-0 table #984: 0 bytes OK
|
||||||
2025/03/31-07:15:11.745296 7f9cf4ff96c0 Delete type=0 #672
|
2026/03/01-01:08:46.378495 7f54e37ef6c0 Delete type=0 #982
|
||||||
2025/03/31-07:15:11.863357 7f9cf4ff96c0 Manual compaction at level-0 from '!items!G3dZTHIabA3LA1hY' @ 72057594037927935 : 1 .. '!items!xhEcsi3WHjbt2ro9' @ 0 : 0; will stop at (end)
|
2026/03/01-01:08:46.391687 7f54e37ef6c0 Manual compaction at level-0 from '!items!G3dZTHIabA3LA1hY' @ 72057594037927935 : 1 .. '!items!xhEcsi3WHjbt2ro9' @ 0 : 0; will stop at (end)
|
||||||
2025/03/31-07:15:11.863483 7f9cf4ff96c0 Manual compaction at level-1 from '!items!G3dZTHIabA3LA1hY' @ 72057594037927935 : 1 .. '!items!xhEcsi3WHjbt2ro9' @ 0 : 0; will stop at (end)
|
2026/03/01-01:08:46.391731 7f54e37ef6c0 Manual compaction at level-1 from '!items!G3dZTHIabA3LA1hY' @ 72057594037927935 : 1 .. '!items!xhEcsi3WHjbt2ro9' @ 0 : 0; will stop at (end)
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
2025/03/31-07:01:18.108119 7f9cf57fa6c0 Recovering log #664
|
2026/02/28-17:23:52.858522 7f56e3fff6c0 Recovering log #975
|
||||||
2025/03/31-07:01:18.118686 7f9cf57fa6c0 Delete type=3 #662
|
2026/02/28-17:23:52.869495 7f56e3fff6c0 Delete type=3 #973
|
||||||
2025/03/31-07:01:18.118791 7f9cf57fa6c0 Delete type=0 #664
|
2026/02/28-17:23:52.869552 7f56e3fff6c0 Delete type=0 #975
|
||||||
2025/03/31-07:05:47.740195 7f9cf4ff96c0 Level-0 table #670: started
|
2026/02/28-22:59:43.737596 7f54e37ef6c0 Level-0 table #980: started
|
||||||
2025/03/31-07:05:47.740253 7f9cf4ff96c0 Level-0 table #670: 0 bytes OK
|
2026/02/28-22:59:43.737635 7f54e37ef6c0 Level-0 table #980: 0 bytes OK
|
||||||
2025/03/31-07:05:47.746679 7f9cf4ff96c0 Delete type=0 #668
|
2026/02/28-22:59:43.743801 7f54e37ef6c0 Delete type=0 #978
|
||||||
2025/03/31-07:05:47.768165 7f9cf4ff96c0 Manual compaction at level-0 from '!items!G3dZTHIabA3LA1hY' @ 72057594037927935 : 1 .. '!items!xhEcsi3WHjbt2ro9' @ 0 : 0; will stop at (end)
|
2026/02/28-22:59:43.758414 7f54e37ef6c0 Manual compaction at level-0 from '!items!G3dZTHIabA3LA1hY' @ 72057594037927935 : 1 .. '!items!xhEcsi3WHjbt2ro9' @ 0 : 0; will stop at (end)
|
||||||
2025/03/31-07:05:47.768278 7f9cf4ff96c0 Manual compaction at level-1 from '!items!G3dZTHIabA3LA1hY' @ 72057594037927935 : 1 .. '!items!xhEcsi3WHjbt2ro9' @ 0 : 0; will stop at (end)
|
2026/02/28-22:59:43.758457 7f54e37ef6c0 Manual compaction at level-1 from '!items!G3dZTHIabA3LA1hY' @ 72057594037927935 : 1 .. '!items!xhEcsi3WHjbt2ro9' @ 0 : 0; will stop at (end)
|
||||||
|
|||||||
Binary file not shown.
BIN
packs/armors/MANIFEST-000981
Normal file
BIN
packs/armors/MANIFEST-000981
Normal file
Binary file not shown.
Binary file not shown.
BIN
packs/boons/000843.ldb
Normal file
BIN
packs/boons/000843.ldb
Normal file
Binary file not shown.
@@ -1 +1 @@
|
|||||||
MANIFEST-000764
|
MANIFEST-001075
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
2025/03/31-07:10:16.407604 7f9cf67fc6c0 Recovering log #762
|
2026/02/28-22:59:53.718001 7f56f8bfd6c0 Recovering log #1073
|
||||||
2025/03/31-07:10:16.479813 7f9cf67fc6c0 Delete type=3 #760
|
2026/02/28-22:59:53.729345 7f56f8bfd6c0 Delete type=3 #1071
|
||||||
2025/03/31-07:10:16.479936 7f9cf67fc6c0 Delete type=0 #762
|
2026/02/28-22:59:53.729412 7f56f8bfd6c0 Delete type=0 #1073
|
||||||
2025/03/31-07:15:11.462830 7f9cf4ff96c0 Level-0 table #767: started
|
2026/03/01-01:08:46.321084 7f54e37ef6c0 Level-0 table #1078: started
|
||||||
2025/03/31-07:15:11.462886 7f9cf4ff96c0 Level-0 table #767: 0 bytes OK
|
2026/03/01-01:08:46.321111 7f54e37ef6c0 Level-0 table #1078: 0 bytes OK
|
||||||
2025/03/31-07:15:11.500813 7f9cf4ff96c0 Delete type=0 #765
|
2026/03/01-01:08:46.327221 7f54e37ef6c0 Delete type=0 #1076
|
||||||
2025/03/31-07:15:11.563807 7f9cf4ff96c0 Manual compaction at level-0 from '!items!039ZF3E3MtAGwbiX' @ 72057594037927935 : 1 .. '!items!zgspy1QKaxdEetEw' @ 0 : 0; will stop at (end)
|
2026/03/01-01:08:46.339937 7f54e37ef6c0 Manual compaction at level-0 from '!items!039ZF3E3MtAGwbiX' @ 72057594037927935 : 1 .. '!items!zgspy1QKaxdEetEw' @ 0 : 0; will stop at (end)
|
||||||
2025/03/31-07:15:11.563949 7f9cf4ff96c0 Manual compaction at level-1 from '!items!039ZF3E3MtAGwbiX' @ 72057594037927935 : 1 .. '!items!zgspy1QKaxdEetEw' @ 0 : 0; will stop at (end)
|
2026/03/01-01:08:46.339972 7f54e37ef6c0 Manual compaction at level-1 from '!items!039ZF3E3MtAGwbiX' @ 72057594037927935 : 1 .. '!items!zgspy1QKaxdEetEw' @ 0 : 0; will stop at (end)
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
2025/03/31-07:01:17.972300 7f9cf57fa6c0 Recovering log #757
|
2026/02/28-17:23:52.757933 7f56f9bff6c0 Recovering log #1069
|
||||||
2025/03/31-07:01:17.983482 7f9cf57fa6c0 Delete type=3 #755
|
2026/02/28-17:23:52.767692 7f56f9bff6c0 Delete type=3 #1067
|
||||||
2025/03/31-07:01:17.983631 7f9cf57fa6c0 Delete type=0 #757
|
2026/02/28-17:23:52.767761 7f56f9bff6c0 Delete type=0 #1069
|
||||||
2025/03/31-07:05:47.692525 7f9cf4ff96c0 Level-0 table #763: started
|
2026/02/28-22:59:43.697108 7f54e37ef6c0 Level-0 table #1074: started
|
||||||
2025/03/31-07:05:47.692582 7f9cf4ff96c0 Level-0 table #763: 0 bytes OK
|
2026/02/28-22:59:43.697152 7f54e37ef6c0 Level-0 table #1074: 0 bytes OK
|
||||||
2025/03/31-07:05:47.698782 7f9cf4ff96c0 Delete type=0 #761
|
2026/02/28-22:59:43.704224 7f54e37ef6c0 Delete type=0 #1072
|
||||||
2025/03/31-07:05:47.712293 7f9cf4ff96c0 Manual compaction at level-0 from '!items!039ZF3E3MtAGwbiX' @ 72057594037927935 : 1 .. '!items!zgspy1QKaxdEetEw' @ 0 : 0; will stop at (end)
|
2026/02/28-22:59:43.704461 7f54e37ef6c0 Manual compaction at level-0 from '!items!039ZF3E3MtAGwbiX' @ 72057594037927935 : 1 .. '!items!zgspy1QKaxdEetEw' @ 0 : 0; will stop at (end)
|
||||||
2025/03/31-07:05:47.712359 7f9cf4ff96c0 Manual compaction at level-1 from '!items!039ZF3E3MtAGwbiX' @ 72057594037927935 : 1 .. '!items!zgspy1QKaxdEetEw' @ 0 : 0; will stop at (end)
|
2026/02/28-22:59:43.704511 7f54e37ef6c0 Manual compaction at level-1 from '!items!039ZF3E3MtAGwbiX' @ 72057594037927935 : 1 .. '!items!zgspy1QKaxdEetEw' @ 0 : 0; will stop at (end)
|
||||||
|
|||||||
Binary file not shown.
BIN
packs/boons/MANIFEST-001075
Normal file
BIN
packs/boons/MANIFEST-001075
Normal file
Binary file not shown.
Binary file not shown.
@@ -1 +1 @@
|
|||||||
MANIFEST-000764
|
MANIFEST-001074
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
2025/03/31-07:10:16.483153 7f9cf6ffd6c0 Recovering log #762
|
2026/02/28-22:59:53.732583 7f56e3fff6c0 Recovering log #1072
|
||||||
2025/03/31-07:10:16.551518 7f9cf6ffd6c0 Delete type=3 #760
|
2026/02/28-22:59:53.742972 7f56e3fff6c0 Delete type=3 #1070
|
||||||
2025/03/31-07:10:16.551693 7f9cf6ffd6c0 Delete type=0 #762
|
2026/02/28-22:59:53.743061 7f56e3fff6c0 Delete type=0 #1072
|
||||||
2025/03/31-07:15:11.534471 7f9cf4ff96c0 Level-0 table #767: started
|
2026/03/01-01:08:46.313828 7f54e37ef6c0 Level-0 table #1077: started
|
||||||
2025/03/31-07:15:11.534518 7f9cf4ff96c0 Level-0 table #767: 0 bytes OK
|
2026/03/01-01:08:46.313877 7f54e37ef6c0 Level-0 table #1077: 0 bytes OK
|
||||||
2025/03/31-07:15:11.563419 7f9cf4ff96c0 Delete type=0 #765
|
2026/03/01-01:08:46.320973 7f54e37ef6c0 Delete type=0 #1075
|
||||||
2025/03/31-07:15:11.563892 7f9cf4ff96c0 Manual compaction at level-0 from '!items!CoqlfsDV1gL5swbK' @ 72057594037927935 : 1 .. '!items!yofwG0YrsL902G77' @ 0 : 0; will stop at (end)
|
2026/03/01-01:08:46.339925 7f54e37ef6c0 Manual compaction at level-0 from '!items!CoqlfsDV1gL5swbK' @ 72057594037927935 : 1 .. '!items!yofwG0YrsL902G77' @ 0 : 0; will stop at (end)
|
||||||
2025/03/31-07:15:11.564007 7f9cf4ff96c0 Manual compaction at level-1 from '!items!CoqlfsDV1gL5swbK' @ 72057594037927935 : 1 .. '!items!yofwG0YrsL902G77' @ 0 : 0; will stop at (end)
|
2026/03/01-01:08:46.339953 7f54e37ef6c0 Manual compaction at level-1 from '!items!CoqlfsDV1gL5swbK' @ 72057594037927935 : 1 .. '!items!yofwG0YrsL902G77' @ 0 : 0; will stop at (end)
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
2025/03/31-07:01:17.988979 7f9cf5ffb6c0 Recovering log #757
|
2026/02/28-17:23:52.769847 7f56f93fe6c0 Recovering log #1068
|
||||||
2025/03/31-07:01:18.000788 7f9cf5ffb6c0 Delete type=3 #755
|
2026/02/28-17:23:52.780583 7f56f93fe6c0 Delete type=3 #1066
|
||||||
2025/03/31-07:01:18.000890 7f9cf5ffb6c0 Delete type=0 #757
|
2026/02/28-17:23:52.780639 7f56f93fe6c0 Delete type=0 #1068
|
||||||
2025/03/31-07:05:47.684708 7f9cf4ff96c0 Level-0 table #763: started
|
2026/02/28-22:59:43.677524 7f54e37ef6c0 Level-0 table #1073: started
|
||||||
2025/03/31-07:05:47.684770 7f9cf4ff96c0 Level-0 table #763: 0 bytes OK
|
2026/02/28-22:59:43.677620 7f54e37ef6c0 Level-0 table #1073: 0 bytes OK
|
||||||
2025/03/31-07:05:47.692347 7f9cf4ff96c0 Delete type=0 #761
|
2026/02/28-22:59:43.684329 7f54e37ef6c0 Delete type=0 #1071
|
||||||
2025/03/31-07:05:47.712274 7f9cf4ff96c0 Manual compaction at level-0 from '!items!CoqlfsDV1gL5swbK' @ 72057594037927935 : 1 .. '!items!yofwG0YrsL902G77' @ 0 : 0; will stop at (end)
|
2026/02/28-22:59:43.704401 7f54e37ef6c0 Manual compaction at level-0 from '!items!CoqlfsDV1gL5swbK' @ 72057594037927935 : 1 .. '!items!yofwG0YrsL902G77' @ 0 : 0; will stop at (end)
|
||||||
2025/03/31-07:05:47.712328 7f9cf4ff96c0 Manual compaction at level-1 from '!items!CoqlfsDV1gL5swbK' @ 72057594037927935 : 1 .. '!items!yofwG0YrsL902G77' @ 0 : 0; will stop at (end)
|
2026/02/28-22:59:43.704474 7f54e37ef6c0 Manual compaction at level-1 from '!items!CoqlfsDV1gL5swbK' @ 72057594037927935 : 1 .. '!items!yofwG0YrsL902G77' @ 0 : 0; will stop at (end)
|
||||||
|
|||||||
Binary file not shown.
BIN
packs/boonsflawscreatures/MANIFEST-001074
Normal file
BIN
packs/boonsflawscreatures/MANIFEST-001074
Normal file
Binary file not shown.
Binary file not shown.
@@ -1 +1 @@
|
|||||||
MANIFEST-000764
|
MANIFEST-001074
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
2025/03/31-07:10:16.627946 7f9cf57fa6c0 Recovering log #762
|
2026/02/28-22:59:53.759689 7f56f8bfd6c0 Recovering log #1072
|
||||||
2025/03/31-07:10:16.690160 7f9cf57fa6c0 Delete type=3 #760
|
2026/02/28-22:59:53.770229 7f56f8bfd6c0 Delete type=3 #1070
|
||||||
2025/03/31-07:10:16.690297 7f9cf57fa6c0 Delete type=0 #762
|
2026/02/28-22:59:53.770305 7f56f8bfd6c0 Delete type=0 #1072
|
||||||
2025/03/31-07:15:11.501071 7f9cf4ff96c0 Level-0 table #767: started
|
2026/03/01-01:08:46.327327 7f54e37ef6c0 Level-0 table #1077: started
|
||||||
2025/03/31-07:15:11.501145 7f9cf4ff96c0 Level-0 table #767: 0 bytes OK
|
2026/03/01-01:08:46.327354 7f54e37ef6c0 Level-0 table #1077: 0 bytes OK
|
||||||
2025/03/31-07:15:11.534293 7f9cf4ff96c0 Delete type=0 #765
|
2026/03/01-01:08:46.333262 7f54e37ef6c0 Delete type=0 #1075
|
||||||
2025/03/31-07:15:11.563855 7f9cf4ff96c0 Manual compaction at level-0 from '!items!4S4xAfMXGnuU0O1a' @ 72057594037927935 : 1 .. '!items!zxY3sW0iCJBvwjOS' @ 0 : 0; will stop at (end)
|
2026/03/01-01:08:46.339946 7f54e37ef6c0 Manual compaction at level-0 from '!items!4S4xAfMXGnuU0O1a' @ 72057594037927935 : 1 .. '!items!zxY3sW0iCJBvwjOS' @ 0 : 0; will stop at (end)
|
||||||
2025/03/31-07:15:11.563976 7f9cf4ff96c0 Manual compaction at level-1 from '!items!4S4xAfMXGnuU0O1a' @ 72057594037927935 : 1 .. '!items!zxY3sW0iCJBvwjOS' @ 0 : 0; will stop at (end)
|
2026/03/01-01:08:46.339979 7f54e37ef6c0 Manual compaction at level-1 from '!items!4S4xAfMXGnuU0O1a' @ 72057594037927935 : 1 .. '!items!zxY3sW0iCJBvwjOS' @ 0 : 0; will stop at (end)
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
2025/03/31-07:01:18.022229 7f9cf6ffd6c0 Recovering log #757
|
2026/02/28-17:23:52.796426 7f56f9bff6c0 Recovering log #1068
|
||||||
2025/03/31-07:01:18.032764 7f9cf6ffd6c0 Delete type=3 #755
|
2026/02/28-17:23:52.805920 7f56f9bff6c0 Delete type=3 #1066
|
||||||
2025/03/31-07:01:18.032860 7f9cf6ffd6c0 Delete type=0 #757
|
2026/02/28-17:23:52.805973 7f56f9bff6c0 Delete type=0 #1068
|
||||||
2025/03/31-07:05:47.699022 7f9cf4ff96c0 Level-0 table #763: started
|
2026/02/28-22:59:43.711333 7f54e37ef6c0 Level-0 table #1073: started
|
||||||
2025/03/31-07:05:47.699076 7f9cf4ff96c0 Level-0 table #763: 0 bytes OK
|
2026/02/28-22:59:43.711370 7f54e37ef6c0 Level-0 table #1073: 0 bytes OK
|
||||||
2025/03/31-07:05:47.705257 7f9cf4ff96c0 Delete type=0 #761
|
2026/02/28-22:59:43.717336 7f54e37ef6c0 Delete type=0 #1071
|
||||||
2025/03/31-07:05:47.712313 7f9cf4ff96c0 Manual compaction at level-0 from '!items!4S4xAfMXGnuU0O1a' @ 72057594037927935 : 1 .. '!items!zxY3sW0iCJBvwjOS' @ 0 : 0; will stop at (end)
|
2026/02/28-22:59:43.731041 7f54e37ef6c0 Manual compaction at level-0 from '!items!4S4xAfMXGnuU0O1a' @ 72057594037927935 : 1 .. '!items!zxY3sW0iCJBvwjOS' @ 0 : 0; will stop at (end)
|
||||||
2025/03/31-07:05:47.712370 7f9cf4ff96c0 Manual compaction at level-1 from '!items!4S4xAfMXGnuU0O1a' @ 72057594037927935 : 1 .. '!items!zxY3sW0iCJBvwjOS' @ 0 : 0; will stop at (end)
|
2026/02/28-22:59:43.731086 7f54e37ef6c0 Manual compaction at level-1 from '!items!4S4xAfMXGnuU0O1a' @ 72057594037927935 : 1 .. '!items!zxY3sW0iCJBvwjOS' @ 0 : 0; will stop at (end)
|
||||||
|
|||||||
Binary file not shown.
BIN
packs/careers/MANIFEST-001074
Normal file
BIN
packs/careers/MANIFEST-001074
Normal file
Binary file not shown.
Binary file not shown.
@@ -1 +1 @@
|
|||||||
MANIFEST-000762
|
MANIFEST-001072
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
2025/03/31-07:10:17.506385 7f9cf6ffd6c0 Recovering log #760
|
2026/02/28-22:59:53.948768 7f56f93fe6c0 Recovering log #1070
|
||||||
2025/03/31-07:10:17.575234 7f9cf6ffd6c0 Delete type=3 #758
|
2026/02/28-22:59:53.958702 7f56f93fe6c0 Delete type=3 #1068
|
||||||
2025/03/31-07:10:17.575341 7f9cf6ffd6c0 Delete type=0 #760
|
2026/02/28-22:59:53.958781 7f56f93fe6c0 Delete type=0 #1070
|
||||||
2025/03/31-07:15:12.157098 7f9cf4ff96c0 Level-0 table #765: started
|
2026/03/01-01:08:46.425514 7f54e37ef6c0 Level-0 table #1075: started
|
||||||
2025/03/31-07:15:12.157181 7f9cf4ff96c0 Level-0 table #765: 0 bytes OK
|
2026/03/01-01:08:46.425561 7f54e37ef6c0 Level-0 table #1075: 0 bytes OK
|
||||||
2025/03/31-07:15:12.193443 7f9cf4ff96c0 Delete type=0 #763
|
2026/03/01-01:08:46.431671 7f54e37ef6c0 Delete type=0 #1073
|
||||||
2025/03/31-07:15:12.193715 7f9cf4ff96c0 Manual compaction at level-0 from '!items!6fTZ6hOKR4pWbWOe' @ 72057594037927935 : 1 .. '!items!zwSNMO9HpiqUCMt8' @ 0 : 0; will stop at (end)
|
2026/03/01-01:08:46.445290 7f54e37ef6c0 Manual compaction at level-0 from '!items!6fTZ6hOKR4pWbWOe' @ 72057594037927935 : 1 .. '!items!zwSNMO9HpiqUCMt8' @ 0 : 0; will stop at (end)
|
||||||
2025/03/31-07:15:12.241607 7f9cf4ff96c0 Manual compaction at level-1 from '!items!6fTZ6hOKR4pWbWOe' @ 72057594037927935 : 1 .. '!items!zwSNMO9HpiqUCMt8' @ 0 : 0; will stop at (end)
|
2026/03/01-01:08:46.445328 7f54e37ef6c0 Manual compaction at level-1 from '!items!6fTZ6hOKR4pWbWOe' @ 72057594037927935 : 1 .. '!items!zwSNMO9HpiqUCMt8' @ 0 : 0; will stop at (end)
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
2025/03/31-07:01:18.249810 7f9cf5ffb6c0 Recovering log #755
|
2026/02/28-17:23:52.970603 7f56f9bff6c0 Recovering log #1066
|
||||||
2025/03/31-07:01:18.261010 7f9cf5ffb6c0 Delete type=3 #753
|
2026/02/28-17:23:52.981835 7f56f9bff6c0 Delete type=3 #1064
|
||||||
2025/03/31-07:01:18.261104 7f9cf5ffb6c0 Delete type=0 #755
|
2026/02/28-17:23:52.981888 7f56f9bff6c0 Delete type=0 #1066
|
||||||
2025/03/31-07:05:47.811953 7f9cf4ff96c0 Level-0 table #761: started
|
2026/02/28-22:59:43.785498 7f54e37ef6c0 Level-0 table #1071: started
|
||||||
2025/03/31-07:05:47.811991 7f9cf4ff96c0 Level-0 table #761: 0 bytes OK
|
2026/02/28-22:59:43.785523 7f54e37ef6c0 Level-0 table #1071: 0 bytes OK
|
||||||
2025/03/31-07:05:47.818468 7f9cf4ff96c0 Delete type=0 #759
|
2026/02/28-22:59:43.792317 7f54e37ef6c0 Delete type=0 #1069
|
||||||
2025/03/31-07:05:47.826264 7f9cf4ff96c0 Manual compaction at level-0 from '!items!6fTZ6hOKR4pWbWOe' @ 72057594037927935 : 1 .. '!items!zwSNMO9HpiqUCMt8' @ 0 : 0; will stop at (end)
|
2026/02/28-22:59:43.813749 7f54e37ef6c0 Manual compaction at level-0 from '!items!6fTZ6hOKR4pWbWOe' @ 72057594037927935 : 1 .. '!items!zwSNMO9HpiqUCMt8' @ 0 : 0; will stop at (end)
|
||||||
2025/03/31-07:05:47.826363 7f9cf4ff96c0 Manual compaction at level-1 from '!items!6fTZ6hOKR4pWbWOe' @ 72057594037927935 : 1 .. '!items!zwSNMO9HpiqUCMt8' @ 0 : 0; will stop at (end)
|
2026/02/28-22:59:43.813808 7f54e37ef6c0 Manual compaction at level-1 from '!items!6fTZ6hOKR4pWbWOe' @ 72057594037927935 : 1 .. '!items!zwSNMO9HpiqUCMt8' @ 0 : 0; will stop at (end)
|
||||||
|
|||||||
Binary file not shown.
BIN
packs/effets-exemples/MANIFEST-001072
Normal file
BIN
packs/effets-exemples/MANIFEST-001072
Normal file
Binary file not shown.
Binary file not shown.
@@ -1 +1 @@
|
|||||||
MANIFEST-000765
|
MANIFEST-001075
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
2025/03/31-07:10:16.812596 7f9cf5ffb6c0 Recovering log #763
|
2026/02/28-22:59:53.798832 7f56f9bff6c0 Recovering log #1073
|
||||||
2025/03/31-07:10:16.868280 7f9cf5ffb6c0 Delete type=3 #761
|
2026/02/28-22:59:53.809449 7f56f9bff6c0 Delete type=3 #1071
|
||||||
2025/03/31-07:10:16.868401 7f9cf5ffb6c0 Delete type=0 #763
|
2026/02/28-22:59:53.809533 7f56f9bff6c0 Delete type=0 #1073
|
||||||
2025/03/31-07:15:11.637784 7f9cf4ff96c0 Level-0 table #768: started
|
2026/03/01-01:08:46.340100 7f54e37ef6c0 Level-0 table #1078: started
|
||||||
2025/03/31-07:15:11.637835 7f9cf4ff96c0 Level-0 table #768: 0 bytes OK
|
2026/03/01-01:08:46.340139 7f54e37ef6c0 Level-0 table #1078: 0 bytes OK
|
||||||
2025/03/31-07:15:11.674608 7f9cf4ff96c0 Delete type=0 #766
|
2026/03/01-01:08:46.346846 7f54e37ef6c0 Delete type=0 #1076
|
||||||
2025/03/31-07:15:11.712020 7f9cf4ff96c0 Manual compaction at level-0 from '!items!0ErhyqifZLDCmMfT' @ 72057594037927935 : 1 .. '!items!yE8UH6YAgNGjKDEu' @ 0 : 0; will stop at (end)
|
2026/03/01-01:08:46.366221 7f54e37ef6c0 Manual compaction at level-0 from '!items!0ErhyqifZLDCmMfT' @ 72057594037927935 : 1 .. '!items!yE8UH6YAgNGjKDEu' @ 0 : 0; will stop at (end)
|
||||||
2025/03/31-07:15:11.712092 7f9cf4ff96c0 Manual compaction at level-1 from '!items!0ErhyqifZLDCmMfT' @ 72057594037927935 : 1 .. '!items!yE8UH6YAgNGjKDEu' @ 0 : 0; will stop at (end)
|
2026/03/01-01:08:46.366278 7f54e37ef6c0 Manual compaction at level-1 from '!items!0ErhyqifZLDCmMfT' @ 72057594037927935 : 1 .. '!items!yE8UH6YAgNGjKDEu' @ 0 : 0; will stop at (end)
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
2025/03/31-07:01:18.075041 7f9cf67fc6c0 Recovering log #758
|
2026/02/28-17:23:52.834261 7f56f9bff6c0 Recovering log #1069
|
||||||
2025/03/31-07:01:18.085656 7f9cf67fc6c0 Delete type=3 #756
|
2026/02/28-17:23:52.843912 7f56f9bff6c0 Delete type=3 #1067
|
||||||
2025/03/31-07:01:18.085755 7f9cf67fc6c0 Delete type=0 #758
|
2026/02/28-17:23:52.843969 7f56f9bff6c0 Delete type=0 #1069
|
||||||
2025/03/31-07:05:47.712589 7f9cf4ff96c0 Level-0 table #764: started
|
2026/02/28-22:59:43.704672 7f54e37ef6c0 Level-0 table #1074: started
|
||||||
2025/03/31-07:05:47.712636 7f9cf4ff96c0 Level-0 table #764: 0 bytes OK
|
2026/02/28-22:59:43.704745 7f54e37ef6c0 Level-0 table #1074: 0 bytes OK
|
||||||
2025/03/31-07:05:47.719221 7f9cf4ff96c0 Delete type=0 #762
|
2026/02/28-22:59:43.711212 7f54e37ef6c0 Delete type=0 #1072
|
||||||
2025/03/31-07:05:47.739829 7f9cf4ff96c0 Manual compaction at level-0 from '!items!0ErhyqifZLDCmMfT' @ 72057594037927935 : 1 .. '!items!yE8UH6YAgNGjKDEu' @ 0 : 0; will stop at (end)
|
2026/02/28-22:59:43.731026 7f54e37ef6c0 Manual compaction at level-0 from '!items!0ErhyqifZLDCmMfT' @ 72057594037927935 : 1 .. '!items!yE8UH6YAgNGjKDEu' @ 0 : 0; will stop at (end)
|
||||||
2025/03/31-07:05:47.739948 7f9cf4ff96c0 Manual compaction at level-1 from '!items!0ErhyqifZLDCmMfT' @ 72057594037927935 : 1 .. '!items!yE8UH6YAgNGjKDEu' @ 0 : 0; will stop at (end)
|
2026/02/28-22:59:43.731077 7f54e37ef6c0 Manual compaction at level-1 from '!items!0ErhyqifZLDCmMfT' @ 72057594037927935 : 1 .. '!items!yE8UH6YAgNGjKDEu' @ 0 : 0; will stop at (end)
|
||||||
|
|||||||
Binary file not shown.
BIN
packs/equipment/MANIFEST-001075
Normal file
BIN
packs/equipment/MANIFEST-001075
Normal file
Binary file not shown.
Binary file not shown.
@@ -1 +1 @@
|
|||||||
MANIFEST-000764
|
MANIFEST-001074
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
2025/03/31-07:10:17.225555 7f9cf6ffd6c0 Recovering log #762
|
2026/02/28-22:59:53.895577 7f56f8bfd6c0 Recovering log #1072
|
||||||
2025/03/31-07:10:17.275960 7f9cf6ffd6c0 Delete type=3 #760
|
2026/02/28-22:59:53.906749 7f56f8bfd6c0 Delete type=3 #1070
|
||||||
2025/03/31-07:10:17.276058 7f9cf6ffd6c0 Delete type=0 #762
|
2026/02/28-22:59:53.906807 7f56f8bfd6c0 Delete type=0 #1072
|
||||||
2025/03/31-07:15:11.899738 7f9cf4ff96c0 Level-0 table #767: started
|
2026/03/01-01:08:46.391890 7f54e37ef6c0 Level-0 table #1077: started
|
||||||
2025/03/31-07:15:11.899801 7f9cf4ff96c0 Level-0 table #767: 0 bytes OK
|
2026/03/01-01:08:46.391936 7f54e37ef6c0 Level-0 table #1077: 0 bytes OK
|
||||||
2025/03/31-07:15:11.936459 7f9cf4ff96c0 Delete type=0 #765
|
2026/03/01-01:08:46.398187 7f54e37ef6c0 Delete type=0 #1075
|
||||||
2025/03/31-07:15:12.016531 7f9cf4ff96c0 Manual compaction at level-0 from '!items!AoT2c0af4lY6aBsx' @ 72057594037927935 : 1 .. '!items!vGydqADwTsHZ9B3j' @ 0 : 0; will stop at (end)
|
2026/03/01-01:08:46.417834 7f54e37ef6c0 Manual compaction at level-0 from '!items!AoT2c0af4lY6aBsx' @ 72057594037927935 : 1 .. '!items!vGydqADwTsHZ9B3j' @ 0 : 0; will stop at (end)
|
||||||
2025/03/31-07:15:12.016632 7f9cf4ff96c0 Manual compaction at level-1 from '!items!AoT2c0af4lY6aBsx' @ 72057594037927935 : 1 .. '!items!vGydqADwTsHZ9B3j' @ 0 : 0; will stop at (end)
|
2026/03/01-01:08:46.417875 7f54e37ef6c0 Manual compaction at level-1 from '!items!AoT2c0af4lY6aBsx' @ 72057594037927935 : 1 .. '!items!vGydqADwTsHZ9B3j' @ 0 : 0; will stop at (end)
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
2025/03/31-07:01:18.187598 7f9cf5ffb6c0 Recovering log #757
|
2026/02/28-17:23:52.920377 7f56e3fff6c0 Recovering log #1068
|
||||||
2025/03/31-07:01:18.198216 7f9cf5ffb6c0 Delete type=3 #755
|
2026/02/28-17:23:52.930570 7f56e3fff6c0 Delete type=3 #1066
|
||||||
2025/03/31-07:01:18.198369 7f9cf5ffb6c0 Delete type=0 #757
|
2026/02/28-17:23:52.930642 7f56e3fff6c0 Delete type=0 #1068
|
||||||
2025/03/31-07:05:47.776499 7f9cf4ff96c0 Level-0 table #763: started
|
2026/02/28-22:59:43.758590 7f54e37ef6c0 Level-0 table #1073: started
|
||||||
2025/03/31-07:05:47.776619 7f9cf4ff96c0 Level-0 table #763: 0 bytes OK
|
2026/02/28-22:59:43.758628 7f54e37ef6c0 Level-0 table #1073: 0 bytes OK
|
||||||
2025/03/31-07:05:47.783148 7f9cf4ff96c0 Delete type=0 #761
|
2026/02/28-22:59:43.764731 7f54e37ef6c0 Delete type=0 #1071
|
||||||
2025/03/31-07:05:47.797620 7f9cf4ff96c0 Manual compaction at level-0 from '!items!AoT2c0af4lY6aBsx' @ 72057594037927935 : 1 .. '!items!vGydqADwTsHZ9B3j' @ 0 : 0; will stop at (end)
|
2026/02/28-22:59:43.785330 7f54e37ef6c0 Manual compaction at level-0 from '!items!AoT2c0af4lY6aBsx' @ 72057594037927935 : 1 .. '!items!vGydqADwTsHZ9B3j' @ 0 : 0; will stop at (end)
|
||||||
2025/03/31-07:05:47.797706 7f9cf4ff96c0 Manual compaction at level-1 from '!items!AoT2c0af4lY6aBsx' @ 72057594037927935 : 1 .. '!items!vGydqADwTsHZ9B3j' @ 0 : 0; will stop at (end)
|
2026/02/28-22:59:43.785372 7f54e37ef6c0 Manual compaction at level-1 from '!items!AoT2c0af4lY6aBsx' @ 72057594037927935 : 1 .. '!items!vGydqADwTsHZ9B3j' @ 0 : 0; will stop at (end)
|
||||||
|
|||||||
Binary file not shown.
BIN
packs/fightoptions/MANIFEST-001074
Normal file
BIN
packs/fightoptions/MANIFEST-001074
Normal file
Binary file not shown.
Binary file not shown.
@@ -1 +1 @@
|
|||||||
MANIFEST-000247
|
MANIFEST-000557
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user