Compare commits
27 Commits
bol-v12.1.
...
13.1.1
| Author | SHA1 | Date | |
|---|---|---|---|
| 0eb952e43e | |||
| a549262d25 | |||
| 7adc1b3f07 | |||
| 6c70dc147c | |||
| 1ffb8b08fc | |||
| 8017bb207d | |||
| 364278527d | |||
| 93d35abde2 | |||
| 0409be64eb | |||
| ed76a49e7d | |||
| 2abd2c881a | |||
| 3fa5ca66d1 | |||
| 6de15eeda7 | |||
| 724c096743 | |||
| 3e3a4b9ec1 | |||
| 425a2a1fc0 | |||
| 203d7add66 | |||
| 8ae193dc34 | |||
| 3904f595b5 | |||
| 1bf21fae7f | |||
| 22579c21bc | |||
| 50c5c31e7b | |||
| a8c05cd4de | |||
| e1cea78059 | |||
| c2f9934f5f | |||
| 313c8a85fa | |||
| 74f6d4d54a |
@@ -12,37 +12,35 @@ jobs:
|
|||||||
|
|
||||||
#- 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
|
||||||
@@ -51,4 +49,15 @@ jobs:
|
|||||||
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"
|
||||||
|
|||||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -8,3 +8,4 @@ todo.md
|
|||||||
/jsconfig.json
|
/jsconfig.json
|
||||||
/package.json
|
/package.json
|
||||||
/package-lock.json
|
/package-lock.json
|
||||||
|
/.github
|
||||||
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
|
||||||
15
changelog.md
15
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
|
||||||
@@ -55,4 +63,3 @@ Changes :
|
|||||||
- 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é
|
||||||
|
|
||||||
@@ -74,8 +74,8 @@
|
|||||||
"description": "<h1>Shamballah</h1><p>Shamballahns are generally a dark-skinned and dark-haired people with purple, mauve, scarlet, and indigo eye colouring. They are very perceptive and make good hunters.</p>"
|
"description": "<h1>Shamballah</h1><p>Shamballahns are generally a dark-skinned and dark-haired people with purple, mauve, scarlet, and indigo eye colouring. They are very perceptive and make good hunters.</p>"
|
||||||
},
|
},
|
||||||
"Terres Désolées": {
|
"Terres Désolées": {
|
||||||
"name": "Terres Désolées",
|
"name": "Empty Lands",
|
||||||
"description": "<h1>Terres Désolées</h1><p>Personne ne sait grand-chose au sujet des Terres Désolées, et moins encore sur les contrées qui s’étendraient au-delà. Des gens vivent assurément dans cette région, s’il faut en croire les récits de chasseurs et d’explorateurs qui ont relevé des traces de présence. Mais à ce jour, personne n’a découvert le moindre village ou hameau, et on ignore tout de l’apparence de leurs habitants.</p><p>Si votre héros est originaire des Terres Désolées, il vous faudra travailler avec le MJ pour déterminer à quoi ressemble votre personnage. Mais attendezvous à ce qu’il soit toujours considéré comme un étranger, où qu’il se rende en Lémurie.</p>"
|
"description": "<h1>Empty Lands</h1><p>No one knows what exists in and beyond the Empty Lands. People do live there, because hunters and explorers have seen evidence of them. However, no towns or even villages have been discovered, and no one has any idea of what the people are like. If you come from the Empty Lands, you will need to work with the GM to determine what your character is like. He or she will always be treated as an outsider.</p>"
|
||||||
},
|
},
|
||||||
"Tyrus": {
|
"Tyrus": {
|
||||||
"name": "Tyrus",
|
"name": "Tyrus",
|
||||||
|
|||||||
2044
css/bol.css
2044
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",
|
||||||
|
|||||||
23
lang/en.json
23
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",
|
||||||
@@ -477,6 +478,7 @@
|
|||||||
"BOL.chat.damageresult": "Damages of {name} : {total}",
|
"BOL.chat.damageresult": "Damages of {name} : {total}",
|
||||||
"BOL.chat.damagetarget": "Target : {target}",
|
"BOL.chat.damagetarget": "Target : {target}",
|
||||||
"BOL.chat.applydamagetotarget": "Apply damages to the target",
|
"BOL.chat.applydamagetotarget": "Apply damages to the target",
|
||||||
|
"BOL.chat.selecttarget": "Choose a target:",
|
||||||
"BOL.chat.fightoption": "Combat options",
|
"BOL.chat.fightoption": "Combat options",
|
||||||
"BOL.chat.reroll": "Reroll (1 HP)",
|
"BOL.chat.reroll": "Reroll (1 HP)",
|
||||||
"BOL.chat.heroicreminder": "In addition of the actions below, you can : <ul><li>Carnage : Do a second free attack on the same opponent</li><li>Precise : 1 Malus Die on your opponent on a chosen location</li><li>Disarm</li><li>Rabble Massacre</li><li>Prone : Push your opponent on the ground (max +1 size)</li></ul>If you spent 1 Hero Point in addition, all these effects can be doubled.",
|
"BOL.chat.heroicreminder": "In addition of the actions below, you can : <ul><li>Carnage : Do a second free attack on the same opponent</li><li>Precise : 1 Malus Die on your opponent on a chosen location</li><li>Disarm</li><li>Rabble Massacre</li><li>Prone : Push your opponent on the ground (max +1 size)</li></ul>If you spent 1 Hero Point in addition, all these effects can be doubled.",
|
||||||
@@ -546,15 +548,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)",
|
||||||
@@ -579,11 +587,11 @@
|
|||||||
"BOL.ui.bionotes": "Notes",
|
"BOL.ui.bionotes": "Notes",
|
||||||
|
|
||||||
"BOL.chat.welcome1": "Welcome to Barbarians of Lemuria (Ludospherik version)",
|
"BOL.chat.welcome1": "Welcome to Barbarians of Lemuria (Ludospherik version)",
|
||||||
"BOL.chat.welcome2": "Books are necessary to play, and ca be found here : http://www.ludospherik.fr/content/14-barbarians-of-lemuria",
|
"BOL.chat.welcome2": "Books are necessary to play, and <a href='http://www.ludospherik.fr/content/14-barbarians-of-lemuria'>can be found here.</a> ",
|
||||||
"BOL.chat.welcome3": "The integrated maps are authorized by Guillaume Tavernier and Ludospherik. Thanks to them !.",
|
"BOL.chat.welcome3": "The integrated maps are authorized by Emmanuel Roudier and Ludospherik. Thanks to them !.",
|
||||||
"BOL.chat.welcome4": "All support for this system is available on this Discord server : https://discord.gg/pPSDNJk",
|
"BOL.chat.welcome4": "All support for this system is available on this Discord server : https://discord.gg/pPSDNJk",
|
||||||
"BOL.chat.welcome5": "Good game in Lemuria !",
|
"BOL.chat.welcome5": "<strong>In order to see compendiums in English, you must install and enable the Babele module.</strong>",
|
||||||
"BOL.chat.welcome6": "",
|
"BOL.chat.welcome6": "Good game in Lemuria !",
|
||||||
|
|
||||||
"BOL.settings.rollArmor": "Roll for armor",
|
"BOL.settings.rollArmor": "Roll for armor",
|
||||||
"BOL.settings.rollArmorTooltip": "Roll for armor value, fixed value if unchecked",
|
"BOL.settings.rollArmorTooltip": "Roll for armor value, fixed value if unchecked",
|
||||||
@@ -602,5 +610,10 @@
|
|||||||
"BOL.settings.defaultLogoActorSheetPath" : "Path for Actor sheet logo",
|
"BOL.settings.defaultLogoActorSheetPath" : "Path for Actor sheet logo",
|
||||||
"BOL.settings.defaultLogoPathActorSheetTooltip": "Path of the Actor sheet logo (346 x 200, default : /systems/bol/ui/logo.webp)",
|
"BOL.settings.defaultLogoPathActorSheetTooltip": "Path of the Actor sheet logo (346 x 200, default : /systems/bol/ui/logo.webp)",
|
||||||
"BOL.settings.defaultLogoTopLeftPath" : "Path for main top left logo",
|
"BOL.settings.defaultLogoTopLeftPath" : "Path for main top left logo",
|
||||||
"BOL.settings.defaultLogoTopLeftPathTooltip": "Path of the logo in the top left window (718 x 416, default : /systems/bol/ui/logo2.webp)"
|
"BOL.settings.defaultLogoTopLeftPathTooltip": "Path of the logo in the top left window (718 x 416, default : /systems/bol/ui/logo2.webp)",
|
||||||
|
|
||||||
|
"BOL.ui.charSummaryTitle": "Character Summary",
|
||||||
|
"BOL.ui.colGroupAttributes": "Attributes",
|
||||||
|
"BOL.ui.colGroupAptitudes": "Aptitudes",
|
||||||
|
"BOL.ui.colGroupResources": "Resources"
|
||||||
}
|
}
|
||||||
@@ -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",
|
||||||
|
|||||||
22
lang/fr.json
22
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",
|
||||||
@@ -505,6 +506,7 @@
|
|||||||
"BOL.chat.damageresult": "Dommages de {name} : {total}",
|
"BOL.chat.damageresult": "Dommages de {name} : {total}",
|
||||||
"BOL.chat.damagetarget": "Cible : {target}",
|
"BOL.chat.damagetarget": "Cible : {target}",
|
||||||
"BOL.chat.applydamagetotarget": "Appliquer les dommages à la cible",
|
"BOL.chat.applydamagetotarget": "Appliquer les dommages à la cible",
|
||||||
|
"BOL.chat.selecttarget": "Choisir une cible :",
|
||||||
"BOL.chat.fightoption": "Option de combat",
|
"BOL.chat.fightoption": "Option de combat",
|
||||||
"BOL.chat.reroll": "Relancer (1 P. Heroisme)",
|
"BOL.chat.reroll": "Relancer (1 P. Heroisme)",
|
||||||
"BOL.chat.heroicreminder": "En plus des actions indiquées sur les boutons ci-dessous, vous pouvez : <ul><li>Carnage : Attaquer une seconde fois le même adversaire</li><li>Coup précis : Un dé de malus à votre adversaire sur une localisation choisie</li><li>Désarmement</li><li>Massacrer la piétaille</li><li>Renversement : Renversez votre adversaire (1 taille de plus max)</li></ul>Si vous dépensez un Point d'Héroisme en plus, tout ces effets peuvent être doublés",
|
"BOL.chat.heroicreminder": "En plus des actions indiquées sur les boutons ci-dessous, vous pouvez : <ul><li>Carnage : Attaquer une seconde fois le même adversaire</li><li>Coup précis : Un dé de malus à votre adversaire sur une localisation choisie</li><li>Désarmement</li><li>Massacrer la piétaille</li><li>Renversement : Renversez votre adversaire (1 taille de plus max)</li></ul>Si vous dépensez un Point d'Héroisme en plus, tout ces effets peuvent être doublés",
|
||||||
@@ -573,17 +575,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)",
|
||||||
@@ -611,16 +621,15 @@
|
|||||||
|
|
||||||
"BOL.chat.welcome1": "Bienvenue dans Barbarians of Lemuria (Ludospherik version)",
|
"BOL.chat.welcome1": "Bienvenue dans Barbarians of Lemuria (Ludospherik version)",
|
||||||
"BOL.chat.welcome2": "Les livres nécessaires pour jouer sont disponibles sur le site de <a href='http://www.ludospherik.fr/content/14-barbarians-of-lemuria'>l'éditeur Ludospherik.</a>",
|
"BOL.chat.welcome2": "Les livres nécessaires pour jouer sont disponibles sur le site de <a href='http://www.ludospherik.fr/content/14-barbarians-of-lemuria'>l'éditeur Ludospherik.</a>",
|
||||||
"BOL.chat.welcome3": "Les cartes intégrées au système le sont grace à l'aimable autorisation de leur auteur Guillaume Tavernier et des éditions Ludospherik. Merci à eux !.",
|
"BOL.chat.welcome3": "Les cartes intégrées au système le sont grace à l'aimable autorisation d'Emmanuel Roudier et des éditions Ludospherik. Merci à eux !.",
|
||||||
"BOL.chat.welcome4": "Tout le support et le suivi de ce système est disponible via le <a href='https://discord.gg/pPSDNJk'>Discord Foundry FR</a>.",
|
"BOL.chat.welcome4": "Tout le support et le suivi de ce système est disponible via le <a href='https://discord.gg/pPSDNJk'>Discord Foundry FR</a>.",
|
||||||
"BOL.chat.welcome5": "Consulter l'aide en ligne pour plus d'informations : @UUID[Compendium.bol.aides-de-jeu.JournalEntry.8ihDiCxC47fcdKVA]{Aide du Jeu}.",
|
"BOL.chat.welcome5": "Consulter l'aide en ligne pour plus d'informations : @UUID[Compendium.bol.aides-de-jeu.JournalEntry.8ihDiCxC47fcdKVA]{Aide du Jeu}.<br>Si vous souhaitez jouer en anglais, n'oubliez pas d'activer le module Babele.",
|
||||||
"BOL.chat.welcome6": "Bon jeu en Lemurie !",
|
"BOL.chat.welcome6": "Bon jeu en Lemurie !",
|
||||||
"BOL.chat.nodamage": "Ne pas appliquer les dommages",
|
"BOL.chat.nodamage": "Ne pas appliquer les dommages",
|
||||||
"BOL.chat.pcwarning": "Attention ! Aucun personnage n'est relié au joueur !",
|
"BOL.chat.pcwarning": "Attention ! Aucun personnage n'est relié au joueur !",
|
||||||
"BOL.chat.pcwarningmsg": "<b>ATTENTION</b> Le joueur n'est relié à aucun personnage !",
|
"BOL.chat.pcwarningmsg": "<b>ATTENTION</b> Le joueur n'est relié à aucun personnage !",
|
||||||
"BOL.chat.pcnotlinked": "Le token du personnage joueur n'est pas relié à l'acteur",
|
"BOL.chat.pcnotlinked": "Le token du personnage joueur n'est pas relié à l'acteur",
|
||||||
"BOL.chat.pcnotlinkedmsg": "<b>ATTENTION</b> Le token du personnage joueur n'est pas relié à l'acteur !",
|
"BOL.chat.pcnotlinkedmsg": "<b>ATTENTION</b> Le token du personnage joueur n'est pas relié à l'acteur !",
|
||||||
"BOL.chat.armorRoll": "Jet d'armure",
|
|
||||||
|
|
||||||
"BOL.settings.rollArmor": "Effectuer des jets pour les armures",
|
"BOL.settings.rollArmor": "Effectuer des jets pour les armures",
|
||||||
"BOL.settings.rollArmorTooltip": "Effectue un jet de dés pour les armures (valeur fixe si désactivé)",
|
"BOL.settings.rollArmorTooltip": "Effectue un jet de dés pour les armures (valeur fixe si désactivé)",
|
||||||
@@ -642,5 +651,10 @@
|
|||||||
"BOL.settings.defaultLogoTopLeftPathTooltip": "Vous pouvez changer le logo BoL en haut à gauche de chaque écran (idéalement 718 x 416, défaut : /systems/bol/ui/logo2.webp)",
|
"BOL.settings.defaultLogoTopLeftPathTooltip": "Vous pouvez changer le logo BoL en haut à gauche de chaque écran (idéalement 718 x 416, défaut : /systems/bol/ui/logo2.webp)",
|
||||||
|
|
||||||
"EFFECT.StatusProne": "A terre",
|
"EFFECT.StatusProne": "A terre",
|
||||||
"EFFECT.StatusDead": "Mort"
|
"EFFECT.StatusDead": "Mort",
|
||||||
|
|
||||||
|
"BOL.ui.charSummaryTitle": "Résumé des Personnages",
|
||||||
|
"BOL.ui.colGroupAttributes": "Attributs",
|
||||||
|
"BOL.ui.colGroupAptitudes": "Aptitudes",
|
||||||
|
"BOL.ui.colGroupResources": "Ressources"
|
||||||
}
|
}
|
||||||
@@ -5,7 +5,7 @@
|
|||||||
import { BoLRoll } from "../controllers/bol-rolls.js";
|
import { BoLRoll } from "../controllers/bol-rolls.js";
|
||||||
import { BoLUtility } from "../system/bol-utility.js";
|
import { BoLUtility } from "../system/bol-utility.js";
|
||||||
|
|
||||||
export class BoLActorSheet extends ActorSheet {
|
export class BoLActorSheet extends foundry.appv1.sheets.ActorSheet {
|
||||||
|
|
||||||
/** @override */
|
/** @override */
|
||||||
static get defaultOptions() {
|
static get defaultOptions() {
|
||||||
@@ -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.renderTemplate('systems/bol/templates/chat/chat-activate-fight-option.hbs', { name: this.name, img: fightOption.img, foName: fightOption.name, state: state })
|
||||||
})
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -852,6 +854,9 @@ export class BoLActor extends Actor {
|
|||||||
|
|
||||||
/*-------------------------------------------- */
|
/*-------------------------------------------- */
|
||||||
async manageHealthState() {
|
async manageHealthState() {
|
||||||
|
if (BoLActor._healthLock.has(this.id)) return
|
||||||
|
BoLActor._healthLock.add(this.id)
|
||||||
|
try {
|
||||||
let hpID = "lastHP" + this.id
|
let hpID = "lastHP" + this.id
|
||||||
let lastHP = await this.getFlag("world", hpID)
|
let lastHP = await this.getFlag("world", hpID)
|
||||||
if (lastHP != this.system.resources.hp.value && game.user.isGM) { // Only GM sends this
|
if (lastHP != this.system.resources.hp.value && game.user.isGM) { // Only GM sends this
|
||||||
@@ -872,7 +877,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-vitality-zero.hbs', { name: this.name, img: this.img, hp: this.system.resources.hp.value, isHeroAdversary: this.isHeroAdversary() })
|
content: await foundry.applications.handlebars.renderTemplate('systems/bol/templates/chat/chat-vitality-zero.hbs', { name: this.name, img: this.img, hp: this.system.resources.hp.value, isHeroAdversary: this.isHeroAdversary() })
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
if (prone) {
|
if (prone) {
|
||||||
@@ -883,6 +888,9 @@ export class BoLActor extends Actor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} 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.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>" +
|
"systems/bol/templates/chat/chat-welcome.hbs",
|
||||||
game.i18n.localize("BOL.chat.welcome3") + "<p>" +
|
{ noRulebook }
|
||||||
game.i18n.localize("BOL.chat.welcome4") + "</p>" +
|
)
|
||||||
game.i18n.localize("BOL.chat.welcome5") + "<br>" +
|
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 ( !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")) {
|
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]
|
||||||
@@ -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 ?
|
||||||
|
const nbDiceEl = document.querySelector('#roll-nbdice')
|
||||||
|
if (nbDiceEl) {
|
||||||
if (this.rollData.bmDice == 0) {
|
if (this.rollData.bmDice == 0) {
|
||||||
$('#roll-nbdice').val("2")
|
nbDiceEl.value = "2"
|
||||||
} else {
|
} else {
|
||||||
let letter = (this.rollData.bmDice > 0) ? "B" : "M"
|
let letter = (this.rollData.bmDice > 0) ? "B" : "M"
|
||||||
$('#roll-nbdice').val("2 + " + String(Math.abs(this.rollData.bmDice)) + letter)
|
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -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,
|
|
||||||
rollMode: game.settings.get("core", "rollMode"),
|
|
||||||
flavor: msgFlavor,
|
flavor: msgFlavor,
|
||||||
speaker: ChatMessage.getSpeaker({ actor: actor }),
|
speaker: ChatMessage.getSpeaker({ actor: actor }),
|
||||||
})
|
}, { rollMode })
|
||||||
this.rollData.roll = foundry.utils.duplicate(this.rollData.roll) // Remove object, keep data (v111 ready)
|
this.rollData.roll = foundry.utils.duplicate(this.rollData.roll)
|
||||||
msg.setFlag("world", "bol-roll-data", this.rollData)
|
if (msg) await msg.setFlag("world", "bol-roll-data", this.rollData)
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
@@ -747,6 +747,12 @@ export class BoLDefaultRoll {
|
|||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
async sendDamageMessage() {
|
async sendDamageMessage() {
|
||||||
let actor = BoLUtility.getActorFromRollData(this.rollData)
|
let actor = BoLUtility.getActorFromRollData(this.rollData)
|
||||||
|
// If no target, collect potential targets from active scene (excluding attacker)
|
||||||
|
if (!this.rollData.targetId && game.scenes.current) {
|
||||||
|
this.rollData.potentialTargets = game.scenes.current.tokens
|
||||||
|
.filter(t => t.actor && t.actor.id !== this.rollData.actorId)
|
||||||
|
.map(t => ({ id: t.id, actorId: t.actor.id, name: t.name, img: t.texture?.src || t.actor.img }))
|
||||||
|
}
|
||||||
this._buildDamageChatMessage(this.rollData).then(async msgFlavor => {
|
this._buildDamageChatMessage(this.rollData).then(async msgFlavor => {
|
||||||
let msg = await this.rollData.damageRoll.toMessage({
|
let msg = await this.rollData.damageRoll.toMessage({
|
||||||
user: game.user.id,
|
user: game.user.id,
|
||||||
@@ -805,13 +811,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)
|
||||||
@@ -388,6 +395,16 @@ export class BoLUtility {
|
|||||||
BoLUtility.sendAttackSuccess(rollData)
|
BoLUtility.sendAttackSuccess(rollData)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
html.on("click", '.chat-target-select', event => {
|
||||||
|
event.preventDefault()
|
||||||
|
const btn = event.currentTarget
|
||||||
|
let rollData = BoLUtility.getRollDataFromMessage(event)
|
||||||
|
rollData.targetId = btn.dataset.tokenId
|
||||||
|
rollData.defenderId = btn.dataset.actorId
|
||||||
|
BoLUtility.cleanupButtons(rollData.applyId)
|
||||||
|
BoLUtility.sendAttackSuccess(rollData)
|
||||||
|
});
|
||||||
|
|
||||||
html.on("click", '.chat-damage-roll', event => {
|
html.on("click", '.chat-damage-roll', event => {
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
let rollData = BoLUtility.getRollDataFromMessage(event)
|
let rollData = BoLUtility.getRollDataFromMessage(event)
|
||||||
@@ -480,13 +497,17 @@ export class BoLUtility {
|
|||||||
|
|
||||||
if (defenseMode == 'damage-with-armor') {
|
if (defenseMode == 'damage-with-armor') {
|
||||||
let armorFormula = defender.getArmorFormula()
|
let armorFormula = defender.getArmorFormula()
|
||||||
|
if (armorFormula === "0") {
|
||||||
|
rollData.armorProtect = 0
|
||||||
|
} else {
|
||||||
rollData.rollArmor = new Roll(armorFormula)
|
rollData.rollArmor = new Roll(armorFormula)
|
||||||
await rollData.rollArmor.roll()
|
await rollData.rollArmor.roll()
|
||||||
let msg = await rollData.rollArmor.toMessage({ flavor: "BOL.chat.armorRoll : " + armorFormula });
|
let msg = await rollData.rollArmor.toMessage({ flavor: game.i18n.localize("BOL.chat.armorRoll") + " : " + armorFormula })
|
||||||
if ( game.dice3d) { // wait animation end when DsN is there
|
if (game.dice3d && msg) {
|
||||||
await game.dice3d.waitFor3DAnimationByMessageID(msg.id);
|
await game.dice3d.waitFor3DAnimationByMessageID(msg.id)
|
||||||
}
|
}
|
||||||
rollData.armorProtect = (rollData.rollArmor.total < 0) ? 0 : rollData.rollArmor.total
|
rollData.armorProtect = (rollData.rollArmor.total < 0) ? 0 : rollData.rollArmor.total
|
||||||
|
}
|
||||||
rollData.finalDamage = rollData.damageTotal - rollData.armorProtect
|
rollData.finalDamage = rollData.damageTotal - rollData.armorProtect
|
||||||
rollData.finalDamage = (rollData.finalDamage < 0) ? 0 : rollData.finalDamage
|
rollData.finalDamage = (rollData.finalDamage < 0) ? 0 : rollData.finalDamage
|
||||||
await defender.sufferDamage(rollData.finalDamage)
|
await defender.sufferDamage(rollData.finalDamage)
|
||||||
@@ -498,9 +519,17 @@ export class BoLUtility {
|
|||||||
}
|
}
|
||||||
if (defenseMode == 'hero-reduce-damage') {
|
if (defenseMode == 'hero-reduce-damage') {
|
||||||
let armorFormula = defender.getArmorFormula()
|
let armorFormula = defender.getArmorFormula()
|
||||||
|
if (armorFormula === "0") {
|
||||||
|
rollData.armorProtect = 0
|
||||||
|
} else {
|
||||||
rollData.rollArmor = new Roll(armorFormula)
|
rollData.rollArmor = new Roll(armorFormula)
|
||||||
await rollData.rollArmor.roll()
|
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.rollHero = new Roll("1d6")
|
rollData.rollHero = new Roll("1d6")
|
||||||
await rollData.rollHero.roll()
|
await rollData.rollHero.roll()
|
||||||
rollData.finalDamage = rollData.damageTotal - rollData.rollHero.total - rollData.armorProtect
|
rollData.finalDamage = rollData.damageTotal - rollData.rollHero.total - rollData.armorProtect
|
||||||
@@ -535,13 +564,13 @@ export class BoLUtility {
|
|||||||
ChatMessage.create({
|
ChatMessage.create({
|
||||||
alias: defender.name,
|
alias: defender.name,
|
||||||
whisper: BoLUtility.getWhisperRecipientsAndGMs(defender.name),
|
whisper: BoLUtility.getWhisperRecipientsAndGMs(defender.name),
|
||||||
content: await renderTemplate('systems/bol/templates/chat/rolls/defense-result-card.hbs', damageResults)
|
content: await foundry.applications.handlebars.renderTemplate('systems/bol/templates/chat/rolls/defense-result-card.hbs', damageResults)
|
||||||
})
|
})
|
||||||
console.log("Defender data : ", defenderUser)
|
console.log("Defender data : ", defenderUser)
|
||||||
ChatMessage.create({
|
ChatMessage.create({
|
||||||
alias: defender.name,
|
alias: defender.name,
|
||||||
whisper: BoLUtility.getOtherWhisperRecipients(defenderUser?.name),
|
whisper: BoLUtility.getOtherWhisperRecipients(defenderUser?.name),
|
||||||
content: await renderTemplate('systems/bol/templates/chat/rolls/defense-summary-card.hbs', damageResults)
|
content: await foundry.applications.handlebars.renderTemplate('systems/bol/templates/chat/rolls/defense-summary-card.hbs', damageResults)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -628,7 +657,7 @@ export class BoLUtility {
|
|||||||
let msg = await ChatMessage.create({
|
let msg = await ChatMessage.create({
|
||||||
alias: defender.name,
|
alias: defender.name,
|
||||||
whisper: BoLUtility.getWhisperRecipientsAndGMs(defender.name),
|
whisper: BoLUtility.getWhisperRecipientsAndGMs(defender.name),
|
||||||
content: await renderTemplate('systems/bol/templates/chat/rolls/defense-request-card.hbs', {
|
content: await foundry.applications.handlebars.renderTemplate('systems/bol/templates/chat/rolls/defense-request-card.hbs', {
|
||||||
attackId: rollData.id,
|
attackId: rollData.id,
|
||||||
attacker: rollData.attacker,
|
attacker: rollData.attacker,
|
||||||
defender: defender,
|
defender: defender,
|
||||||
|
|||||||
@@ -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.
BIN
packs/aides-de-jeu/001088.ldb
Normal file
BIN
packs/aides-de-jeu/001088.ldb
Normal file
Binary file not shown.
@@ -1 +1 @@
|
|||||||
MANIFEST-000741
|
MANIFEST-001084
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
2025/02/11-21:52:03.987644 7f92b57fa6c0 Recovering log #739
|
2026/03/16-19:46:09.197185 7f766a3fe6c0 Delete type=3 #1
|
||||||
2025/02/11-21:52:03.997651 7f92b57fa6c0 Delete type=3 #737
|
2026/03/16-20:16:08.421989 7f7668bfb6c0 Level-0 table #1087: started
|
||||||
2025/02/11-21:52:03.997734 7f92b57fa6c0 Delete type=0 #739
|
2026/03/16-20:16:08.422032 7f7668bfb6c0 Level-0 table #1087: 0 bytes OK
|
||||||
2025/02/11-21:54:35.598552 7f92b3bff6c0 Level-0 table #744: started
|
2026/03/16-20:16:08.428629 7f7668bfb6c0 Delete type=0 #1085
|
||||||
2025/02/11-21:54:35.598583 7f92b3bff6c0 Level-0 table #744: 0 bytes OK
|
2026/03/16-20:16:08.454903 7f7668bfb6c0 Manual compaction at level-0 from '!journal!3xJg1rCxnWvEmoxS' @ 72057594037927935 : 1 .. '!journal.pages!veAAxCtCKcFIsnln.0kUgZspxXO7VS8bd' @ 0 : 0; will stop at '!journal.pages!veAAxCtCKcFIsnln.0kUgZspxXO7VS8bd' @ 283 : 1
|
||||||
2025/02/11-21:54:35.604608 7f92b3bff6c0 Delete type=0 #742
|
2026/03/16-20:16:08.454928 7f7668bfb6c0 Compacting 1@0 + 0@1 files
|
||||||
2025/02/11-21:54:35.611345 7f92b3bff6c0 Manual compaction at level-0 from '!journal!3xJg1rCxnWvEmoxS' @ 72057594037927935 : 1 .. '!journal.pages!veAAxCtCKcFIsnln.0kUgZspxXO7VS8bd' @ 0 : 0; will stop at (end)
|
2026/03/16-20:16:08.459641 7f7668bfb6c0 Generated table #1088@0: 24 keys, 28007 bytes
|
||||||
2025/02/11-21:54:35.611398 7f92b3bff6c0 Manual compaction at level-1 from '!journal!3xJg1rCxnWvEmoxS' @ 72057594037927935 : 1 .. '!journal.pages!veAAxCtCKcFIsnln.0kUgZspxXO7VS8bd' @ 0 : 0; will stop at (end)
|
2026/03/16-20:16:08.459663 7f7668bfb6c0 Compacted 1@0 + 0@1 files => 28007 bytes
|
||||||
|
2026/03/16-20:16:08.466040 7f7668bfb6c0 compacted to: files[ 0 1 0 0 0 0 0 ]
|
||||||
|
2026/03/16-20:16:08.466219 7f7668bfb6c0 Delete type=2 #774
|
||||||
|
2026/03/16-20:16:08.488702 7f7668bfb6c0 Manual compaction at level-0 from '!journal.pages!veAAxCtCKcFIsnln.0kUgZspxXO7VS8bd' @ 283 : 1 .. '!journal.pages!veAAxCtCKcFIsnln.0kUgZspxXO7VS8bd' @ 0 : 0; will stop at (end)
|
||||||
|
|||||||
@@ -1,8 +1,4 @@
|
|||||||
2025/02/11-21:46:57.957249 7f92b4ff96c0 Recovering log #735
|
2026/03/16-19:46:09.175786 7f766a3fe6c0 Log #1082: 0 ops saved to Table #1083 OK
|
||||||
2025/02/11-21:46:58.011032 7f92b4ff96c0 Delete type=3 #733
|
2026/03/16-19:46:09.176080 7f766a3fe6c0 Archiving /home/morr/foundry/foundrydata-v13/Data/systems/bol/packs/aides-de-jeu/001082.log: OK
|
||||||
2025/02/11-21:46:58.011095 7f92b4ff96c0 Delete type=0 #735
|
2026/03/16-19:46:09.177100 7f766a3fe6c0 Table #774: 24 entries OK
|
||||||
2025/02/11-21:51:51.193085 7f92b3bff6c0 Level-0 table #740: started
|
2026/03/16-19:46:09.180960 7f766a3fe6c0 **** Repaired leveldb /home/morr/foundry/foundrydata-v13/Data/systems/bol/packs/aides-de-jeu; recovered 1 files; 28007 bytes. Some data may have been lost. ****
|
||||||
2025/02/11-21:51:51.193106 7f92b3bff6c0 Level-0 table #740: 0 bytes OK
|
|
||||||
2025/02/11-21:51:51.199589 7f92b3bff6c0 Delete type=0 #738
|
|
||||||
2025/02/11-21:51:51.219732 7f92b3bff6c0 Manual compaction at level-0 from '!journal!3xJg1rCxnWvEmoxS' @ 72057594037927935 : 1 .. '!journal.pages!veAAxCtCKcFIsnln.0kUgZspxXO7VS8bd' @ 0 : 0; will stop at (end)
|
|
||||||
2025/02/11-21:51:51.219765 7f92b3bff6c0 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-001084
Normal file
BIN
packs/aides-de-jeu/MANIFEST-001084
Normal file
Binary file not shown.
Binary file not shown.
BIN
packs/armors/000993.ldb
Normal file
BIN
packs/armors/000993.ldb
Normal file
Binary file not shown.
@@ -1 +1 @@
|
|||||||
MANIFEST-000646
|
MANIFEST-000989
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
2025/02/11-21:52:03.961891 7f92b5ffb6c0 Recovering log #644
|
2026/03/16-19:46:09.143692 7f7669bfd6c0 Delete type=3 #1
|
||||||
2025/02/11-21:52:03.971934 7f92b5ffb6c0 Delete type=3 #642
|
2026/03/16-20:16:08.436084 7f7668bfb6c0 Level-0 table #992: started
|
||||||
2025/02/11-21:52:03.972018 7f92b5ffb6c0 Delete type=0 #644
|
2026/03/16-20:16:08.436127 7f7668bfb6c0 Level-0 table #992: 0 bytes OK
|
||||||
2025/02/11-21:54:35.590985 7f92b3bff6c0 Level-0 table #649: started
|
2026/03/16-20:16:08.443698 7f7668bfb6c0 Delete type=0 #990
|
||||||
2025/02/11-21:54:35.591011 7f92b3bff6c0 Level-0 table #649: 0 bytes OK
|
2026/03/16-20:16:08.477884 7f7668bfb6c0 Manual compaction at level-0 from '!items!G3dZTHIabA3LA1hY' @ 72057594037927935 : 1 .. '!items!xhEcsi3WHjbt2ro9' @ 0 : 0; will stop at '!items!xhEcsi3WHjbt2ro9' @ 42 : 1
|
||||||
2025/02/11-21:54:35.598433 7f92b3bff6c0 Delete type=0 #647
|
2026/03/16-20:16:08.477902 7f7668bfb6c0 Compacting 1@0 + 0@1 files
|
||||||
2025/02/11-21:54:35.611337 7f92b3bff6c0 Manual compaction at level-0 from '!items!G3dZTHIabA3LA1hY' @ 72057594037927935 : 1 .. '!items!xhEcsi3WHjbt2ro9' @ 0 : 0; will stop at (end)
|
2026/03/16-20:16:08.481701 7f7668bfb6c0 Generated table #993@0: 6 keys, 5424 bytes
|
||||||
2025/02/11-21:54:35.611373 7f92b3bff6c0 Manual compaction at level-1 from '!items!G3dZTHIabA3LA1hY' @ 72057594037927935 : 1 .. '!items!xhEcsi3WHjbt2ro9' @ 0 : 0; will stop at (end)
|
2026/03/16-20:16:08.481748 7f7668bfb6c0 Compacted 1@0 + 0@1 files => 5424 bytes
|
||||||
|
2026/03/16-20:16:08.488315 7f7668bfb6c0 compacted to: files[ 0 1 0 0 0 0 0 ]
|
||||||
|
2026/03/16-20:16:08.488463 7f7668bfb6c0 Delete type=2 #679
|
||||||
|
2026/03/16-20:16:08.488751 7f7668bfb6c0 Manual compaction at level-0 from '!items!xhEcsi3WHjbt2ro9' @ 42 : 1 .. '!items!xhEcsi3WHjbt2ro9' @ 0 : 0; will stop at (end)
|
||||||
|
|||||||
@@ -1,8 +1,4 @@
|
|||||||
2025/02/11-21:46:57.864537 7f92b57fa6c0 Recovering log #640
|
2026/03/16-19:46:09.120613 7f7669bfd6c0 Log #987: 0 ops saved to Table #988 OK
|
||||||
2025/02/11-21:46:57.903541 7f92b57fa6c0 Delete type=3 #638
|
2026/03/16-19:46:09.120850 7f7669bfd6c0 Archiving /home/morr/foundry/foundrydata-v13/Data/systems/bol/packs/armors/000987.log: OK
|
||||||
2025/02/11-21:46:57.903634 7f92b57fa6c0 Delete type=0 #640
|
2026/03/16-19:46:09.121424 7f7669bfd6c0 Table #679: 6 entries OK
|
||||||
2025/02/11-21:51:51.199721 7f92b3bff6c0 Level-0 table #645: started
|
2026/03/16-19:46:09.125224 7f7669bfd6c0 **** Repaired leveldb /home/morr/foundry/foundrydata-v13/Data/systems/bol/packs/armors; recovered 1 files; 5424 bytes. Some data may have been lost. ****
|
||||||
2025/02/11-21:51:51.199750 7f92b3bff6c0 Level-0 table #645: 0 bytes OK
|
|
||||||
2025/02/11-21:51:51.205891 7f92b3bff6c0 Delete type=0 #643
|
|
||||||
2025/02/11-21:51:51.219744 7f92b3bff6c0 Manual compaction at level-0 from '!items!G3dZTHIabA3LA1hY' @ 72057594037927935 : 1 .. '!items!xhEcsi3WHjbt2ro9' @ 0 : 0; will stop at (end)
|
|
||||||
2025/02/11-21:51:51.219794 7f92b3bff6c0 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-000989
Normal file
BIN
packs/armors/MANIFEST-000989
Normal file
Binary file not shown.
Binary file not shown.
BIN
packs/boons/001087.ldb
Normal file
BIN
packs/boons/001087.ldb
Normal file
Binary file not shown.
@@ -1 +1 @@
|
|||||||
MANIFEST-000739
|
MANIFEST-001083
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
2025/02/11-21:52:03.851261 7f92b5ffb6c0 Recovering log #737
|
2026/03/16-19:46:08.857890 7f766abff6c0 Delete type=3 #1
|
||||||
2025/02/11-21:52:03.861605 7f92b5ffb6c0 Delete type=3 #735
|
2026/03/16-20:16:08.265157 7f7668bfb6c0 Level-0 table #1086: started
|
||||||
2025/02/11-21:52:03.861680 7f92b5ffb6c0 Delete type=0 #737
|
2026/03/16-20:16:08.265207 7f7668bfb6c0 Level-0 table #1086: 0 bytes OK
|
||||||
2025/02/11-21:54:35.551224 7f92b3bff6c0 Level-0 table #742: started
|
2026/03/16-20:16:08.272133 7f7668bfb6c0 Delete type=0 #1084
|
||||||
2025/02/11-21:54:35.551250 7f92b3bff6c0 Level-0 table #742: 0 bytes OK
|
2026/03/16-20:16:08.299945 7f7668bfb6c0 Manual compaction at level-0 from '!items!039ZF3E3MtAGwbiX' @ 72057594037927935 : 1 .. '!items!zgspy1QKaxdEetEw' @ 0 : 0; will stop at '!items!zgspy1QKaxdEetEw' @ 533 : 1
|
||||||
2025/02/11-21:54:35.557302 7f92b3bff6c0 Delete type=0 #740
|
2026/03/16-20:16:08.299966 7f7668bfb6c0 Compacting 1@0 + 0@1 files
|
||||||
2025/02/11-21:54:35.557440 7f92b3bff6c0 Manual compaction at level-0 from '!items!039ZF3E3MtAGwbiX' @ 72057594037927935 : 1 .. '!items!zgspy1QKaxdEetEw' @ 0 : 0; will stop at (end)
|
2026/03/16-20:16:08.305068 7f7668bfb6c0 Generated table #1087@0: 61 keys, 20970 bytes
|
||||||
2025/02/11-21:54:35.557467 7f92b3bff6c0 Manual compaction at level-1 from '!items!039ZF3E3MtAGwbiX' @ 72057594037927935 : 1 .. '!items!zgspy1QKaxdEetEw' @ 0 : 0; will stop at (end)
|
2026/03/16-20:16:08.305111 7f7668bfb6c0 Compacted 1@0 + 0@1 files => 20970 bytes
|
||||||
|
2026/03/16-20:16:08.311829 7f7668bfb6c0 compacted to: files[ 0 1 0 0 0 0 0 ]
|
||||||
|
2026/03/16-20:16:08.312005 7f7668bfb6c0 Delete type=2 #843
|
||||||
|
2026/03/16-20:16:08.335606 7f7668bfb6c0 Manual compaction at level-0 from '!items!zgspy1QKaxdEetEw' @ 533 : 1 .. '!items!zgspy1QKaxdEetEw' @ 0 : 0; will stop at (end)
|
||||||
|
|||||||
@@ -1,8 +1,4 @@
|
|||||||
2025/02/11-21:46:57.609960 7f92b5ffb6c0 Recovering log #733
|
2026/03/16-19:46:08.539383 7f766abff6c0 Log #1081: 0 ops saved to Table #1082 OK
|
||||||
2025/02/11-21:46:57.630801 7f92b5ffb6c0 Delete type=3 #731
|
2026/03/16-19:46:08.539570 7f766abff6c0 Archiving /home/morr/foundry/foundrydata-v13/Data/systems/bol/packs/boons/001081.log: OK
|
||||||
2025/02/11-21:46:57.630870 7f92b5ffb6c0 Delete type=0 #733
|
2026/03/16-19:46:08.540406 7f766abff6c0 Table #843: 61 entries OK
|
||||||
2025/02/11-21:51:51.157989 7f92b3bff6c0 Level-0 table #738: started
|
2026/03/16-19:46:08.544540 7f766abff6c0 **** Repaired leveldb /home/morr/foundry/foundrydata-v13/Data/systems/bol/packs/boons; recovered 1 files; 20970 bytes. Some data may have been lost. ****
|
||||||
2025/02/11-21:51:51.158009 7f92b3bff6c0 Level-0 table #738: 0 bytes OK
|
|
||||||
2025/02/11-21:51:51.165246 7f92b3bff6c0 Delete type=0 #736
|
|
||||||
2025/02/11-21:51:51.165430 7f92b3bff6c0 Manual compaction at level-0 from '!items!039ZF3E3MtAGwbiX' @ 72057594037927935 : 1 .. '!items!zgspy1QKaxdEetEw' @ 0 : 0; will stop at (end)
|
|
||||||
2025/02/11-21:51:51.165460 7f92b3bff6c0 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-001083
Normal file
BIN
packs/boons/MANIFEST-001083
Normal file
Binary file not shown.
Binary file not shown.
BIN
packs/boonsflawscreatures/001086.ldb
Normal file
BIN
packs/boonsflawscreatures/001086.ldb
Normal file
Binary file not shown.
@@ -1 +1 @@
|
|||||||
MANIFEST-000739
|
MANIFEST-001082
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
2025/02/11-21:52:03.864307 7f92b4ff96c0 Recovering log #737
|
2026/03/16-19:46:08.909016 7f76693fc6c0 Delete type=3 #1
|
||||||
2025/02/11-21:52:03.874891 7f92b4ff96c0 Delete type=3 #735
|
2026/03/16-20:16:08.272330 7f7668bfb6c0 Level-0 table #1085: started
|
||||||
2025/02/11-21:52:03.874942 7f92b4ff96c0 Delete type=0 #737
|
2026/03/16-20:16:08.272372 7f7668bfb6c0 Level-0 table #1085: 0 bytes OK
|
||||||
2025/02/11-21:54:35.544201 7f92b3bff6c0 Level-0 table #742: started
|
2026/03/16-20:16:08.279546 7f7668bfb6c0 Delete type=0 #1083
|
||||||
2025/02/11-21:54:35.544228 7f92b3bff6c0 Level-0 table #742: 0 bytes OK
|
2026/03/16-20:16:08.312273 7f7668bfb6c0 Manual compaction at level-0 from '!items!CoqlfsDV1gL5swbK' @ 72057594037927935 : 1 .. '!items!yofwG0YrsL902G77' @ 0 : 0; will stop at '!items!yofwG0YrsL902G77' @ 64 : 1
|
||||||
2025/02/11-21:54:35.551120 7f92b3bff6c0 Delete type=0 #740
|
2026/03/16-20:16:08.312291 7f7668bfb6c0 Compacting 1@0 + 0@1 files
|
||||||
2025/02/11-21:54:35.557431 7f92b3bff6c0 Manual compaction at level-0 from '!items!CoqlfsDV1gL5swbK' @ 72057594037927935 : 1 .. '!items!yofwG0YrsL902G77' @ 0 : 0; will stop at (end)
|
2026/03/16-20:16:08.316030 7f7668bfb6c0 Generated table #1086@0: 8 keys, 2453 bytes
|
||||||
2025/02/11-21:54:35.557476 7f92b3bff6c0 Manual compaction at level-1 from '!items!CoqlfsDV1gL5swbK' @ 72057594037927935 : 1 .. '!items!yofwG0YrsL902G77' @ 0 : 0; will stop at (end)
|
2026/03/16-20:16:08.316070 7f7668bfb6c0 Compacted 1@0 + 0@1 files => 2453 bytes
|
||||||
|
2026/03/16-20:16:08.323057 7f7668bfb6c0 compacted to: files[ 0 1 0 0 0 0 0 ]
|
||||||
|
2026/03/16-20:16:08.323234 7f7668bfb6c0 Delete type=2 #772
|
||||||
|
2026/03/16-20:16:08.335626 7f7668bfb6c0 Manual compaction at level-0 from '!items!yofwG0YrsL902G77' @ 64 : 1 .. '!items!yofwG0YrsL902G77' @ 0 : 0; will stop at (end)
|
||||||
|
|||||||
@@ -1,8 +1,4 @@
|
|||||||
2025/02/11-21:46:57.634030 7f92b4ff96c0 Recovering log #733
|
2026/03/16-19:46:08.865328 7f76693fc6c0 Log #1080: 0 ops saved to Table #1081 OK
|
||||||
2025/02/11-21:46:57.667250 7f92b4ff96c0 Delete type=3 #731
|
2026/03/16-19:46:08.865565 7f76693fc6c0 Archiving /home/morr/foundry/foundrydata-v13/Data/systems/bol/packs/boonsflawscreatures/001080.log: OK
|
||||||
2025/02/11-21:46:57.667306 7f92b4ff96c0 Delete type=0 #733
|
2026/03/16-19:46:08.865990 7f76693fc6c0 Table #772: 8 entries OK
|
||||||
2025/02/11-21:51:51.135962 7f92b3bff6c0 Level-0 table #738: started
|
2026/03/16-19:46:08.869744 7f76693fc6c0 **** Repaired leveldb /home/morr/foundry/foundrydata-v13/Data/systems/bol/packs/boonsflawscreatures; recovered 1 files; 2453 bytes. Some data may have been lost. ****
|
||||||
2025/02/11-21:51:51.136026 7f92b3bff6c0 Level-0 table #738: 0 bytes OK
|
|
||||||
2025/02/11-21:51:51.143488 7f92b3bff6c0 Delete type=0 #736
|
|
||||||
2025/02/11-21:51:51.165385 7f92b3bff6c0 Manual compaction at level-0 from '!items!CoqlfsDV1gL5swbK' @ 72057594037927935 : 1 .. '!items!yofwG0YrsL902G77' @ 0 : 0; will stop at (end)
|
|
||||||
2025/02/11-21:51:51.165441 7f92b3bff6c0 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-001082
Normal file
BIN
packs/boonsflawscreatures/MANIFEST-001082
Normal file
Binary file not shown.
Binary file not shown.
BIN
packs/careers/001086.ldb
Normal file
BIN
packs/careers/001086.ldb
Normal file
Binary file not shown.
@@ -1 +1 @@
|
|||||||
MANIFEST-000739
|
MANIFEST-001082
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
2025/02/11-21:52:03.893611 7f92b47f86c0 Recovering log #737
|
2026/03/16-19:46:09.002243 7f76693fc6c0 Delete type=3 #1
|
||||||
2025/02/11-21:52:03.903497 7f92b47f86c0 Delete type=3 #735
|
2026/03/16-20:16:08.279807 7f7668bfb6c0 Level-0 table #1085: started
|
||||||
2025/02/11-21:52:03.903562 7f92b47f86c0 Delete type=0 #737
|
2026/03/16-20:16:08.279852 7f7668bfb6c0 Level-0 table #1085: 0 bytes OK
|
||||||
2025/02/11-21:54:35.537763 7f92b3bff6c0 Level-0 table #742: started
|
2026/03/16-20:16:08.287482 7f7668bfb6c0 Delete type=0 #1083
|
||||||
2025/02/11-21:54:35.537788 7f92b3bff6c0 Level-0 table #742: 0 bytes OK
|
2026/03/16-20:16:08.323479 7f7668bfb6c0 Manual compaction at level-0 from '!items!4S4xAfMXGnuU0O1a' @ 72057594037927935 : 1 .. '!items!zxY3sW0iCJBvwjOS' @ 0 : 0; will stop at '!items!zxY3sW0iCJBvwjOS' @ 215 : 1
|
||||||
2025/02/11-21:54:35.544087 7f92b3bff6c0 Delete type=0 #740
|
2026/03/16-20:16:08.323495 7f7668bfb6c0 Compacting 1@0 + 0@1 files
|
||||||
2025/02/11-21:54:35.557421 7f92b3bff6c0 Manual compaction at level-0 from '!items!4S4xAfMXGnuU0O1a' @ 72057594037927935 : 1 .. '!items!zxY3sW0iCJBvwjOS' @ 0 : 0; will stop at (end)
|
2026/03/16-20:16:08.328403 7f7668bfb6c0 Generated table #1086@0: 27 keys, 42639 bytes
|
||||||
2025/02/11-21:54:35.557458 7f92b3bff6c0 Manual compaction at level-1 from '!items!4S4xAfMXGnuU0O1a' @ 72057594037927935 : 1 .. '!items!zxY3sW0iCJBvwjOS' @ 0 : 0; will stop at (end)
|
2026/03/16-20:16:08.328434 7f7668bfb6c0 Compacted 1@0 + 0@1 files => 42639 bytes
|
||||||
|
2026/03/16-20:16:08.335062 7f7668bfb6c0 compacted to: files[ 0 1 0 0 0 0 0 ]
|
||||||
|
2026/03/16-20:16:08.335267 7f7668bfb6c0 Delete type=2 #772
|
||||||
|
2026/03/16-20:16:08.335642 7f7668bfb6c0 Manual compaction at level-0 from '!items!zxY3sW0iCJBvwjOS' @ 215 : 1 .. '!items!zxY3sW0iCJBvwjOS' @ 0 : 0; will stop at (end)
|
||||||
|
|||||||
@@ -1,8 +1,4 @@
|
|||||||
2025/02/11-21:46:57.718347 7f92b5ffb6c0 Recovering log #733
|
2026/03/16-19:46:08.971933 7f76693fc6c0 Log #1080: 0 ops saved to Table #1081 OK
|
||||||
2025/02/11-21:46:57.741441 7f92b5ffb6c0 Delete type=3 #731
|
2026/03/16-19:46:08.972193 7f76693fc6c0 Archiving /home/morr/foundry/foundrydata-v13/Data/systems/bol/packs/careers/001080.log: OK
|
||||||
2025/02/11-21:46:57.741502 7f92b5ffb6c0 Delete type=0 #733
|
2026/03/16-19:46:08.973605 7f76693fc6c0 Table #772: 27 entries OK
|
||||||
2025/02/11-21:51:51.143598 7f92b3bff6c0 Level-0 table #738: started
|
2026/03/16-19:46:08.977409 7f76693fc6c0 **** Repaired leveldb /home/morr/foundry/foundrydata-v13/Data/systems/bol/packs/careers; recovered 1 files; 42639 bytes. Some data may have been lost. ****
|
||||||
2025/02/11-21:51:51.143622 7f92b3bff6c0 Level-0 table #738: 0 bytes OK
|
|
||||||
2025/02/11-21:51:51.150418 7f92b3bff6c0 Delete type=0 #736
|
|
||||||
2025/02/11-21:51:51.165405 7f92b3bff6c0 Manual compaction at level-0 from '!items!4S4xAfMXGnuU0O1a' @ 72057594037927935 : 1 .. '!items!zxY3sW0iCJBvwjOS' @ 0 : 0; will stop at (end)
|
|
||||||
2025/02/11-21:51:51.165450 7f92b3bff6c0 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-001082
Normal file
BIN
packs/careers/MANIFEST-001082
Normal file
Binary file not shown.
Binary file not shown.
BIN
packs/effets-exemples/001084.ldb
Normal file
BIN
packs/effets-exemples/001084.ldb
Normal file
Binary file not shown.
@@ -1 +1 @@
|
|||||||
MANIFEST-000737
|
MANIFEST-001080
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
2025/02/11-21:52:04.078087 7f92b4ff96c0 Recovering log #735
|
2026/03/16-19:46:09.384452 7f766abff6c0 Delete type=3 #1
|
||||||
2025/02/11-21:52:04.088545 7f92b4ff96c0 Delete type=3 #733
|
2026/03/16-20:16:08.596026 7f7668bfb6c0 Level-0 table #1083: started
|
||||||
2025/02/11-21:52:04.088597 7f92b4ff96c0 Delete type=0 #735
|
2026/03/16-20:16:08.596072 7f7668bfb6c0 Level-0 table #1083: 0 bytes OK
|
||||||
2025/02/11-21:54:35.646391 7f92b3bff6c0 Level-0 table #740: started
|
2026/03/16-20:16:08.604284 7f7668bfb6c0 Delete type=0 #1081
|
||||||
2025/02/11-21:54:35.646414 7f92b3bff6c0 Level-0 table #740: 0 bytes OK
|
2026/03/16-20:16:08.616512 7f7668bfb6c0 Manual compaction at level-0 from '!items!6fTZ6hOKR4pWbWOe' @ 72057594037927935 : 1 .. '!items!zwSNMO9HpiqUCMt8' @ 0 : 0; will stop at '!items!zwSNMO9HpiqUCMt8' @ 24 : 1
|
||||||
2025/02/11-21:54:35.652511 7f92b3bff6c0 Delete type=0 #738
|
2026/03/16-20:16:08.616529 7f7668bfb6c0 Compacting 1@0 + 0@1 files
|
||||||
2025/02/11-21:54:35.665492 7f92b3bff6c0 Manual compaction at level-0 from '!items!6fTZ6hOKR4pWbWOe' @ 72057594037927935 : 1 .. '!items!zwSNMO9HpiqUCMt8' @ 0 : 0; will stop at (end)
|
2026/03/16-20:16:08.620595 7f7668bfb6c0 Generated table #1084@0: 4 keys, 990 bytes
|
||||||
2025/02/11-21:54:35.665529 7f92b3bff6c0 Manual compaction at level-1 from '!items!6fTZ6hOKR4pWbWOe' @ 72057594037927935 : 1 .. '!items!zwSNMO9HpiqUCMt8' @ 0 : 0; will stop at (end)
|
2026/03/16-20:16:08.620628 7f7668bfb6c0 Compacted 1@0 + 0@1 files => 990 bytes
|
||||||
|
2026/03/16-20:16:08.627657 7f7668bfb6c0 compacted to: files[ 0 1 0 0 0 0 0 ]
|
||||||
|
2026/03/16-20:16:08.627801 7f7668bfb6c0 Delete type=2 #770
|
||||||
|
2026/03/16-20:16:08.667532 7f7668bfb6c0 Manual compaction at level-0 from '!items!zwSNMO9HpiqUCMt8' @ 24 : 1 .. '!items!zwSNMO9HpiqUCMt8' @ 0 : 0; will stop at (end)
|
||||||
|
|||||||
@@ -1,8 +1,4 @@
|
|||||||
2025/02/11-21:46:58.388995 7f92b47f86c0 Recovering log #731
|
2026/03/16-19:46:09.364109 7f766abff6c0 Log #1078: 0 ops saved to Table #1079 OK
|
||||||
2025/02/11-21:46:58.441520 7f92b47f86c0 Delete type=3 #729
|
2026/03/16-19:46:09.364398 7f766abff6c0 Archiving /home/morr/foundry/foundrydata-v13/Data/systems/bol/packs/effets-exemples/001078.log: OK
|
||||||
2025/02/11-21:46:58.441593 7f92b47f86c0 Delete type=0 #731
|
2026/03/16-19:46:09.364562 7f766abff6c0 Table #770: 4 entries OK
|
||||||
2025/02/11-21:51:51.256745 7f92b3bff6c0 Level-0 table #736: started
|
2026/03/16-19:46:09.368408 7f766abff6c0 **** Repaired leveldb /home/morr/foundry/foundrydata-v13/Data/systems/bol/packs/effets-exemples; recovered 1 files; 990 bytes. Some data may have been lost. ****
|
||||||
2025/02/11-21:51:51.256779 7f92b3bff6c0 Level-0 table #736: 0 bytes OK
|
|
||||||
2025/02/11-21:51:51.263802 7f92b3bff6c0 Delete type=0 #734
|
|
||||||
2025/02/11-21:51:51.277287 7f92b3bff6c0 Manual compaction at level-0 from '!items!6fTZ6hOKR4pWbWOe' @ 72057594037927935 : 1 .. '!items!zwSNMO9HpiqUCMt8' @ 0 : 0; will stop at (end)
|
|
||||||
2025/02/11-21:51:51.277328 7f92b3bff6c0 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-001080
Normal file
BIN
packs/effets-exemples/MANIFEST-001080
Normal file
Binary file not shown.
Binary file not shown.
BIN
packs/equipment/001087.ldb
Normal file
BIN
packs/equipment/001087.ldb
Normal file
Binary file not shown.
@@ -1 +1 @@
|
|||||||
MANIFEST-000740
|
MANIFEST-001083
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user