Compare commits
23 Commits
bol-v12.1.
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 7adc1b3f07 | |||
| 6c70dc147c | |||
| 1ffb8b08fc | |||
| 8017bb207d | |||
| 364278527d | |||
| 93d35abde2 | |||
| 0409be64eb | |||
| ed76a49e7d | |||
| 2abd2c881a | |||
| 3fa5ca66d1 | |||
| 6de15eeda7 | |||
| 724c096743 | |||
| 3e3a4b9ec1 | |||
| 425a2a1fc0 | |||
| 203d7add66 | |||
| 8ae193dc34 | |||
| 3904f595b5 | |||
| 1bf21fae7f | |||
| 22579c21bc | |||
| 50c5c31e7b | |||
| a8c05cd4de | |||
| e1cea78059 | |||
| c2f9934f5f |
@@ -12,37 +12,35 @@ jobs:
|
||||
|
||||
#- uses: actions/checkout@v3
|
||||
- uses: RouxAntoine/checkout@v3.5.4
|
||||
with:
|
||||
ref: 'v10'
|
||||
|
||||
# get part of the tag after the `v`
|
||||
- name: Extract tag version number
|
||||
id: get_version
|
||||
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
|
||||
id: sub_manifest_link_version
|
||||
uses: microsoft/variable-substitution@v1
|
||||
with:
|
||||
files: 'system.json'
|
||||
files: "system.json"
|
||||
env:
|
||||
version: ${{steps.get_version.outputs.version-without-v}}
|
||||
url: https://www.uberwald.me/gitea/public/bol
|
||||
manifest: https://www.uberwald.me/gitea/public/bol/releases/latest/system.json
|
||||
download: https://www.uberwald.me/gitea/public/bol/releases/download/${{github.event.release.tag_name}}/bol.zip
|
||||
url: https://www.uberwald.me/gitea/${{gitea.repository}}
|
||||
manifest: https://www.uberwald.me/gitea/public/bol/releases/download/latest/system.json
|
||||
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
|
||||
- run: |
|
||||
apt update -y
|
||||
apt install -y zip
|
||||
|
||||
- run: zip -r ./bol.zip system.json template.json README.md LICENSE assets/ css/ fonts/ images/ lang/ module/ packs/ styles/ templates/ ui/
|
||||
- run: zip -r ./bol.zip system.json template.json README.md LICENSE assets/ compendiums/ css/ fonts/ images/ lang/ module/ packs/ styles/ templates/ ui/
|
||||
|
||||
- name: setup go
|
||||
uses: https://github.com/actions/setup-go@v4
|
||||
with:
|
||||
go-version: '>=1.20.1'
|
||||
go-version: ">=1.20.1"
|
||||
|
||||
- name: Use Go Action
|
||||
id: use-go-action
|
||||
@@ -51,4 +49,15 @@ jobs:
|
||||
files: |-
|
||||
./bol.zip
|
||||
system.json
|
||||
api_key: '${{secrets.RELEASE_TOKEN_UBERWALD}}'
|
||||
api_key: "${{secrets.ALLOW_PUSH_RELEASE}}"
|
||||
|
||||
- name: Publish to Foundry server
|
||||
uses: https://github.com/djlechuck/foundryvtt-publish-package-action@v1
|
||||
with:
|
||||
token: ${{ secrets.FOUNDRYVTT_RELEASE_TOKEN }}
|
||||
id: "bol"
|
||||
version: ${{github.event.release.tag_name}}
|
||||
manifest: "https://www.uberwald.me/gitea/public/bol/releases/download/latest/system.json"
|
||||
notes: "https://www.uberwald.me/gitea/${{gitea.repository}}/releases/download/${{github.event.release.tag_name}}/bol.zip"
|
||||
compatibility-minimum: "13"
|
||||
compatibility-verified: "13"
|
||||
|
||||
286
APPV2_ITEMS_MIGRATION.md
Normal file
286
APPV2_ITEMS_MIGRATION.md
Normal file
@@ -0,0 +1,286 @@
|
||||
# Migration AppV2 - Item Sheets
|
||||
|
||||
## Vue d'ensemble
|
||||
|
||||
Migration des feuilles d'items de BoL vers l'architecture **ApplicationV2** de Foundry VTT v12+.
|
||||
|
||||
## Fichiers créés
|
||||
|
||||
### Classes AppV2 (module/applications/sheets/)
|
||||
|
||||
1. **base-item-sheet.mjs** - Classe de base pour tous les item sheets
|
||||
- Hérite de `foundry.applications.sheets.ItemSheetV2`
|
||||
- Utilise `HandlebarsApplicationMixin`
|
||||
- Gère les tabs, drag & drop, actions communes
|
||||
- 272 lignes de code
|
||||
|
||||
2. **item-sheet.mjs** - Sheet pour le type "item"
|
||||
- Équipements, armes, protections, sorts, etc.
|
||||
- Hérite de `BoLBaseItemSheet`
|
||||
- Contexte spécifique aux items
|
||||
|
||||
3. **feature-sheet.mjs** - Sheet pour le type "feature"
|
||||
- Boons, flaws, careers, origins, races, etc.
|
||||
- Hérite de `BoLBaseItemSheet`
|
||||
- Contexte spécifique aux features
|
||||
|
||||
4. **_module.mjs** - Export des sheets
|
||||
|
||||
### Templates (templates/item/)
|
||||
|
||||
1. **item-sheet.hbs** - Template pour les items
|
||||
2. **feature-sheet.hbs** - Template pour les features
|
||||
3. **parts/item-header.hbs** - Header mis à jour pour AppV2
|
||||
|
||||
### Backups
|
||||
|
||||
- `templates/item.backup/` - Backup des templates originaux
|
||||
- `module/item.backup/` - Backup de l'ancienne classe ItemSheet
|
||||
- `templates/item/parts/item-header.hbs.backup` - Backup du header
|
||||
|
||||
## Architecture AppV2
|
||||
|
||||
### Différences avec AppV1
|
||||
|
||||
| Aspect | AppV1 (avant) | AppV2 (après) |
|
||||
|--------|---------------|---------------|
|
||||
| Classe de base | `ItemSheet` | `ItemSheetV2` |
|
||||
| Options | `static get defaultOptions()` | `static DEFAULT_OPTIONS` |
|
||||
| getData | `async getData()` | `async _prepareContext()` |
|
||||
| Template | Unique | Peut utiliser PARTS |
|
||||
| Tabs | Automatiques | Gestion manuelle |
|
||||
| Actions | Event listeners | `actions:` dans OPTIONS |
|
||||
| Render | `activateListeners()` | `_onRender()` |
|
||||
|
||||
### Structure de BoLBaseItemSheet
|
||||
|
||||
```javascript
|
||||
class BoLBaseItemSheet extends ItemSheetV2 {
|
||||
// Options statiques
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes, position, form, window,
|
||||
actions, dragDrop, tabs
|
||||
}
|
||||
|
||||
// State
|
||||
tabGroups = { primary: "description" }
|
||||
|
||||
// Méthodes principales
|
||||
async _prepareContext() // Prépare les données
|
||||
_onRender() // Après le render
|
||||
_activateTabs() // Active les tabs
|
||||
_activateListeners() // Event listeners
|
||||
|
||||
// Actions
|
||||
static #onEditImage() // data-action="editImage"
|
||||
static #onPostItem() // data-action="postItem"
|
||||
|
||||
// Drag & Drop
|
||||
#createDragDropHandlers()
|
||||
_canDragStart()
|
||||
_onDragStart()
|
||||
}
|
||||
```
|
||||
|
||||
## Fonctionnalités migrées
|
||||
|
||||
### ✅ Depuis l'ancien BoLItemSheet
|
||||
|
||||
1. **getData** → **_prepareContext**
|
||||
- Enrichissement de la description
|
||||
- Configuration des données dynamiques
|
||||
- Gestion des catégories
|
||||
- Propriétés des items
|
||||
- Careers depuis l'actor
|
||||
|
||||
2. **Tabs**
|
||||
- Navigation entre Description et Properties
|
||||
- State persistant avec `tabGroups`
|
||||
- Activation manuelle des tabs
|
||||
|
||||
3. **Actions**
|
||||
- Edit Image (FilePicker)
|
||||
- Post Item (chat)
|
||||
|
||||
4. **Listeners spécifiques**
|
||||
- Armor quality → soak formula
|
||||
|
||||
5. **Dynamic defaults**
|
||||
- Category par défaut
|
||||
- Spell conditions (mandatory/optional)
|
||||
- Equipment slots
|
||||
|
||||
## Utilisation dans les templates
|
||||
|
||||
### Actions (data-action)
|
||||
|
||||
```handlebars
|
||||
{{!-- Éditer l'image --}}
|
||||
<img data-action="editImage" src="{{item.img}}" />
|
||||
|
||||
{{!-- Poster au chat --}}
|
||||
<button data-action="postItem">
|
||||
<i class="fas fa-comment"></i>
|
||||
</button>
|
||||
```
|
||||
|
||||
### Tabs
|
||||
|
||||
```handlebars
|
||||
{{!-- Navigation --}}
|
||||
<nav class="tabs" data-group="primary">
|
||||
{{#each tabs}}
|
||||
<a data-tab="{{this.id}}" class="{{#if (eq ../activeTab this.id)}}active{{/if}}">
|
||||
{{localize this.label}}
|
||||
</a>
|
||||
{{/each}}
|
||||
</nav>
|
||||
|
||||
{{!-- Contenu --}}
|
||||
<div class="tab {{#if (eq activeTab 'description')}}active{{/if}}"
|
||||
data-tab="description">
|
||||
...
|
||||
</div>
|
||||
```
|
||||
|
||||
### Editor
|
||||
|
||||
```handlebars
|
||||
{{!-- AppV2 avec ProseMirror --}}
|
||||
{{editor enrichedDescription
|
||||
target="system.description"
|
||||
button=true
|
||||
editable=isEditable
|
||||
engine="prosemirror"}}
|
||||
```
|
||||
|
||||
## Context disponible dans les templates
|
||||
|
||||
```javascript
|
||||
{
|
||||
// Document & system
|
||||
fields: schema.fields,
|
||||
systemFields: system.schema.fields,
|
||||
item: document,
|
||||
system: document.system,
|
||||
source: document.toObject(),
|
||||
|
||||
// Content
|
||||
enrichedDescription: "HTML enrichi",
|
||||
category: "equipment|weapon|spell|...",
|
||||
itemProperties: ["prop1", "prop2"],
|
||||
|
||||
// Config
|
||||
config: game.bol.config,
|
||||
isGM: boolean,
|
||||
isEditable: boolean,
|
||||
|
||||
// Tabs
|
||||
tabs: [{id, label, icon}],
|
||||
activeTab: "description|properties",
|
||||
|
||||
// Type-specific (item-sheet.mjs)
|
||||
isItem: true,
|
||||
isEquipment: boolean,
|
||||
isWeapon: boolean,
|
||||
isProtection: boolean,
|
||||
isSpell: boolean,
|
||||
|
||||
// Type-specific (feature-sheet.mjs)
|
||||
isFeature: true,
|
||||
isBoon: boolean,
|
||||
isFlaw: boolean,
|
||||
isCareer: boolean,
|
||||
isOrigin: boolean,
|
||||
isRace: boolean,
|
||||
|
||||
// Optional
|
||||
careers: actor.careers // Si item sur actor
|
||||
}
|
||||
```
|
||||
|
||||
## Configuration dans bol.js
|
||||
|
||||
```javascript
|
||||
// Import
|
||||
import * as sheets from "./applications/sheets/_module.mjs"
|
||||
|
||||
// Enregistrement
|
||||
foundry.documents.collections.Items.unregisterSheet("core", ...)
|
||||
foundry.documents.collections.Items.registerSheet("bol",
|
||||
sheets.BoLItemSheet,
|
||||
{ types: ["item"], makeDefault: true }
|
||||
)
|
||||
foundry.documents.collections.Items.registerSheet("bol",
|
||||
sheets.BoLFeatureSheet,
|
||||
{ types: ["feature"], makeDefault: true }
|
||||
)
|
||||
```
|
||||
|
||||
## Avantages de AppV2
|
||||
|
||||
1. **Performance** : Meilleur rendu et gestion des updates
|
||||
2. **Structure** : Code plus organisé et maintenable
|
||||
3. **Actions** : Système d'actions déclaratif
|
||||
4. **Context** : Préparation des données séparée du template
|
||||
5. **Standard** : Aligné sur Foundry VTT v12+
|
||||
6. **Future-proof** : Architecture pérenne
|
||||
|
||||
## Points d'attention
|
||||
|
||||
### Compatibilité
|
||||
|
||||
- Les données restent 100% compatibles
|
||||
- Seule l'interface de sheet change
|
||||
- Pas de migration de données nécessaire
|
||||
|
||||
### Tabs
|
||||
|
||||
Les tabs ne sont plus automatiques dans AppV2 :
|
||||
- Navigation manuelle avec `_activateTabs()`
|
||||
- State persistant avec `tabGroups`
|
||||
- CSS `.active` géré manuellement
|
||||
|
||||
### Editor
|
||||
|
||||
ProseMirror est maintenant le moteur par défaut :
|
||||
```handlebars
|
||||
{{editor content engine="prosemirror"}}
|
||||
```
|
||||
|
||||
### Actions
|
||||
|
||||
Système déclaratif :
|
||||
```javascript
|
||||
actions: {
|
||||
myAction: ClassName.#onMyAction
|
||||
}
|
||||
```
|
||||
|
||||
Dans le template :
|
||||
```handlebars
|
||||
<button data-action="myAction">Click</button>
|
||||
```
|
||||
|
||||
## Prochaines étapes
|
||||
|
||||
### Court terme
|
||||
1. Tester les sheets dans Foundry
|
||||
2. Vérifier toutes les fonctionnalités
|
||||
3. Ajuster les CSS si nécessaire
|
||||
|
||||
### Moyen terme
|
||||
4. Migrer les actor sheets vers AppV2
|
||||
5. Ajouter des features AppV2 (parts, etc.)
|
||||
6. Optimiser les templates
|
||||
|
||||
### Long terme
|
||||
7. Utiliser PARTS pour modularité
|
||||
8. Ajouter des actions avancées
|
||||
9. Améliorer la UX
|
||||
|
||||
## Références
|
||||
|
||||
- [Foundry AppV2 Documentation](https://foundryvtt.com/api/classes/foundry.applications.api.ApplicationV2.html)
|
||||
- [ItemSheetV2 API](https://foundryvtt.com/api/classes/foundry.applications.sheets.ItemSheetV2.html)
|
||||
- Exemples : fvtt-cthulhu-eternal, fvtt-mournblade
|
||||
35
changelog.md
35
changelog.md
@@ -1,18 +1,26 @@
|
||||
Changes :
|
||||
|
||||
# v12.1.0
|
||||
# v13.0.0
|
||||
|
||||
- Foundry v13 only
|
||||
|
||||
# v12.1.7
|
||||
|
||||
- Enhance welcome message
|
||||
|
||||
# v12.1.1
|
||||
|
||||
## French
|
||||
|
||||
- Correction sur les conditions des sorts
|
||||
- Jet d'armures correctement affichés
|
||||
- Dégat à 0 possibles sur les armes/capacités
|
||||
|
||||
## English
|
||||
|
||||
- Corrected spell conditions
|
||||
- Armor rolls are now correctly displayed
|
||||
- Weapon/capacity damage can now be set to 0
|
||||
|
||||
|
||||
# v12.1.0
|
||||
|
||||
- Gestion des Hordes
|
||||
@@ -39,20 +47,19 @@ Changes :
|
||||
|
||||
# v11.0.8
|
||||
|
||||
- Correction sur les malus de bouclier (blocage)
|
||||
- Corrrection sur le malus d'init des boucliers qui était mal affiché dans la fiche d'item
|
||||
- Correction sur les malus de bouclier (blocage)
|
||||
- Corrrection sur le malus d'init des boucliers qui était mal affiché dans la fiche d'item
|
||||
|
||||
# v10.4.0
|
||||
|
||||
- Ajout de la gestion d'effets
|
||||
- Aide intégré
|
||||
- Intégration du PDF de la bougette
|
||||
- Ajout de la gestion d'effets
|
||||
- Aide intégré
|
||||
- Intégration du PDF de la bougette
|
||||
|
||||
# v10.3.3
|
||||
|
||||
- Nouvelles clés de traduction
|
||||
- Lorsqu'une arme a un dé bonus, prise en compte plus claire du dé bonus et affichage de l'information dans la fenêtre de jet
|
||||
- Lorsqu'une arme relance les 1 sur ses dégats, l'information est affichée dans le tchat
|
||||
- Termes corrects pour les PNJs (ie rival)
|
||||
- Nouveaux équipements issus du Dieu Voilé
|
||||
|
||||
- Nouvelles clés de traduction
|
||||
- Lorsqu'une arme a un dé bonus, prise en compte plus claire du dé bonus et affichage de l'information dans la fenêtre de jet
|
||||
- Lorsqu'une arme relance les 1 sur ses dégats, l'information est affichée dans le tchat
|
||||
- Termes corrects pour les PNJs (ie rival)
|
||||
- Nouveaux équipements issus du Dieu Voilé
|
||||
|
||||
1995
css/bol.css
1995
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.natural": "Natürliche Waffe",
|
||||
"BOL.itemProperty.onlymodifier": "Nur Modifikator (d.h. Angriffe von Kreaturen)",
|
||||
"BOL.itemProperty.attackMalusDice": "Angriffsmalus (Würfel)",
|
||||
|
||||
"BOL.itemStat.quantity": "Anzahl",
|
||||
"BOL.itemStat.weight": "Gewicht",
|
||||
|
||||
14
lang/en.json
14
lang/en.json
@@ -365,6 +365,7 @@
|
||||
"BOL.itemProperty.difficulty": "Difficulty",
|
||||
"BOL.itemProperty.natural": "Natural weapon",
|
||||
"BOL.itemProperty.onlymodifier": "Modifier only (ie creatures attacks)",
|
||||
"BOL.itemProperty.attackMalusDice": "Attack Malus (Dice)",
|
||||
|
||||
"BOL.itemStat.quantity": "Quantity",
|
||||
"BOL.itemStat.weight": "Weight",
|
||||
@@ -546,15 +547,21 @@
|
||||
"BOL.chat.bolRulebookMessage": "Don't miss the full Rulebook module (including Sagas) available at : https://www.ludospherik-editions.com/en_gb/ !",
|
||||
|
||||
"BOL.dialog.soeasy": "So easy (+4)",
|
||||
"BOL.dialog.soeasy3": "So easy (+3)",
|
||||
"BOL.dialog.veryeasy": "Very easy (+2)",
|
||||
"BOL.dialog.easy": "Easy (+1)",
|
||||
"BOL.dialog.moderate": "Moderate (0)",
|
||||
"BOL.dialog.hard": "Hard (-1)",
|
||||
"BOL.dialog.tough": "Tough (-2)",
|
||||
"BOL.dialog.tough3": "Tough (-3)",
|
||||
"BOL.dialog.demanding": "Demanding (-4)",
|
||||
"BOL.dialog.demanding5": "Demanding (-5)",
|
||||
"BOL.dialog.formidable": "Formidable (-6)",
|
||||
"BOL.dialog.formidable7": "Formidable (-7)",
|
||||
"BOL.dialog.heroic": "Heroic (-8)",
|
||||
"BOL.dialog.heroic9": "Heroic (-9)",
|
||||
"BOL.dialog.mythic": "Mythic (-10)",
|
||||
"BOL.dialog.mythic11": "Mythic (-11)",
|
||||
"BOL.dialog.divine": "Divine (-12)",
|
||||
|
||||
"BOL.dialog.pointblank": "Point blank (+1)",
|
||||
@@ -602,5 +609,10 @@
|
||||
"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.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.natural": "Arma natural",
|
||||
"BOL.itemProperty.onlymodifier": "Sólo modificador (ej criatura)",
|
||||
"BOL.itemProperty.attackMalusDice": "Dado Desventaja Ataque",
|
||||
|
||||
"BOL.itemStat.quantity": "Cantidad",
|
||||
"BOL.itemStat.weight": "Peso",
|
||||
|
||||
17
lang/fr.json
17
lang/fr.json
@@ -394,6 +394,7 @@
|
||||
"BOL.itemProperty.isboarding": "Abordage",
|
||||
"BOL.itemProperty.isspur": "Eperonnage",
|
||||
"BOL.itemProperty.isbreakrow": "Briser les rames",
|
||||
"BOL.itemProperty.attackMalusDice": "Malus d'attaque (Dés)",
|
||||
|
||||
"BOL.itemStat.quantity": "Quantité",
|
||||
"BOL.itemStat.weight": "Poids",
|
||||
@@ -573,17 +574,25 @@
|
||||
"BOL.chat.losshp": "{name} a perdu {lossHP} points de Vitalité. Si il se repose quelques minutes, il peut récupérer {recupHP} points de Vitalité.",
|
||||
"BOL.chat.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.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.soeasy3": "Inmanquable (+3)",
|
||||
"BOL.dialog.veryeasy": "Trés Facile (+2)",
|
||||
"BOL.dialog.easy": "Facile (+1)",
|
||||
"BOL.dialog.moderate": "Moyenne (0)",
|
||||
"BOL.dialog.hard": "Ardue (-1)",
|
||||
"BOL.dialog.tough": "Difficile (-2)",
|
||||
"BOL.dialog.tough3": "Difficile (-3)",
|
||||
"BOL.dialog.demanding": "Très Difficile (-4)",
|
||||
"BOL.dialog.demanding5": "Très Difficile (-5)",
|
||||
"BOL.dialog.formidable": "Impossible (-6)",
|
||||
"BOL.dialog.formidable7": "Impossible (-7)",
|
||||
"BOL.dialog.heroic": "Héroïque (-8)",
|
||||
"BOL.dialog.heroic9": "Héroïque (-9)",
|
||||
"BOL.dialog.mythic": "Mythique (-10)",
|
||||
"BOL.dialog.mythic11": "Mythique (-11)",
|
||||
"BOL.dialog.divine": "Divine (-12)",
|
||||
|
||||
"BOL.dialog.pointblank": "Bout portant (+1)",
|
||||
@@ -620,7 +629,6 @@
|
||||
"BOL.chat.pcwarningmsg": "<b>ATTENTION</b> Le joueur n'est relié à aucun personnage !",
|
||||
"BOL.chat.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.armorRoll": "Jet d'armure",
|
||||
|
||||
"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é)",
|
||||
@@ -642,5 +650,10 @@
|
||||
"BOL.settings.defaultLogoTopLeftPathTooltip": "Vous pouvez changer le logo BoL en haut à gauche de chaque écran (idéalement 718 x 416, défaut : /systems/bol/ui/logo2.webp)",
|
||||
|
||||
"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 { BoLUtility } from "../system/bol-utility.js";
|
||||
|
||||
export class BoLActorSheet extends ActorSheet {
|
||||
export class BoLActorSheet extends foundry.appv1.sheets.ActorSheet {
|
||||
|
||||
/** @override */
|
||||
static get defaultOptions() {
|
||||
@@ -170,8 +170,8 @@ export class BoLActorSheet extends ActorSheet {
|
||||
formData.charType = this.actor.getCharType()
|
||||
formData.villainy = this.actor.getVillainy()
|
||||
formData.isUndead = this.actor.isUndead()
|
||||
formData.biography = await TextEditor.enrichHTML(this.object.system.details?.biography || "", { async: true })
|
||||
formData.notes = await TextEditor.enrichHTML(this.object.system.details.notes || "", { async: true })
|
||||
formData.biography = await foundry.applications.ux.TextEditor.implementation.enrichHTML(this.object.system.details?.biography || "", { async: true })
|
||||
formData.notes = await foundry.applications.ux.TextEditor.implementation.enrichHTML(this.object.system.details.notes || "", { async: true })
|
||||
formData.isSorcerer = this.actor.isSorcerer()
|
||||
formData.isAlchemist = this.actor.isAlchemist()
|
||||
formData.isAstrologer = this.actor.isAstrologer()
|
||||
|
||||
@@ -7,6 +7,8 @@ import { BoLUtility } from "../system/bol-utility.js";
|
||||
*/
|
||||
export class BoLActor extends Actor {
|
||||
|
||||
static _healthLock = new Set()
|
||||
|
||||
static async create(data, options) {
|
||||
|
||||
// Case of compendium global import
|
||||
@@ -357,7 +359,7 @@ export class BoLActor extends Actor {
|
||||
ChatMessage.create({
|
||||
alias: this.name,
|
||||
whisper: BoLUtility.getWhisperRecipientsAndGMs(this.name),
|
||||
content: await renderTemplate('systems/bol/templates/chat/chat-activate-fight-option.hbs', { name: this.name, img: fightOption.img, foName: fightOption.name, state: state })
|
||||
content: await foundry.applications.handlebars.foundry.applications.handlebars.renderTemplate('systems/bol/templates/chat/chat-activate-fight-option.hbs', { name: this.name, img: fightOption.img, foName: fightOption.name, state: state })
|
||||
})
|
||||
|
||||
}
|
||||
@@ -852,6 +854,9 @@ export class BoLActor extends Actor {
|
||||
|
||||
/*-------------------------------------------- */
|
||||
async manageHealthState() {
|
||||
if (BoLActor._healthLock.has(this.id)) return
|
||||
BoLActor._healthLock.add(this.id)
|
||||
try {
|
||||
let hpID = "lastHP" + this.id
|
||||
let lastHP = await this.getFlag("world", hpID)
|
||||
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({
|
||||
alias: this.name,
|
||||
whisper: BoLUtility.getWhisperRecipientsAndGMs(this.name),
|
||||
content: await renderTemplate('systems/bol/templates/chat/chat-vitality-zero.hbs', { name: this.name, img: this.img, hp: this.system.resources.hp.value, isHeroAdversary: this.isHeroAdversary() })
|
||||
content: await foundry.applications.handlebars.foundry.applications.handlebars.renderTemplate('systems/bol/templates/chat/chat-vitality-zero.hbs', { name: this.name, img: this.img, hp: this.system.resources.hp.value, isHeroAdversary: this.isHeroAdversary() })
|
||||
})
|
||||
} else {
|
||||
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({
|
||||
alias: this.name,
|
||||
whisper: BoLUtility.getWhisperRecipientsAndGMs(this.name),
|
||||
content: await renderTemplate('systems/bol/templates/chat/chat-recup-information.hbs', {
|
||||
content: await foundry.applications.handlebars.foundry.applications.handlebars.renderTemplate('systems/bol/templates/chat/chat-recup-information.hbs', {
|
||||
name: this.name,
|
||||
img: this.img,
|
||||
actorId: this.id,
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
import { BoLRoll } from "../controllers/bol-rolls.js";
|
||||
import { BoLUtility } from "../system/bol-utility.js";
|
||||
|
||||
export class BoLHordeSheet extends ActorSheet {
|
||||
export class BoLHordeSheet extends foundry.appv1.sheets.ActorSheet {
|
||||
|
||||
/** @override */
|
||||
static get defaultOptions() {
|
||||
@@ -116,7 +116,7 @@ export class BoLHordeSheet extends ActorSheet {
|
||||
formData.options = this.options
|
||||
formData.owner = this.document.isOwner
|
||||
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
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
import { BoLRoll } from "../controllers/bol-rolls.js";
|
||||
import { BoLUtility } from "../system/bol-utility.js";
|
||||
|
||||
export class BoLVehicleSheet extends ActorSheet {
|
||||
export class BoLVehicleSheet extends foundry.appv1.sheets.ActorSheet {
|
||||
|
||||
/** @override */
|
||||
static get defaultOptions() {
|
||||
@@ -127,7 +127,7 @@ export class BoLVehicleSheet extends ActorSheet {
|
||||
formData.options = this.options
|
||||
formData.owner = this.document.isOwner
|
||||
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
|
||||
|
||||
|
||||
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 { BoLActor } from "./actor/actor.js"
|
||||
import { BoLActorSheet } from "./actor/actor-sheet.js"
|
||||
import { BoLVehicleSheet } from "./actor/vehicle-sheet.js"
|
||||
import { BoLHordeSheet } from "./actor/horde-sheet.js"
|
||||
// AppV1 actor sheets kept for reference only (AppV2 used via sheets.* below)
|
||||
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 { preloadHandlebarsTemplates } from "./system/templates.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 { 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 () {
|
||||
|
||||
@@ -28,7 +32,9 @@ Hooks.once('init', async function () {
|
||||
BoLRoll,
|
||||
BoLUtility,
|
||||
macros: Macros,
|
||||
config: BOL
|
||||
config: BOL,
|
||||
models,
|
||||
sheets
|
||||
};
|
||||
|
||||
// Game socket
|
||||
@@ -47,17 +53,38 @@ Hooks.once('init', async function () {
|
||||
|
||||
// Define custom Entity classes
|
||||
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.dataModels = {
|
||||
item: models.BoLItem,
|
||||
feature: models.BoLFeature
|
||||
}
|
||||
|
||||
CONFIG.Combat.documentClass = BoLCombatManager;
|
||||
|
||||
// Register sheet application classes
|
||||
Actors.unregisterSheet("core", ActorSheet);
|
||||
Actors.registerSheet("bol", BoLActorSheet, { types: ["character", "encounter"], makeDefault: true })
|
||||
Actors.registerSheet("bol", BoLVehicleSheet, { types: ["vehicle"], makeDefault: true })
|
||||
Actors.registerSheet("bol", BoLHordeSheet, { types: ["horde"], makeDefault: true })
|
||||
foundry.documents.collections.Actors.unregisterSheet("core", foundry.appv1.sheets.ActorSheet);
|
||||
foundry.documents.collections.Actors.registerSheet("bol", sheets.BoLActorSheet, { types: ["character", "encounter"], makeDefault: true })
|
||||
foundry.documents.collections.Actors.registerSheet("bol", sheets.BoLVehicleSheet, { types: ["vehicle"], makeDefault: true })
|
||||
foundry.documents.collections.Actors.registerSheet("bol", sheets.BoLHordeSheet, { types: ["horde"], makeDefault: true })
|
||||
|
||||
Items.unregisterSheet("core", ItemSheet);
|
||||
Items.registerSheet("bol", BoLItemSheet, { makeDefault: true });
|
||||
// Register AppV2 Item Sheets
|
||||
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
|
||||
BoLUtility.init()
|
||||
@@ -83,35 +110,22 @@ Hooks.once('init', async function () {
|
||||
|
||||
|
||||
/* -------------------------------------------- */
|
||||
function welcomeMessage() {
|
||||
let content = `<div id="welcome-message-bol"><span class="rdd-roll-part">
|
||||
<strong>` + game.i18n.localize("BOL.chat.welcome1") + `</strong><p>` +
|
||||
game.i18n.localize("BOL.chat.welcome2") + "</p><p>" +
|
||||
game.i18n.localize("BOL.chat.welcome3") + "</p><p>" +
|
||||
game.i18n.localize("BOL.chat.welcome4") + "</p><p>" +
|
||||
game.i18n.localize("BOL.chat.welcome5") + "</p>" +
|
||||
game.i18n.localize("BOL.chat.welcome6")
|
||||
async function welcomeMessage() {
|
||||
const noRulebook = !game.modules.find(m => m.id === "bol-rulebook")
|
||||
const content = await foundry.applications.handlebars.renderTemplate(
|
||||
"systems/bol/templates/chat/chat-welcome.hbs",
|
||||
{ noRulebook }
|
||||
)
|
||||
ChatMessage.create({ user: game.user.id, whisper: [game.user.id], content })
|
||||
|
||||
let rulebook = game.modules.find( m => m.id === "bol-rulebook")
|
||||
if ( !rulebook ) {
|
||||
content += "<p>" + game.i18n.localize("BOL.chat.bolRulebookMessage") + "</p>"
|
||||
}
|
||||
if (game.user.isGM && game.i18n.lang == 'en' && !game.modules.find(m => m.id == "babele")) {
|
||||
ChatMessage.create({
|
||||
user: game.user.id,
|
||||
whisper: [game.user.id],
|
||||
content: content
|
||||
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>`
|
||||
})
|
||||
|
||||
if (game.user.isGM && game.i18n.lang == 'en' && !game.modules.find(m => m.id == "babele") ){
|
||||
ChatMessage.create({
|
||||
user: game.user.id,
|
||||
whisper: [game.user.id],
|
||||
content: `<div id="welcome-message-bol"><span class="rdd-roll-part">
|
||||
<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.")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
@@ -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 {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static options() {
|
||||
return { classes: ["bol", "dialog"], width: 480, height: 'fit-content' };
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static getDefaultAttribute(key) {
|
||||
return _apt2attr[key]
|
||||
@@ -19,9 +14,9 @@ export class BoLRoll {
|
||||
static updateApplicableEffects(rollData) {
|
||||
let appEffects = []
|
||||
for (let effect of rollData.bolEffects) {
|
||||
if ( (effect.system.properties.identifier == "always") ||
|
||||
if ((effect.system.properties.identifier == "always") ||
|
||||
(effect.system.properties.identifier.includes(rollData.attribute.key)) ||
|
||||
(rollData.aptitude && effect.system.properties.identifier.includes(rollData.aptitude.key)) ){
|
||||
(rollData.aptitude && effect.system.properties.identifier.includes(rollData.aptitude.key))) {
|
||||
appEffects.push(effect)
|
||||
}
|
||||
}
|
||||
@@ -76,7 +71,7 @@ export class BoLRoll {
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static attributeCheck(actor, key="vigor", event=undefined, combatData=undefined) {
|
||||
static attributeCheck(actor, key = "vigor", event = undefined, combatData = undefined) {
|
||||
|
||||
let attribute = eval(`actor.system.attributes.${key}`)
|
||||
|
||||
@@ -89,7 +84,7 @@ export class BoLRoll {
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static aptitudeCheck(actor, key="init", event=undefined, combatData=undefined) {
|
||||
static aptitudeCheck(actor, key = "init", event = undefined, combatData = undefined) {
|
||||
|
||||
let aptitude = eval(`actor.system.aptitudes.${key}`)
|
||||
let attrKey = this.getDefaultAttribute(key)
|
||||
@@ -129,7 +124,7 @@ export class BoLRoll {
|
||||
rangeMsg = "BOL.chat.range6"
|
||||
}
|
||||
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,
|
||||
attackerName: _token.actor.name,
|
||||
defenderName: target.actor.name,
|
||||
@@ -308,26 +303,31 @@ export class BoLRoll {
|
||||
// Final number of dices
|
||||
this.rollData.nbDice = 2 + Math.abs(this.rollData.bmDice)
|
||||
// Bonus or Malus ?
|
||||
const nbDiceEl = document.querySelector('#roll-nbdice')
|
||||
if (nbDiceEl) {
|
||||
if (this.rollData.bmDice == 0) {
|
||||
$('#roll-nbdice').val("2")
|
||||
nbDiceEl.value = "2"
|
||||
} else {
|
||||
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
|
||||
if (this.rollData.weapon && this.rollData.weapon.system.properties.onlymodifier) {
|
||||
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.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 = ""
|
||||
for (let effect of this.rollData.bolApplicableEffects) {
|
||||
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) {
|
||||
rollData.appliedArmorMalus = 0
|
||||
const agiEl = document.querySelector('#armor-agi-malus')
|
||||
if (rollData.attribute.key == "agility") {
|
||||
$("#armor-agi-malus").show()
|
||||
if (agiEl) agiEl.style.display = ''
|
||||
rollData.appliedArmorMalus += rollData.armorAgiMalus
|
||||
} 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") {
|
||||
$("#armor-init-malus").show()
|
||||
if (initEl) initEl.style.display = ''
|
||||
rollData.appliedArmorMalus += rollData.armorInitMalus
|
||||
} else {
|
||||
$("#armor-init-malus").hide()
|
||||
if (initEl) initEl.style.display = 'none'
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------ -------------- */
|
||||
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) {
|
||||
|
||||
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)
|
||||
this.rollData.ppCost = pp
|
||||
this.updatePPCost(this.rollData)
|
||||
})
|
||||
|
||||
html.find('#mod').change((event) => {
|
||||
html.querySelector('#mod')?.addEventListener('change', (event) => {
|
||||
this.rollData.mod = Number(event.currentTarget.value)
|
||||
this.updateTotalDice()
|
||||
})
|
||||
html.find('#modRanged').change((event) => {
|
||||
html.querySelector('#modRanged')?.addEventListener('change', (event) => {
|
||||
this.rollData.modRanged = Number(event.currentTarget.value)
|
||||
this.updateTotalDice()
|
||||
})
|
||||
|
||||
html.find('#attr').change((event) => {
|
||||
html.querySelector('#attr')?.addEventListener('change', (event) => {
|
||||
let attrKey = event.currentTarget.value
|
||||
let actor = BoLUtility.getActorFromRollData(this.rollData)
|
||||
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.updateTotalDice()
|
||||
})
|
||||
html.find('#apt').change((event) => {
|
||||
html.querySelector('#apt')?.addEventListener('change', (event) => {
|
||||
let aptKey = event.currentTarget.value
|
||||
let actor = BoLUtility.getActorFromRollData(this.rollData)
|
||||
this.rollData.aptitude = foundry.utils.duplicate(actor.system.aptitudes[aptKey])
|
||||
@@ -416,65 +418,58 @@ export class BoLRoll {
|
||||
this.updateTotalDice()
|
||||
})
|
||||
|
||||
html.find('#applyShieldMalus').click((event) => {
|
||||
if (event.currentTarget.checked) {
|
||||
this.rollData.shieldMalus = this.rollData.shieldAttackMalus
|
||||
} else {
|
||||
this.rollData.shieldMalus = 0
|
||||
}
|
||||
html.querySelector('#applyShieldMalus')?.addEventListener('click', (event) => {
|
||||
this.rollData.shieldMalus = event.currentTarget.checked ? this.rollData.shieldAttackMalus : 0
|
||||
this.updateTotalDice()
|
||||
})
|
||||
|
||||
html.find('#career').change((event) => {
|
||||
let careers = $('#career').val()
|
||||
html.querySelector('#career')?.addEventListener('change', (event) => {
|
||||
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.updateTotalDice()
|
||||
})
|
||||
html.find('#boon').change((event) => {
|
||||
let boons = $('#boon').val()
|
||||
html.querySelector('#boon')?.addEventListener('change', (event) => {
|
||||
let boons = Array.from(event.currentTarget.selectedOptions).map(o => o.value)
|
||||
this.rollData.nbBoons = (!boons || boons.length == 0) ? 0 : boons.length
|
||||
this.updateTotalDice()
|
||||
})
|
||||
html.find('#flaw').change((event) => {
|
||||
let flaws = $('#flaw').val()
|
||||
html.querySelector('#flaw')?.addEventListener('change', (event) => {
|
||||
let flaws = Array.from(event.currentTarget.selectedOptions).map(o => o.value)
|
||||
this.rollData.nbFlaws = (!flaws || flaws.length == 0) ? 0 : flaws.length
|
||||
this.updateTotalDice()
|
||||
})
|
||||
html.find('.bdice').click((event) => {
|
||||
html.querySelectorAll('.bdice').forEach(el => el.addEventListener('click', (event) => {
|
||||
this.rollData.mDice = 0
|
||||
this.rollData.bDice = Number(event.currentTarget.value)
|
||||
this.updateTotalDice()
|
||||
})
|
||||
html.find('.mdice').click((event) => {
|
||||
}))
|
||||
html.querySelectorAll('.mdice').forEach(el => el.addEventListener('click', (event) => {
|
||||
this.rollData.bDice = 0
|
||||
this.rollData.mDice = Number(event.currentTarget.value)
|
||||
this.updateTotalDice()
|
||||
})
|
||||
html.find('#horoscope-bonus-applied').change((event) => {
|
||||
}))
|
||||
html.querySelector('#horoscope-bonus-applied')?.addEventListener('change', (event) => {
|
||||
this.rollData.selectedHoroscope = []
|
||||
for (let option of event.currentTarget.selectedOptions) {
|
||||
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.updateTotalDice()
|
||||
})
|
||||
|
||||
html.find('#horoscope-malus-applied').change((event) => {
|
||||
html.querySelector('#horoscope-malus-applied')?.addEventListener('change', (event) => {
|
||||
this.rollData.selectedHoroscope = []
|
||||
for (let option of event.currentTarget.selectedOptions) {
|
||||
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.updateTotalDice()
|
||||
})
|
||||
html.find('#horoscope-group-applied').change((event) => {
|
||||
html.querySelector('#horoscope-group-applied')?.addEventListener('change', (event) => {
|
||||
this.rollData.selectedGroupHoroscopeIndex = event.currentTarget.value
|
||||
this.updateTotalDice()
|
||||
})
|
||||
|
||||
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
@@ -482,10 +477,15 @@ export class BoLRoll {
|
||||
if (rollData.mode == "weapon") {
|
||||
rollData.weaponModifier = rollData.weapon.system.properties.attackModifiers ?? 0
|
||||
rollData.attackBonusDice = rollData.weapon.system.properties.attackBonusDice
|
||||
rollData.attackMalusDice = rollData.weapon.system.properties.attackMalusDice
|
||||
if (rollData.attackBonusDice) {
|
||||
rollData.adv = "1B"
|
||||
rollData.bDice = 1
|
||||
}
|
||||
if (rollData.attackMalusDice) {
|
||||
rollData.adv = "1M"
|
||||
rollData.mDice = 1
|
||||
}
|
||||
if (defender) { // If target is selected
|
||||
rollData.defence = defender.defenseValue
|
||||
rollData.armorMalus = defender.armorMalusValue
|
||||
@@ -534,6 +534,7 @@ export class BoLRoll {
|
||||
rollData.id = foundry.utils.randomID(16)
|
||||
rollData.weaponModifier = 0
|
||||
rollData.attackBonusDice = false
|
||||
rollData.attackMalusDice = false
|
||||
rollData.armorMalus = 0
|
||||
// Specific stuff
|
||||
this.preProcessWeapon(rollData, defender)
|
||||
@@ -546,41 +547,47 @@ export class BoLRoll {
|
||||
} else {
|
||||
rollData.shieldMalus = 0
|
||||
}
|
||||
// Save
|
||||
// Save & pre-initialize computed fields
|
||||
this.rollData = rollData
|
||||
this.updateTotalDice()
|
||||
console.log("ROLLDATA", rollData)
|
||||
|
||||
// Then display+process the dialog
|
||||
const rollOptionContent = await renderTemplate(rollOptionTpl, rollData);
|
||||
let d = new Dialog({
|
||||
title: rollData.label,
|
||||
const rollOptionContent = await foundry.applications.handlebars.renderTemplate(rollOptionTpl, rollData);
|
||||
// Use Hooks to reliably get the rendered HTMLElement (renderDialogV2 receives (app, element, context))
|
||||
Hooks.once('renderDialogV2', (app, element) => {
|
||||
element.classList.add('bol');
|
||||
this.rollDialogListener(element);
|
||||
});
|
||||
return foundry.applications.api.DialogV2.wait({
|
||||
window: { title: rollData.label },
|
||||
content: rollOptionContent,
|
||||
rollData: rollData,
|
||||
render: html => this.rollDialogListener(html),
|
||||
buttons: {
|
||||
cancel: {
|
||||
icon: '<i class="fas fa-times"></i>',
|
||||
rejectClose: false,
|
||||
buttons: [
|
||||
{
|
||||
type: 'button',
|
||||
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"),
|
||||
callback: (html) => {
|
||||
icon: 'fas fa-check',
|
||||
action: 'submit',
|
||||
callback: (event, button, dialog) => {
|
||||
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 !")
|
||||
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)
|
||||
|
||||
let rollbase = rollData.attrValue + rollData.aptValue
|
||||
if (rollData.weapon?.system.properties.onlymodifier) {
|
||||
rollbase = 0
|
||||
}
|
||||
if (rollData.weapon?.system.properties.onlymodifier) rollbase = 0
|
||||
|
||||
let diceData = BoLUtility.getDiceData()
|
||||
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
|
||||
@@ -593,12 +600,8 @@ export class BoLRoll {
|
||||
r.roll();
|
||||
}
|
||||
}
|
||||
},
|
||||
default: onEnter,
|
||||
close: () => { }
|
||||
}, this.options());
|
||||
|
||||
return d.render(true);
|
||||
]
|
||||
}, { classes: ['bol', 'dialog'], width: 480 });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -634,7 +637,7 @@ export class BoLDefaultRoll {
|
||||
const diceTotal = activeDice.map(r => r.result).reduce((a, b) => a + b)
|
||||
this.rollData.roll = r
|
||||
this.rollData.isFumble = (diceTotal <= diceData.criticalFailureValue)
|
||||
if ( this.rollData.isFumble ) {
|
||||
if (this.rollData.isFumble) {
|
||||
this.rollData.isSuccess = false
|
||||
this.rollData.isCritical = false
|
||||
this.rollData.isRealCritical = false
|
||||
@@ -642,7 +645,7 @@ export class BoLDefaultRoll {
|
||||
this.rollData.isFailure = true
|
||||
} else {
|
||||
this.rollData.isCritical = (diceTotal >= diceData.criticalSuccessValue)
|
||||
if ( this.rollData.isCritical) {
|
||||
if (this.rollData.isCritical) {
|
||||
this.rollData.isSuccess = true
|
||||
} else {
|
||||
this.rollData.isSuccess = (r.total >= diceData.successValue)
|
||||
@@ -692,18 +695,15 @@ export class BoLDefaultRoll {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async sendChatMessage() {
|
||||
let actor = BoLUtility.getActorFromRollData(this.rollData)
|
||||
this._buildChatMessage(this.rollData).then(async msgFlavor => {
|
||||
//console.log("MSG", msgFlavor )
|
||||
let msg = await this.rollData.roll.toMessage({
|
||||
user: game.user.id,
|
||||
rollMode: game.settings.get("core", "rollMode"),
|
||||
const actor = BoLUtility.getActorFromRollData(this.rollData)
|
||||
const rollMode = game.settings.get("core", "rollMode")
|
||||
const msgFlavor = await this._buildChatMessage(this.rollData)
|
||||
const msg = await this.rollData.roll.toMessage({
|
||||
flavor: msgFlavor,
|
||||
speaker: ChatMessage.getSpeaker({ actor: actor }),
|
||||
})
|
||||
this.rollData.roll = foundry.utils.duplicate(this.rollData.roll) // Remove object, keep data (v111 ready)
|
||||
msg.setFlag("world", "bol-roll-data", this.rollData)
|
||||
})
|
||||
}, { rollMode })
|
||||
this.rollData.roll = foundry.utils.duplicate(this.rollData.roll)
|
||||
if (msg) await msg.setFlag("world", "bol-roll-data", this.rollData)
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
@@ -805,13 +805,13 @@ export class BoLDefaultRoll {
|
||||
/* -------------------------------------------- */
|
||||
_buildDamageChatMessage(rollData) {
|
||||
const rollMessageTpl = 'systems/bol/templates/chat/rolls/damage-roll-card.hbs';
|
||||
return renderTemplate(rollMessageTpl, rollData)
|
||||
return foundry.applications.handlebars.renderTemplate(rollMessageTpl, rollData)
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
_buildChatMessage(rollData) {
|
||||
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
|
||||
* @extends {ItemSheet}
|
||||
*/
|
||||
export class BoLItemSheet extends ItemSheet {
|
||||
export class BoLItemSheet extends foundry.appv1.sheets.ItemSheet {
|
||||
|
||||
/** @override */
|
||||
static get defaultOptions() {
|
||||
@@ -13,6 +13,7 @@ export class BoLItemSheet extends ItemSheet {
|
||||
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" }]
|
||||
});
|
||||
}
|
||||
@@ -27,7 +28,7 @@ export class BoLItemSheet extends ItemSheet {
|
||||
data.category = itemData.system.category
|
||||
data.isGM = game.user.isGM;
|
||||
data.itemProperties = this.item.itemProperties;
|
||||
data.description = await TextEditor.enrichHTML(this.object.system.description, { async: true })
|
||||
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
|
||||
}
|
||||
@@ -102,6 +103,7 @@ export class BoLItemSheet extends ItemSheet {
|
||||
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.
|
||||
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) {
|
||||
html.find('.control-icon.bol-roll').remove()
|
||||
html.find('.control-icon.bol-action').remove()
|
||||
$(html).find('.control-icon.bol-roll').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 controlIconActions = html.find('.control-icon[data-action=combat]');
|
||||
const controlIconActions = $(html).find('.control-icon[data-action=combat]');
|
||||
// initiative
|
||||
await BoLTokenHud._configureSubMenu(controlIconActions, 'systems/bol/templates/token/hud-actor-actions.hbs', hudData,
|
||||
(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
|
||||
await BoLTokenHud._configureSubMenu(controlIconTarget, 'systems/bol/templates/token/hud-actor-rolls.hbs', hudData,
|
||||
(event) => {
|
||||
@@ -59,7 +59,7 @@ export class BoLTokenHud {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
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) {
|
||||
BoLTokenHud.addExtensionHud(app, html, tokenId);
|
||||
}
|
||||
@@ -67,7 +67,7 @@ export class BoLTokenHud {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
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')
|
||||
|
||||
BoLTokenHud._toggleHudListActive(hud, list);
|
||||
|
||||
@@ -331,7 +331,7 @@ export class BoLCalendar extends Application {
|
||||
calendrierData.jourMoisOptions = RdDCalendrier.buildJoursMois();
|
||||
calendrierData.heuresOptions = [0, 1];
|
||||
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.updateData(calendrierData);
|
||||
|
||||
@@ -237,6 +237,11 @@ export class BoLUtility {
|
||||
if (chatData.img.includes("/blank.png")) {
|
||||
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
|
||||
chatData.jsondata = JSON.stringify(
|
||||
{
|
||||
@@ -244,7 +249,7 @@ export class BoLUtility {
|
||||
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);
|
||||
ChatMessage.create(chatOptions)
|
||||
});
|
||||
@@ -344,7 +349,7 @@ export class BoLUtility {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async chatMessageHandler(message, html, data) {
|
||||
const chatCard = html.find('.flavor-text')
|
||||
const chatCard = $(html).find('.flavor-text')
|
||||
if (chatCard.length > 0) {
|
||||
// If the user is the message author or the actor owner, proceed
|
||||
const actor = game.actors.get(data.message.speaker.actor)
|
||||
@@ -381,6 +386,8 @@ export class BoLUtility {
|
||||
/* -------------------------------------------- */
|
||||
static async chatListeners(html) {
|
||||
|
||||
html = $(html);
|
||||
|
||||
// Damage handling
|
||||
html.on("click", '.chat-damage-apply', event => {
|
||||
let rollData = BoLUtility.getRollDataFromMessage(event)
|
||||
@@ -427,7 +434,7 @@ export class BoLUtility {
|
||||
html.on("click", '.damage-handling', event => {
|
||||
event.preventDefault()
|
||||
let attr = event.currentTarget.attributes['data-attack-id']
|
||||
if ( !attr) {
|
||||
if (!attr) {
|
||||
ui.notifications.warn("Impossible de trouver l'attaque correspondante, erreur de suivi de combat.")
|
||||
return
|
||||
}
|
||||
@@ -480,13 +487,17 @@ export class BoLUtility {
|
||||
|
||||
if (defenseMode == 'damage-with-armor') {
|
||||
let armorFormula = defender.getArmorFormula()
|
||||
if (armorFormula === "0") {
|
||||
rollData.armorProtect = 0
|
||||
} else {
|
||||
rollData.rollArmor = new Roll(armorFormula)
|
||||
await rollData.rollArmor.roll()
|
||||
let msg = await rollData.rollArmor.toMessage({ flavor: "BOL.chat.armorRoll : " + armorFormula });
|
||||
if ( game.dice3d) { // wait animation end when DsN is there
|
||||
await game.dice3d.waitFor3DAnimationByMessageID(msg.id);
|
||||
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.finalDamage = rollData.damageTotal - rollData.armorProtect
|
||||
rollData.finalDamage = (rollData.finalDamage < 0) ? 0 : rollData.finalDamage
|
||||
await defender.sufferDamage(rollData.finalDamage)
|
||||
@@ -498,9 +509,17 @@ export class BoLUtility {
|
||||
}
|
||||
if (defenseMode == 'hero-reduce-damage') {
|
||||
let armorFormula = defender.getArmorFormula()
|
||||
if (armorFormula === "0") {
|
||||
rollData.armorProtect = 0
|
||||
} else {
|
||||
rollData.rollArmor = new Roll(armorFormula)
|
||||
await rollData.rollArmor.roll()
|
||||
let msg = await rollData.rollArmor.toMessage({ flavor: game.i18n.localize("BOL.chat.armorRoll") + " : " + armorFormula })
|
||||
if (game.dice3d && msg) {
|
||||
await game.dice3d.waitFor3DAnimationByMessageID(msg.id)
|
||||
}
|
||||
rollData.armorProtect = (rollData.rollArmor.total < 0) ? 0 : rollData.rollArmor.total
|
||||
}
|
||||
rollData.rollHero = new Roll("1d6")
|
||||
await rollData.rollHero.roll()
|
||||
rollData.finalDamage = rollData.damageTotal - rollData.rollHero.total - rollData.armorProtect
|
||||
@@ -535,13 +554,13 @@ export class BoLUtility {
|
||||
ChatMessage.create({
|
||||
alias: defender.name,
|
||||
whisper: BoLUtility.getWhisperRecipientsAndGMs(defender.name),
|
||||
content: await renderTemplate('systems/bol/templates/chat/rolls/defense-result-card.hbs', damageResults)
|
||||
content: await foundry.applications.handlebars.foundry.applications.handlebars.renderTemplate('systems/bol/templates/chat/rolls/defense-result-card.hbs', damageResults)
|
||||
})
|
||||
console.log("Defender data : ", defenderUser)
|
||||
ChatMessage.create({
|
||||
alias: defender.name,
|
||||
whisper: BoLUtility.getOtherWhisperRecipients(defenderUser?.name),
|
||||
content: await renderTemplate('systems/bol/templates/chat/rolls/defense-summary-card.hbs', damageResults)
|
||||
content: await foundry.applications.handlebars.foundry.applications.handlebars.renderTemplate('systems/bol/templates/chat/rolls/defense-summary-card.hbs', damageResults)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -628,11 +647,11 @@ export class BoLUtility {
|
||||
let msg = await ChatMessage.create({
|
||||
alias: defender.name,
|
||||
whisper: BoLUtility.getWhisperRecipientsAndGMs(defender.name),
|
||||
content: await renderTemplate('systems/bol/templates/chat/rolls/defense-request-card.hbs', {
|
||||
content: await foundry.applications.handlebars.foundry.applications.handlebars.renderTemplate('systems/bol/templates/chat/rolls/defense-request-card.hbs', {
|
||||
attackId: rollData.id,
|
||||
attacker: rollData.attacker,
|
||||
defender: defender,
|
||||
defenderHeroPoints:defender.getHeroPoints(),
|
||||
defenderHeroPoints: defender.getHeroPoints(),
|
||||
defenderWeapons: defenderWeapons,
|
||||
damageTotal: rollData.damageTotal,
|
||||
damagesIgnoresArmor: rollData.damagesIgnoresArmor,
|
||||
|
||||
@@ -188,19 +188,25 @@ BOL.rangeModifiers = {
|
||||
"-8": "BOL.dialog.utmost"
|
||||
}
|
||||
|
||||
BOL.difficultyModifiers = {
|
||||
"4": "BOL.dialog.soeasy",
|
||||
"2": "BOL.dialog.veryeasy",
|
||||
"1": "BOL.dialog.easy",
|
||||
"0": "BOL.dialog.moderate",
|
||||
"-1": "BOL.dialog.hard",
|
||||
"-2": "BOL.dialog.tough",
|
||||
"-4": "BOL.dialog.demanding",
|
||||
"-6": "BOL.dialog.formidable",
|
||||
"-8": "BOL.dialog.heroic",
|
||||
"-10": "BOL.dialog.mythic",
|
||||
"-12": "BOL.dialog.divine"
|
||||
}
|
||||
BOL.difficultyModifiers = [
|
||||
{ value: "-12", label: "BOL.dialog.divine" },
|
||||
{ value: "-11", label: "BOL.dialog.mythic11" },
|
||||
{ value: "-10", label: "BOL.dialog.mythic" },
|
||||
{ value: "-9", label: "BOL.dialog.heroic9" },
|
||||
{ value: "-8", label: "BOL.dialog.heroic" },
|
||||
{ value: "-7", label: "BOL.dialog.formidable7" },
|
||||
{ value: "-6", label: "BOL.dialog.formidable" },
|
||||
{ value: "-5", label: "BOL.dialog.demanding5" },
|
||||
{ value: "-4", label: "BOL.dialog.demanding" },
|
||||
{ value: "-3", label: "BOL.dialog.tough3" },
|
||||
{ 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 = {
|
||||
"2": "BOL.dialog.veryeasy",
|
||||
|
||||
@@ -15,7 +15,7 @@ export default function registerHooks() {
|
||||
}))
|
||||
|
||||
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
|
||||
@@ -73,7 +73,7 @@ export default function registerHooks() {
|
||||
button.addEventListener('click', () => {
|
||||
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/selected-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/attribute-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/total-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
|
||||
return loadTemplates(templatePaths);
|
||||
return foundry.applications.handlebars.loadTemplates(templatePaths);
|
||||
};
|
||||
|
||||
Binary file not shown.
@@ -1 +1 @@
|
||||
MANIFEST-000766
|
||||
MANIFEST-001076
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
2025/03/31-07:10:17.059640 7f9cf5ffb6c0 Recovering log #764
|
||||
2025/03/31-07:10:17.113093 7f9cf5ffb6c0 Delete type=3 #762
|
||||
2025/03/31-07:10:17.113203 7f9cf5ffb6c0 Delete type=0 #764
|
||||
2025/03/31-07:15:11.784077 7f9cf4ff96c0 Level-0 table #769: started
|
||||
2025/03/31-07:15:11.784139 7f9cf4ff96c0 Level-0 table #769: 0 bytes OK
|
||||
2025/03/31-07:15:11.820358 7f9cf4ff96c0 Delete type=0 #767
|
||||
2025/03/31-07:15:11.863418 7f9cf4ff96c0 Manual compaction at level-0 from '!journal!3xJg1rCxnWvEmoxS' @ 72057594037927935 : 1 .. '!journal.pages!veAAxCtCKcFIsnln.0kUgZspxXO7VS8bd' @ 0 : 0; will stop at (end)
|
||||
2025/03/31-07:15:11.863502 7f9cf4ff96c0 Manual compaction at level-1 from '!journal!3xJg1rCxnWvEmoxS' @ 72057594037927935 : 1 .. '!journal.pages!veAAxCtCKcFIsnln.0kUgZspxXO7VS8bd' @ 0 : 0; will stop at (end)
|
||||
2026/02/28-22:59:53.852685 7f56e3fff6c0 Recovering log #1074
|
||||
2026/02/28-22:59:53.863099 7f56e3fff6c0 Delete type=3 #1072
|
||||
2026/02/28-22:59:53.863210 7f56e3fff6c0 Delete type=0 #1074
|
||||
2026/03/01-01:08:46.366409 7f54e37ef6c0 Level-0 table #1079: started
|
||||
2026/03/01-01:08:46.366440 7f54e37ef6c0 Level-0 table #1079: 0 bytes OK
|
||||
2026/03/01-01:08:46.372420 7f54e37ef6c0 Delete type=0 #1077
|
||||
2026/03/01-01:08:46.391669 7f54e37ef6c0 Manual compaction at level-0 from '!journal!3xJg1rCxnWvEmoxS' @ 72057594037927935 : 1 .. '!journal.pages!veAAxCtCKcFIsnln.0kUgZspxXO7VS8bd' @ 0 : 0; will stop at (end)
|
||||
2026/03/01-01:08:46.391720 7f54e37ef6c0 Manual compaction at level-1 from '!journal!3xJg1rCxnWvEmoxS' @ 72057594037927935 : 1 .. '!journal.pages!veAAxCtCKcFIsnln.0kUgZspxXO7VS8bd' @ 0 : 0; will stop at (end)
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
2025/03/31-07:01:18.138827 7f9cf67fc6c0 Recovering log #759
|
||||
2025/03/31-07:01:18.151000 7f9cf67fc6c0 Delete type=3 #757
|
||||
2025/03/31-07:01:18.151096 7f9cf67fc6c0 Delete type=0 #759
|
||||
2025/03/31-07:05:47.761503 7f9cf4ff96c0 Level-0 table #765: started
|
||||
2025/03/31-07:05:47.761554 7f9cf4ff96c0 Level-0 table #765: 0 bytes OK
|
||||
2025/03/31-07:05:47.767897 7f9cf4ff96c0 Delete type=0 #763
|
||||
2025/03/31-07:05:47.768254 7f9cf4ff96c0 Manual compaction at level-0 from '!journal!3xJg1rCxnWvEmoxS' @ 72057594037927935 : 1 .. '!journal.pages!veAAxCtCKcFIsnln.0kUgZspxXO7VS8bd' @ 0 : 0; will stop at (end)
|
||||
2025/03/31-07:05:47.768322 7f9cf4ff96c0 Manual compaction at level-1 from '!journal!3xJg1rCxnWvEmoxS' @ 72057594037927935 : 1 .. '!journal.pages!veAAxCtCKcFIsnln.0kUgZspxXO7VS8bd' @ 0 : 0; will stop at (end)
|
||||
2026/02/28-17:23:52.883622 7f56f93fe6c0 Recovering log #1070
|
||||
2026/02/28-17:23:52.893895 7f56f93fe6c0 Delete type=3 #1068
|
||||
2026/02/28-17:23:52.893967 7f56f93fe6c0 Delete type=0 #1070
|
||||
2026/02/28-22:59:43.750682 7f54e37ef6c0 Level-0 table #1075: started
|
||||
2026/02/28-22:59:43.750749 7f54e37ef6c0 Level-0 table #1075: 0 bytes OK
|
||||
2026/02/28-22:59:43.758241 7f54e37ef6c0 Delete type=0 #1073
|
||||
2026/02/28-22:59:43.758440 7f54e37ef6c0 Manual compaction at level-0 from '!journal!3xJg1rCxnWvEmoxS' @ 72057594037927935 : 1 .. '!journal.pages!veAAxCtCKcFIsnln.0kUgZspxXO7VS8bd' @ 0 : 0; will stop at (end)
|
||||
2026/02/28-22:59:43.758473 7f54e37ef6c0 Manual compaction at level-1 from '!journal!3xJg1rCxnWvEmoxS' @ 72057594037927935 : 1 .. '!journal.pages!veAAxCtCKcFIsnln.0kUgZspxXO7VS8bd' @ 0 : 0; will stop at (end)
|
||||
|
||||
Binary file not shown.
BIN
packs/aides-de-jeu/MANIFEST-001076
Normal file
BIN
packs/aides-de-jeu/MANIFEST-001076
Normal file
Binary file not shown.
Binary file not shown.
@@ -1 +1 @@
|
||||
MANIFEST-000671
|
||||
MANIFEST-000981
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
2025/03/31-07:10:16.947165 7f9cf67fc6c0 Recovering log #669
|
||||
2025/03/31-07:10:17.010788 7f9cf67fc6c0 Delete type=3 #667
|
||||
2025/03/31-07:10:17.010920 7f9cf67fc6c0 Delete type=0 #669
|
||||
2025/03/31-07:15:11.712245 7f9cf4ff96c0 Level-0 table #674: started
|
||||
2025/03/31-07:15:11.712293 7f9cf4ff96c0 Level-0 table #674: 0 bytes OK
|
||||
2025/03/31-07:15:11.745296 7f9cf4ff96c0 Delete type=0 #672
|
||||
2025/03/31-07:15:11.863357 7f9cf4ff96c0 Manual compaction at level-0 from '!items!G3dZTHIabA3LA1hY' @ 72057594037927935 : 1 .. '!items!xhEcsi3WHjbt2ro9' @ 0 : 0; will stop at (end)
|
||||
2025/03/31-07:15:11.863483 7f9cf4ff96c0 Manual compaction at level-1 from '!items!G3dZTHIabA3LA1hY' @ 72057594037927935 : 1 .. '!items!xhEcsi3WHjbt2ro9' @ 0 : 0; will stop at (end)
|
||||
2026/02/28-22:59:53.826224 7f56f8bfd6c0 Recovering log #979
|
||||
2026/02/28-22:59:53.836758 7f56f8bfd6c0 Delete type=3 #977
|
||||
2026/02/28-22:59:53.836823 7f56f8bfd6c0 Delete type=0 #979
|
||||
2026/03/01-01:08:46.372471 7f54e37ef6c0 Level-0 table #984: started
|
||||
2026/03/01-01:08:46.372486 7f54e37ef6c0 Level-0 table #984: 0 bytes OK
|
||||
2026/03/01-01:08:46.378495 7f54e37ef6c0 Delete type=0 #982
|
||||
2026/03/01-01:08:46.391687 7f54e37ef6c0 Manual compaction at level-0 from '!items!G3dZTHIabA3LA1hY' @ 72057594037927935 : 1 .. '!items!xhEcsi3WHjbt2ro9' @ 0 : 0; will stop at (end)
|
||||
2026/03/01-01:08:46.391731 7f54e37ef6c0 Manual compaction at level-1 from '!items!G3dZTHIabA3LA1hY' @ 72057594037927935 : 1 .. '!items!xhEcsi3WHjbt2ro9' @ 0 : 0; will stop at (end)
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
2025/03/31-07:01:18.108119 7f9cf57fa6c0 Recovering log #664
|
||||
2025/03/31-07:01:18.118686 7f9cf57fa6c0 Delete type=3 #662
|
||||
2025/03/31-07:01:18.118791 7f9cf57fa6c0 Delete type=0 #664
|
||||
2025/03/31-07:05:47.740195 7f9cf4ff96c0 Level-0 table #670: started
|
||||
2025/03/31-07:05:47.740253 7f9cf4ff96c0 Level-0 table #670: 0 bytes OK
|
||||
2025/03/31-07:05:47.746679 7f9cf4ff96c0 Delete type=0 #668
|
||||
2025/03/31-07:05:47.768165 7f9cf4ff96c0 Manual compaction at level-0 from '!items!G3dZTHIabA3LA1hY' @ 72057594037927935 : 1 .. '!items!xhEcsi3WHjbt2ro9' @ 0 : 0; will stop at (end)
|
||||
2025/03/31-07:05:47.768278 7f9cf4ff96c0 Manual compaction at level-1 from '!items!G3dZTHIabA3LA1hY' @ 72057594037927935 : 1 .. '!items!xhEcsi3WHjbt2ro9' @ 0 : 0; will stop at (end)
|
||||
2026/02/28-17:23:52.858522 7f56e3fff6c0 Recovering log #975
|
||||
2026/02/28-17:23:52.869495 7f56e3fff6c0 Delete type=3 #973
|
||||
2026/02/28-17:23:52.869552 7f56e3fff6c0 Delete type=0 #975
|
||||
2026/02/28-22:59:43.737596 7f54e37ef6c0 Level-0 table #980: started
|
||||
2026/02/28-22:59:43.737635 7f54e37ef6c0 Level-0 table #980: 0 bytes OK
|
||||
2026/02/28-22:59:43.743801 7f54e37ef6c0 Delete type=0 #978
|
||||
2026/02/28-22:59:43.758414 7f54e37ef6c0 Manual compaction at level-0 from '!items!G3dZTHIabA3LA1hY' @ 72057594037927935 : 1 .. '!items!xhEcsi3WHjbt2ro9' @ 0 : 0; will stop at (end)
|
||||
2026/02/28-22:59:43.758457 7f54e37ef6c0 Manual compaction at level-1 from '!items!G3dZTHIabA3LA1hY' @ 72057594037927935 : 1 .. '!items!xhEcsi3WHjbt2ro9' @ 0 : 0; will stop at (end)
|
||||
|
||||
Binary file not shown.
BIN
packs/armors/MANIFEST-000981
Normal file
BIN
packs/armors/MANIFEST-000981
Normal file
Binary file not shown.
Binary file not shown.
BIN
packs/boons/000843.ldb
Normal file
BIN
packs/boons/000843.ldb
Normal file
Binary file not shown.
@@ -1 +1 @@
|
||||
MANIFEST-000764
|
||||
MANIFEST-001075
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
2025/03/31-07:10:16.407604 7f9cf67fc6c0 Recovering log #762
|
||||
2025/03/31-07:10:16.479813 7f9cf67fc6c0 Delete type=3 #760
|
||||
2025/03/31-07:10:16.479936 7f9cf67fc6c0 Delete type=0 #762
|
||||
2025/03/31-07:15:11.462830 7f9cf4ff96c0 Level-0 table #767: started
|
||||
2025/03/31-07:15:11.462886 7f9cf4ff96c0 Level-0 table #767: 0 bytes OK
|
||||
2025/03/31-07:15:11.500813 7f9cf4ff96c0 Delete type=0 #765
|
||||
2025/03/31-07:15:11.563807 7f9cf4ff96c0 Manual compaction at level-0 from '!items!039ZF3E3MtAGwbiX' @ 72057594037927935 : 1 .. '!items!zgspy1QKaxdEetEw' @ 0 : 0; will stop at (end)
|
||||
2025/03/31-07:15:11.563949 7f9cf4ff96c0 Manual compaction at level-1 from '!items!039ZF3E3MtAGwbiX' @ 72057594037927935 : 1 .. '!items!zgspy1QKaxdEetEw' @ 0 : 0; will stop at (end)
|
||||
2026/02/28-22:59:53.718001 7f56f8bfd6c0 Recovering log #1073
|
||||
2026/02/28-22:59:53.729345 7f56f8bfd6c0 Delete type=3 #1071
|
||||
2026/02/28-22:59:53.729412 7f56f8bfd6c0 Delete type=0 #1073
|
||||
2026/03/01-01:08:46.321084 7f54e37ef6c0 Level-0 table #1078: started
|
||||
2026/03/01-01:08:46.321111 7f54e37ef6c0 Level-0 table #1078: 0 bytes OK
|
||||
2026/03/01-01:08:46.327221 7f54e37ef6c0 Delete type=0 #1076
|
||||
2026/03/01-01:08:46.339937 7f54e37ef6c0 Manual compaction at level-0 from '!items!039ZF3E3MtAGwbiX' @ 72057594037927935 : 1 .. '!items!zgspy1QKaxdEetEw' @ 0 : 0; will stop at (end)
|
||||
2026/03/01-01:08:46.339972 7f54e37ef6c0 Manual compaction at level-1 from '!items!039ZF3E3MtAGwbiX' @ 72057594037927935 : 1 .. '!items!zgspy1QKaxdEetEw' @ 0 : 0; will stop at (end)
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
2025/03/31-07:01:17.972300 7f9cf57fa6c0 Recovering log #757
|
||||
2025/03/31-07:01:17.983482 7f9cf57fa6c0 Delete type=3 #755
|
||||
2025/03/31-07:01:17.983631 7f9cf57fa6c0 Delete type=0 #757
|
||||
2025/03/31-07:05:47.692525 7f9cf4ff96c0 Level-0 table #763: started
|
||||
2025/03/31-07:05:47.692582 7f9cf4ff96c0 Level-0 table #763: 0 bytes OK
|
||||
2025/03/31-07:05:47.698782 7f9cf4ff96c0 Delete type=0 #761
|
||||
2025/03/31-07:05:47.712293 7f9cf4ff96c0 Manual compaction at level-0 from '!items!039ZF3E3MtAGwbiX' @ 72057594037927935 : 1 .. '!items!zgspy1QKaxdEetEw' @ 0 : 0; will stop at (end)
|
||||
2025/03/31-07:05:47.712359 7f9cf4ff96c0 Manual compaction at level-1 from '!items!039ZF3E3MtAGwbiX' @ 72057594037927935 : 1 .. '!items!zgspy1QKaxdEetEw' @ 0 : 0; will stop at (end)
|
||||
2026/02/28-17:23:52.757933 7f56f9bff6c0 Recovering log #1069
|
||||
2026/02/28-17:23:52.767692 7f56f9bff6c0 Delete type=3 #1067
|
||||
2026/02/28-17:23:52.767761 7f56f9bff6c0 Delete type=0 #1069
|
||||
2026/02/28-22:59:43.697108 7f54e37ef6c0 Level-0 table #1074: started
|
||||
2026/02/28-22:59:43.697152 7f54e37ef6c0 Level-0 table #1074: 0 bytes OK
|
||||
2026/02/28-22:59:43.704224 7f54e37ef6c0 Delete type=0 #1072
|
||||
2026/02/28-22:59:43.704461 7f54e37ef6c0 Manual compaction at level-0 from '!items!039ZF3E3MtAGwbiX' @ 72057594037927935 : 1 .. '!items!zgspy1QKaxdEetEw' @ 0 : 0; will stop at (end)
|
||||
2026/02/28-22:59:43.704511 7f54e37ef6c0 Manual compaction at level-1 from '!items!039ZF3E3MtAGwbiX' @ 72057594037927935 : 1 .. '!items!zgspy1QKaxdEetEw' @ 0 : 0; will stop at (end)
|
||||
|
||||
Binary file not shown.
BIN
packs/boons/MANIFEST-001075
Normal file
BIN
packs/boons/MANIFEST-001075
Normal file
Binary file not shown.
Binary file not shown.
@@ -1 +1 @@
|
||||
MANIFEST-000764
|
||||
MANIFEST-001074
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
2025/03/31-07:10:16.483153 7f9cf6ffd6c0 Recovering log #762
|
||||
2025/03/31-07:10:16.551518 7f9cf6ffd6c0 Delete type=3 #760
|
||||
2025/03/31-07:10:16.551693 7f9cf6ffd6c0 Delete type=0 #762
|
||||
2025/03/31-07:15:11.534471 7f9cf4ff96c0 Level-0 table #767: started
|
||||
2025/03/31-07:15:11.534518 7f9cf4ff96c0 Level-0 table #767: 0 bytes OK
|
||||
2025/03/31-07:15:11.563419 7f9cf4ff96c0 Delete type=0 #765
|
||||
2025/03/31-07:15:11.563892 7f9cf4ff96c0 Manual compaction at level-0 from '!items!CoqlfsDV1gL5swbK' @ 72057594037927935 : 1 .. '!items!yofwG0YrsL902G77' @ 0 : 0; will stop at (end)
|
||||
2025/03/31-07:15:11.564007 7f9cf4ff96c0 Manual compaction at level-1 from '!items!CoqlfsDV1gL5swbK' @ 72057594037927935 : 1 .. '!items!yofwG0YrsL902G77' @ 0 : 0; will stop at (end)
|
||||
2026/02/28-22:59:53.732583 7f56e3fff6c0 Recovering log #1072
|
||||
2026/02/28-22:59:53.742972 7f56e3fff6c0 Delete type=3 #1070
|
||||
2026/02/28-22:59:53.743061 7f56e3fff6c0 Delete type=0 #1072
|
||||
2026/03/01-01:08:46.313828 7f54e37ef6c0 Level-0 table #1077: started
|
||||
2026/03/01-01:08:46.313877 7f54e37ef6c0 Level-0 table #1077: 0 bytes OK
|
||||
2026/03/01-01:08:46.320973 7f54e37ef6c0 Delete type=0 #1075
|
||||
2026/03/01-01:08:46.339925 7f54e37ef6c0 Manual compaction at level-0 from '!items!CoqlfsDV1gL5swbK' @ 72057594037927935 : 1 .. '!items!yofwG0YrsL902G77' @ 0 : 0; will stop at (end)
|
||||
2026/03/01-01:08:46.339953 7f54e37ef6c0 Manual compaction at level-1 from '!items!CoqlfsDV1gL5swbK' @ 72057594037927935 : 1 .. '!items!yofwG0YrsL902G77' @ 0 : 0; will stop at (end)
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
2025/03/31-07:01:17.988979 7f9cf5ffb6c0 Recovering log #757
|
||||
2025/03/31-07:01:18.000788 7f9cf5ffb6c0 Delete type=3 #755
|
||||
2025/03/31-07:01:18.000890 7f9cf5ffb6c0 Delete type=0 #757
|
||||
2025/03/31-07:05:47.684708 7f9cf4ff96c0 Level-0 table #763: started
|
||||
2025/03/31-07:05:47.684770 7f9cf4ff96c0 Level-0 table #763: 0 bytes OK
|
||||
2025/03/31-07:05:47.692347 7f9cf4ff96c0 Delete type=0 #761
|
||||
2025/03/31-07:05:47.712274 7f9cf4ff96c0 Manual compaction at level-0 from '!items!CoqlfsDV1gL5swbK' @ 72057594037927935 : 1 .. '!items!yofwG0YrsL902G77' @ 0 : 0; will stop at (end)
|
||||
2025/03/31-07:05:47.712328 7f9cf4ff96c0 Manual compaction at level-1 from '!items!CoqlfsDV1gL5swbK' @ 72057594037927935 : 1 .. '!items!yofwG0YrsL902G77' @ 0 : 0; will stop at (end)
|
||||
2026/02/28-17:23:52.769847 7f56f93fe6c0 Recovering log #1068
|
||||
2026/02/28-17:23:52.780583 7f56f93fe6c0 Delete type=3 #1066
|
||||
2026/02/28-17:23:52.780639 7f56f93fe6c0 Delete type=0 #1068
|
||||
2026/02/28-22:59:43.677524 7f54e37ef6c0 Level-0 table #1073: started
|
||||
2026/02/28-22:59:43.677620 7f54e37ef6c0 Level-0 table #1073: 0 bytes OK
|
||||
2026/02/28-22:59:43.684329 7f54e37ef6c0 Delete type=0 #1071
|
||||
2026/02/28-22:59:43.704401 7f54e37ef6c0 Manual compaction at level-0 from '!items!CoqlfsDV1gL5swbK' @ 72057594037927935 : 1 .. '!items!yofwG0YrsL902G77' @ 0 : 0; will stop at (end)
|
||||
2026/02/28-22:59:43.704474 7f54e37ef6c0 Manual compaction at level-1 from '!items!CoqlfsDV1gL5swbK' @ 72057594037927935 : 1 .. '!items!yofwG0YrsL902G77' @ 0 : 0; will stop at (end)
|
||||
|
||||
Binary file not shown.
BIN
packs/boonsflawscreatures/MANIFEST-001074
Normal file
BIN
packs/boonsflawscreatures/MANIFEST-001074
Normal file
Binary file not shown.
Binary file not shown.
@@ -1 +1 @@
|
||||
MANIFEST-000764
|
||||
MANIFEST-001074
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
2025/03/31-07:10:16.627946 7f9cf57fa6c0 Recovering log #762
|
||||
2025/03/31-07:10:16.690160 7f9cf57fa6c0 Delete type=3 #760
|
||||
2025/03/31-07:10:16.690297 7f9cf57fa6c0 Delete type=0 #762
|
||||
2025/03/31-07:15:11.501071 7f9cf4ff96c0 Level-0 table #767: started
|
||||
2025/03/31-07:15:11.501145 7f9cf4ff96c0 Level-0 table #767: 0 bytes OK
|
||||
2025/03/31-07:15:11.534293 7f9cf4ff96c0 Delete type=0 #765
|
||||
2025/03/31-07:15:11.563855 7f9cf4ff96c0 Manual compaction at level-0 from '!items!4S4xAfMXGnuU0O1a' @ 72057594037927935 : 1 .. '!items!zxY3sW0iCJBvwjOS' @ 0 : 0; will stop at (end)
|
||||
2025/03/31-07:15:11.563976 7f9cf4ff96c0 Manual compaction at level-1 from '!items!4S4xAfMXGnuU0O1a' @ 72057594037927935 : 1 .. '!items!zxY3sW0iCJBvwjOS' @ 0 : 0; will stop at (end)
|
||||
2026/02/28-22:59:53.759689 7f56f8bfd6c0 Recovering log #1072
|
||||
2026/02/28-22:59:53.770229 7f56f8bfd6c0 Delete type=3 #1070
|
||||
2026/02/28-22:59:53.770305 7f56f8bfd6c0 Delete type=0 #1072
|
||||
2026/03/01-01:08:46.327327 7f54e37ef6c0 Level-0 table #1077: started
|
||||
2026/03/01-01:08:46.327354 7f54e37ef6c0 Level-0 table #1077: 0 bytes OK
|
||||
2026/03/01-01:08:46.333262 7f54e37ef6c0 Delete type=0 #1075
|
||||
2026/03/01-01:08:46.339946 7f54e37ef6c0 Manual compaction at level-0 from '!items!4S4xAfMXGnuU0O1a' @ 72057594037927935 : 1 .. '!items!zxY3sW0iCJBvwjOS' @ 0 : 0; will stop at (end)
|
||||
2026/03/01-01:08:46.339979 7f54e37ef6c0 Manual compaction at level-1 from '!items!4S4xAfMXGnuU0O1a' @ 72057594037927935 : 1 .. '!items!zxY3sW0iCJBvwjOS' @ 0 : 0; will stop at (end)
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
2025/03/31-07:01:18.022229 7f9cf6ffd6c0 Recovering log #757
|
||||
2025/03/31-07:01:18.032764 7f9cf6ffd6c0 Delete type=3 #755
|
||||
2025/03/31-07:01:18.032860 7f9cf6ffd6c0 Delete type=0 #757
|
||||
2025/03/31-07:05:47.699022 7f9cf4ff96c0 Level-0 table #763: started
|
||||
2025/03/31-07:05:47.699076 7f9cf4ff96c0 Level-0 table #763: 0 bytes OK
|
||||
2025/03/31-07:05:47.705257 7f9cf4ff96c0 Delete type=0 #761
|
||||
2025/03/31-07:05:47.712313 7f9cf4ff96c0 Manual compaction at level-0 from '!items!4S4xAfMXGnuU0O1a' @ 72057594037927935 : 1 .. '!items!zxY3sW0iCJBvwjOS' @ 0 : 0; will stop at (end)
|
||||
2025/03/31-07:05:47.712370 7f9cf4ff96c0 Manual compaction at level-1 from '!items!4S4xAfMXGnuU0O1a' @ 72057594037927935 : 1 .. '!items!zxY3sW0iCJBvwjOS' @ 0 : 0; will stop at (end)
|
||||
2026/02/28-17:23:52.796426 7f56f9bff6c0 Recovering log #1068
|
||||
2026/02/28-17:23:52.805920 7f56f9bff6c0 Delete type=3 #1066
|
||||
2026/02/28-17:23:52.805973 7f56f9bff6c0 Delete type=0 #1068
|
||||
2026/02/28-22:59:43.711333 7f54e37ef6c0 Level-0 table #1073: started
|
||||
2026/02/28-22:59:43.711370 7f54e37ef6c0 Level-0 table #1073: 0 bytes OK
|
||||
2026/02/28-22:59:43.717336 7f54e37ef6c0 Delete type=0 #1071
|
||||
2026/02/28-22:59:43.731041 7f54e37ef6c0 Manual compaction at level-0 from '!items!4S4xAfMXGnuU0O1a' @ 72057594037927935 : 1 .. '!items!zxY3sW0iCJBvwjOS' @ 0 : 0; will stop at (end)
|
||||
2026/02/28-22:59:43.731086 7f54e37ef6c0 Manual compaction at level-1 from '!items!4S4xAfMXGnuU0O1a' @ 72057594037927935 : 1 .. '!items!zxY3sW0iCJBvwjOS' @ 0 : 0; will stop at (end)
|
||||
|
||||
Binary file not shown.
BIN
packs/careers/MANIFEST-001074
Normal file
BIN
packs/careers/MANIFEST-001074
Normal file
Binary file not shown.
Binary file not shown.
@@ -1 +1 @@
|
||||
MANIFEST-000762
|
||||
MANIFEST-001072
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
2025/03/31-07:10:17.506385 7f9cf6ffd6c0 Recovering log #760
|
||||
2025/03/31-07:10:17.575234 7f9cf6ffd6c0 Delete type=3 #758
|
||||
2025/03/31-07:10:17.575341 7f9cf6ffd6c0 Delete type=0 #760
|
||||
2025/03/31-07:15:12.157098 7f9cf4ff96c0 Level-0 table #765: started
|
||||
2025/03/31-07:15:12.157181 7f9cf4ff96c0 Level-0 table #765: 0 bytes OK
|
||||
2025/03/31-07:15:12.193443 7f9cf4ff96c0 Delete type=0 #763
|
||||
2025/03/31-07:15:12.193715 7f9cf4ff96c0 Manual compaction at level-0 from '!items!6fTZ6hOKR4pWbWOe' @ 72057594037927935 : 1 .. '!items!zwSNMO9HpiqUCMt8' @ 0 : 0; will stop at (end)
|
||||
2025/03/31-07:15:12.241607 7f9cf4ff96c0 Manual compaction at level-1 from '!items!6fTZ6hOKR4pWbWOe' @ 72057594037927935 : 1 .. '!items!zwSNMO9HpiqUCMt8' @ 0 : 0; will stop at (end)
|
||||
2026/02/28-22:59:53.948768 7f56f93fe6c0 Recovering log #1070
|
||||
2026/02/28-22:59:53.958702 7f56f93fe6c0 Delete type=3 #1068
|
||||
2026/02/28-22:59:53.958781 7f56f93fe6c0 Delete type=0 #1070
|
||||
2026/03/01-01:08:46.425514 7f54e37ef6c0 Level-0 table #1075: started
|
||||
2026/03/01-01:08:46.425561 7f54e37ef6c0 Level-0 table #1075: 0 bytes OK
|
||||
2026/03/01-01:08:46.431671 7f54e37ef6c0 Delete type=0 #1073
|
||||
2026/03/01-01:08:46.445290 7f54e37ef6c0 Manual compaction at level-0 from '!items!6fTZ6hOKR4pWbWOe' @ 72057594037927935 : 1 .. '!items!zwSNMO9HpiqUCMt8' @ 0 : 0; will stop at (end)
|
||||
2026/03/01-01:08:46.445328 7f54e37ef6c0 Manual compaction at level-1 from '!items!6fTZ6hOKR4pWbWOe' @ 72057594037927935 : 1 .. '!items!zwSNMO9HpiqUCMt8' @ 0 : 0; will stop at (end)
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
2025/03/31-07:01:18.249810 7f9cf5ffb6c0 Recovering log #755
|
||||
2025/03/31-07:01:18.261010 7f9cf5ffb6c0 Delete type=3 #753
|
||||
2025/03/31-07:01:18.261104 7f9cf5ffb6c0 Delete type=0 #755
|
||||
2025/03/31-07:05:47.811953 7f9cf4ff96c0 Level-0 table #761: started
|
||||
2025/03/31-07:05:47.811991 7f9cf4ff96c0 Level-0 table #761: 0 bytes OK
|
||||
2025/03/31-07:05:47.818468 7f9cf4ff96c0 Delete type=0 #759
|
||||
2025/03/31-07:05:47.826264 7f9cf4ff96c0 Manual compaction at level-0 from '!items!6fTZ6hOKR4pWbWOe' @ 72057594037927935 : 1 .. '!items!zwSNMO9HpiqUCMt8' @ 0 : 0; will stop at (end)
|
||||
2025/03/31-07:05:47.826363 7f9cf4ff96c0 Manual compaction at level-1 from '!items!6fTZ6hOKR4pWbWOe' @ 72057594037927935 : 1 .. '!items!zwSNMO9HpiqUCMt8' @ 0 : 0; will stop at (end)
|
||||
2026/02/28-17:23:52.970603 7f56f9bff6c0 Recovering log #1066
|
||||
2026/02/28-17:23:52.981835 7f56f9bff6c0 Delete type=3 #1064
|
||||
2026/02/28-17:23:52.981888 7f56f9bff6c0 Delete type=0 #1066
|
||||
2026/02/28-22:59:43.785498 7f54e37ef6c0 Level-0 table #1071: started
|
||||
2026/02/28-22:59:43.785523 7f54e37ef6c0 Level-0 table #1071: 0 bytes OK
|
||||
2026/02/28-22:59:43.792317 7f54e37ef6c0 Delete type=0 #1069
|
||||
2026/02/28-22:59:43.813749 7f54e37ef6c0 Manual compaction at level-0 from '!items!6fTZ6hOKR4pWbWOe' @ 72057594037927935 : 1 .. '!items!zwSNMO9HpiqUCMt8' @ 0 : 0; will stop at (end)
|
||||
2026/02/28-22:59:43.813808 7f54e37ef6c0 Manual compaction at level-1 from '!items!6fTZ6hOKR4pWbWOe' @ 72057594037927935 : 1 .. '!items!zwSNMO9HpiqUCMt8' @ 0 : 0; will stop at (end)
|
||||
|
||||
Binary file not shown.
BIN
packs/effets-exemples/MANIFEST-001072
Normal file
BIN
packs/effets-exemples/MANIFEST-001072
Normal file
Binary file not shown.
Binary file not shown.
@@ -1 +1 @@
|
||||
MANIFEST-000765
|
||||
MANIFEST-001075
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
2025/03/31-07:10:16.812596 7f9cf5ffb6c0 Recovering log #763
|
||||
2025/03/31-07:10:16.868280 7f9cf5ffb6c0 Delete type=3 #761
|
||||
2025/03/31-07:10:16.868401 7f9cf5ffb6c0 Delete type=0 #763
|
||||
2025/03/31-07:15:11.637784 7f9cf4ff96c0 Level-0 table #768: started
|
||||
2025/03/31-07:15:11.637835 7f9cf4ff96c0 Level-0 table #768: 0 bytes OK
|
||||
2025/03/31-07:15:11.674608 7f9cf4ff96c0 Delete type=0 #766
|
||||
2025/03/31-07:15:11.712020 7f9cf4ff96c0 Manual compaction at level-0 from '!items!0ErhyqifZLDCmMfT' @ 72057594037927935 : 1 .. '!items!yE8UH6YAgNGjKDEu' @ 0 : 0; will stop at (end)
|
||||
2025/03/31-07:15:11.712092 7f9cf4ff96c0 Manual compaction at level-1 from '!items!0ErhyqifZLDCmMfT' @ 72057594037927935 : 1 .. '!items!yE8UH6YAgNGjKDEu' @ 0 : 0; will stop at (end)
|
||||
2026/02/28-22:59:53.798832 7f56f9bff6c0 Recovering log #1073
|
||||
2026/02/28-22:59:53.809449 7f56f9bff6c0 Delete type=3 #1071
|
||||
2026/02/28-22:59:53.809533 7f56f9bff6c0 Delete type=0 #1073
|
||||
2026/03/01-01:08:46.340100 7f54e37ef6c0 Level-0 table #1078: started
|
||||
2026/03/01-01:08:46.340139 7f54e37ef6c0 Level-0 table #1078: 0 bytes OK
|
||||
2026/03/01-01:08:46.346846 7f54e37ef6c0 Delete type=0 #1076
|
||||
2026/03/01-01:08:46.366221 7f54e37ef6c0 Manual compaction at level-0 from '!items!0ErhyqifZLDCmMfT' @ 72057594037927935 : 1 .. '!items!yE8UH6YAgNGjKDEu' @ 0 : 0; will stop at (end)
|
||||
2026/03/01-01:08:46.366278 7f54e37ef6c0 Manual compaction at level-1 from '!items!0ErhyqifZLDCmMfT' @ 72057594037927935 : 1 .. '!items!yE8UH6YAgNGjKDEu' @ 0 : 0; will stop at (end)
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
2025/03/31-07:01:18.075041 7f9cf67fc6c0 Recovering log #758
|
||||
2025/03/31-07:01:18.085656 7f9cf67fc6c0 Delete type=3 #756
|
||||
2025/03/31-07:01:18.085755 7f9cf67fc6c0 Delete type=0 #758
|
||||
2025/03/31-07:05:47.712589 7f9cf4ff96c0 Level-0 table #764: started
|
||||
2025/03/31-07:05:47.712636 7f9cf4ff96c0 Level-0 table #764: 0 bytes OK
|
||||
2025/03/31-07:05:47.719221 7f9cf4ff96c0 Delete type=0 #762
|
||||
2025/03/31-07:05:47.739829 7f9cf4ff96c0 Manual compaction at level-0 from '!items!0ErhyqifZLDCmMfT' @ 72057594037927935 : 1 .. '!items!yE8UH6YAgNGjKDEu' @ 0 : 0; will stop at (end)
|
||||
2025/03/31-07:05:47.739948 7f9cf4ff96c0 Manual compaction at level-1 from '!items!0ErhyqifZLDCmMfT' @ 72057594037927935 : 1 .. '!items!yE8UH6YAgNGjKDEu' @ 0 : 0; will stop at (end)
|
||||
2026/02/28-17:23:52.834261 7f56f9bff6c0 Recovering log #1069
|
||||
2026/02/28-17:23:52.843912 7f56f9bff6c0 Delete type=3 #1067
|
||||
2026/02/28-17:23:52.843969 7f56f9bff6c0 Delete type=0 #1069
|
||||
2026/02/28-22:59:43.704672 7f54e37ef6c0 Level-0 table #1074: started
|
||||
2026/02/28-22:59:43.704745 7f54e37ef6c0 Level-0 table #1074: 0 bytes OK
|
||||
2026/02/28-22:59:43.711212 7f54e37ef6c0 Delete type=0 #1072
|
||||
2026/02/28-22:59:43.731026 7f54e37ef6c0 Manual compaction at level-0 from '!items!0ErhyqifZLDCmMfT' @ 72057594037927935 : 1 .. '!items!yE8UH6YAgNGjKDEu' @ 0 : 0; will stop at (end)
|
||||
2026/02/28-22:59:43.731077 7f54e37ef6c0 Manual compaction at level-1 from '!items!0ErhyqifZLDCmMfT' @ 72057594037927935 : 1 .. '!items!yE8UH6YAgNGjKDEu' @ 0 : 0; will stop at (end)
|
||||
|
||||
Binary file not shown.
BIN
packs/equipment/MANIFEST-001075
Normal file
BIN
packs/equipment/MANIFEST-001075
Normal file
Binary file not shown.
Binary file not shown.
@@ -1 +1 @@
|
||||
MANIFEST-000764
|
||||
MANIFEST-001074
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
2025/03/31-07:10:17.225555 7f9cf6ffd6c0 Recovering log #762
|
||||
2025/03/31-07:10:17.275960 7f9cf6ffd6c0 Delete type=3 #760
|
||||
2025/03/31-07:10:17.276058 7f9cf6ffd6c0 Delete type=0 #762
|
||||
2025/03/31-07:15:11.899738 7f9cf4ff96c0 Level-0 table #767: started
|
||||
2025/03/31-07:15:11.899801 7f9cf4ff96c0 Level-0 table #767: 0 bytes OK
|
||||
2025/03/31-07:15:11.936459 7f9cf4ff96c0 Delete type=0 #765
|
||||
2025/03/31-07:15:12.016531 7f9cf4ff96c0 Manual compaction at level-0 from '!items!AoT2c0af4lY6aBsx' @ 72057594037927935 : 1 .. '!items!vGydqADwTsHZ9B3j' @ 0 : 0; will stop at (end)
|
||||
2025/03/31-07:15:12.016632 7f9cf4ff96c0 Manual compaction at level-1 from '!items!AoT2c0af4lY6aBsx' @ 72057594037927935 : 1 .. '!items!vGydqADwTsHZ9B3j' @ 0 : 0; will stop at (end)
|
||||
2026/02/28-22:59:53.895577 7f56f8bfd6c0 Recovering log #1072
|
||||
2026/02/28-22:59:53.906749 7f56f8bfd6c0 Delete type=3 #1070
|
||||
2026/02/28-22:59:53.906807 7f56f8bfd6c0 Delete type=0 #1072
|
||||
2026/03/01-01:08:46.391890 7f54e37ef6c0 Level-0 table #1077: started
|
||||
2026/03/01-01:08:46.391936 7f54e37ef6c0 Level-0 table #1077: 0 bytes OK
|
||||
2026/03/01-01:08:46.398187 7f54e37ef6c0 Delete type=0 #1075
|
||||
2026/03/01-01:08:46.417834 7f54e37ef6c0 Manual compaction at level-0 from '!items!AoT2c0af4lY6aBsx' @ 72057594037927935 : 1 .. '!items!vGydqADwTsHZ9B3j' @ 0 : 0; will stop at (end)
|
||||
2026/03/01-01:08:46.417875 7f54e37ef6c0 Manual compaction at level-1 from '!items!AoT2c0af4lY6aBsx' @ 72057594037927935 : 1 .. '!items!vGydqADwTsHZ9B3j' @ 0 : 0; will stop at (end)
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
2025/03/31-07:01:18.187598 7f9cf5ffb6c0 Recovering log #757
|
||||
2025/03/31-07:01:18.198216 7f9cf5ffb6c0 Delete type=3 #755
|
||||
2025/03/31-07:01:18.198369 7f9cf5ffb6c0 Delete type=0 #757
|
||||
2025/03/31-07:05:47.776499 7f9cf4ff96c0 Level-0 table #763: started
|
||||
2025/03/31-07:05:47.776619 7f9cf4ff96c0 Level-0 table #763: 0 bytes OK
|
||||
2025/03/31-07:05:47.783148 7f9cf4ff96c0 Delete type=0 #761
|
||||
2025/03/31-07:05:47.797620 7f9cf4ff96c0 Manual compaction at level-0 from '!items!AoT2c0af4lY6aBsx' @ 72057594037927935 : 1 .. '!items!vGydqADwTsHZ9B3j' @ 0 : 0; will stop at (end)
|
||||
2025/03/31-07:05:47.797706 7f9cf4ff96c0 Manual compaction at level-1 from '!items!AoT2c0af4lY6aBsx' @ 72057594037927935 : 1 .. '!items!vGydqADwTsHZ9B3j' @ 0 : 0; will stop at (end)
|
||||
2026/02/28-17:23:52.920377 7f56e3fff6c0 Recovering log #1068
|
||||
2026/02/28-17:23:52.930570 7f56e3fff6c0 Delete type=3 #1066
|
||||
2026/02/28-17:23:52.930642 7f56e3fff6c0 Delete type=0 #1068
|
||||
2026/02/28-22:59:43.758590 7f54e37ef6c0 Level-0 table #1073: started
|
||||
2026/02/28-22:59:43.758628 7f54e37ef6c0 Level-0 table #1073: 0 bytes OK
|
||||
2026/02/28-22:59:43.764731 7f54e37ef6c0 Delete type=0 #1071
|
||||
2026/02/28-22:59:43.785330 7f54e37ef6c0 Manual compaction at level-0 from '!items!AoT2c0af4lY6aBsx' @ 72057594037927935 : 1 .. '!items!vGydqADwTsHZ9B3j' @ 0 : 0; will stop at (end)
|
||||
2026/02/28-22:59:43.785372 7f54e37ef6c0 Manual compaction at level-1 from '!items!AoT2c0af4lY6aBsx' @ 72057594037927935 : 1 .. '!items!vGydqADwTsHZ9B3j' @ 0 : 0; will stop at (end)
|
||||
|
||||
Binary file not shown.
BIN
packs/fightoptions/MANIFEST-001074
Normal file
BIN
packs/fightoptions/MANIFEST-001074
Normal file
Binary file not shown.
Binary file not shown.
@@ -1 +1 @@
|
||||
MANIFEST-000247
|
||||
MANIFEST-000557
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user