Compare commits
5 Commits
6c70dc147c
...
v13
| Author | SHA1 | Date | |
|---|---|---|---|
| 12faf34631 | |||
| afa6e7a323 | |||
| 89f5674fb9 | |||
| cd06d2e5ec | |||
| cdddcb6aee |
@@ -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
|
|
||||||
2084
css/bol.css
2084
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.
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