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: "13"
|
|
||||||
|
|||||||
@@ -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
|
|
||||||
2082
css/bol.css
2082
css/bol.css
File diff suppressed because it is too large
Load Diff
@@ -609,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"
|
|
||||||
}
|
}
|
||||||
@@ -650,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.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.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.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)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
|
|||||||
@@ -1,119 +0,0 @@
|
|||||||
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,36 +0,0 @@
|
|||||||
/**
|
|
||||||
* Extend the basic Item with some very simple modifications.
|
|
||||||
* @extends {Item}
|
|
||||||
*/
|
|
||||||
export class BoLItem extends Item {
|
|
||||||
/**
|
|
||||||
* Augment the basic Item data model with additional dynamic data.
|
|
||||||
*/
|
|
||||||
prepareData() {
|
|
||||||
super.prepareData()
|
|
||||||
|
|
||||||
const actorData = this.actor ? this.actor.system : {}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
|
||||||
get properties() {
|
|
||||||
return this.system.properties
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
|
||||||
/**
|
|
||||||
* Get the Array of item properties which are used in the small sidebar of the description tab
|
|
||||||
* @return {Array}
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
get itemProperties() {
|
|
||||||
const props = [];
|
|
||||||
if ( this.type === "item" ) {
|
|
||||||
const entries = Object.entries(this.system.properties)
|
|
||||||
props.push(...entries.filter(e => e[1] === true).map(e => { return game.bol.config.itemProperties2[e[0]] }))
|
|
||||||
}
|
|
||||||
return props.filter(p => !!p)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,112 +0,0 @@
|
|||||||
# BoL DataModels
|
|
||||||
|
|
||||||
Ce dossier contient les DataModels pour le système Barbarians of Lemuria (BoL).
|
|
||||||
|
|
||||||
## Structure
|
|
||||||
|
|
||||||
### Actors DataModels
|
|
||||||
|
|
||||||
- **character.mjs** : Personnages joueurs
|
|
||||||
- Attributs (Vigor, Agility, Mind, Appeal)
|
|
||||||
- Aptitudes (Initiative, Mêlée, Distance, Défense)
|
|
||||||
- Ressources (HP, Hero Points, Faith, Power, Alchemy, Astrology)
|
|
||||||
- XP et création
|
|
||||||
- Bougette (argent)
|
|
||||||
|
|
||||||
- **encounter.mjs** : PNJ et créatures
|
|
||||||
- Mêmes attributs que character
|
|
||||||
- Champs spécifiques : chartype (tough/villain), isundead, size, environment
|
|
||||||
|
|
||||||
- **horde.mjs** : Hordes de créatures
|
|
||||||
- Mêmes attributs de base
|
|
||||||
- Champs spécifiques : hordesize, hordebasehp, hasdamagerule, damagerule
|
|
||||||
|
|
||||||
- **vehicle.mjs** : Véhicules (navires, chars, etc.)
|
|
||||||
- Attributs véhicules : hull, crew, resources
|
|
||||||
- Champs spécifiques : vehicletype, row, spur, status
|
|
||||||
|
|
||||||
### Items DataModels
|
|
||||||
|
|
||||||
- **item.mjs** : Équipements et objets
|
|
||||||
- Propriétés (weapon, armor, magical, etc.)
|
|
||||||
- Équipement (quantity, weight, price, worn)
|
|
||||||
- Category et subtype
|
|
||||||
|
|
||||||
- **feature.mjs** : Capacités, traits, sorts
|
|
||||||
- Rank (niveau/rang)
|
|
||||||
- Description
|
|
||||||
- Category et subtype
|
|
||||||
|
|
||||||
## Architecture
|
|
||||||
|
|
||||||
Tous les DataModels héritent de `foundry.abstract.TypeDataModel` et définissent leur schéma via `defineSchema()`.
|
|
||||||
|
|
||||||
Exemple de structure :
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
export default class BoLCharacterDataModel extends foundry.abstract.TypeDataModel {
|
|
||||||
static defineSchema() {
|
|
||||||
const fields = foundry.data.fields;
|
|
||||||
const requiredInteger = { required: true, nullable: false, integer: true };
|
|
||||||
|
|
||||||
return {
|
|
||||||
// Définition des champs
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
static LOCALIZATION_PREFIXES = ["BOL.Character"];
|
|
||||||
|
|
||||||
// Méthodes personnalisées (à ajouter)
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Types de champs utilisés
|
|
||||||
|
|
||||||
- `StringField` : Chaînes de caractères
|
|
||||||
- `NumberField` : Nombres (avec option `integer: true` pour entiers)
|
|
||||||
- `BooleanField` : Booléens
|
|
||||||
- `HTMLField` : HTML enrichi (descriptions, biographies)
|
|
||||||
- `ArrayField` : Tableaux
|
|
||||||
- `SchemaField` : Objets imbriqués
|
|
||||||
|
|
||||||
## Export
|
|
||||||
|
|
||||||
Le fichier `_module.mjs` exporte tous les DataModels :
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
export { default as BoLCharacter } from "./character.mjs"
|
|
||||||
export { default as BoLEncounter } from "./encounter.mjs"
|
|
||||||
export { default as BoLHorde } from "./horde.mjs"
|
|
||||||
export { default as BoLVehicle } from "./vehicle.mjs"
|
|
||||||
export { default as BoLItem } from "./item.mjs"
|
|
||||||
export { default as BoLFeature } from "./feature.mjs"
|
|
||||||
```
|
|
||||||
|
|
||||||
## Configuration dans bol.js
|
|
||||||
|
|
||||||
Les DataModels sont enregistrés dans `CONFIG` :
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
CONFIG.Actor.dataModels = {
|
|
||||||
character: models.BoLCharacter,
|
|
||||||
encounter: models.BoLEncounter,
|
|
||||||
horde: models.BoLHorde,
|
|
||||||
vehicle: models.BoLVehicle
|
|
||||||
}
|
|
||||||
|
|
||||||
CONFIG.Item.dataModels = {
|
|
||||||
item: models.BoLItem,
|
|
||||||
feature: models.BoLFeature
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Compatibilité
|
|
||||||
|
|
||||||
Les DataModels sont compatibles avec le `template.json` existant. La migration est transparente pour les données existantes.
|
|
||||||
|
|
||||||
## Prochaines étapes
|
|
||||||
|
|
||||||
1. Ajouter `prepareDerivedData()` pour les calculs automatiques
|
|
||||||
2. Migrer la logique métier depuis actor.js
|
|
||||||
3. Ajouter des validations personnalisées
|
|
||||||
4. Documenter avec JSDoc
|
|
||||||
@@ -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)
|
||||||
});
|
});
|
||||||
@@ -487,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
|
||||||
@@ -509,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
|
||||||
@@ -554,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.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.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)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -647,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.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-001076
|
MANIFEST-000990
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
2026/02/28-22:59:53.852685 7f56e3fff6c0 Recovering log #1074
|
2026/01/19-19:47:49.729596 7f14da7fc6c0 Recovering log #988
|
||||||
2026/02/28-22:59:53.863099 7f56e3fff6c0 Delete type=3 #1072
|
2026/01/19-19:47:49.739434 7f14da7fc6c0 Delete type=3 #986
|
||||||
2026/02/28-22:59:53.863210 7f56e3fff6c0 Delete type=0 #1074
|
2026/01/19-19:47:49.739512 7f14da7fc6c0 Delete type=0 #988
|
||||||
2026/03/01-01:08:46.366409 7f54e37ef6c0 Level-0 table #1079: started
|
2026/01/19-20:19:02.579851 7f1243fff6c0 Level-0 table #993: started
|
||||||
2026/03/01-01:08:46.366440 7f54e37ef6c0 Level-0 table #1079: 0 bytes OK
|
2026/01/19-20:19:02.579872 7f1243fff6c0 Level-0 table #993: 0 bytes OK
|
||||||
2026/03/01-01:08:46.372420 7f54e37ef6c0 Delete type=0 #1077
|
2026/01/19-20:19:02.585797 7f1243fff6c0 Delete type=0 #991
|
||||||
2026/03/01-01:08:46.391669 7f54e37ef6c0 Manual compaction at level-0 from '!journal!3xJg1rCxnWvEmoxS' @ 72057594037927935 : 1 .. '!journal.pages!veAAxCtCKcFIsnln.0kUgZspxXO7VS8bd' @ 0 : 0; will stop at (end)
|
2026/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)
|
||||||
2026/03/01-01:08:46.391720 7f54e37ef6c0 Manual compaction at level-1 from '!journal!3xJg1rCxnWvEmoxS' @ 72057594037927935 : 1 .. '!journal.pages!veAAxCtCKcFIsnln.0kUgZspxXO7VS8bd' @ 0 : 0; will stop at (end)
|
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
2026/02/28-17:23:52.883622 7f56f93fe6c0 Recovering log #1070
|
2026/01/18-20:07:47.845406 7f14d8ff96c0 Recovering log #984
|
||||||
2026/02/28-17:23:52.893895 7f56f93fe6c0 Delete type=3 #1068
|
2026/01/18-20:07:47.861224 7f14d8ff96c0 Delete type=3 #982
|
||||||
2026/02/28-17:23:52.893967 7f56f93fe6c0 Delete type=0 #1070
|
2026/01/18-20:07:47.861280 7f14d8ff96c0 Delete type=0 #984
|
||||||
2026/02/28-22:59:43.750682 7f54e37ef6c0 Level-0 table #1075: started
|
2026/01/18-20:13:44.130598 7f1243fff6c0 Level-0 table #989: started
|
||||||
2026/02/28-22:59:43.750749 7f54e37ef6c0 Level-0 table #1075: 0 bytes OK
|
2026/01/18-20:13:44.130625 7f1243fff6c0 Level-0 table #989: 0 bytes OK
|
||||||
2026/02/28-22:59:43.758241 7f54e37ef6c0 Delete type=0 #1073
|
2026/01/18-20:13:44.157241 7f1243fff6c0 Delete type=0 #987
|
||||||
2026/02/28-22:59:43.758440 7f54e37ef6c0 Manual compaction at level-0 from '!journal!3xJg1rCxnWvEmoxS' @ 72057594037927935 : 1 .. '!journal.pages!veAAxCtCKcFIsnln.0kUgZspxXO7VS8bd' @ 0 : 0; will stop at (end)
|
2026/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)
|
||||||
2026/02/28-22:59:43.758473 7f54e37ef6c0 Manual compaction at level-1 from '!journal!3xJg1rCxnWvEmoxS' @ 72057594037927935 : 1 .. '!journal.pages!veAAxCtCKcFIsnln.0kUgZspxXO7VS8bd' @ 0 : 0; will stop at (end)
|
|
||||||
|
|||||||
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-000981
|
MANIFEST-000895
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
2026/02/28-22:59:53.826224 7f56f8bfd6c0 Recovering log #979
|
2026/01/19-19:47:49.702991 7f14d97fa6c0 Recovering log #893
|
||||||
2026/02/28-22:59:53.836758 7f56f8bfd6c0 Delete type=3 #977
|
2026/01/19-19:47:49.714316 7f14d97fa6c0 Delete type=3 #891
|
||||||
2026/02/28-22:59:53.836823 7f56f8bfd6c0 Delete type=0 #979
|
2026/01/19-19:47:49.714383 7f14d97fa6c0 Delete type=0 #893
|
||||||
2026/03/01-01:08:46.372471 7f54e37ef6c0 Level-0 table #984: started
|
2026/01/19-20:19:02.560145 7f1243fff6c0 Level-0 table #898: started
|
||||||
2026/03/01-01:08:46.372486 7f54e37ef6c0 Level-0 table #984: 0 bytes OK
|
2026/01/19-20:19:02.560173 7f1243fff6c0 Level-0 table #898: 0 bytes OK
|
||||||
2026/03/01-01:08:46.378495 7f54e37ef6c0 Delete type=0 #982
|
2026/01/19-20:19:02.566093 7f1243fff6c0 Delete type=0 #896
|
||||||
2026/03/01-01:08:46.391687 7f54e37ef6c0 Manual compaction at level-0 from '!items!G3dZTHIabA3LA1hY' @ 72057594037927935 : 1 .. '!items!xhEcsi3WHjbt2ro9' @ 0 : 0; will stop at (end)
|
2026/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)
|
||||||
2026/03/01-01:08:46.391731 7f54e37ef6c0 Manual compaction at level-1 from '!items!G3dZTHIabA3LA1hY' @ 72057594037927935 : 1 .. '!items!xhEcsi3WHjbt2ro9' @ 0 : 0; will stop at (end)
|
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
2026/02/28-17:23:52.858522 7f56e3fff6c0 Recovering log #975
|
2026/01/18-20:07:47.807797 7f14d9ffb6c0 Recovering log #889
|
||||||
2026/02/28-17:23:52.869495 7f56e3fff6c0 Delete type=3 #973
|
2026/01/18-20:07:47.824331 7f14d9ffb6c0 Delete type=3 #887
|
||||||
2026/02/28-17:23:52.869552 7f56e3fff6c0 Delete type=0 #975
|
2026/01/18-20:07:47.824381 7f14d9ffb6c0 Delete type=0 #889
|
||||||
2026/02/28-22:59:43.737596 7f54e37ef6c0 Level-0 table #980: started
|
2026/01/18-20:13:44.157350 7f1243fff6c0 Level-0 table #894: started
|
||||||
2026/02/28-22:59:43.737635 7f54e37ef6c0 Level-0 table #980: 0 bytes OK
|
2026/01/18-20:13:44.157372 7f1243fff6c0 Level-0 table #894: 0 bytes OK
|
||||||
2026/02/28-22:59:43.743801 7f54e37ef6c0 Delete type=0 #978
|
2026/01/18-20:13:44.192480 7f1243fff6c0 Delete type=0 #892
|
||||||
2026/02/28-22:59:43.758414 7f54e37ef6c0 Manual compaction at level-0 from '!items!G3dZTHIabA3LA1hY' @ 72057594037927935 : 1 .. '!items!xhEcsi3WHjbt2ro9' @ 0 : 0; will stop at (end)
|
2026/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)
|
||||||
2026/02/28-22:59:43.758457 7f54e37ef6c0 Manual compaction at level-1 from '!items!G3dZTHIabA3LA1hY' @ 72057594037927935 : 1 .. '!items!xhEcsi3WHjbt2ro9' @ 0 : 0; will stop at (end)
|
|
||||||
|
|||||||
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-001075
|
MANIFEST-000989
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
2026/02/28-22:59:53.718001 7f56f8bfd6c0 Recovering log #1073
|
2026/01/19-19:47:49.594444 7f14d8ff96c0 Recovering log #987
|
||||||
2026/02/28-22:59:53.729345 7f56f8bfd6c0 Delete type=3 #1071
|
2026/01/19-19:47:49.605020 7f14d8ff96c0 Delete type=3 #985
|
||||||
2026/02/28-22:59:53.729412 7f56f8bfd6c0 Delete type=0 #1073
|
2026/01/19-19:47:49.605095 7f14d8ff96c0 Delete type=0 #987
|
||||||
2026/03/01-01:08:46.321084 7f54e37ef6c0 Level-0 table #1078: started
|
2026/01/19-20:19:02.521702 7f1243fff6c0 Level-0 table #992: started
|
||||||
2026/03/01-01:08:46.321111 7f54e37ef6c0 Level-0 table #1078: 0 bytes OK
|
2026/01/19-20:19:02.521733 7f1243fff6c0 Level-0 table #992: 0 bytes OK
|
||||||
2026/03/01-01:08:46.327221 7f54e37ef6c0 Delete type=0 #1076
|
2026/01/19-20:19:02.528339 7f1243fff6c0 Delete type=0 #990
|
||||||
2026/03/01-01:08:46.339937 7f54e37ef6c0 Manual compaction at level-0 from '!items!039ZF3E3MtAGwbiX' @ 72057594037927935 : 1 .. '!items!zgspy1QKaxdEetEw' @ 0 : 0; will stop at (end)
|
2026/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)
|
||||||
2026/03/01-01:08:46.339972 7f54e37ef6c0 Manual compaction at level-1 from '!items!039ZF3E3MtAGwbiX' @ 72057594037927935 : 1 .. '!items!zgspy1QKaxdEetEw' @ 0 : 0; will stop at (end)
|
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
2026/02/28-17:23:52.757933 7f56f9bff6c0 Recovering log #1069
|
2026/01/18-20:07:47.640110 7f14da7fc6c0 Recovering log #983
|
||||||
2026/02/28-17:23:52.767692 7f56f9bff6c0 Delete type=3 #1067
|
2026/01/18-20:07:47.659075 7f14da7fc6c0 Delete type=3 #981
|
||||||
2026/02/28-17:23:52.767761 7f56f9bff6c0 Delete type=0 #1069
|
2026/01/18-20:07:47.659147 7f14da7fc6c0 Delete type=0 #983
|
||||||
2026/02/28-22:59:43.697108 7f54e37ef6c0 Level-0 table #1074: started
|
2026/01/18-20:13:43.881522 7f1243fff6c0 Level-0 table #988: started
|
||||||
2026/02/28-22:59:43.697152 7f54e37ef6c0 Level-0 table #1074: 0 bytes OK
|
2026/01/18-20:13:43.881548 7f1243fff6c0 Level-0 table #988: 0 bytes OK
|
||||||
2026/02/28-22:59:43.704224 7f54e37ef6c0 Delete type=0 #1072
|
2026/01/18-20:13:43.921371 7f1243fff6c0 Delete type=0 #986
|
||||||
2026/02/28-22:59:43.704461 7f54e37ef6c0 Manual compaction at level-0 from '!items!039ZF3E3MtAGwbiX' @ 72057594037927935 : 1 .. '!items!zgspy1QKaxdEetEw' @ 0 : 0; will stop at (end)
|
2026/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)
|
||||||
2026/02/28-22:59:43.704511 7f54e37ef6c0 Manual compaction at level-1 from '!items!039ZF3E3MtAGwbiX' @ 72057594037927935 : 1 .. '!items!zgspy1QKaxdEetEw' @ 0 : 0; will stop at (end)
|
|
||||||
|
|||||||
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-001074
|
MANIFEST-000988
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
2026/02/28-22:59:53.732583 7f56e3fff6c0 Recovering log #1072
|
2026/01/19-19:47:49.609310 7f14da7fc6c0 Recovering log #986
|
||||||
2026/02/28-22:59:53.742972 7f56e3fff6c0 Delete type=3 #1070
|
2026/01/19-19:47:49.619302 7f14da7fc6c0 Delete type=3 #984
|
||||||
2026/02/28-22:59:53.743061 7f56e3fff6c0 Delete type=0 #1072
|
2026/01/19-19:47:49.619373 7f14da7fc6c0 Delete type=0 #986
|
||||||
2026/03/01-01:08:46.313828 7f54e37ef6c0 Level-0 table #1077: started
|
2026/01/19-20:19:02.515027 7f1243fff6c0 Level-0 table #991: started
|
||||||
2026/03/01-01:08:46.313877 7f54e37ef6c0 Level-0 table #1077: 0 bytes OK
|
2026/01/19-20:19:02.515048 7f1243fff6c0 Level-0 table #991: 0 bytes OK
|
||||||
2026/03/01-01:08:46.320973 7f54e37ef6c0 Delete type=0 #1075
|
2026/01/19-20:19:02.521555 7f1243fff6c0 Delete type=0 #989
|
||||||
2026/03/01-01:08:46.339925 7f54e37ef6c0 Manual compaction at level-0 from '!items!CoqlfsDV1gL5swbK' @ 72057594037927935 : 1 .. '!items!yofwG0YrsL902G77' @ 0 : 0; will stop at (end)
|
2026/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)
|
||||||
2026/03/01-01:08:46.339953 7f54e37ef6c0 Manual compaction at level-1 from '!items!CoqlfsDV1gL5swbK' @ 72057594037927935 : 1 .. '!items!yofwG0YrsL902G77' @ 0 : 0; will stop at (end)
|
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
2026/02/28-17:23:52.769847 7f56f93fe6c0 Recovering log #1068
|
2026/01/18-20:07:47.664234 7f14d8ff96c0 Recovering log #982
|
||||||
2026/02/28-17:23:52.780583 7f56f93fe6c0 Delete type=3 #1066
|
2026/01/18-20:07:47.679427 7f14d8ff96c0 Delete type=3 #980
|
||||||
2026/02/28-17:23:52.780639 7f56f93fe6c0 Delete type=0 #1068
|
2026/01/18-20:07:47.679484 7f14d8ff96c0 Delete type=0 #982
|
||||||
2026/02/28-22:59:43.677524 7f54e37ef6c0 Level-0 table #1073: started
|
2026/01/18-20:13:43.851971 7f1243fff6c0 Level-0 table #987: started
|
||||||
2026/02/28-22:59:43.677620 7f54e37ef6c0 Level-0 table #1073: 0 bytes OK
|
2026/01/18-20:13:43.851994 7f1243fff6c0 Level-0 table #987: 0 bytes OK
|
||||||
2026/02/28-22:59:43.684329 7f54e37ef6c0 Delete type=0 #1071
|
2026/01/18-20:13:43.881382 7f1243fff6c0 Delete type=0 #985
|
||||||
2026/02/28-22:59:43.704401 7f54e37ef6c0 Manual compaction at level-0 from '!items!CoqlfsDV1gL5swbK' @ 72057594037927935 : 1 .. '!items!yofwG0YrsL902G77' @ 0 : 0; will stop at (end)
|
2026/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)
|
||||||
2026/02/28-22:59:43.704474 7f54e37ef6c0 Manual compaction at level-1 from '!items!CoqlfsDV1gL5swbK' @ 72057594037927935 : 1 .. '!items!yofwG0YrsL902G77' @ 0 : 0; will stop at (end)
|
|
||||||
|
|||||||
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-001074
|
MANIFEST-000988
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
2026/02/28-22:59:53.759689 7f56f8bfd6c0 Recovering log #1072
|
2026/01/19-19:47:49.635172 7f14d8ff96c0 Recovering log #986
|
||||||
2026/02/28-22:59:53.770229 7f56f8bfd6c0 Delete type=3 #1070
|
2026/01/19-19:47:49.644889 7f14d8ff96c0 Delete type=3 #984
|
||||||
2026/02/28-22:59:53.770305 7f56f8bfd6c0 Delete type=0 #1072
|
2026/01/19-19:47:49.644941 7f14d8ff96c0 Delete type=0 #986
|
||||||
2026/03/01-01:08:46.327327 7f54e37ef6c0 Level-0 table #1077: started
|
2026/01/19-20:19:02.508864 7f1243fff6c0 Level-0 table #991: started
|
||||||
2026/03/01-01:08:46.327354 7f54e37ef6c0 Level-0 table #1077: 0 bytes OK
|
2026/01/19-20:19:02.508913 7f1243fff6c0 Level-0 table #991: 0 bytes OK
|
||||||
2026/03/01-01:08:46.333262 7f54e37ef6c0 Delete type=0 #1075
|
2026/01/19-20:19:02.514913 7f1243fff6c0 Delete type=0 #989
|
||||||
2026/03/01-01:08:46.339946 7f54e37ef6c0 Manual compaction at level-0 from '!items!4S4xAfMXGnuU0O1a' @ 72057594037927935 : 1 .. '!items!zxY3sW0iCJBvwjOS' @ 0 : 0; will stop at (end)
|
2026/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)
|
||||||
2026/03/01-01:08:46.339979 7f54e37ef6c0 Manual compaction at level-1 from '!items!4S4xAfMXGnuU0O1a' @ 72057594037927935 : 1 .. '!items!zxY3sW0iCJBvwjOS' @ 0 : 0; will stop at (end)
|
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
2026/02/28-17:23:52.796426 7f56f9bff6c0 Recovering log #1068
|
2026/01/18-20:07:47.704039 7f14d8ff96c0 Recovering log #982
|
||||||
2026/02/28-17:23:52.805920 7f56f9bff6c0 Delete type=3 #1066
|
2026/01/18-20:07:47.721242 7f14d8ff96c0 Delete type=3 #980
|
||||||
2026/02/28-17:23:52.805973 7f56f9bff6c0 Delete type=0 #1068
|
2026/01/18-20:07:47.721902 7f14d8ff96c0 Delete type=0 #982
|
||||||
2026/02/28-22:59:43.711333 7f54e37ef6c0 Level-0 table #1073: started
|
2026/01/18-20:13:43.777269 7f1243fff6c0 Level-0 table #987: started
|
||||||
2026/02/28-22:59:43.711370 7f54e37ef6c0 Level-0 table #1073: 0 bytes OK
|
2026/01/18-20:13:43.777312 7f1243fff6c0 Level-0 table #987: 0 bytes OK
|
||||||
2026/02/28-22:59:43.717336 7f54e37ef6c0 Delete type=0 #1071
|
2026/01/18-20:13:43.819988 7f1243fff6c0 Delete type=0 #985
|
||||||
2026/02/28-22:59:43.731041 7f54e37ef6c0 Manual compaction at level-0 from '!items!4S4xAfMXGnuU0O1a' @ 72057594037927935 : 1 .. '!items!zxY3sW0iCJBvwjOS' @ 0 : 0; will stop at (end)
|
2026/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)
|
||||||
2026/02/28-22:59:43.731086 7f54e37ef6c0 Manual compaction at level-1 from '!items!4S4xAfMXGnuU0O1a' @ 72057594037927935 : 1 .. '!items!zxY3sW0iCJBvwjOS' @ 0 : 0; will stop at (end)
|
|
||||||
|
|||||||
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-001072
|
MANIFEST-000986
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
2026/02/28-22:59:53.948768 7f56f93fe6c0 Recovering log #1070
|
2026/01/19-19:47:49.822315 7f14d9ffb6c0 Recovering log #984
|
||||||
2026/02/28-22:59:53.958702 7f56f93fe6c0 Delete type=3 #1068
|
2026/01/19-19:47:49.833348 7f14d9ffb6c0 Delete type=3 #982
|
||||||
2026/02/28-22:59:53.958781 7f56f93fe6c0 Delete type=0 #1070
|
2026/01/19-19:47:49.833401 7f14d9ffb6c0 Delete type=0 #984
|
||||||
2026/03/01-01:08:46.425514 7f54e37ef6c0 Level-0 table #1075: started
|
2026/01/19-20:19:02.619154 7f1243fff6c0 Level-0 table #989: started
|
||||||
2026/03/01-01:08:46.425561 7f54e37ef6c0 Level-0 table #1075: 0 bytes OK
|
2026/01/19-20:19:02.619176 7f1243fff6c0 Level-0 table #989: 0 bytes OK
|
||||||
2026/03/01-01:08:46.431671 7f54e37ef6c0 Delete type=0 #1073
|
2026/01/19-20:19:02.626822 7f1243fff6c0 Delete type=0 #987
|
||||||
2026/03/01-01:08:46.445290 7f54e37ef6c0 Manual compaction at level-0 from '!items!6fTZ6hOKR4pWbWOe' @ 72057594037927935 : 1 .. '!items!zwSNMO9HpiqUCMt8' @ 0 : 0; will stop at (end)
|
2026/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)
|
||||||
2026/03/01-01:08:46.445328 7f54e37ef6c0 Manual compaction at level-1 from '!items!6fTZ6hOKR4pWbWOe' @ 72057594037927935 : 1 .. '!items!zwSNMO9HpiqUCMt8' @ 0 : 0; will stop at (end)
|
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
2026/02/28-17:23:52.970603 7f56f9bff6c0 Recovering log #1066
|
2026/01/18-20:07:48.004635 7f14d9ffb6c0 Recovering log #980
|
||||||
2026/02/28-17:23:52.981835 7f56f9bff6c0 Delete type=3 #1064
|
2026/01/18-20:07:48.021334 7f14d9ffb6c0 Delete type=3 #978
|
||||||
2026/02/28-17:23:52.981888 7f56f9bff6c0 Delete type=0 #1066
|
2026/01/18-20:07:48.021403 7f14d9ffb6c0 Delete type=0 #980
|
||||||
2026/02/28-22:59:43.785498 7f54e37ef6c0 Level-0 table #1071: started
|
2026/01/18-20:13:44.336530 7f1243fff6c0 Level-0 table #985: started
|
||||||
2026/02/28-22:59:43.785523 7f54e37ef6c0 Level-0 table #1071: 0 bytes OK
|
2026/01/18-20:13:44.336556 7f1243fff6c0 Level-0 table #985: 0 bytes OK
|
||||||
2026/02/28-22:59:43.792317 7f54e37ef6c0 Delete type=0 #1069
|
2026/01/18-20:13:44.372711 7f1243fff6c0 Delete type=0 #983
|
||||||
2026/02/28-22:59:43.813749 7f54e37ef6c0 Manual compaction at level-0 from '!items!6fTZ6hOKR4pWbWOe' @ 72057594037927935 : 1 .. '!items!zwSNMO9HpiqUCMt8' @ 0 : 0; will stop at (end)
|
2026/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)
|
||||||
2026/02/28-22:59:43.813808 7f54e37ef6c0 Manual compaction at level-1 from '!items!6fTZ6hOKR4pWbWOe' @ 72057594037927935 : 1 .. '!items!zwSNMO9HpiqUCMt8' @ 0 : 0; will stop at (end)
|
|
||||||
|
|||||||
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-001075
|
MANIFEST-000989
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
2026/02/28-22:59:53.798832 7f56f9bff6c0 Recovering log #1073
|
2026/01/19-19:47:49.675978 7f14d8ff96c0 Recovering log #987
|
||||||
2026/02/28-22:59:53.809449 7f56f9bff6c0 Delete type=3 #1071
|
2026/01/19-19:47:49.685972 7f14d8ff96c0 Delete type=3 #985
|
||||||
2026/02/28-22:59:53.809533 7f56f9bff6c0 Delete type=0 #1073
|
2026/01/19-19:47:49.686034 7f14d8ff96c0 Delete type=0 #987
|
||||||
2026/03/01-01:08:46.340100 7f54e37ef6c0 Level-0 table #1078: started
|
2026/01/19-20:19:02.553787 7f1243fff6c0 Level-0 table #992: started
|
||||||
2026/03/01-01:08:46.340139 7f54e37ef6c0 Level-0 table #1078: 0 bytes OK
|
2026/01/19-20:19:02.553814 7f1243fff6c0 Level-0 table #992: 0 bytes OK
|
||||||
2026/03/01-01:08:46.346846 7f54e37ef6c0 Delete type=0 #1076
|
2026/01/19-20:19:02.559887 7f1243fff6c0 Delete type=0 #990
|
||||||
2026/03/01-01:08:46.366221 7f54e37ef6c0 Manual compaction at level-0 from '!items!0ErhyqifZLDCmMfT' @ 72057594037927935 : 1 .. '!items!yE8UH6YAgNGjKDEu' @ 0 : 0; will stop at (end)
|
2026/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)
|
||||||
2026/03/01-01:08:46.366278 7f54e37ef6c0 Manual compaction at level-1 from '!items!0ErhyqifZLDCmMfT' @ 72057594037927935 : 1 .. '!items!yE8UH6YAgNGjKDEu' @ 0 : 0; will stop at (end)
|
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
2026/02/28-17:23:52.834261 7f56f9bff6c0 Recovering log #1069
|
2026/01/18-20:07:47.766393 7f14d8ff96c0 Recovering log #983
|
||||||
2026/02/28-17:23:52.843912 7f56f9bff6c0 Delete type=3 #1067
|
2026/01/18-20:07:47.781538 7f14d8ff96c0 Delete type=3 #981
|
||||||
2026/02/28-17:23:52.843969 7f56f9bff6c0 Delete type=0 #1069
|
2026/01/18-20:07:47.781589 7f14d8ff96c0 Delete type=0 #983
|
||||||
2026/02/28-22:59:43.704672 7f54e37ef6c0 Level-0 table #1074: started
|
2026/01/18-20:13:43.983716 7f1243fff6c0 Level-0 table #988: started
|
||||||
2026/02/28-22:59:43.704745 7f54e37ef6c0 Level-0 table #1074: 0 bytes OK
|
2026/01/18-20:13:43.983740 7f1243fff6c0 Level-0 table #988: 0 bytes OK
|
||||||
2026/02/28-22:59:43.711212 7f54e37ef6c0 Delete type=0 #1072
|
2026/01/18-20:13:44.023789 7f1243fff6c0 Delete type=0 #986
|
||||||
2026/02/28-22:59:43.731026 7f54e37ef6c0 Manual compaction at level-0 from '!items!0ErhyqifZLDCmMfT' @ 72057594037927935 : 1 .. '!items!yE8UH6YAgNGjKDEu' @ 0 : 0; will stop at (end)
|
2026/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)
|
||||||
2026/02/28-22:59:43.731077 7f54e37ef6c0 Manual compaction at level-1 from '!items!0ErhyqifZLDCmMfT' @ 72057594037927935 : 1 .. '!items!yE8UH6YAgNGjKDEu' @ 0 : 0; will stop at (end)
|
|
||||||
|
|||||||
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-001074
|
MANIFEST-000988
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
2026/02/28-22:59:53.895577 7f56f8bfd6c0 Recovering log #1072
|
2026/01/19-19:47:49.769389 7f14d8ff96c0 Recovering log #986
|
||||||
2026/02/28-22:59:53.906749 7f56f8bfd6c0 Delete type=3 #1070
|
2026/01/19-19:47:49.779377 7f14d8ff96c0 Delete type=3 #984
|
||||||
2026/02/28-22:59:53.906807 7f56f8bfd6c0 Delete type=0 #1072
|
2026/01/19-19:47:49.779429 7f14d8ff96c0 Delete type=0 #986
|
||||||
2026/03/01-01:08:46.391890 7f54e37ef6c0 Level-0 table #1077: started
|
2026/01/19-20:19:02.593611 7f1243fff6c0 Level-0 table #991: started
|
||||||
2026/03/01-01:08:46.391936 7f54e37ef6c0 Level-0 table #1077: 0 bytes OK
|
2026/01/19-20:19:02.593633 7f1243fff6c0 Level-0 table #991: 0 bytes OK
|
||||||
2026/03/01-01:08:46.398187 7f54e37ef6c0 Delete type=0 #1075
|
2026/01/19-20:19:02.599673 7f1243fff6c0 Delete type=0 #989
|
||||||
2026/03/01-01:08:46.417834 7f54e37ef6c0 Manual compaction at level-0 from '!items!AoT2c0af4lY6aBsx' @ 72057594037927935 : 1 .. '!items!vGydqADwTsHZ9B3j' @ 0 : 0; will stop at (end)
|
2026/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)
|
||||||
2026/03/01-01:08:46.417875 7f54e37ef6c0 Manual compaction at level-1 from '!items!AoT2c0af4lY6aBsx' @ 72057594037927935 : 1 .. '!items!vGydqADwTsHZ9B3j' @ 0 : 0; will stop at (end)
|
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
2026/02/28-17:23:52.920377 7f56e3fff6c0 Recovering log #1068
|
2026/01/18-20:07:47.909338 7f14d9ffb6c0 Recovering log #982
|
||||||
2026/02/28-17:23:52.930570 7f56e3fff6c0 Delete type=3 #1066
|
2026/01/18-20:07:47.941648 7f14d9ffb6c0 Delete type=3 #980
|
||||||
2026/02/28-17:23:52.930642 7f56e3fff6c0 Delete type=0 #1068
|
2026/01/18-20:07:47.941699 7f14d9ffb6c0 Delete type=0 #982
|
||||||
2026/02/28-22:59:43.758590 7f54e37ef6c0 Level-0 table #1073: started
|
2026/01/18-20:13:44.233085 7f1243fff6c0 Level-0 table #987: started
|
||||||
2026/02/28-22:59:43.758628 7f54e37ef6c0 Level-0 table #1073: 0 bytes OK
|
2026/01/18-20:13:44.233108 7f1243fff6c0 Level-0 table #987: 0 bytes OK
|
||||||
2026/02/28-22:59:43.764731 7f54e37ef6c0 Delete type=0 #1071
|
2026/01/18-20:13:44.259693 7f1243fff6c0 Delete type=0 #985
|
||||||
2026/02/28-22:59:43.785330 7f54e37ef6c0 Manual compaction at level-0 from '!items!AoT2c0af4lY6aBsx' @ 72057594037927935 : 1 .. '!items!vGydqADwTsHZ9B3j' @ 0 : 0; will stop at (end)
|
2026/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)
|
||||||
2026/02/28-22:59:43.785372 7f54e37ef6c0 Manual compaction at level-1 from '!items!AoT2c0af4lY6aBsx' @ 72057594037927935 : 1 .. '!items!vGydqADwTsHZ9B3j' @ 0 : 0; will stop at (end)
|
|
||||||
|
|||||||
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-000557
|
MANIFEST-000471
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
2026/02/28-22:59:53.909216 7f56f93fe6c0 Recovering log #555
|
2026/01/19-19:47:49.781873 7f14d9ffb6c0 Recovering log #469
|
||||||
2026/02/28-22:59:53.919079 7f56f93fe6c0 Delete type=3 #553
|
2026/01/19-19:47:49.791906 7f14d9ffb6c0 Delete type=3 #467
|
||||||
2026/02/28-22:59:53.919136 7f56f93fe6c0 Delete type=0 #555
|
2026/01/19-19:47:49.791963 7f14d9ffb6c0 Delete type=0 #469
|
||||||
2026/03/01-01:08:46.411300 7f54e37ef6c0 Level-0 table #560: started
|
2026/01/19-20:19:02.599791 7f1243fff6c0 Level-0 table #474: started
|
||||||
2026/03/01-01:08:46.411339 7f54e37ef6c0 Level-0 table #560: 0 bytes OK
|
2026/01/19-20:19:02.599817 7f1243fff6c0 Level-0 table #474: 0 bytes OK
|
||||||
2026/03/01-01:08:46.417727 7f54e37ef6c0 Delete type=0 #558
|
2026/01/19-20:19:02.606216 7f1243fff6c0 Delete type=0 #472
|
||||||
2026/03/01-01:08:46.417880 7f54e37ef6c0 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)
|
||||||
2026/03/01-01:08:46.417911 7f54e37ef6c0 Manual compaction at level-1 from '!items!CLRp0k5qV8mD03pW' @ 72057594037927935 : 1 .. '!items!wYEpnhbyYaMkaNdL' @ 0 : 0; will stop at (end)
|
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
2026/02/28-17:23:52.933111 7f56f9bff6c0 Recovering log #551
|
2026/01/18-20:07:47.944158 7f14da7fc6c0 Recovering log #465
|
||||||
2026/02/28-17:23:52.944230 7f56f9bff6c0 Delete type=3 #549
|
2026/01/18-20:07:47.960589 7f14da7fc6c0 Delete type=3 #463
|
||||||
2026/02/28-17:23:52.944299 7f56f9bff6c0 Delete type=0 #551
|
2026/01/18-20:07:47.960660 7f14da7fc6c0 Delete type=0 #465
|
||||||
2026/02/28-22:59:43.771257 7f54e37ef6c0 Level-0 table #556: started
|
2026/01/18-20:13:44.259805 7f1243fff6c0 Level-0 table #470: started
|
||||||
2026/02/28-22:59:43.771301 7f54e37ef6c0 Level-0 table #556: 0 bytes OK
|
2026/01/18-20:13:44.259831 7f1243fff6c0 Level-0 table #470: 0 bytes OK
|
||||||
2026/02/28-22:59:43.778711 7f54e37ef6c0 Delete type=0 #554
|
2026/01/18-20:13:44.295095 7f1243fff6c0 Delete type=0 #468
|
||||||
2026/02/28-22:59:43.785356 7f54e37ef6c0 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)
|
||||||
2026/02/28-22:59:43.785385 7f54e37ef6c0 Manual compaction at level-1 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.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user