Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 12faf34631 | |||
| afa6e7a323 | |||
| 89f5674fb9 | |||
| cd06d2e5ec | |||
| cdddcb6aee |
@@ -12,13 +12,15 @@ jobs:
|
|||||||
|
|
||||||
#- uses: actions/checkout@v3
|
#- uses: actions/checkout@v3
|
||||||
- uses: RouxAntoine/checkout@v3.5.4
|
- uses: RouxAntoine/checkout@v3.5.4
|
||||||
|
with:
|
||||||
|
ref: "v13"
|
||||||
|
|
||||||
# get part of the tag after the `v`
|
# get part of the tag after the `v`
|
||||||
- name: Extract tag version number
|
- name: Extract tag version number
|
||||||
id: get_version
|
id: get_version
|
||||||
uses: battila7/get-version-action@v2
|
uses: battila7/get-version-action@v2
|
||||||
|
|
||||||
# Substitute the Manifest and Download URLs in the system.json
|
# Substitute the Manifest and Download URLs in the module.json
|
||||||
- name: Substitute Manifest and Download Links For Versioned Ones
|
- name: Substitute Manifest and Download Links For Versioned Ones
|
||||||
id: sub_manifest_link_version
|
id: sub_manifest_link_version
|
||||||
uses: microsoft/variable-substitution@v1
|
uses: microsoft/variable-substitution@v1
|
||||||
@@ -26,9 +28,9 @@ jobs:
|
|||||||
files: "system.json"
|
files: "system.json"
|
||||||
env:
|
env:
|
||||||
version: ${{steps.get_version.outputs.version-without-v}}
|
version: ${{steps.get_version.outputs.version-without-v}}
|
||||||
url: https://www.uberwald.me/gitea/${{gitea.repository}}
|
url: https://www.uberwald.me/gitea/public/bol
|
||||||
manifest: https://www.uberwald.me/gitea/public/bol/releases/download/latest/system.json
|
manifest: https://www.uberwald.me/gitea/public/bol/releases/latest/system.json
|
||||||
download: https://www.uberwald.me/gitea/${{gitea.repository}}/releases/download/${{github.event.release.tag_name}}/bol.zip
|
download: https://www.uberwald.me/gitea/public/bol/releases/download/${{github.event.release.tag_name}}/bol.zip
|
||||||
|
|
||||||
# Create a zip file with all files required by the module to add to the release
|
# Create a zip file with all files required by the module to add to the release
|
||||||
- run: |
|
- run: |
|
||||||
@@ -49,15 +51,4 @@ jobs:
|
|||||||
files: |-
|
files: |-
|
||||||
./bol.zip
|
./bol.zip
|
||||||
system.json
|
system.json
|
||||||
api_key: "${{secrets.ALLOW_PUSH_RELEASE}}"
|
api_key: "${{secrets.RELEASE_TOKEN_BOL}}"
|
||||||
|
|
||||||
- name: Publish to Foundry server
|
|
||||||
uses: https://github.com/djlechuck/foundryvtt-publish-package-action@v1
|
|
||||||
with:
|
|
||||||
token: ${{ secrets.FOUNDRYVTT_RELEASE_TOKEN }}
|
|
||||||
id: "bol"
|
|
||||||
version: ${{github.event.release.tag_name}}
|
|
||||||
manifest: "https://www.uberwald.me/gitea/public/bol/releases/download/latest/system.json"
|
|
||||||
notes: "https://www.uberwald.me/gitea/${{gitea.repository}}/releases/download/${{github.event.release.tag_name}}/bol.zip"
|
|
||||||
compatibility-minimum: "13"
|
|
||||||
compatibility-verified: "14"
|
|
||||||
|
|||||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -8,4 +8,3 @@ todo.md
|
|||||||
/jsconfig.json
|
/jsconfig.json
|
||||||
/package.json
|
/package.json
|
||||||
/package-lock.json
|
/package-lock.json
|
||||||
/.github
|
|
||||||
@@ -1,286 +0,0 @@
|
|||||||
# 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
|
|
||||||
2139
css/bol.css
2139
css/bol.css
File diff suppressed because it is too large
Load Diff
@@ -478,7 +478,6 @@
|
|||||||
"BOL.chat.damageresult": "Damages of {name} : {total}",
|
"BOL.chat.damageresult": "Damages of {name} : {total}",
|
||||||
"BOL.chat.damagetarget": "Target : {target}",
|
"BOL.chat.damagetarget": "Target : {target}",
|
||||||
"BOL.chat.applydamagetotarget": "Apply damages to the target",
|
"BOL.chat.applydamagetotarget": "Apply damages to the target",
|
||||||
"BOL.chat.selecttarget": "Choose a target:",
|
|
||||||
"BOL.chat.fightoption": "Combat options",
|
"BOL.chat.fightoption": "Combat options",
|
||||||
"BOL.chat.reroll": "Reroll (1 HP)",
|
"BOL.chat.reroll": "Reroll (1 HP)",
|
||||||
"BOL.chat.heroicreminder": "In addition of the actions below, you can : <ul><li>Carnage : Do a second free attack on the same opponent</li><li>Precise : 1 Malus Die on your opponent on a chosen location</li><li>Disarm</li><li>Rabble Massacre</li><li>Prone : Push your opponent on the ground (max +1 size)</li></ul>If you spent 1 Hero Point in addition, all these effects can be doubled.",
|
"BOL.chat.heroicreminder": "In addition of the actions below, you can : <ul><li>Carnage : Do a second free attack on the same opponent</li><li>Precise : 1 Malus Die on your opponent on a chosen location</li><li>Disarm</li><li>Rabble Massacre</li><li>Prone : Push your opponent on the ground (max +1 size)</li></ul>If you spent 1 Hero Point in addition, all these effects can be doubled.",
|
||||||
@@ -610,10 +609,5 @@
|
|||||||
"BOL.settings.defaultLogoActorSheetPath" : "Path for Actor sheet logo",
|
"BOL.settings.defaultLogoActorSheetPath" : "Path for Actor sheet logo",
|
||||||
"BOL.settings.defaultLogoPathActorSheetTooltip": "Path of the Actor sheet logo (346 x 200, default : /systems/bol/ui/logo.webp)",
|
"BOL.settings.defaultLogoPathActorSheetTooltip": "Path of the Actor sheet logo (346 x 200, default : /systems/bol/ui/logo.webp)",
|
||||||
"BOL.settings.defaultLogoTopLeftPath" : "Path for main top left logo",
|
"BOL.settings.defaultLogoTopLeftPath" : "Path for main top left logo",
|
||||||
"BOL.settings.defaultLogoTopLeftPathTooltip": "Path of the logo in the top left window (718 x 416, default : /systems/bol/ui/logo2.webp)",
|
"BOL.settings.defaultLogoTopLeftPathTooltip": "Path of the logo in the top left window (718 x 416, default : /systems/bol/ui/logo2.webp)"
|
||||||
|
|
||||||
"BOL.ui.charSummaryTitle": "Character Summary",
|
|
||||||
"BOL.ui.colGroupAttributes": "Attributes",
|
|
||||||
"BOL.ui.colGroupAptitudes": "Aptitudes",
|
|
||||||
"BOL.ui.colGroupResources": "Resources"
|
|
||||||
}
|
}
|
||||||
@@ -506,7 +506,6 @@
|
|||||||
"BOL.chat.damageresult": "Dommages de {name} : {total}",
|
"BOL.chat.damageresult": "Dommages de {name} : {total}",
|
||||||
"BOL.chat.damagetarget": "Cible : {target}",
|
"BOL.chat.damagetarget": "Cible : {target}",
|
||||||
"BOL.chat.applydamagetotarget": "Appliquer les dommages à la cible",
|
"BOL.chat.applydamagetotarget": "Appliquer les dommages à la cible",
|
||||||
"BOL.chat.selecttarget": "Choisir une cible :",
|
|
||||||
"BOL.chat.fightoption": "Option de combat",
|
"BOL.chat.fightoption": "Option de combat",
|
||||||
"BOL.chat.reroll": "Relancer (1 P. Heroisme)",
|
"BOL.chat.reroll": "Relancer (1 P. Heroisme)",
|
||||||
"BOL.chat.heroicreminder": "En plus des actions indiquées sur les boutons ci-dessous, vous pouvez : <ul><li>Carnage : Attaquer une seconde fois le même adversaire</li><li>Coup précis : Un dé de malus à votre adversaire sur une localisation choisie</li><li>Désarmement</li><li>Massacrer la piétaille</li><li>Renversement : Renversez votre adversaire (1 taille de plus max)</li></ul>Si vous dépensez un Point d'Héroisme en plus, tout ces effets peuvent être doublés",
|
"BOL.chat.heroicreminder": "En plus des actions indiquées sur les boutons ci-dessous, vous pouvez : <ul><li>Carnage : Attaquer une seconde fois le même adversaire</li><li>Coup précis : Un dé de malus à votre adversaire sur une localisation choisie</li><li>Désarmement</li><li>Massacrer la piétaille</li><li>Renversement : Renversez votre adversaire (1 taille de plus max)</li></ul>Si vous dépensez un Point d'Héroisme en plus, tout ces effets peuvent être doublés",
|
||||||
@@ -651,10 +650,5 @@
|
|||||||
"BOL.settings.defaultLogoTopLeftPathTooltip": "Vous pouvez changer le logo BoL en haut à gauche de chaque écran (idéalement 718 x 416, défaut : /systems/bol/ui/logo2.webp)",
|
"BOL.settings.defaultLogoTopLeftPathTooltip": "Vous pouvez changer le logo BoL en haut à gauche de chaque écran (idéalement 718 x 416, défaut : /systems/bol/ui/logo2.webp)",
|
||||||
|
|
||||||
"EFFECT.StatusProne": "A terre",
|
"EFFECT.StatusProne": "A terre",
|
||||||
"EFFECT.StatusDead": "Mort",
|
"EFFECT.StatusDead": "Mort"
|
||||||
|
|
||||||
"BOL.ui.charSummaryTitle": "Résumé des Personnages",
|
|
||||||
"BOL.ui.colGroupAttributes": "Attributs",
|
|
||||||
"BOL.ui.colGroupAptitudes": "Aptitudes",
|
|
||||||
"BOL.ui.colGroupResources": "Ressources"
|
|
||||||
}
|
}
|
||||||
@@ -7,8 +7,6 @@ import { BoLUtility } from "../system/bol-utility.js";
|
|||||||
*/
|
*/
|
||||||
export class BoLActor extends Actor {
|
export class BoLActor extends Actor {
|
||||||
|
|
||||||
static _healthLock = new Set()
|
|
||||||
|
|
||||||
static async create(data, options) {
|
static async create(data, options) {
|
||||||
|
|
||||||
// Case of compendium global import
|
// Case of compendium global import
|
||||||
@@ -359,7 +357,7 @@ export class BoLActor extends Actor {
|
|||||||
ChatMessage.create({
|
ChatMessage.create({
|
||||||
alias: this.name,
|
alias: this.name,
|
||||||
whisper: BoLUtility.getWhisperRecipientsAndGMs(this.name),
|
whisper: BoLUtility.getWhisperRecipientsAndGMs(this.name),
|
||||||
content: await foundry.applications.handlebars.renderTemplate('systems/bol/templates/chat/chat-activate-fight-option.hbs', { name: this.name, img: fightOption.img, foName: fightOption.name, state: state })
|
content: await renderTemplate('systems/bol/templates/chat/chat-activate-fight-option.hbs', { name: this.name, img: fightOption.img, foName: fightOption.name, state: state })
|
||||||
})
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -854,42 +852,36 @@ export class BoLActor extends Actor {
|
|||||||
|
|
||||||
/*-------------------------------------------- */
|
/*-------------------------------------------- */
|
||||||
async manageHealthState() {
|
async manageHealthState() {
|
||||||
if (BoLActor._healthLock.has(this.id)) return
|
let hpID = "lastHP" + this.id
|
||||||
BoLActor._healthLock.add(this.id)
|
let lastHP = await this.getFlag("world", hpID)
|
||||||
try {
|
if (lastHP != this.system.resources.hp.value && game.user.isGM) { // Only GM sends this
|
||||||
let hpID = "lastHP" + this.id
|
await this.setFlag("world", hpID, this.system.resources.hp.value)
|
||||||
let lastHP = await this.getFlag("world", hpID)
|
let prone = this.effects.find(ef => ef.name == game.i18n.localize("EFFECT.StatusProne"))
|
||||||
if (lastHP != this.system.resources.hp.value && game.user.isGM) { // Only GM sends this
|
let dead = this.effects.find(ef => ef.name == game.i18n.localize("EFFECT.StatusDead"))
|
||||||
await this.setFlag("world", hpID, this.system.resources.hp.value)
|
if (this.system.resources.hp.value <= 0) {
|
||||||
let prone = this.effects.find(ef => ef.name == game.i18n.localize("EFFECT.StatusProne"))
|
if (!prone) {
|
||||||
let dead = this.effects.find(ef => ef.name == game.i18n.localize("EFFECT.StatusDead"))
|
await this.createEmbeddedDocuments("ActiveEffect", [
|
||||||
if (this.system.resources.hp.value <= 0) {
|
{ name: game.i18n.localize('EFFECT.StatusProne'), icon: 'icons/svg/falling.svg', statuses: 'prone' }
|
||||||
if (!prone) {
|
])
|
||||||
await this.createEmbeddedDocuments("ActiveEffect", [
|
}
|
||||||
{ name: game.i18n.localize('EFFECT.StatusProne'), icon: 'icons/svg/falling.svg', statuses: 'prone' }
|
if (this.system.resources.hp.value < -5 && !dead) {
|
||||||
])
|
await this.createEmbeddedDocuments("ActiveEffect", [
|
||||||
}
|
{ name: game.i18n.localize('EFFECT.StatusDead'), icon: 'icons/svg/skull.svg', statuses: 'dead' }
|
||||||
if (this.system.resources.hp.value < -5 && !dead) {
|
])
|
||||||
await this.createEmbeddedDocuments("ActiveEffect", [
|
}
|
||||||
{ name: game.i18n.localize('EFFECT.StatusDead'), icon: 'icons/svg/skull.svg', statuses: 'dead' }
|
ChatMessage.create({
|
||||||
])
|
alias: this.name,
|
||||||
}
|
whisper: BoLUtility.getWhisperRecipientsAndGMs(this.name),
|
||||||
ChatMessage.create({
|
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() })
|
||||||
alias: this.name,
|
})
|
||||||
whisper: BoLUtility.getWhisperRecipientsAndGMs(this.name),
|
} else {
|
||||||
content: await foundry.applications.handlebars.renderTemplate('systems/bol/templates/chat/chat-vitality-zero.hbs', { name: this.name, img: this.img, hp: this.system.resources.hp.value, isHeroAdversary: this.isHeroAdversary() })
|
if (prone) {
|
||||||
})
|
await this.deleteEmbeddedDocuments("ActiveEffect", [prone.id])
|
||||||
} else {
|
}
|
||||||
if (prone) {
|
if (dead) {
|
||||||
await this.deleteEmbeddedDocuments("ActiveEffect", [prone.id])
|
await this.deleteEmbeddedDocuments("ActiveEffect", [dead.id])
|
||||||
}
|
|
||||||
if (dead) {
|
|
||||||
await this.deleteEmbeddedDocuments("ActiveEffect", [dead.id])
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} finally {
|
|
||||||
BoLActor._healthLock.delete(this.id)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -912,7 +904,7 @@ export class BoLActor extends Actor {
|
|||||||
let msg = await ChatMessage.create({
|
let msg = await ChatMessage.create({
|
||||||
alias: this.name,
|
alias: this.name,
|
||||||
whisper: BoLUtility.getWhisperRecipientsAndGMs(this.name),
|
whisper: BoLUtility.getWhisperRecipientsAndGMs(this.name),
|
||||||
content: await foundry.applications.handlebars.renderTemplate('systems/bol/templates/chat/chat-recup-information.hbs', {
|
content: await renderTemplate('systems/bol/templates/chat/chat-recup-information.hbs', {
|
||||||
name: this.name,
|
name: this.name,
|
||||||
img: this.img,
|
img: this.img,
|
||||||
actorId: this.id,
|
actorId: this.id,
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
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"
|
|
||||||
@@ -1,144 +0,0 @@
|
|||||||
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 })
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,307 +0,0 @@
|
|||||||
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
|
|
||||||
}
|
|
||||||
@@ -1,255 +0,0 @@
|
|||||||
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
|
|
||||||
}
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
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 })
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,70 +0,0 @@
|
|||||||
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,9 +1,11 @@
|
|||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
// Import Modules
|
// Import Modules
|
||||||
import { BoLActor } from "./actor/actor.js"
|
import { BoLActor } from "./actor/actor.js"
|
||||||
// AppV1 actor sheets kept for reference only (AppV2 used via sheets.* below)
|
import { BoLActorSheet } from "./actor/actor-sheet.js"
|
||||||
|
import { BoLVehicleSheet } from "./actor/vehicle-sheet.js"
|
||||||
|
import { BoLHordeSheet } from "./actor/horde-sheet.js"
|
||||||
import { BoLItem } from "./item/item.js"
|
import { BoLItem } from "./item/item.js"
|
||||||
// Note: Old BoLItemSheet (AppV1) is now replaced by AppV2 sheets
|
import { BoLItemSheet } from "./item/item-sheet.js"
|
||||||
import { System, BOL } from "./system/config.js"
|
import { System, BOL } from "./system/config.js"
|
||||||
import { preloadHandlebarsTemplates } from "./system/templates.js"
|
import { preloadHandlebarsTemplates } from "./system/templates.js"
|
||||||
import { registerHandlebarsHelpers } from "./system/helpers.js"
|
import { registerHandlebarsHelpers } from "./system/helpers.js"
|
||||||
@@ -16,11 +18,8 @@ import { BoLHotbar } from "./system/bol-hotbar.js"
|
|||||||
import { BoLCommands } from "./system/bol-commands.js"
|
import { BoLCommands } from "./system/bol-commands.js"
|
||||||
import { BoLRoll } from "./controllers/bol-rolls.js"
|
import { BoLRoll } from "./controllers/bol-rolls.js"
|
||||||
|
|
||||||
// Import DataModels
|
/* -------------------------------------------- */
|
||||||
import * as models from "./models/_module.mjs"
|
const BOL_WELCOME_MESSAGE_URL = "https://www.uberwald.me/gitea/public/bol/raw/branch/v13/welcome-message-bol.html"
|
||||||
|
|
||||||
// Import AppV2 Sheets
|
|
||||||
import * as sheets from "./applications/sheets/_module.mjs"
|
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
Hooks.once('init', async function () {
|
Hooks.once('init', async function () {
|
||||||
@@ -32,9 +31,7 @@ Hooks.once('init', async function () {
|
|||||||
BoLRoll,
|
BoLRoll,
|
||||||
BoLUtility,
|
BoLUtility,
|
||||||
macros: Macros,
|
macros: Macros,
|
||||||
config: BOL,
|
config: BOL
|
||||||
models,
|
|
||||||
sheets
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Game socket
|
// Game socket
|
||||||
@@ -53,38 +50,17 @@ Hooks.once('init', async function () {
|
|||||||
|
|
||||||
// Define custom Entity classes
|
// Define custom Entity classes
|
||||||
CONFIG.Actor.documentClass = BoLActor;
|
CONFIG.Actor.documentClass = BoLActor;
|
||||||
CONFIG.Actor.dataModels = {
|
|
||||||
character: models.BoLCharacter,
|
|
||||||
encounter: models.BoLEncounter,
|
|
||||||
horde: models.BoLHorde,
|
|
||||||
vehicle: models.BoLVehicle
|
|
||||||
}
|
|
||||||
|
|
||||||
CONFIG.Item.documentClass = BoLItem;
|
CONFIG.Item.documentClass = BoLItem;
|
||||||
CONFIG.Item.dataModels = {
|
|
||||||
item: models.BoLItem,
|
|
||||||
feature: models.BoLFeature
|
|
||||||
}
|
|
||||||
|
|
||||||
CONFIG.Combat.documentClass = BoLCombatManager;
|
CONFIG.Combat.documentClass = BoLCombatManager;
|
||||||
|
|
||||||
// Register sheet application classes
|
// Register sheet application classes
|
||||||
foundry.documents.collections.Actors.unregisterSheet("core", foundry.appv1.sheets.ActorSheet);
|
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", BoLActorSheet, { types: ["character", "encounter"], makeDefault: true })
|
||||||
foundry.documents.collections.Actors.registerSheet("bol", sheets.BoLVehicleSheet, { types: ["vehicle"], makeDefault: true })
|
foundry.documents.collections.Actors.registerSheet("bol", BoLVehicleSheet, { types: ["vehicle"], makeDefault: true })
|
||||||
foundry.documents.collections.Actors.registerSheet("bol", sheets.BoLHordeSheet, { types: ["horde"], makeDefault: true })
|
foundry.documents.collections.Actors.registerSheet("bol", BoLHordeSheet, { types: ["horde"], makeDefault: true })
|
||||||
|
|
||||||
// Register AppV2 Item Sheets
|
|
||||||
foundry.documents.collections.Items.unregisterSheet("core", foundry.appv1.sheets.ItemSheet);
|
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", BoLItemSheet, { makeDefault: true });
|
||||||
foundry.documents.collections.Items.registerSheet("bol", sheets.BoLFeatureSheet, { types: ["feature"], makeDefault: true });
|
|
||||||
|
|
||||||
// Debug: Verify AppV2 sheets are loaded
|
|
||||||
console.log("BoL Item Sheets registered:", {
|
|
||||||
BoLItemSheet: sheets.BoLItemSheet.name,
|
|
||||||
BoLFeatureSheet: sheets.BoLFeatureSheet.name,
|
|
||||||
extendsApplicationV2: sheets.BoLItemSheet.prototype instanceof foundry.applications.api.ApplicationV2
|
|
||||||
});
|
|
||||||
|
|
||||||
// Inot useful stuff
|
// Inot useful stuff
|
||||||
BoLUtility.init()
|
BoLUtility.init()
|
||||||
@@ -110,22 +86,54 @@ Hooks.once('init', async function () {
|
|||||||
|
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
async function welcomeMessage() {
|
function welcomeMessage() {
|
||||||
const noRulebook = !game.modules.find(m => m.id === "bol-rulebook")
|
let content = `<div id="welcome-message-bol"><span class="rdd-roll-part">
|
||||||
const content = await foundry.applications.handlebars.renderTemplate(
|
<strong>` + game.i18n.localize("BOL.chat.welcome1") + `</strong><p>` +
|
||||||
"systems/bol/templates/chat/chat-welcome.hbs",
|
game.i18n.localize("BOL.chat.welcome2") + "</p><p>" +
|
||||||
{ noRulebook }
|
game.i18n.localize("BOL.chat.welcome3") + "</p><p>" +
|
||||||
)
|
game.i18n.localize("BOL.chat.welcome4") + "</p><p>" +
|
||||||
ChatMessage.create({ user: game.user.id, whisper: [game.user.id], content })
|
game.i18n.localize("BOL.chat.welcome5") + "</p>" +
|
||||||
|
game.i18n.localize("BOL.chat.welcome6")
|
||||||
|
|
||||||
|
let rulebook = game.modules.find(m => m.id === "bol-rulebook")
|
||||||
|
if (!rulebook) {
|
||||||
|
content += "<p>" + game.i18n.localize("BOL.chat.bolRulebookMessage") + "</p>"
|
||||||
|
}
|
||||||
|
ChatMessage.create({
|
||||||
|
user: game.user.id,
|
||||||
|
whisper: [game.user.id],
|
||||||
|
content: content
|
||||||
|
})
|
||||||
|
|
||||||
if (game.user.isGM && game.i18n.lang == 'en' && !game.modules.find(m => m.id == "babele")) {
|
if (game.user.isGM && game.i18n.lang == 'en' && !game.modules.find(m => m.id == "babele")) {
|
||||||
ChatMessage.create({
|
ChatMessage.create({
|
||||||
user: game.user.id,
|
user: game.user.id,
|
||||||
whisper: [game.user.id],
|
whisper: [game.user.id],
|
||||||
content: `<div 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>`
|
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.")
|
ui.notifications.warn("WARNING ! English language selected, but babele module is not installed !<br>Please install babele from the module tab in Foundry interface.")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
function welcomeMessageRepository() {
|
||||||
|
if (game.user.isGM) {
|
||||||
|
// Try to fetch the welcome message from the github repo "welcome-message-ecryme.html"
|
||||||
|
fetch(BOL_WELCOME_MESSAGE_URL)
|
||||||
|
.then(response => response.text())
|
||||||
|
.then(html => {
|
||||||
|
ChatMessage.create({
|
||||||
|
user: game.user.id,
|
||||||
|
whisper: [game.user.id],
|
||||||
|
content: html
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.error("Error fetching welcome message:", error);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
@@ -141,6 +149,7 @@ Hooks.once('ready', async function () {
|
|||||||
)
|
)
|
||||||
|
|
||||||
welcomeMessage()
|
welcomeMessage()
|
||||||
|
welcomeMessageRepository();
|
||||||
|
|
||||||
// User warning
|
// User warning
|
||||||
if (!game.user.isGM && game.user.character == undefined) {
|
if (!game.user.isGM && game.user.character == undefined) {
|
||||||
|
|||||||
@@ -5,6 +5,11 @@ const _apt2attr = { init: "mind", melee: "agility", ranged: "agility", def: "vig
|
|||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
export class BoLRoll {
|
export class BoLRoll {
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
static options() {
|
||||||
|
return { classes: ["bol", "dialog"], width: 480, height: 'fit-content' };
|
||||||
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
static getDefaultAttribute(key) {
|
static getDefaultAttribute(key) {
|
||||||
return _apt2attr[key]
|
return _apt2attr[key]
|
||||||
@@ -124,7 +129,7 @@ export class BoLRoll {
|
|||||||
rangeMsg = "BOL.chat.range6"
|
rangeMsg = "BOL.chat.range6"
|
||||||
}
|
}
|
||||||
ChatMessage.create({
|
ChatMessage.create({
|
||||||
content: await foundry.applications.handlebars.renderTemplate('systems/bol/templates/chat/chat-info-range.hbs', {
|
content: await renderTemplate('systems/bol/templates/chat/chat-info-range.hbs', {
|
||||||
weapon: weapon,
|
weapon: weapon,
|
||||||
attackerName: _token.actor.name,
|
attackerName: _token.actor.name,
|
||||||
defenderName: target.actor.name,
|
defenderName: target.actor.name,
|
||||||
@@ -303,31 +308,26 @@ export class BoLRoll {
|
|||||||
// Final number of dices
|
// Final number of dices
|
||||||
this.rollData.nbDice = 2 + Math.abs(this.rollData.bmDice)
|
this.rollData.nbDice = 2 + Math.abs(this.rollData.bmDice)
|
||||||
// Bonus or Malus ?
|
// Bonus or Malus ?
|
||||||
const nbDiceEl = document.querySelector('#roll-nbdice')
|
if (this.rollData.bmDice == 0) {
|
||||||
if (nbDiceEl) {
|
$('#roll-nbdice').val("2")
|
||||||
if (this.rollData.bmDice == 0) {
|
} else {
|
||||||
nbDiceEl.value = "2"
|
let letter = (this.rollData.bmDice > 0) ? "B" : "M"
|
||||||
} else {
|
$('#roll-nbdice').val("2 + " + String(Math.abs(this.rollData.bmDice)) + letter)
|
||||||
let letter = (this.rollData.bmDice > 0) ? "B" : "M"
|
|
||||||
nbDiceEl.value = "2 + " + String(Math.abs(this.rollData.bmDice)) + letter
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
let rollbase = this.rollData.attrValue + "+" + this.rollData.aptValue
|
let rollbase = this.rollData.attrValue + "+" + this.rollData.aptValue
|
||||||
if (this.rollData.weapon && this.rollData.weapon.system.properties.onlymodifier) {
|
if (this.rollData.weapon && this.rollData.weapon.system.properties.onlymodifier) {
|
||||||
rollbase = ""
|
rollbase = ""
|
||||||
}
|
}
|
||||||
const modifierEl = document.querySelector('#roll-modifier')
|
$('#roll-modifier').val(rollbase + "+" + this.rollData.careerBonus + "+" + this.rollData.mod + "+" +
|
||||||
if (modifierEl) modifierEl.value = rollbase + "+" + this.rollData.careerBonus + "+" + this.rollData.mod + "+" +
|
|
||||||
this.rollData.modRanged + "+" + this.rollData.weaponModifier + "-" + this.rollData.defence + "-" + this.rollData.modArmorMalus + "-" +
|
this.rollData.modRanged + "+" + this.rollData.weaponModifier + "-" + this.rollData.defence + "-" + this.rollData.modArmorMalus + "-" +
|
||||||
this.rollData.shieldMalus + "+" + this.rollData.attackModifier + "+" + this.rollData.appliedArmorMalus + "+" + effectModifier
|
this.rollData.shieldMalus + "+" + this.rollData.attackModifier + "+" + this.rollData.appliedArmorMalus + "+" + effectModifier)
|
||||||
|
|
||||||
// Rebuild list of applicable effects
|
// Rebuild lits of applicable effects
|
||||||
let selectEffects = ""
|
let selectEffects = ""
|
||||||
for (let effect of this.rollData.bolApplicableEffects) {
|
for (let effect of this.rollData.bolApplicableEffects) {
|
||||||
selectEffects += `<option value="${effect.id}" selected>${effect.name}</option>`
|
selectEffects += `<option value="${effect.id}" selected>${effect.name}</option>`
|
||||||
}
|
}
|
||||||
const effectsEl = document.querySelector('#applicable-effects')
|
$('#applicable-effects').html(selectEffects)
|
||||||
if (effectsEl) effectsEl.innerHTML = selectEffects
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
@@ -360,48 +360,46 @@ export class BoLRoll {
|
|||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
static updateArmorMalus(rollData) {
|
static updateArmorMalus(rollData) {
|
||||||
rollData.appliedArmorMalus = 0
|
rollData.appliedArmorMalus = 0
|
||||||
const agiEl = document.querySelector('#armor-agi-malus')
|
|
||||||
if (rollData.attribute.key == "agility") {
|
if (rollData.attribute.key == "agility") {
|
||||||
if (agiEl) agiEl.style.display = ''
|
$("#armor-agi-malus").show()
|
||||||
rollData.appliedArmorMalus += rollData.armorAgiMalus
|
rollData.appliedArmorMalus += rollData.armorAgiMalus
|
||||||
} else {
|
} else {
|
||||||
if (agiEl) agiEl.style.display = 'none'
|
$("#armor-agi-malus").hide()
|
||||||
}
|
}
|
||||||
const initEl = document.querySelector('#armor-init-malus')
|
|
||||||
if (rollData.aptitude && rollData.aptitude.key == "init") {
|
if (rollData.aptitude && rollData.aptitude.key == "init") {
|
||||||
if (initEl) initEl.style.display = ''
|
$("#armor-init-malus").show()
|
||||||
rollData.appliedArmorMalus += rollData.armorInitMalus
|
rollData.appliedArmorMalus += rollData.armorInitMalus
|
||||||
} else {
|
} else {
|
||||||
if (initEl) initEl.style.display = 'none'
|
$("#armor-init-malus").hide()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------ -------------- */
|
/* ------------------------------ -------------- */
|
||||||
static updatePPCost(rollData) {
|
static updatePPCost(rollData) {
|
||||||
const el = document.querySelector('#ppcost')
|
$('#ppcost').html(rollData.ppCost + " + Armor(" + rollData.ppCostArmor + ")=" + Number(rollData.ppCost + rollData.ppCostArmor))
|
||||||
if (el) el.innerHTML = rollData.ppCost + " + Armor(" + rollData.ppCostArmor + ")=" + Number(rollData.ppCost + rollData.ppCostArmor)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------ -------------- */
|
/* ------------------------------ -------------- */
|
||||||
static rollDialogListener(html) {
|
static rollDialogListener(html) {
|
||||||
|
|
||||||
this.updateTotalDice()
|
this.updateTotalDice()
|
||||||
|
|
||||||
html.querySelector('#optcond')?.addEventListener('change', (event) => {
|
html.find('#optcond').change((event) => { // Dynamic change of PP cost of spell
|
||||||
let pp = BoLUtility.computeSpellCost(this.rollData.spell, event.currentTarget.selectedOptions.length)
|
let pp = BoLUtility.computeSpellCost(this.rollData.spell, event.currentTarget.selectedOptions.length)
|
||||||
this.rollData.ppCost = pp
|
this.rollData.ppCost = pp
|
||||||
this.updatePPCost(this.rollData)
|
this.updatePPCost(this.rollData)
|
||||||
})
|
})
|
||||||
|
|
||||||
html.querySelector('#mod')?.addEventListener('change', (event) => {
|
html.find('#mod').change((event) => {
|
||||||
this.rollData.mod = Number(event.currentTarget.value)
|
this.rollData.mod = Number(event.currentTarget.value)
|
||||||
this.updateTotalDice()
|
this.updateTotalDice()
|
||||||
})
|
})
|
||||||
html.querySelector('#modRanged')?.addEventListener('change', (event) => {
|
html.find('#modRanged').change((event) => {
|
||||||
this.rollData.modRanged = Number(event.currentTarget.value)
|
this.rollData.modRanged = Number(event.currentTarget.value)
|
||||||
this.updateTotalDice()
|
this.updateTotalDice()
|
||||||
})
|
})
|
||||||
|
|
||||||
html.querySelector('#attr')?.addEventListener('change', (event) => {
|
html.find('#attr').change((event) => {
|
||||||
let attrKey = event.currentTarget.value
|
let attrKey = event.currentTarget.value
|
||||||
let actor = BoLUtility.getActorFromRollData(this.rollData)
|
let actor = BoLUtility.getActorFromRollData(this.rollData)
|
||||||
this.rollData.attribute = foundry.utils.duplicate(actor.system.attributes[attrKey])
|
this.rollData.attribute = foundry.utils.duplicate(actor.system.attributes[attrKey])
|
||||||
@@ -409,7 +407,7 @@ export class BoLRoll {
|
|||||||
this.rollData.bolApplicableEffects = this.updateApplicableEffects(this.rollData)
|
this.rollData.bolApplicableEffects = this.updateApplicableEffects(this.rollData)
|
||||||
this.updateTotalDice()
|
this.updateTotalDice()
|
||||||
})
|
})
|
||||||
html.querySelector('#apt')?.addEventListener('change', (event) => {
|
html.find('#apt').change((event) => {
|
||||||
let aptKey = event.currentTarget.value
|
let aptKey = event.currentTarget.value
|
||||||
let actor = BoLUtility.getActorFromRollData(this.rollData)
|
let actor = BoLUtility.getActorFromRollData(this.rollData)
|
||||||
this.rollData.aptitude = foundry.utils.duplicate(actor.system.aptitudes[aptKey])
|
this.rollData.aptitude = foundry.utils.duplicate(actor.system.aptitudes[aptKey])
|
||||||
@@ -418,58 +416,65 @@ export class BoLRoll {
|
|||||||
this.updateTotalDice()
|
this.updateTotalDice()
|
||||||
})
|
})
|
||||||
|
|
||||||
html.querySelector('#applyShieldMalus')?.addEventListener('click', (event) => {
|
html.find('#applyShieldMalus').click((event) => {
|
||||||
this.rollData.shieldMalus = event.currentTarget.checked ? this.rollData.shieldAttackMalus : 0
|
if (event.currentTarget.checked) {
|
||||||
|
this.rollData.shieldMalus = this.rollData.shieldAttackMalus
|
||||||
|
} else {
|
||||||
|
this.rollData.shieldMalus = 0
|
||||||
|
}
|
||||||
this.updateTotalDice()
|
this.updateTotalDice()
|
||||||
})
|
})
|
||||||
|
|
||||||
html.querySelector('#career')?.addEventListener('change', (event) => {
|
html.find('#career').change((event) => {
|
||||||
let careers = Array.from(event.currentTarget.selectedOptions).map(o => o.value)
|
let careers = $('#career').val()
|
||||||
this.rollData.careerBonus = (!careers || careers.length == 0) ? 0 : Math.max(...careers.map(i => parseInt(i)))
|
this.rollData.careerBonus = (!careers || careers.length == 0) ? 0 : Math.max(...careers.map(i => parseInt(i)))
|
||||||
this.updateTotalDice()
|
this.updateTotalDice()
|
||||||
})
|
})
|
||||||
html.querySelector('#boon')?.addEventListener('change', (event) => {
|
html.find('#boon').change((event) => {
|
||||||
let boons = Array.from(event.currentTarget.selectedOptions).map(o => o.value)
|
let boons = $('#boon').val()
|
||||||
this.rollData.nbBoons = (!boons || boons.length == 0) ? 0 : boons.length
|
this.rollData.nbBoons = (!boons || boons.length == 0) ? 0 : boons.length
|
||||||
this.updateTotalDice()
|
this.updateTotalDice()
|
||||||
})
|
})
|
||||||
html.querySelector('#flaw')?.addEventListener('change', (event) => {
|
html.find('#flaw').change((event) => {
|
||||||
let flaws = Array.from(event.currentTarget.selectedOptions).map(o => o.value)
|
let flaws = $('#flaw').val()
|
||||||
this.rollData.nbFlaws = (!flaws || flaws.length == 0) ? 0 : flaws.length
|
this.rollData.nbFlaws = (!flaws || flaws.length == 0) ? 0 : flaws.length
|
||||||
this.updateTotalDice()
|
this.updateTotalDice()
|
||||||
})
|
})
|
||||||
html.querySelectorAll('.bdice').forEach(el => el.addEventListener('click', (event) => {
|
html.find('.bdice').click((event) => {
|
||||||
this.rollData.mDice = 0
|
this.rollData.mDice = 0
|
||||||
this.rollData.bDice = Number(event.currentTarget.value)
|
this.rollData.bDice = Number(event.currentTarget.value)
|
||||||
this.updateTotalDice()
|
this.updateTotalDice()
|
||||||
}))
|
})
|
||||||
html.querySelectorAll('.mdice').forEach(el => el.addEventListener('click', (event) => {
|
html.find('.mdice').click((event) => {
|
||||||
this.rollData.bDice = 0
|
this.rollData.bDice = 0
|
||||||
this.rollData.mDice = Number(event.currentTarget.value)
|
this.rollData.mDice = Number(event.currentTarget.value)
|
||||||
this.updateTotalDice()
|
this.updateTotalDice()
|
||||||
}))
|
})
|
||||||
html.querySelector('#horoscope-bonus-applied')?.addEventListener('change', (event) => {
|
html.find('#horoscope-bonus-applied').change((event) => {
|
||||||
this.rollData.selectedHoroscope = []
|
this.rollData.selectedHoroscope = []
|
||||||
for (let option of event.currentTarget.selectedOptions) {
|
for (let option of event.currentTarget.selectedOptions) {
|
||||||
this.rollData.selectedHoroscope.push(foundry.utils.duplicate(this.rollData.horoscopeBonusList[Number(option.index)]))
|
this.rollData.selectedHoroscope.push(foundry.utils.duplicate(this.rollData.horoscopeBonusList[Number(option.index)]))
|
||||||
}
|
}
|
||||||
let horoscopes = Array.from(event.currentTarget.selectedOptions).map(o => o.value)
|
let horoscopes = $('#horoscope-bonus-applied').val()
|
||||||
this.rollData.horoscopeBonus = (!horoscopes || horoscopes.length == 0) ? 0 : horoscopes.length
|
this.rollData.horoscopeBonus = (!horoscopes || horoscopes.length == 0) ? 0 : horoscopes.length
|
||||||
this.updateTotalDice()
|
this.updateTotalDice()
|
||||||
})
|
})
|
||||||
html.querySelector('#horoscope-malus-applied')?.addEventListener('change', (event) => {
|
|
||||||
|
html.find('#horoscope-malus-applied').change((event) => {
|
||||||
this.rollData.selectedHoroscope = []
|
this.rollData.selectedHoroscope = []
|
||||||
for (let option of event.currentTarget.selectedOptions) {
|
for (let option of event.currentTarget.selectedOptions) {
|
||||||
this.rollData.selectedHoroscope.push(foundry.utils.duplicate(this.rollData.horoscopeBonusList[Number(option.index)]))
|
this.rollData.selectedHoroscope.push(foundry.utils.duplicate(this.rollData.horoscopeBonusList[Number(option.index)]))
|
||||||
}
|
}
|
||||||
let horoscopes = Array.from(event.currentTarget.selectedOptions).map(o => o.value)
|
let horoscopes = $('#horoscope-malus-applied').val()
|
||||||
this.rollData.horoscopeMalus = (!horoscopes || horoscopes.length == 0) ? 0 : horoscopes.length
|
this.rollData.horoscopeMalus = (!horoscopes || horoscopes.length == 0) ? 0 : horoscopes.length
|
||||||
this.updateTotalDice()
|
this.updateTotalDice()
|
||||||
})
|
})
|
||||||
html.querySelector('#horoscope-group-applied')?.addEventListener('change', (event) => {
|
html.find('#horoscope-group-applied').change((event) => {
|
||||||
this.rollData.selectedGroupHoroscopeIndex = event.currentTarget.value
|
this.rollData.selectedGroupHoroscopeIndex = event.currentTarget.value
|
||||||
this.updateTotalDice()
|
this.updateTotalDice()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
@@ -547,47 +552,41 @@ export class BoLRoll {
|
|||||||
} else {
|
} else {
|
||||||
rollData.shieldMalus = 0
|
rollData.shieldMalus = 0
|
||||||
}
|
}
|
||||||
// Save & pre-initialize computed fields
|
// Save
|
||||||
this.rollData = rollData
|
this.rollData = rollData
|
||||||
this.updateTotalDice()
|
|
||||||
console.log("ROLLDATA", rollData)
|
console.log("ROLLDATA", rollData)
|
||||||
|
|
||||||
// Then display+process the dialog
|
// Then display+process the dialog
|
||||||
const rollOptionContent = await foundry.applications.handlebars.renderTemplate(rollOptionTpl, rollData);
|
const rollOptionContent = await foundry.applications.handlebars.renderTemplate(rollOptionTpl, rollData);
|
||||||
// Use Hooks to reliably get the rendered HTMLElement (renderDialogV2 receives (app, element, context))
|
let d = new Dialog({
|
||||||
Hooks.once('renderDialogV2', (app, element) => {
|
title: rollData.label,
|
||||||
element.classList.add('bol');
|
|
||||||
this.rollDialogListener(element);
|
|
||||||
});
|
|
||||||
return foundry.applications.api.DialogV2.wait({
|
|
||||||
window: { title: rollData.label },
|
|
||||||
content: rollOptionContent,
|
content: rollOptionContent,
|
||||||
rejectClose: false,
|
rollData: rollData,
|
||||||
buttons: [
|
render: html => this.rollDialogListener(html),
|
||||||
{
|
buttons: {
|
||||||
type: 'button',
|
cancel: {
|
||||||
|
icon: '<i class="fas fa-times"></i>',
|
||||||
label: game.i18n.localize("BOL.ui.cancel"),
|
label: game.i18n.localize("BOL.ui.cancel"),
|
||||||
icon: 'fas fa-times',
|
callback: () => {
|
||||||
action: 'cancel'
|
}
|
||||||
},
|
},
|
||||||
{
|
submit: {
|
||||||
type: 'submit',
|
icon: '<i class="fas fa-check"></i>',
|
||||||
label: game.i18n.localize("BOL.ui.submit"),
|
label: game.i18n.localize("BOL.ui.submit"),
|
||||||
icon: 'fas fa-check',
|
callback: (html) => {
|
||||||
action: 'submit',
|
|
||||||
callback: (event, button, dialog) => {
|
|
||||||
console.log("Submit Roll!!!!");
|
console.log("Submit Roll!!!!");
|
||||||
if (rollData.mode == 'spell' && rollData.ppCurrent < rollData.ppCost) {
|
if (rollData.mode == 'spell' && rollData.ppCurrent < rollData.ppCost) { // Check PP available
|
||||||
ui.notifications.warn("Pas assez de Points de Pouvoir !")
|
ui.notifications.warn("Pas assez de Points de Pouvoir !")
|
||||||
return false
|
return
|
||||||
}
|
}
|
||||||
rollData.registerInit = (rollData.aptitude && rollData.aptitude.key == 'init') ?
|
rollData.registerInit = (rollData.aptitude && rollData.aptitude.key == 'init') ? $('#register-init').is(":checked") : false;
|
||||||
(dialog.element.querySelector('#register-init')?.checked ?? false) : false;
|
|
||||||
|
|
||||||
const isMalus = (rollData.bmDice < 0)
|
const isMalus = (rollData.bmDice < 0)
|
||||||
let rollbase = rollData.attrValue + rollData.aptValue
|
|
||||||
if (rollData.weapon?.system.properties.onlymodifier) rollbase = 0
|
|
||||||
|
|
||||||
|
let rollbase = rollData.attrValue + rollData.aptValue
|
||||||
|
if (rollData.weapon?.system.properties.onlymodifier) {
|
||||||
|
rollbase = 0
|
||||||
|
}
|
||||||
let diceData = BoLUtility.getDiceData()
|
let diceData = BoLUtility.getDiceData()
|
||||||
let malusInit = rollData.combatData?.malusInit || 0
|
let malusInit = rollData.combatData?.malusInit || 0
|
||||||
const modifiers = rollbase + rollData.careerBonus + rollData.mod + rollData.weaponModifier - rollData.defence - rollData.modArmorMalus + rollData.shieldMalus + rollData.attackModifier + rollData.appliedArmorMalus + rollData.effectModifier - malusInit
|
const modifiers = rollbase + rollData.careerBonus + rollData.mod + rollData.weaponModifier - rollData.defence - rollData.modArmorMalus + rollData.shieldMalus + rollData.attackModifier + rollData.appliedArmorMalus + rollData.effectModifier - malusInit
|
||||||
@@ -600,8 +599,12 @@ export class BoLRoll {
|
|||||||
r.roll();
|
r.roll();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
},
|
||||||
}, { classes: ['bol', 'dialog'], width: 480 });
|
default: onEnter,
|
||||||
|
close: () => { }
|
||||||
|
}, this.options());
|
||||||
|
|
||||||
|
return d.render(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -695,15 +698,18 @@ export class BoLDefaultRoll {
|
|||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
async sendChatMessage() {
|
async sendChatMessage() {
|
||||||
const actor = BoLUtility.getActorFromRollData(this.rollData)
|
let actor = BoLUtility.getActorFromRollData(this.rollData)
|
||||||
const rollMode = game.settings.get("core", "rollMode")
|
this._buildChatMessage(this.rollData).then(async msgFlavor => {
|
||||||
const msgFlavor = await this._buildChatMessage(this.rollData)
|
//console.log("MSG", msgFlavor )
|
||||||
const msg = await this.rollData.roll.toMessage({
|
let msg = await this.rollData.roll.toMessage({
|
||||||
flavor: msgFlavor,
|
user: game.user.id,
|
||||||
speaker: ChatMessage.getSpeaker({ actor: actor }),
|
rollMode: game.settings.get("core", "rollMode"),
|
||||||
}, { rollMode })
|
flavor: msgFlavor,
|
||||||
this.rollData.roll = foundry.utils.duplicate(this.rollData.roll)
|
speaker: ChatMessage.getSpeaker({ actor: actor }),
|
||||||
if (msg) await msg.setFlag("world", "bol-roll-data", this.rollData)
|
})
|
||||||
|
this.rollData.roll = foundry.utils.duplicate(this.rollData.roll) // Remove object, keep data (v111 ready)
|
||||||
|
msg.setFlag("world", "bol-roll-data", this.rollData)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
@@ -747,12 +753,6 @@ export class BoLDefaultRoll {
|
|||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
async sendDamageMessage() {
|
async sendDamageMessage() {
|
||||||
let actor = BoLUtility.getActorFromRollData(this.rollData)
|
let actor = BoLUtility.getActorFromRollData(this.rollData)
|
||||||
// If no target, collect potential targets from active scene (excluding attacker)
|
|
||||||
if (!this.rollData.targetId && game.scenes.current) {
|
|
||||||
this.rollData.potentialTargets = game.scenes.current.tokens
|
|
||||||
.filter(t => t.actor && t.actor.id !== this.rollData.actorId)
|
|
||||||
.map(t => ({ id: t.id, actorId: t.actor.id, name: t.name, img: t.texture?.src || t.actor.img }))
|
|
||||||
}
|
|
||||||
this._buildDamageChatMessage(this.rollData).then(async msgFlavor => {
|
this._buildDamageChatMessage(this.rollData).then(async msgFlavor => {
|
||||||
let msg = await this.rollData.damageRoll.toMessage({
|
let msg = await this.rollData.damageRoll.toMessage({
|
||||||
user: game.user.id,
|
user: game.user.id,
|
||||||
|
|||||||
119
module/item/item-sheet.js
Normal file
119
module/item/item-sheet.js
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()]);
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
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"
|
|
||||||
@@ -1,192 +0,0 @@
|
|||||||
/**
|
|
||||||
* 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"];
|
|
||||||
}
|
|
||||||
@@ -1,173 +0,0 @@
|
|||||||
/**
|
|
||||||
* 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"];
|
|
||||||
}
|
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
/**
|
|
||||||
* 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"];
|
|
||||||
}
|
|
||||||
@@ -1,174 +0,0 @@
|
|||||||
/**
|
|
||||||
* 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"];
|
|
||||||
}
|
|
||||||
@@ -1,113 +0,0 @@
|
|||||||
/**
|
|
||||||
* 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"];
|
|
||||||
}
|
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
/**
|
|
||||||
* 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"];
|
|
||||||
}
|
|
||||||
@@ -237,11 +237,6 @@ export class BoLUtility {
|
|||||||
if (chatData.img.includes("/blank.png")) {
|
if (chatData.img.includes("/blank.png")) {
|
||||||
chatData.img = null;
|
chatData.img = null;
|
||||||
}
|
}
|
||||||
// For old-format weapon items lacking stat fields, apply defaults so the chat card can display them
|
|
||||||
if (chatData.system?.properties?.weapon && !chatData.system.properties.damage) {
|
|
||||||
const defaults = game.bol.config.defaultNaturalWeapon?.properties ?? {};
|
|
||||||
chatData.system.properties = Object.assign(foundry.utils.duplicate(defaults), chatData.system.properties);
|
|
||||||
}
|
|
||||||
// JSON object for easy creation
|
// JSON object for easy creation
|
||||||
chatData.jsondata = JSON.stringify(
|
chatData.jsondata = JSON.stringify(
|
||||||
{
|
{
|
||||||
@@ -249,7 +244,7 @@ export class BoLUtility {
|
|||||||
payload: chatData,
|
payload: chatData,
|
||||||
});
|
});
|
||||||
|
|
||||||
foundry.applications.handlebars.renderTemplate('systems/bol/templates/item/post-item.hbs', chatData).then(html => {
|
renderTemplate('systems/bol/templates/item/post-item.hbs', chatData).then(html => {
|
||||||
let chatOptions = BoLUtility.chatDataSetup(html);
|
let chatOptions = BoLUtility.chatDataSetup(html);
|
||||||
ChatMessage.create(chatOptions)
|
ChatMessage.create(chatOptions)
|
||||||
});
|
});
|
||||||
@@ -395,16 +390,6 @@ export class BoLUtility {
|
|||||||
BoLUtility.sendAttackSuccess(rollData)
|
BoLUtility.sendAttackSuccess(rollData)
|
||||||
});
|
});
|
||||||
|
|
||||||
html.on("click", '.chat-target-select', event => {
|
|
||||||
event.preventDefault()
|
|
||||||
const btn = event.currentTarget
|
|
||||||
let rollData = BoLUtility.getRollDataFromMessage(event)
|
|
||||||
rollData.targetId = btn.dataset.tokenId
|
|
||||||
rollData.defenderId = btn.dataset.actorId
|
|
||||||
BoLUtility.cleanupButtons(rollData.applyId)
|
|
||||||
BoLUtility.sendAttackSuccess(rollData)
|
|
||||||
});
|
|
||||||
|
|
||||||
html.on("click", '.chat-damage-roll', event => {
|
html.on("click", '.chat-damage-roll', event => {
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
let rollData = BoLUtility.getRollDataFromMessage(event)
|
let rollData = BoLUtility.getRollDataFromMessage(event)
|
||||||
@@ -497,21 +482,20 @@ export class BoLUtility {
|
|||||||
|
|
||||||
if (defenseMode == 'damage-with-armor') {
|
if (defenseMode == 'damage-with-armor') {
|
||||||
let armorFormula = defender.getArmorFormula()
|
let armorFormula = defender.getArmorFormula()
|
||||||
if (armorFormula === "0") {
|
rollData.armorProtect = 0
|
||||||
rollData.armorProtect = 0
|
armorFormula = String(armorFormula) || "0"
|
||||||
} else {
|
if (armorFormula && armorFormula != "0" ) {
|
||||||
rollData.rollArmor = new Roll(armorFormula)
|
rollData.rollArmor = new Roll(armorFormula)
|
||||||
await rollData.rollArmor.roll()
|
await rollData.rollArmor.roll()
|
||||||
let msg = await rollData.rollArmor.toMessage({ flavor: game.i18n.localize("BOL.chat.armorRoll") + " : " + armorFormula })
|
let msg = await rollData.rollArmor.toMessage({ flavor: game.i18n.localize("BOL.chat.armorRoll") + " : " + armorFormula });
|
||||||
if (game.dice3d && msg) {
|
if (game.dice3d) { // wait animation end when DsN is there
|
||||||
await game.dice3d.waitFor3DAnimationByMessageID(msg.id)
|
await game.dice3d.waitFor3DAnimationByMessageID(msg.id);
|
||||||
}
|
}
|
||||||
rollData.armorProtect = (rollData.rollArmor.total < 0) ? 0 : rollData.rollArmor.total
|
rollData.armorProtect = (rollData.rollArmor.total < 0) ? 0 : rollData.rollArmor.total
|
||||||
}
|
}
|
||||||
rollData.finalDamage = rollData.damageTotal - rollData.armorProtect
|
rollData.finalDamage = rollData.damageTotal - rollData.armorProtect
|
||||||
rollData.finalDamage = (rollData.finalDamage < 0) ? 0 : rollData.finalDamage
|
rollData.finalDamage = (rollData.finalDamage < 0) ? 0 : rollData.finalDamage
|
||||||
await defender.sufferDamage(rollData.finalDamage)
|
await defender.sufferDamage(rollData.finalDamage)
|
||||||
console.log("Armor roll -> result ", rollData)
|
|
||||||
}
|
}
|
||||||
if (defenseMode == 'damage-without-armor') {
|
if (defenseMode == 'damage-without-armor') {
|
||||||
rollData.finalDamage = rollData.damageTotal
|
rollData.finalDamage = rollData.damageTotal
|
||||||
@@ -519,17 +503,9 @@ export class BoLUtility {
|
|||||||
}
|
}
|
||||||
if (defenseMode == 'hero-reduce-damage') {
|
if (defenseMode == 'hero-reduce-damage') {
|
||||||
let armorFormula = defender.getArmorFormula()
|
let armorFormula = defender.getArmorFormula()
|
||||||
if (armorFormula === "0") {
|
rollData.rollArmor = new Roll(armorFormula)
|
||||||
rollData.armorProtect = 0
|
await rollData.rollArmor.roll()
|
||||||
} else {
|
rollData.armorProtect = (rollData.rollArmor.total < 0) ? 0 : rollData.rollArmor.total
|
||||||
rollData.rollArmor = new Roll(armorFormula)
|
|
||||||
await rollData.rollArmor.roll()
|
|
||||||
let msg = await rollData.rollArmor.toMessage({ flavor: game.i18n.localize("BOL.chat.armorRoll") + " : " + armorFormula })
|
|
||||||
if (game.dice3d && msg) {
|
|
||||||
await game.dice3d.waitFor3DAnimationByMessageID(msg.id)
|
|
||||||
}
|
|
||||||
rollData.armorProtect = (rollData.rollArmor.total < 0) ? 0 : rollData.rollArmor.total
|
|
||||||
}
|
|
||||||
rollData.rollHero = new Roll("1d6")
|
rollData.rollHero = new Roll("1d6")
|
||||||
await rollData.rollHero.roll()
|
await rollData.rollHero.roll()
|
||||||
rollData.finalDamage = rollData.damageTotal - rollData.rollHero.total - rollData.armorProtect
|
rollData.finalDamage = rollData.damageTotal - rollData.rollHero.total - rollData.armorProtect
|
||||||
@@ -564,13 +540,13 @@ export class BoLUtility {
|
|||||||
ChatMessage.create({
|
ChatMessage.create({
|
||||||
alias: defender.name,
|
alias: defender.name,
|
||||||
whisper: BoLUtility.getWhisperRecipientsAndGMs(defender.name),
|
whisper: BoLUtility.getWhisperRecipientsAndGMs(defender.name),
|
||||||
content: await foundry.applications.handlebars.renderTemplate('systems/bol/templates/chat/rolls/defense-result-card.hbs', damageResults)
|
content: await renderTemplate('systems/bol/templates/chat/rolls/defense-result-card.hbs', damageResults)
|
||||||
})
|
})
|
||||||
console.log("Defender data : ", defenderUser)
|
console.log("Defender data : ", defenderUser)
|
||||||
ChatMessage.create({
|
ChatMessage.create({
|
||||||
alias: defender.name,
|
alias: defender.name,
|
||||||
whisper: BoLUtility.getOtherWhisperRecipients(defenderUser?.name),
|
whisper: BoLUtility.getOtherWhisperRecipients(defenderUser?.name),
|
||||||
content: await foundry.applications.handlebars.renderTemplate('systems/bol/templates/chat/rolls/defense-summary-card.hbs', damageResults)
|
content: await renderTemplate('systems/bol/templates/chat/rolls/defense-summary-card.hbs', damageResults)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -657,7 +633,7 @@ export class BoLUtility {
|
|||||||
let msg = await ChatMessage.create({
|
let msg = await ChatMessage.create({
|
||||||
alias: defender.name,
|
alias: defender.name,
|
||||||
whisper: BoLUtility.getWhisperRecipientsAndGMs(defender.name),
|
whisper: BoLUtility.getWhisperRecipientsAndGMs(defender.name),
|
||||||
content: await foundry.applications.handlebars.renderTemplate('systems/bol/templates/chat/rolls/defense-request-card.hbs', {
|
content: await renderTemplate('systems/bol/templates/chat/rolls/defense-request-card.hbs', {
|
||||||
attackId: rollData.id,
|
attackId: rollData.id,
|
||||||
attacker: rollData.attacker,
|
attacker: rollData.attacker,
|
||||||
defender: defender,
|
defender: defender,
|
||||||
|
|||||||
@@ -188,25 +188,25 @@ BOL.rangeModifiers = {
|
|||||||
"-8": "BOL.dialog.utmost"
|
"-8": "BOL.dialog.utmost"
|
||||||
}
|
}
|
||||||
|
|
||||||
BOL.difficultyModifiers = [
|
BOL.difficultyModifiers = {
|
||||||
{ value: "-12", label: "BOL.dialog.divine" },
|
"4": "BOL.dialog.soeasy",
|
||||||
{ value: "-11", label: "BOL.dialog.mythic11" },
|
"3": "BOL.dialog.soeasy3",
|
||||||
{ value: "-10", label: "BOL.dialog.mythic" },
|
"2": "BOL.dialog.veryeasy",
|
||||||
{ value: "-9", label: "BOL.dialog.heroic9" },
|
"1": "BOL.dialog.easy",
|
||||||
{ value: "-8", label: "BOL.dialog.heroic" },
|
"0": "BOL.dialog.moderate",
|
||||||
{ value: "-7", label: "BOL.dialog.formidable7" },
|
"-1": "BOL.dialog.hard",
|
||||||
{ value: "-6", label: "BOL.dialog.formidable" },
|
"-2": "BOL.dialog.tough",
|
||||||
{ value: "-5", label: "BOL.dialog.demanding5" },
|
"-3": "BOL.dialog.tough3",
|
||||||
{ value: "-4", label: "BOL.dialog.demanding" },
|
"-4": "BOL.dialog.demanding",
|
||||||
{ value: "-3", label: "BOL.dialog.tough3" },
|
"-5": "BOL.dialog.demanding5",
|
||||||
{ value: "-2", label: "BOL.dialog.tough" },
|
"-6": "BOL.dialog.formidable",
|
||||||
{ value: "-1", label: "BOL.dialog.hard" },
|
"-7": "BOL.dialog.formidable7",
|
||||||
{ value: "0", label: "BOL.dialog.moderate" },
|
"-8": "BOL.dialog.heroic",
|
||||||
{ value: "1", label: "BOL.dialog.easy" },
|
"-9": "BOL.dialog.heroic9",
|
||||||
{ value: "2", label: "BOL.dialog.veryeasy" },
|
"-10": "BOL.dialog.mythic",
|
||||||
{ value: "3", label: "BOL.dialog.soeasy3" },
|
"-11": "BOL.dialog.mythic11",
|
||||||
{ value: "4", label: "BOL.dialog.soeasy" },
|
"-12": "BOL.dialog.divine"
|
||||||
]
|
}
|
||||||
|
|
||||||
BOL.alchemyModifiers = {
|
BOL.alchemyModifiers = {
|
||||||
"2": "BOL.dialog.veryeasy",
|
"2": "BOL.dialog.veryeasy",
|
||||||
|
|||||||
@@ -52,7 +52,6 @@ export const preloadHandlebarsTemplates = async function () {
|
|||||||
"systems/bol/templates/chat/rolls/alchemy-roll-card.hbs",
|
"systems/bol/templates/chat/rolls/alchemy-roll-card.hbs",
|
||||||
"systems/bol/templates/chat/rolls/selected-horoscope-roll-card.hbs",
|
"systems/bol/templates/chat/rolls/selected-horoscope-roll-card.hbs",
|
||||||
"systems/bol/templates/chat/rolls/horoscope-roll-card.hbs",
|
"systems/bol/templates/chat/rolls/horoscope-roll-card.hbs",
|
||||||
"systems/bol/templates/chat/chat-welcome.hbs",
|
|
||||||
"systems/bol/templates/dialogs/aptitude-roll-part.hbs",
|
"systems/bol/templates/dialogs/aptitude-roll-part.hbs",
|
||||||
"systems/bol/templates/dialogs/attribute-roll-part.hbs",
|
"systems/bol/templates/dialogs/attribute-roll-part.hbs",
|
||||||
"systems/bol/templates/dialogs/mod-roll-part.hbs",
|
"systems/bol/templates/dialogs/mod-roll-part.hbs",
|
||||||
@@ -63,8 +62,7 @@ export const preloadHandlebarsTemplates = async function () {
|
|||||||
"systems/bol/templates/dialogs/flaws-roll-part.hbs",
|
"systems/bol/templates/dialogs/flaws-roll-part.hbs",
|
||||||
"systems/bol/templates/dialogs/total-roll-part.hbs",
|
"systems/bol/templates/dialogs/total-roll-part.hbs",
|
||||||
"systems/bol/templates/dialogs/fightoptions-roll-part.hbs",
|
"systems/bol/templates/dialogs/fightoptions-roll-part.hbs",
|
||||||
"systems/bol/templates/dialogs/horoscope-roll-part.hbs",
|
"systems/bol/templates/dialogs/horoscope-roll-part.hbs"
|
||||||
"systems/bol/templates/apps/character-summary-template.html"
|
|
||||||
];
|
];
|
||||||
|
|
||||||
// Load the template parts
|
// Load the template parts
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
MANIFEST-001105
|
MANIFEST-000990
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
2026/03/31-20:06:53.991987 7ff9c7fff6c0 Recovering log #1103
|
2026/01/19-19:47:49.729596 7f14da7fc6c0 Recovering log #988
|
||||||
2026/03/31-20:06:54.001305 7ff9c7fff6c0 Delete type=3 #1101
|
2026/01/19-19:47:49.739434 7f14da7fc6c0 Delete type=3 #986
|
||||||
2026/03/31-20:06:54.001357 7ff9c7fff6c0 Delete type=0 #1103
|
2026/01/19-19:47:49.739512 7f14da7fc6c0 Delete type=0 #988
|
||||||
2026/03/31-20:07:15.402162 7ff7477ef6c0 Level-0 table #1108: started
|
2026/01/19-20:19:02.579851 7f1243fff6c0 Level-0 table #993: started
|
||||||
2026/03/31-20:07:15.402189 7ff7477ef6c0 Level-0 table #1108: 0 bytes OK
|
2026/01/19-20:19:02.579872 7f1243fff6c0 Level-0 table #993: 0 bytes OK
|
||||||
2026/03/31-20:07:15.409398 7ff7477ef6c0 Delete type=0 #1106
|
2026/01/19-20:19:02.585797 7f1243fff6c0 Delete type=0 #991
|
||||||
2026/03/31-20:07:15.409627 7ff7477ef6c0 Manual compaction at level-0 from '!journal!3xJg1rCxnWvEmoxS' @ 72057594037927935 : 1 .. '!journal.pages!veAAxCtCKcFIsnln.0kUgZspxXO7VS8bd' @ 0 : 0; will stop at (end)
|
2026/01/19-20:19:02.586018 7f1243fff6c0 Manual compaction at level-0 from '!journal!3xJg1rCxnWvEmoxS' @ 72057594037927935 : 1 .. '!journal.pages!veAAxCtCKcFIsnln.0kUgZspxXO7VS8bd' @ 0 : 0; will stop at (end)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
2026/03/31-14:46:22.078470 7ff9c7fff6c0 Recovering log #1099
|
2026/01/18-20:07:47.845406 7f14d8ff96c0 Recovering log #984
|
||||||
2026/03/31-14:46:22.102288 7ff9c7fff6c0 Delete type=3 #1097
|
2026/01/18-20:07:47.861224 7f14d8ff96c0 Delete type=3 #982
|
||||||
2026/03/31-14:46:22.102356 7ff9c7fff6c0 Delete type=0 #1099
|
2026/01/18-20:07:47.861280 7f14d8ff96c0 Delete type=0 #984
|
||||||
2026/03/31-14:51:39.421905 7ff7477ef6c0 Level-0 table #1104: started
|
2026/01/18-20:13:44.130598 7f1243fff6c0 Level-0 table #989: started
|
||||||
2026/03/31-14:51:39.421933 7ff7477ef6c0 Level-0 table #1104: 0 bytes OK
|
2026/01/18-20:13:44.130625 7f1243fff6c0 Level-0 table #989: 0 bytes OK
|
||||||
2026/03/31-14:51:39.492511 7ff7477ef6c0 Delete type=0 #1102
|
2026/01/18-20:13:44.157241 7f1243fff6c0 Delete type=0 #987
|
||||||
2026/03/31-14:51:39.632201 7ff7477ef6c0 Manual compaction at level-0 from '!journal!3xJg1rCxnWvEmoxS' @ 72057594037927935 : 1 .. '!journal.pages!veAAxCtCKcFIsnln.0kUgZspxXO7VS8bd' @ 0 : 0; will stop at (end)
|
2026/01/18-20:13:44.192634 7f1243fff6c0 Manual compaction at level-0 from '!journal!3xJg1rCxnWvEmoxS' @ 72057594037927935 : 1 .. '!journal.pages!veAAxCtCKcFIsnln.0kUgZspxXO7VS8bd' @ 0 : 0; will stop at (end)
|
||||||
|
|||||||
BIN
packs/aides-de-jeu/MANIFEST-000990
Normal file
BIN
packs/aides-de-jeu/MANIFEST-000990
Normal file
Binary file not shown.
Binary file not shown.
@@ -1 +1 @@
|
|||||||
MANIFEST-001010
|
MANIFEST-000895
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
2026/03/31-20:06:53.966374 7ff9fd1fe6c0 Recovering log #1008
|
2026/01/19-19:47:49.702991 7f14d97fa6c0 Recovering log #893
|
||||||
2026/03/31-20:06:53.976141 7ff9fd1fe6c0 Delete type=3 #1006
|
2026/01/19-19:47:49.714316 7f14d97fa6c0 Delete type=3 #891
|
||||||
2026/03/31-20:06:53.976208 7ff9fd1fe6c0 Delete type=0 #1008
|
2026/01/19-19:47:49.714383 7f14d97fa6c0 Delete type=0 #893
|
||||||
2026/03/31-20:07:15.381727 7ff7477ef6c0 Level-0 table #1013: started
|
2026/01/19-20:19:02.560145 7f1243fff6c0 Level-0 table #898: started
|
||||||
2026/03/31-20:07:15.381754 7ff7477ef6c0 Level-0 table #1013: 0 bytes OK
|
2026/01/19-20:19:02.560173 7f1243fff6c0 Level-0 table #898: 0 bytes OK
|
||||||
2026/03/31-20:07:15.388075 7ff7477ef6c0 Delete type=0 #1011
|
2026/01/19-20:19:02.566093 7f1243fff6c0 Delete type=0 #896
|
||||||
2026/03/31-20:07:15.409588 7ff7477ef6c0 Manual compaction at level-0 from '!items!G3dZTHIabA3LA1hY' @ 72057594037927935 : 1 .. '!items!xhEcsi3WHjbt2ro9' @ 0 : 0; will stop at (end)
|
2026/01/19-20:19:02.585964 7f1243fff6c0 Manual compaction at level-0 from '!items!G3dZTHIabA3LA1hY' @ 72057594037927935 : 1 .. '!items!xhEcsi3WHjbt2ro9' @ 0 : 0; will stop at (end)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
2026/03/31-14:46:22.050419 7ff9fd9ff6c0 Recovering log #1004
|
2026/01/18-20:07:47.807797 7f14d9ffb6c0 Recovering log #889
|
||||||
2026/03/31-14:46:22.061129 7ff9fd9ff6c0 Delete type=3 #1002
|
2026/01/18-20:07:47.824331 7f14d9ffb6c0 Delete type=3 #887
|
||||||
2026/03/31-14:46:22.061186 7ff9fd9ff6c0 Delete type=0 #1004
|
2026/01/18-20:07:47.824381 7f14d9ffb6c0 Delete type=0 #889
|
||||||
2026/03/31-14:51:39.282491 7ff7477ef6c0 Level-0 table #1009: started
|
2026/01/18-20:13:44.157350 7f1243fff6c0 Level-0 table #894: started
|
||||||
2026/03/31-14:51:39.282521 7ff7477ef6c0 Level-0 table #1009: 0 bytes OK
|
2026/01/18-20:13:44.157372 7f1243fff6c0 Level-0 table #894: 0 bytes OK
|
||||||
2026/03/31-14:51:39.343764 7ff7477ef6c0 Delete type=0 #1007
|
2026/01/18-20:13:44.192480 7f1243fff6c0 Delete type=0 #892
|
||||||
2026/03/31-14:51:39.421893 7ff7477ef6c0 Manual compaction at level-0 from '!items!G3dZTHIabA3LA1hY' @ 72057594037927935 : 1 .. '!items!xhEcsi3WHjbt2ro9' @ 0 : 0; will stop at (end)
|
2026/01/18-20:13:44.192647 7f1243fff6c0 Manual compaction at level-0 from '!items!G3dZTHIabA3LA1hY' @ 72057594037927935 : 1 .. '!items!xhEcsi3WHjbt2ro9' @ 0 : 0; will stop at (end)
|
||||||
|
|||||||
BIN
packs/armors/MANIFEST-000895
Normal file
BIN
packs/armors/MANIFEST-000895
Normal file
Binary file not shown.
Binary file not shown.
@@ -1 +1 @@
|
|||||||
MANIFEST-001104
|
MANIFEST-000989
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
2026/03/31-20:06:53.857244 7ff9c7fff6c0 Recovering log #1102
|
2026/01/19-19:47:49.594444 7f14d8ff96c0 Recovering log #987
|
||||||
2026/03/31-20:06:53.867361 7ff9c7fff6c0 Delete type=3 #1100
|
2026/01/19-19:47:49.605020 7f14d8ff96c0 Delete type=3 #985
|
||||||
2026/03/31-20:06:53.867406 7ff9c7fff6c0 Delete type=0 #1102
|
2026/01/19-19:47:49.605095 7f14d8ff96c0 Delete type=0 #987
|
||||||
2026/03/31-20:07:15.333382 7ff7477ef6c0 Level-0 table #1107: started
|
2026/01/19-20:19:02.521702 7f1243fff6c0 Level-0 table #992: started
|
||||||
2026/03/31-20:07:15.333411 7ff7477ef6c0 Level-0 table #1107: 0 bytes OK
|
2026/01/19-20:19:02.521733 7f1243fff6c0 Level-0 table #992: 0 bytes OK
|
||||||
2026/03/31-20:07:15.339801 7ff7477ef6c0 Delete type=0 #1105
|
2026/01/19-20:19:02.528339 7f1243fff6c0 Delete type=0 #990
|
||||||
2026/03/31-20:07:15.353373 7ff7477ef6c0 Manual compaction at level-0 from '!items!039ZF3E3MtAGwbiX' @ 72057594037927935 : 1 .. '!items!zgspy1QKaxdEetEw' @ 0 : 0; will stop at (end)
|
2026/01/19-20:19:02.534634 7f1243fff6c0 Manual compaction at level-0 from '!items!039ZF3E3MtAGwbiX' @ 72057594037927935 : 1 .. '!items!zgspy1QKaxdEetEw' @ 0 : 0; will stop at (end)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
2026/03/31-14:46:21.936175 7ff9fc9fd6c0 Recovering log #1098
|
2026/01/18-20:07:47.640110 7f14da7fc6c0 Recovering log #983
|
||||||
2026/03/31-14:46:21.946959 7ff9fc9fd6c0 Delete type=3 #1096
|
2026/01/18-20:07:47.659075 7f14da7fc6c0 Delete type=3 #981
|
||||||
2026/03/31-14:46:21.947024 7ff9fc9fd6c0 Delete type=0 #1098
|
2026/01/18-20:07:47.659147 7f14da7fc6c0 Delete type=0 #983
|
||||||
2026/03/31-14:51:38.889578 7ff7477ef6c0 Level-0 table #1103: started
|
2026/01/18-20:13:43.881522 7f1243fff6c0 Level-0 table #988: started
|
||||||
2026/03/31-14:51:38.889609 7ff7477ef6c0 Level-0 table #1103: 0 bytes OK
|
2026/01/18-20:13:43.881548 7f1243fff6c0 Level-0 table #988: 0 bytes OK
|
||||||
2026/03/31-14:51:38.959453 7ff7477ef6c0 Delete type=0 #1101
|
2026/01/18-20:13:43.921371 7f1243fff6c0 Delete type=0 #986
|
||||||
2026/03/31-14:51:39.078798 7ff7477ef6c0 Manual compaction at level-0 from '!items!039ZF3E3MtAGwbiX' @ 72057594037927935 : 1 .. '!items!zgspy1QKaxdEetEw' @ 0 : 0; will stop at (end)
|
2026/01/18-20:13:43.921513 7f1243fff6c0 Manual compaction at level-0 from '!items!039ZF3E3MtAGwbiX' @ 72057594037927935 : 1 .. '!items!zgspy1QKaxdEetEw' @ 0 : 0; will stop at (end)
|
||||||
|
|||||||
BIN
packs/boons/MANIFEST-000989
Normal file
BIN
packs/boons/MANIFEST-000989
Normal file
Binary file not shown.
Binary file not shown.
@@ -1 +1 @@
|
|||||||
MANIFEST-001103
|
MANIFEST-000988
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
2026/03/31-20:06:53.872789 7ff9fc9fd6c0 Recovering log #1101
|
2026/01/19-19:47:49.609310 7f14da7fc6c0 Recovering log #986
|
||||||
2026/03/31-20:06:53.882612 7ff9fc9fd6c0 Delete type=3 #1099
|
2026/01/19-19:47:49.619302 7f14da7fc6c0 Delete type=3 #984
|
||||||
2026/03/31-20:06:53.882655 7ff9fc9fd6c0 Delete type=0 #1101
|
2026/01/19-19:47:49.619373 7f14da7fc6c0 Delete type=0 #986
|
||||||
2026/03/31-20:07:15.346737 7ff7477ef6c0 Level-0 table #1106: started
|
2026/01/19-20:19:02.515027 7f1243fff6c0 Level-0 table #991: started
|
||||||
2026/03/31-20:07:15.346766 7ff7477ef6c0 Level-0 table #1106: 0 bytes OK
|
2026/01/19-20:19:02.515048 7f1243fff6c0 Level-0 table #991: 0 bytes OK
|
||||||
2026/03/31-20:07:15.353211 7ff7477ef6c0 Delete type=0 #1104
|
2026/01/19-20:19:02.521555 7f1243fff6c0 Delete type=0 #989
|
||||||
2026/03/31-20:07:15.353392 7ff7477ef6c0 Manual compaction at level-0 from '!items!CoqlfsDV1gL5swbK' @ 72057594037927935 : 1 .. '!items!yofwG0YrsL902G77' @ 0 : 0; will stop at (end)
|
2026/01/19-20:19:02.534623 7f1243fff6c0 Manual compaction at level-0 from '!items!CoqlfsDV1gL5swbK' @ 72057594037927935 : 1 .. '!items!yofwG0YrsL902G77' @ 0 : 0; will stop at (end)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
2026/03/31-14:46:21.951356 7ff9fd1fe6c0 Recovering log #1097
|
2026/01/18-20:07:47.664234 7f14d8ff96c0 Recovering log #982
|
||||||
2026/03/31-14:46:21.961416 7ff9fd1fe6c0 Delete type=3 #1095
|
2026/01/18-20:07:47.679427 7f14d8ff96c0 Delete type=3 #980
|
||||||
2026/03/31-14:46:21.961501 7ff9fd1fe6c0 Delete type=0 #1097
|
2026/01/18-20:07:47.679484 7f14d8ff96c0 Delete type=0 #982
|
||||||
2026/03/31-14:51:38.959612 7ff7477ef6c0 Level-0 table #1102: started
|
2026/01/18-20:13:43.851971 7f1243fff6c0 Level-0 table #987: started
|
||||||
2026/03/31-14:51:38.959651 7ff7477ef6c0 Level-0 table #1102: 0 bytes OK
|
2026/01/18-20:13:43.851994 7f1243fff6c0 Level-0 table #987: 0 bytes OK
|
||||||
2026/03/31-14:51:39.018752 7ff7477ef6c0 Delete type=0 #1100
|
2026/01/18-20:13:43.881382 7f1243fff6c0 Delete type=0 #985
|
||||||
2026/03/31-14:51:39.143657 7ff7477ef6c0 Manual compaction at level-0 from '!items!CoqlfsDV1gL5swbK' @ 72057594037927935 : 1 .. '!items!yofwG0YrsL902G77' @ 0 : 0; will stop at (end)
|
2026/01/18-20:13:43.921506 7f1243fff6c0 Manual compaction at level-0 from '!items!CoqlfsDV1gL5swbK' @ 72057594037927935 : 1 .. '!items!yofwG0YrsL902G77' @ 0 : 0; will stop at (end)
|
||||||
|
|||||||
BIN
packs/boonsflawscreatures/MANIFEST-000988
Normal file
BIN
packs/boonsflawscreatures/MANIFEST-000988
Normal file
Binary file not shown.
Binary file not shown.
@@ -1 +1 @@
|
|||||||
MANIFEST-001103
|
MANIFEST-000988
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
2026/03/31-20:06:53.899920 7ff9fd9ff6c0 Recovering log #1101
|
2026/01/19-19:47:49.635172 7f14d8ff96c0 Recovering log #986
|
||||||
2026/03/31-20:06:53.909847 7ff9fd9ff6c0 Delete type=3 #1099
|
2026/01/19-19:47:49.644889 7f14d8ff96c0 Delete type=3 #984
|
||||||
2026/03/31-20:06:53.909916 7ff9fd9ff6c0 Delete type=0 #1101
|
2026/01/19-19:47:49.644941 7f14d8ff96c0 Delete type=0 #986
|
||||||
2026/03/31-20:07:15.339949 7ff7477ef6c0 Level-0 table #1106: started
|
2026/01/19-20:19:02.508864 7f1243fff6c0 Level-0 table #991: started
|
||||||
2026/03/31-20:07:15.339973 7ff7477ef6c0 Level-0 table #1106: 0 bytes OK
|
2026/01/19-20:19:02.508913 7f1243fff6c0 Level-0 table #991: 0 bytes OK
|
||||||
2026/03/31-20:07:15.346571 7ff7477ef6c0 Delete type=0 #1104
|
2026/01/19-20:19:02.514913 7f1243fff6c0 Delete type=0 #989
|
||||||
2026/03/31-20:07:15.353383 7ff7477ef6c0 Manual compaction at level-0 from '!items!4S4xAfMXGnuU0O1a' @ 72057594037927935 : 1 .. '!items!zxY3sW0iCJBvwjOS' @ 0 : 0; will stop at (end)
|
2026/01/19-20:19:02.534608 7f1243fff6c0 Manual compaction at level-0 from '!items!4S4xAfMXGnuU0O1a' @ 72057594037927935 : 1 .. '!items!zxY3sW0iCJBvwjOS' @ 0 : 0; will stop at (end)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
2026/03/31-14:46:21.979659 7ff9fc9fd6c0 Recovering log #1097
|
2026/01/18-20:07:47.704039 7f14d8ff96c0 Recovering log #982
|
||||||
2026/03/31-14:46:21.989353 7ff9fc9fd6c0 Delete type=3 #1095
|
2026/01/18-20:07:47.721242 7f14d8ff96c0 Delete type=3 #980
|
||||||
2026/03/31-14:46:21.989419 7ff9fc9fd6c0 Delete type=0 #1097
|
2026/01/18-20:07:47.721902 7f14d8ff96c0 Delete type=0 #982
|
||||||
2026/03/31-14:51:38.683653 7ff7477ef6c0 Level-0 table #1102: started
|
2026/01/18-20:13:43.777269 7f1243fff6c0 Level-0 table #987: started
|
||||||
2026/03/31-14:51:38.683703 7ff7477ef6c0 Level-0 table #1102: 0 bytes OK
|
2026/01/18-20:13:43.777312 7f1243fff6c0 Level-0 table #987: 0 bytes OK
|
||||||
2026/03/31-14:51:38.749228 7ff7477ef6c0 Delete type=0 #1100
|
2026/01/18-20:13:43.819988 7f1243fff6c0 Delete type=0 #985
|
||||||
2026/03/31-14:51:38.889551 7ff7477ef6c0 Manual compaction at level-0 from '!items!4S4xAfMXGnuU0O1a' @ 72057594037927935 : 1 .. '!items!zxY3sW0iCJBvwjOS' @ 0 : 0; will stop at (end)
|
2026/01/18-20:13:43.921486 7f1243fff6c0 Manual compaction at level-0 from '!items!4S4xAfMXGnuU0O1a' @ 72057594037927935 : 1 .. '!items!zxY3sW0iCJBvwjOS' @ 0 : 0; will stop at (end)
|
||||||
|
|||||||
BIN
packs/careers/MANIFEST-000988
Normal file
BIN
packs/careers/MANIFEST-000988
Normal file
Binary file not shown.
Binary file not shown.
@@ -1 +1 @@
|
|||||||
MANIFEST-001101
|
MANIFEST-000986
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
2026/03/31-20:06:54.082205 7ff9fc9fd6c0 Recovering log #1099
|
2026/01/19-19:47:49.822315 7f14d9ffb6c0 Recovering log #984
|
||||||
2026/03/31-20:06:54.093327 7ff9fc9fd6c0 Delete type=3 #1097
|
2026/01/19-19:47:49.833348 7f14d9ffb6c0 Delete type=3 #982
|
||||||
2026/03/31-20:06:54.093384 7ff9fc9fd6c0 Delete type=0 #1099
|
2026/01/19-19:47:49.833401 7f14d9ffb6c0 Delete type=0 #984
|
||||||
2026/03/31-20:07:15.444437 7ff7477ef6c0 Level-0 table #1104: started
|
2026/01/19-20:19:02.619154 7f1243fff6c0 Level-0 table #989: started
|
||||||
2026/03/31-20:07:15.444468 7ff7477ef6c0 Level-0 table #1104: 0 bytes OK
|
2026/01/19-20:19:02.619176 7f1243fff6c0 Level-0 table #989: 0 bytes OK
|
||||||
2026/03/31-20:07:15.450792 7ff7477ef6c0 Delete type=0 #1102
|
2026/01/19-20:19:02.626822 7f1243fff6c0 Delete type=0 #987
|
||||||
2026/03/31-20:07:15.465290 7ff7477ef6c0 Manual compaction at level-0 from '!items!6fTZ6hOKR4pWbWOe' @ 72057594037927935 : 1 .. '!items!zwSNMO9HpiqUCMt8' @ 0 : 0; will stop at (end)
|
2026/01/19-20:19:02.639748 7f1243fff6c0 Manual compaction at level-0 from '!items!6fTZ6hOKR4pWbWOe' @ 72057594037927935 : 1 .. '!items!zwSNMO9HpiqUCMt8' @ 0 : 0; will stop at (end)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
2026/03/31-14:46:22.190057 7ff9fd1fe6c0 Recovering log #1095
|
2026/01/18-20:07:48.004635 7f14d9ffb6c0 Recovering log #980
|
||||||
2026/03/31-14:46:22.200351 7ff9fd1fe6c0 Delete type=3 #1093
|
2026/01/18-20:07:48.021334 7f14d9ffb6c0 Delete type=3 #978
|
||||||
2026/03/31-14:46:22.200449 7ff9fd1fe6c0 Delete type=0 #1095
|
2026/01/18-20:07:48.021403 7f14d9ffb6c0 Delete type=0 #980
|
||||||
2026/03/31-14:51:40.071820 7ff7477ef6c0 Level-0 table #1100: started
|
2026/01/18-20:13:44.336530 7f1243fff6c0 Level-0 table #985: started
|
||||||
2026/03/31-14:51:40.071876 7ff7477ef6c0 Level-0 table #1100: 0 bytes OK
|
2026/01/18-20:13:44.336556 7f1243fff6c0 Level-0 table #985: 0 bytes OK
|
||||||
2026/03/31-14:51:40.145396 7ff7477ef6c0 Delete type=0 #1098
|
2026/01/18-20:13:44.372711 7f1243fff6c0 Delete type=0 #983
|
||||||
2026/03/31-14:51:40.339229 7ff7477ef6c0 Manual compaction at level-0 from '!items!6fTZ6hOKR4pWbWOe' @ 72057594037927935 : 1 .. '!items!zwSNMO9HpiqUCMt8' @ 0 : 0; will stop at (end)
|
2026/01/18-20:13:44.502487 7f1243fff6c0 Manual compaction at level-0 from '!items!6fTZ6hOKR4pWbWOe' @ 72057594037927935 : 1 .. '!items!zwSNMO9HpiqUCMt8' @ 0 : 0; will stop at (end)
|
||||||
|
|||||||
BIN
packs/effets-exemples/MANIFEST-000986
Normal file
BIN
packs/effets-exemples/MANIFEST-000986
Normal file
Binary file not shown.
Binary file not shown.
@@ -1 +1 @@
|
|||||||
MANIFEST-001104
|
MANIFEST-000989
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
2026/03/31-20:06:53.939108 7ff9fd9ff6c0 Recovering log #1102
|
2026/01/19-19:47:49.675978 7f14d8ff96c0 Recovering log #987
|
||||||
2026/03/31-20:06:53.949583 7ff9fd9ff6c0 Delete type=3 #1100
|
2026/01/19-19:47:49.685972 7f14d8ff96c0 Delete type=3 #985
|
||||||
2026/03/31-20:06:53.949633 7ff9fd9ff6c0 Delete type=0 #1102
|
2026/01/19-19:47:49.686034 7f14d8ff96c0 Delete type=0 #987
|
||||||
2026/03/31-20:07:15.353516 7ff7477ef6c0 Level-0 table #1107: started
|
2026/01/19-20:19:02.553787 7f1243fff6c0 Level-0 table #992: started
|
||||||
2026/03/31-20:07:15.353537 7ff7477ef6c0 Level-0 table #1107: 0 bytes OK
|
2026/01/19-20:19:02.553814 7f1243fff6c0 Level-0 table #992: 0 bytes OK
|
||||||
2026/03/31-20:07:15.360004 7ff7477ef6c0 Delete type=0 #1105
|
2026/01/19-20:19:02.559887 7f1243fff6c0 Delete type=0 #990
|
||||||
2026/03/31-20:07:15.381550 7ff7477ef6c0 Manual compaction at level-0 from '!items!0ErhyqifZLDCmMfT' @ 72057594037927935 : 1 .. '!items!yE8UH6YAgNGjKDEu' @ 0 : 0; will stop at (end)
|
2026/01/19-20:19:02.560019 7f1243fff6c0 Manual compaction at level-0 from '!items!0ErhyqifZLDCmMfT' @ 72057594037927935 : 1 .. '!items!yE8UH6YAgNGjKDEu' @ 0 : 0; will stop at (end)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
2026/03/31-14:46:22.022217 7ff9fd1fe6c0 Recovering log #1098
|
2026/01/18-20:07:47.766393 7f14d8ff96c0 Recovering log #983
|
||||||
2026/03/31-14:46:22.031799 7ff9fd1fe6c0 Delete type=3 #1096
|
2026/01/18-20:07:47.781538 7f14d8ff96c0 Delete type=3 #981
|
||||||
2026/03/31-14:46:22.031876 7ff9fd1fe6c0 Delete type=0 #1098
|
2026/01/18-20:07:47.781589 7f14d8ff96c0 Delete type=0 #983
|
||||||
2026/03/31-14:51:39.078812 7ff7477ef6c0 Level-0 table #1103: started
|
2026/01/18-20:13:43.983716 7f1243fff6c0 Level-0 table #988: started
|
||||||
2026/03/31-14:51:39.078841 7ff7477ef6c0 Level-0 table #1103: 0 bytes OK
|
2026/01/18-20:13:43.983740 7f1243fff6c0 Level-0 table #988: 0 bytes OK
|
||||||
2026/03/31-14:51:39.143521 7ff7477ef6c0 Delete type=0 #1101
|
2026/01/18-20:13:44.023789 7f1243fff6c0 Delete type=0 #986
|
||||||
2026/03/31-14:51:39.208918 7ff7477ef6c0 Manual compaction at level-0 from '!items!0ErhyqifZLDCmMfT' @ 72057594037927935 : 1 .. '!items!yE8UH6YAgNGjKDEu' @ 0 : 0; will stop at (end)
|
2026/01/18-20:13:44.053229 7f1243fff6c0 Manual compaction at level-0 from '!items!0ErhyqifZLDCmMfT' @ 72057594037927935 : 1 .. '!items!yE8UH6YAgNGjKDEu' @ 0 : 0; will stop at (end)
|
||||||
|
|||||||
BIN
packs/equipment/MANIFEST-000989
Normal file
BIN
packs/equipment/MANIFEST-000989
Normal file
Binary file not shown.
Binary file not shown.
@@ -1 +1 @@
|
|||||||
MANIFEST-001103
|
MANIFEST-000988
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
2026/03/31-20:06:54.031544 7ff9fd1fe6c0 Recovering log #1101
|
2026/01/19-19:47:49.769389 7f14d8ff96c0 Recovering log #986
|
||||||
2026/03/31-20:06:54.041287 7ff9fd1fe6c0 Delete type=3 #1099
|
2026/01/19-19:47:49.779377 7f14d8ff96c0 Delete type=3 #984
|
||||||
2026/03/31-20:06:54.041342 7ff9fd1fe6c0 Delete type=0 #1101
|
2026/01/19-19:47:49.779429 7f14d8ff96c0 Delete type=0 #986
|
||||||
2026/03/31-20:07:15.416507 7ff7477ef6c0 Level-0 table #1106: started
|
2026/01/19-20:19:02.593611 7f1243fff6c0 Level-0 table #991: started
|
||||||
2026/03/31-20:07:15.416537 7ff7477ef6c0 Level-0 table #1106: 0 bytes OK
|
2026/01/19-20:19:02.593633 7f1243fff6c0 Level-0 table #991: 0 bytes OK
|
||||||
2026/03/31-20:07:15.423296 7ff7477ef6c0 Delete type=0 #1104
|
2026/01/19-20:19:02.599673 7f1243fff6c0 Delete type=0 #989
|
||||||
2026/03/31-20:07:15.437157 7ff7477ef6c0 Manual compaction at level-0 from '!items!AoT2c0af4lY6aBsx' @ 72057594037927935 : 1 .. '!items!vGydqADwTsHZ9B3j' @ 0 : 0; will stop at (end)
|
2026/01/19-20:19:02.612871 7f1243fff6c0 Manual compaction at level-0 from '!items!AoT2c0af4lY6aBsx' @ 72057594037927935 : 1 .. '!items!vGydqADwTsHZ9B3j' @ 0 : 0; will stop at (end)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
2026/03/31-14:46:22.132692 7ff9fd1fe6c0 Recovering log #1097
|
2026/01/18-20:07:47.909338 7f14d9ffb6c0 Recovering log #982
|
||||||
2026/03/31-14:46:22.143399 7ff9fd1fe6c0 Delete type=3 #1095
|
2026/01/18-20:07:47.941648 7f14d9ffb6c0 Delete type=3 #980
|
||||||
2026/03/31-14:46:22.143467 7ff9fd1fe6c0 Delete type=0 #1097
|
2026/01/18-20:07:47.941699 7f14d9ffb6c0 Delete type=0 #982
|
||||||
2026/03/31-14:51:39.562744 7ff7477ef6c0 Level-0 table #1102: started
|
2026/01/18-20:13:44.233085 7f1243fff6c0 Level-0 table #987: started
|
||||||
2026/03/31-14:51:39.562775 7ff7477ef6c0 Level-0 table #1102: 0 bytes OK
|
2026/01/18-20:13:44.233108 7f1243fff6c0 Level-0 table #987: 0 bytes OK
|
||||||
2026/03/31-14:51:39.632049 7ff7477ef6c0 Delete type=0 #1100
|
2026/01/18-20:13:44.259693 7f1243fff6c0 Delete type=0 #985
|
||||||
2026/03/31-14:51:39.698800 7ff7477ef6c0 Manual compaction at level-0 from '!items!AoT2c0af4lY6aBsx' @ 72057594037927935 : 1 .. '!items!vGydqADwTsHZ9B3j' @ 0 : 0; will stop at (end)
|
2026/01/18-20:13:44.336426 7f1243fff6c0 Manual compaction at level-0 from '!items!AoT2c0af4lY6aBsx' @ 72057594037927935 : 1 .. '!items!vGydqADwTsHZ9B3j' @ 0 : 0; will stop at (end)
|
||||||
|
|||||||
BIN
packs/fightoptions/MANIFEST-000988
Normal file
BIN
packs/fightoptions/MANIFEST-000988
Normal file
Binary file not shown.
Binary file not shown.
@@ -1 +1 @@
|
|||||||
MANIFEST-000586
|
MANIFEST-000471
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
2026/03/31-20:06:54.043863 7ff9fd9ff6c0 Recovering log #584
|
2026/01/19-19:47:49.781873 7f14d9ffb6c0 Recovering log #469
|
||||||
2026/03/31-20:06:54.054130 7ff9fd9ff6c0 Delete type=3 #582
|
2026/01/19-19:47:49.791906 7f14d9ffb6c0 Delete type=3 #467
|
||||||
2026/03/31-20:06:54.054200 7ff9fd9ff6c0 Delete type=0 #584
|
2026/01/19-19:47:49.791963 7f14d9ffb6c0 Delete type=0 #469
|
||||||
2026/03/31-20:07:15.409740 7ff7477ef6c0 Level-0 table #589: started
|
2026/01/19-20:19:02.599791 7f1243fff6c0 Level-0 table #474: started
|
||||||
2026/03/31-20:07:15.409767 7ff7477ef6c0 Level-0 table #589: 0 bytes OK
|
2026/01/19-20:19:02.599817 7f1243fff6c0 Level-0 table #474: 0 bytes OK
|
||||||
2026/03/31-20:07:15.416319 7ff7477ef6c0 Delete type=0 #587
|
2026/01/19-20:19:02.606216 7f1243fff6c0 Delete type=0 #472
|
||||||
2026/03/31-20:07:15.437145 7ff7477ef6c0 Manual compaction at level-0 from '!items!CLRp0k5qV8mD03pW' @ 72057594037927935 : 1 .. '!items!wYEpnhbyYaMkaNdL' @ 0 : 0; will stop at (end)
|
2026/01/19-20:19:02.612886 7f1243fff6c0 Manual compaction at level-0 from '!items!CLRp0k5qV8mD03pW' @ 72057594037927935 : 1 .. '!items!wYEpnhbyYaMkaNdL' @ 0 : 0; will stop at (end)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
2026/03/31-14:46:22.147793 7ff9fd9ff6c0 Recovering log #580
|
2026/01/18-20:07:47.944158 7f14da7fc6c0 Recovering log #465
|
||||||
2026/03/31-14:46:22.157625 7ff9fd9ff6c0 Delete type=3 #578
|
2026/01/18-20:07:47.960589 7f14da7fc6c0 Delete type=3 #463
|
||||||
2026/03/31-14:46:22.157691 7ff9fd9ff6c0 Delete type=0 #580
|
2026/01/18-20:07:47.960660 7f14da7fc6c0 Delete type=0 #465
|
||||||
2026/03/31-14:51:39.632217 7ff7477ef6c0 Level-0 table #585: started
|
2026/01/18-20:13:44.259805 7f1243fff6c0 Level-0 table #470: started
|
||||||
2026/03/31-14:51:39.632248 7ff7477ef6c0 Level-0 table #585: 0 bytes OK
|
2026/01/18-20:13:44.259831 7f1243fff6c0 Level-0 table #470: 0 bytes OK
|
||||||
2026/03/31-14:51:39.698676 7ff7477ef6c0 Delete type=0 #583
|
2026/01/18-20:13:44.295095 7f1243fff6c0 Delete type=0 #468
|
||||||
2026/03/31-14:51:39.756392 7ff7477ef6c0 Manual compaction at level-0 from '!items!CLRp0k5qV8mD03pW' @ 72057594037927935 : 1 .. '!items!wYEpnhbyYaMkaNdL' @ 0 : 0; will stop at (end)
|
2026/01/18-20:13:44.336439 7f1243fff6c0 Manual compaction at level-0 from '!items!CLRp0k5qV8mD03pW' @ 72057594037927935 : 1 .. '!items!wYEpnhbyYaMkaNdL' @ 0 : 0; will stop at (end)
|
||||||
|
|||||||
BIN
packs/fightoptionsfanmade/MANIFEST-000471
Normal file
BIN
packs/fightoptionsfanmade/MANIFEST-000471
Normal file
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user