Compare commits
5 Commits
13.1.0
...
bol-v13.0.
| Author | SHA1 | Date | |
|---|---|---|---|
| 12faf34631 | |||
| afa6e7a323 | |||
| 89f5674fb9 | |||
| cd06d2e5ec | |||
| cdddcb6aee |
@@ -12,13 +12,15 @@ jobs:
|
||||
|
||||
#- uses: actions/checkout@v3
|
||||
- uses: RouxAntoine/checkout@v3.5.4
|
||||
with:
|
||||
ref: "v13"
|
||||
|
||||
# get part of the tag after the `v`
|
||||
- name: Extract tag version number
|
||||
id: get_version
|
||||
uses: battila7/get-version-action@v2
|
||||
|
||||
# Substitute the Manifest and Download URLs in the system.json
|
||||
# Substitute the Manifest and Download URLs in the module.json
|
||||
- name: Substitute Manifest and Download Links For Versioned Ones
|
||||
id: sub_manifest_link_version
|
||||
uses: microsoft/variable-substitution@v1
|
||||
@@ -26,9 +28,9 @@ jobs:
|
||||
files: "system.json"
|
||||
env:
|
||||
version: ${{steps.get_version.outputs.version-without-v}}
|
||||
url: https://www.uberwald.me/gitea/${{gitea.repository}}
|
||||
manifest: https://www.uberwald.me/gitea/public/bol/releases/download/latest/system.json
|
||||
download: https://www.uberwald.me/gitea/${{gitea.repository}}/releases/download/${{github.event.release.tag_name}}/bol.zip
|
||||
url: https://www.uberwald.me/gitea/public/bol
|
||||
manifest: https://www.uberwald.me/gitea/public/bol/releases/latest/system.json
|
||||
download: https://www.uberwald.me/gitea/public/bol/releases/download/${{github.event.release.tag_name}}/bol.zip
|
||||
|
||||
# Create a zip file with all files required by the module to add to the release
|
||||
- run: |
|
||||
@@ -49,15 +51,4 @@ jobs:
|
||||
files: |-
|
||||
./bol.zip
|
||||
system.json
|
||||
api_key: "${{secrets.ALLOW_PUSH_RELEASE}}"
|
||||
|
||||
- name: Publish to Foundry server
|
||||
uses: https://github.com/djlechuck/foundryvtt-publish-package-action@v1
|
||||
with:
|
||||
token: ${{ secrets.FOUNDRYVTT_RELEASE_TOKEN }}
|
||||
id: "bol"
|
||||
version: ${{github.event.release.tag_name}}
|
||||
manifest: "https://www.uberwald.me/gitea/public/bol/releases/download/latest/system.json"
|
||||
notes: "https://www.uberwald.me/gitea/${{gitea.repository}}/releases/download/${{github.event.release.tag_name}}/bol.zip"
|
||||
compatibility-minimum: "13"
|
||||
compatibility-verified: "13"
|
||||
api_key: "${{secrets.RELEASE_TOKEN_BOL}}"
|
||||
|
||||
@@ -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.defaultLogoPathActorSheetTooltip": "Path of the Actor sheet logo (346 x 200, default : /systems/bol/ui/logo.webp)",
|
||||
"BOL.settings.defaultLogoTopLeftPath" : "Path for main top left logo",
|
||||
"BOL.settings.defaultLogoTopLeftPathTooltip": "Path of the logo in the top left window (718 x 416, default : /systems/bol/ui/logo2.webp)",
|
||||
|
||||
"BOL.ui.charSummaryTitle": "Character Summary",
|
||||
"BOL.ui.colGroupAttributes": "Attributes",
|
||||
"BOL.ui.colGroupAptitudes": "Aptitudes",
|
||||
"BOL.ui.colGroupResources": "Resources"
|
||||
"BOL.settings.defaultLogoTopLeftPathTooltip": "Path of the logo in the top left window (718 x 416, default : /systems/bol/ui/logo2.webp)"
|
||||
}
|
||||
@@ -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)",
|
||||
|
||||
"EFFECT.StatusProne": "A terre",
|
||||
"EFFECT.StatusDead": "Mort",
|
||||
|
||||
"BOL.ui.charSummaryTitle": "Résumé des Personnages",
|
||||
"BOL.ui.colGroupAttributes": "Attributs",
|
||||
"BOL.ui.colGroupAptitudes": "Aptitudes",
|
||||
"BOL.ui.colGroupResources": "Ressources"
|
||||
"EFFECT.StatusDead": "Mort"
|
||||
}
|
||||
@@ -7,8 +7,6 @@ import { BoLUtility } from "../system/bol-utility.js";
|
||||
*/
|
||||
export class BoLActor extends Actor {
|
||||
|
||||
static _healthLock = new Set()
|
||||
|
||||
static async create(data, options) {
|
||||
|
||||
// Case of compendium global import
|
||||
@@ -359,7 +357,7 @@ export class BoLActor extends Actor {
|
||||
ChatMessage.create({
|
||||
alias: 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() {
|
||||
if (BoLActor._healthLock.has(this.id)) return
|
||||
BoLActor._healthLock.add(this.id)
|
||||
try {
|
||||
let hpID = "lastHP" + this.id
|
||||
let lastHP = await this.getFlag("world", hpID)
|
||||
if (lastHP != this.system.resources.hp.value && game.user.isGM) { // Only GM sends this
|
||||
await this.setFlag("world", hpID, this.system.resources.hp.value)
|
||||
let prone = this.effects.find(ef => ef.name == game.i18n.localize("EFFECT.StatusProne"))
|
||||
let dead = this.effects.find(ef => ef.name == game.i18n.localize("EFFECT.StatusDead"))
|
||||
if (this.system.resources.hp.value <= 0) {
|
||||
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' }
|
||||
])
|
||||
}
|
||||
ChatMessage.create({
|
||||
alias: this.name,
|
||||
whisper: BoLUtility.getWhisperRecipientsAndGMs(this.name),
|
||||
content: await foundry.applications.handlebars.foundry.applications.handlebars.renderTemplate('systems/bol/templates/chat/chat-vitality-zero.hbs', { name: this.name, img: this.img, hp: this.system.resources.hp.value, isHeroAdversary: this.isHeroAdversary() })
|
||||
})
|
||||
} else {
|
||||
if (prone) {
|
||||
await this.deleteEmbeddedDocuments("ActiveEffect", [prone.id])
|
||||
}
|
||||
if (dead) {
|
||||
await this.deleteEmbeddedDocuments("ActiveEffect", [dead.id])
|
||||
}
|
||||
let hpID = "lastHP" + this.id
|
||||
let lastHP = await this.getFlag("world", hpID)
|
||||
if (lastHP != this.system.resources.hp.value && game.user.isGM) { // Only GM sends this
|
||||
await this.setFlag("world", hpID, this.system.resources.hp.value)
|
||||
let prone = this.effects.find(ef => ef.name == game.i18n.localize("EFFECT.StatusProne"))
|
||||
let dead = this.effects.find(ef => ef.name == game.i18n.localize("EFFECT.StatusDead"))
|
||||
if (this.system.resources.hp.value <= 0) {
|
||||
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' }
|
||||
])
|
||||
}
|
||||
ChatMessage.create({
|
||||
alias: this.name,
|
||||
whisper: BoLUtility.getWhisperRecipientsAndGMs(this.name),
|
||||
content: await renderTemplate('systems/bol/templates/chat/chat-vitality-zero.hbs', { name: this.name, img: this.img, hp: this.system.resources.hp.value, isHeroAdversary: this.isHeroAdversary() })
|
||||
})
|
||||
} else {
|
||||
if (prone) {
|
||||
await this.deleteEmbeddedDocuments("ActiveEffect", [prone.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({
|
||||
alias: 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,
|
||||
img: this.img,
|
||||
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 { 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"
|
||||
// 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 { preloadHandlebarsTemplates } from "./system/templates.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 { BoLRoll } from "./controllers/bol-rolls.js"
|
||||
|
||||
// Import DataModels
|
||||
import * as models from "./models/_module.mjs"
|
||||
|
||||
// Import AppV2 Sheets
|
||||
import * as sheets from "./applications/sheets/_module.mjs"
|
||||
/* -------------------------------------------- */
|
||||
const BOL_WELCOME_MESSAGE_URL = "https://www.uberwald.me/gitea/public/bol/raw/branch/v13/welcome-message-bol.html"
|
||||
|
||||
/* -------------------------------------------- */
|
||||
Hooks.once('init', async function () {
|
||||
@@ -32,9 +31,7 @@ Hooks.once('init', async function () {
|
||||
BoLRoll,
|
||||
BoLUtility,
|
||||
macros: Macros,
|
||||
config: BOL,
|
||||
models,
|
||||
sheets
|
||||
config: BOL
|
||||
};
|
||||
|
||||
// Game socket
|
||||
@@ -53,38 +50,17 @@ Hooks.once('init', async function () {
|
||||
|
||||
// Define custom Entity classes
|
||||
CONFIG.Actor.documentClass = BoLActor;
|
||||
CONFIG.Actor.dataModels = {
|
||||
character: models.BoLCharacter,
|
||||
encounter: models.BoLEncounter,
|
||||
horde: models.BoLHorde,
|
||||
vehicle: models.BoLVehicle
|
||||
}
|
||||
|
||||
CONFIG.Item.documentClass = BoLItem;
|
||||
CONFIG.Item.dataModels = {
|
||||
item: models.BoLItem,
|
||||
feature: models.BoLFeature
|
||||
}
|
||||
|
||||
CONFIG.Combat.documentClass = BoLCombatManager;
|
||||
|
||||
// Register sheet application classes
|
||||
foundry.documents.collections.Actors.unregisterSheet("core", foundry.appv1.sheets.ActorSheet);
|
||||
foundry.documents.collections.Actors.registerSheet("bol", sheets.BoLActorSheet, { types: ["character", "encounter"], makeDefault: true })
|
||||
foundry.documents.collections.Actors.registerSheet("bol", sheets.BoLVehicleSheet, { types: ["vehicle"], makeDefault: true })
|
||||
foundry.documents.collections.Actors.registerSheet("bol", sheets.BoLHordeSheet, { types: ["horde"], makeDefault: true })
|
||||
foundry.documents.collections.Actors.registerSheet("bol", BoLActorSheet, { types: ["character", "encounter"], makeDefault: true })
|
||||
foundry.documents.collections.Actors.registerSheet("bol", BoLVehicleSheet, { types: ["vehicle"], 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.registerSheet("bol", sheets.BoLItemSheet, { types: ["item"], makeDefault: true });
|
||||
foundry.documents.collections.Items.registerSheet("bol", sheets.BoLFeatureSheet, { types: ["feature"], makeDefault: true });
|
||||
|
||||
// Debug: Verify AppV2 sheets are loaded
|
||||
console.log("BoL Item Sheets registered:", {
|
||||
BoLItemSheet: sheets.BoLItemSheet.name,
|
||||
BoLFeatureSheet: sheets.BoLFeatureSheet.name,
|
||||
extendsApplicationV2: sheets.BoLItemSheet.prototype instanceof foundry.applications.api.ApplicationV2
|
||||
});
|
||||
foundry.documents.collections.Items.registerSheet("bol", BoLItemSheet, { makeDefault: true });
|
||||
|
||||
// Inot useful stuff
|
||||
BoLUtility.init()
|
||||
@@ -110,22 +86,54 @@ Hooks.once('init', async function () {
|
||||
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async function welcomeMessage() {
|
||||
const noRulebook = !game.modules.find(m => m.id === "bol-rulebook")
|
||||
const content = await foundry.applications.handlebars.renderTemplate(
|
||||
"systems/bol/templates/chat/chat-welcome.hbs",
|
||||
{ noRulebook }
|
||||
)
|
||||
ChatMessage.create({ user: game.user.id, whisper: [game.user.id], content })
|
||||
function welcomeMessage() {
|
||||
let content = `<div id="welcome-message-bol"><span class="rdd-roll-part">
|
||||
<strong>` + game.i18n.localize("BOL.chat.welcome1") + `</strong><p>` +
|
||||
game.i18n.localize("BOL.chat.welcome2") + "</p><p>" +
|
||||
game.i18n.localize("BOL.chat.welcome3") + "</p><p>" +
|
||||
game.i18n.localize("BOL.chat.welcome4") + "</p><p>" +
|
||||
game.i18n.localize("BOL.chat.welcome5") + "</p>" +
|
||||
game.i18n.localize("BOL.chat.welcome6")
|
||||
|
||||
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")) {
|
||||
ChatMessage.create({
|
||||
user: 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.")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
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()
|
||||
welcomeMessageRepository();
|
||||
|
||||
// User warning
|
||||
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 {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static options() {
|
||||
return { classes: ["bol", "dialog"], width: 480, height: 'fit-content' };
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static getDefaultAttribute(key) {
|
||||
return _apt2attr[key]
|
||||
@@ -124,7 +129,7 @@ export class BoLRoll {
|
||||
rangeMsg = "BOL.chat.range6"
|
||||
}
|
||||
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,
|
||||
attackerName: _token.actor.name,
|
||||
defenderName: target.actor.name,
|
||||
@@ -303,31 +308,26 @@ export class BoLRoll {
|
||||
// Final number of dices
|
||||
this.rollData.nbDice = 2 + Math.abs(this.rollData.bmDice)
|
||||
// Bonus or Malus ?
|
||||
const nbDiceEl = document.querySelector('#roll-nbdice')
|
||||
if (nbDiceEl) {
|
||||
if (this.rollData.bmDice == 0) {
|
||||
nbDiceEl.value = "2"
|
||||
} else {
|
||||
let letter = (this.rollData.bmDice > 0) ? "B" : "M"
|
||||
nbDiceEl.value = "2 + " + String(Math.abs(this.rollData.bmDice)) + letter
|
||||
}
|
||||
if (this.rollData.bmDice == 0) {
|
||||
$('#roll-nbdice').val("2")
|
||||
} else {
|
||||
let letter = (this.rollData.bmDice > 0) ? "B" : "M"
|
||||
$('#roll-nbdice').val("2 + " + String(Math.abs(this.rollData.bmDice)) + letter)
|
||||
}
|
||||
let rollbase = this.rollData.attrValue + "+" + this.rollData.aptValue
|
||||
if (this.rollData.weapon && this.rollData.weapon.system.properties.onlymodifier) {
|
||||
rollbase = ""
|
||||
}
|
||||
const modifierEl = document.querySelector('#roll-modifier')
|
||||
if (modifierEl) modifierEl.value = rollbase + "+" + this.rollData.careerBonus + "+" + this.rollData.mod + "+" +
|
||||
$('#roll-modifier').val(rollbase + "+" + this.rollData.careerBonus + "+" + this.rollData.mod + "+" +
|
||||
this.rollData.modRanged + "+" + this.rollData.weaponModifier + "-" + this.rollData.defence + "-" + this.rollData.modArmorMalus + "-" +
|
||||
this.rollData.shieldMalus + "+" + this.rollData.attackModifier + "+" + this.rollData.appliedArmorMalus + "+" + effectModifier
|
||||
this.rollData.shieldMalus + "+" + this.rollData.attackModifier + "+" + this.rollData.appliedArmorMalus + "+" + effectModifier)
|
||||
|
||||
// Rebuild list of applicable effects
|
||||
// Rebuild lits of applicable effects
|
||||
let selectEffects = ""
|
||||
for (let effect of this.rollData.bolApplicableEffects) {
|
||||
selectEffects += `<option value="${effect.id}" selected>${effect.name}</option>`
|
||||
}
|
||||
const effectsEl = document.querySelector('#applicable-effects')
|
||||
if (effectsEl) effectsEl.innerHTML = selectEffects
|
||||
$('#applicable-effects').html(selectEffects)
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
@@ -360,48 +360,46 @@ export class BoLRoll {
|
||||
/* -------------------------------------------- */
|
||||
static updateArmorMalus(rollData) {
|
||||
rollData.appliedArmorMalus = 0
|
||||
const agiEl = document.querySelector('#armor-agi-malus')
|
||||
if (rollData.attribute.key == "agility") {
|
||||
if (agiEl) agiEl.style.display = ''
|
||||
$("#armor-agi-malus").show()
|
||||
rollData.appliedArmorMalus += rollData.armorAgiMalus
|
||||
} 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 (initEl) initEl.style.display = ''
|
||||
$("#armor-init-malus").show()
|
||||
rollData.appliedArmorMalus += rollData.armorInitMalus
|
||||
} else {
|
||||
if (initEl) initEl.style.display = 'none'
|
||||
$("#armor-init-malus").hide()
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------ -------------- */
|
||||
static updatePPCost(rollData) {
|
||||
const el = document.querySelector('#ppcost')
|
||||
if (el) el.innerHTML = rollData.ppCost + " + Armor(" + rollData.ppCostArmor + ")=" + Number(rollData.ppCost + rollData.ppCostArmor)
|
||||
$('#ppcost').html(rollData.ppCost + " + Armor(" + rollData.ppCostArmor + ")=" + Number(rollData.ppCost + rollData.ppCostArmor))
|
||||
}
|
||||
|
||||
/* ------------------------------ -------------- */
|
||||
static rollDialogListener(html) {
|
||||
|
||||
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)
|
||||
this.rollData.ppCost = pp
|
||||
this.updatePPCost(this.rollData)
|
||||
})
|
||||
|
||||
html.querySelector('#mod')?.addEventListener('change', (event) => {
|
||||
html.find('#mod').change((event) => {
|
||||
this.rollData.mod = Number(event.currentTarget.value)
|
||||
this.updateTotalDice()
|
||||
})
|
||||
html.querySelector('#modRanged')?.addEventListener('change', (event) => {
|
||||
html.find('#modRanged').change((event) => {
|
||||
this.rollData.modRanged = Number(event.currentTarget.value)
|
||||
this.updateTotalDice()
|
||||
})
|
||||
|
||||
html.querySelector('#attr')?.addEventListener('change', (event) => {
|
||||
html.find('#attr').change((event) => {
|
||||
let attrKey = event.currentTarget.value
|
||||
let actor = BoLUtility.getActorFromRollData(this.rollData)
|
||||
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.updateTotalDice()
|
||||
})
|
||||
html.querySelector('#apt')?.addEventListener('change', (event) => {
|
||||
html.find('#apt').change((event) => {
|
||||
let aptKey = event.currentTarget.value
|
||||
let actor = BoLUtility.getActorFromRollData(this.rollData)
|
||||
this.rollData.aptitude = foundry.utils.duplicate(actor.system.aptitudes[aptKey])
|
||||
@@ -418,58 +416,65 @@ export class BoLRoll {
|
||||
this.updateTotalDice()
|
||||
})
|
||||
|
||||
html.querySelector('#applyShieldMalus')?.addEventListener('click', (event) => {
|
||||
this.rollData.shieldMalus = event.currentTarget.checked ? this.rollData.shieldAttackMalus : 0
|
||||
html.find('#applyShieldMalus').click((event) => {
|
||||
if (event.currentTarget.checked) {
|
||||
this.rollData.shieldMalus = this.rollData.shieldAttackMalus
|
||||
} else {
|
||||
this.rollData.shieldMalus = 0
|
||||
}
|
||||
this.updateTotalDice()
|
||||
})
|
||||
|
||||
html.querySelector('#career')?.addEventListener('change', (event) => {
|
||||
let careers = Array.from(event.currentTarget.selectedOptions).map(o => o.value)
|
||||
html.find('#career').change((event) => {
|
||||
let careers = $('#career').val()
|
||||
this.rollData.careerBonus = (!careers || careers.length == 0) ? 0 : Math.max(...careers.map(i => parseInt(i)))
|
||||
this.updateTotalDice()
|
||||
})
|
||||
html.querySelector('#boon')?.addEventListener('change', (event) => {
|
||||
let boons = Array.from(event.currentTarget.selectedOptions).map(o => o.value)
|
||||
html.find('#boon').change((event) => {
|
||||
let boons = $('#boon').val()
|
||||
this.rollData.nbBoons = (!boons || boons.length == 0) ? 0 : boons.length
|
||||
this.updateTotalDice()
|
||||
})
|
||||
html.querySelector('#flaw')?.addEventListener('change', (event) => {
|
||||
let flaws = Array.from(event.currentTarget.selectedOptions).map(o => o.value)
|
||||
html.find('#flaw').change((event) => {
|
||||
let flaws = $('#flaw').val()
|
||||
this.rollData.nbFlaws = (!flaws || flaws.length == 0) ? 0 : flaws.length
|
||||
this.updateTotalDice()
|
||||
})
|
||||
html.querySelectorAll('.bdice').forEach(el => el.addEventListener('click', (event) => {
|
||||
html.find('.bdice').click((event) => {
|
||||
this.rollData.mDice = 0
|
||||
this.rollData.bDice = Number(event.currentTarget.value)
|
||||
this.updateTotalDice()
|
||||
}))
|
||||
html.querySelectorAll('.mdice').forEach(el => el.addEventListener('click', (event) => {
|
||||
})
|
||||
html.find('.mdice').click((event) => {
|
||||
this.rollData.bDice = 0
|
||||
this.rollData.mDice = Number(event.currentTarget.value)
|
||||
this.updateTotalDice()
|
||||
}))
|
||||
html.querySelector('#horoscope-bonus-applied')?.addEventListener('change', (event) => {
|
||||
})
|
||||
html.find('#horoscope-bonus-applied').change((event) => {
|
||||
this.rollData.selectedHoroscope = []
|
||||
for (let option of event.currentTarget.selectedOptions) {
|
||||
this.rollData.selectedHoroscope.push(foundry.utils.duplicate(this.rollData.horoscopeBonusList[Number(option.index)]))
|
||||
}
|
||||
let horoscopes = 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.updateTotalDice()
|
||||
})
|
||||
html.querySelector('#horoscope-malus-applied')?.addEventListener('change', (event) => {
|
||||
|
||||
html.find('#horoscope-malus-applied').change((event) => {
|
||||
this.rollData.selectedHoroscope = []
|
||||
for (let option of event.currentTarget.selectedOptions) {
|
||||
this.rollData.selectedHoroscope.push(foundry.utils.duplicate(this.rollData.horoscopeBonusList[Number(option.index)]))
|
||||
}
|
||||
let horoscopes = 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.updateTotalDice()
|
||||
})
|
||||
html.querySelector('#horoscope-group-applied')?.addEventListener('change', (event) => {
|
||||
html.find('#horoscope-group-applied').change((event) => {
|
||||
this.rollData.selectedGroupHoroscopeIndex = event.currentTarget.value
|
||||
this.updateTotalDice()
|
||||
})
|
||||
|
||||
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
@@ -547,47 +552,41 @@ export class BoLRoll {
|
||||
} else {
|
||||
rollData.shieldMalus = 0
|
||||
}
|
||||
// Save & pre-initialize computed fields
|
||||
// Save
|
||||
this.rollData = rollData
|
||||
this.updateTotalDice()
|
||||
console.log("ROLLDATA", rollData)
|
||||
|
||||
// Then display+process the dialog
|
||||
const rollOptionContent = await foundry.applications.handlebars.renderTemplate(rollOptionTpl, rollData);
|
||||
// Use Hooks to reliably get the rendered HTMLElement (renderDialogV2 receives (app, element, context))
|
||||
Hooks.once('renderDialogV2', (app, element) => {
|
||||
element.classList.add('bol');
|
||||
this.rollDialogListener(element);
|
||||
});
|
||||
return foundry.applications.api.DialogV2.wait({
|
||||
window: { title: rollData.label },
|
||||
let d = new Dialog({
|
||||
title: rollData.label,
|
||||
content: rollOptionContent,
|
||||
rejectClose: false,
|
||||
buttons: [
|
||||
{
|
||||
type: 'button',
|
||||
rollData: rollData,
|
||||
render: html => this.rollDialogListener(html),
|
||||
buttons: {
|
||||
cancel: {
|
||||
icon: '<i class="fas fa-times"></i>',
|
||||
label: game.i18n.localize("BOL.ui.cancel"),
|
||||
icon: 'fas fa-times',
|
||||
action: 'cancel'
|
||||
callback: () => {
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'submit',
|
||||
submit: {
|
||||
icon: '<i class="fas fa-check"></i>',
|
||||
label: game.i18n.localize("BOL.ui.submit"),
|
||||
icon: 'fas fa-check',
|
||||
action: 'submit',
|
||||
callback: (event, button, dialog) => {
|
||||
callback: (html) => {
|
||||
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 !")
|
||||
return false
|
||||
return
|
||||
}
|
||||
rollData.registerInit = (rollData.aptitude && rollData.aptitude.key == 'init') ?
|
||||
(dialog.element.querySelector('#register-init')?.checked ?? false) : false;
|
||||
rollData.registerInit = (rollData.aptitude && rollData.aptitude.key == 'init') ? $('#register-init').is(":checked") : false;
|
||||
|
||||
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 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
|
||||
@@ -600,8 +599,12 @@ export class BoLRoll {
|
||||
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() {
|
||||
const actor = BoLUtility.getActorFromRollData(this.rollData)
|
||||
const rollMode = game.settings.get("core", "rollMode")
|
||||
const msgFlavor = await this._buildChatMessage(this.rollData)
|
||||
const msg = await this.rollData.roll.toMessage({
|
||||
flavor: msgFlavor,
|
||||
speaker: ChatMessage.getSpeaker({ actor: actor }),
|
||||
}, { rollMode })
|
||||
this.rollData.roll = foundry.utils.duplicate(this.rollData.roll)
|
||||
if (msg) await msg.setFlag("world", "bol-roll-data", this.rollData)
|
||||
let actor = BoLUtility.getActorFromRollData(this.rollData)
|
||||
this._buildChatMessage(this.rollData).then(async msgFlavor => {
|
||||
//console.log("MSG", msgFlavor )
|
||||
let msg = await this.rollData.roll.toMessage({
|
||||
user: game.user.id,
|
||||
rollMode: game.settings.get("core", "rollMode"),
|
||||
flavor: msgFlavor,
|
||||
speaker: ChatMessage.getSpeaker({ actor: actor }),
|
||||
})
|
||||
this.rollData.roll = foundry.utils.duplicate(this.rollData.roll) // Remove object, keep data (v111 ready)
|
||||
msg.setFlag("world", "bol-roll-data", this.rollData)
|
||||
})
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
@@ -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")) {
|
||||
chatData.img = null;
|
||||
}
|
||||
// For old-format weapon items lacking stat fields, apply defaults so the chat card can display them
|
||||
if (chatData.system?.properties?.weapon && !chatData.system.properties.damage) {
|
||||
const defaults = game.bol.config.defaultNaturalWeapon?.properties ?? {};
|
||||
chatData.system.properties = Object.assign(foundry.utils.duplicate(defaults), chatData.system.properties);
|
||||
}
|
||||
// JSON object for easy creation
|
||||
chatData.jsondata = JSON.stringify(
|
||||
{
|
||||
@@ -249,7 +244,7 @@ export class BoLUtility {
|
||||
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);
|
||||
ChatMessage.create(chatOptions)
|
||||
});
|
||||
@@ -487,21 +482,20 @@ export class BoLUtility {
|
||||
|
||||
if (defenseMode == 'damage-with-armor') {
|
||||
let armorFormula = defender.getArmorFormula()
|
||||
if (armorFormula === "0") {
|
||||
rollData.armorProtect = 0
|
||||
} else {
|
||||
rollData.armorProtect = 0
|
||||
armorFormula = String(armorFormula) || "0"
|
||||
if (armorFormula && armorFormula != "0" ) {
|
||||
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)
|
||||
let msg = await rollData.rollArmor.toMessage({ flavor: game.i18n.localize("BOL.chat.armorRoll") + " : " + armorFormula });
|
||||
if (game.dice3d) { // wait animation end when DsN is there
|
||||
await game.dice3d.waitFor3DAnimationByMessageID(msg.id);
|
||||
}
|
||||
rollData.armorProtect = (rollData.rollArmor.total < 0) ? 0 : rollData.rollArmor.total
|
||||
}
|
||||
rollData.finalDamage = rollData.damageTotal - rollData.armorProtect
|
||||
rollData.finalDamage = (rollData.finalDamage < 0) ? 0 : rollData.finalDamage
|
||||
await defender.sufferDamage(rollData.finalDamage)
|
||||
console.log("Armor roll -> result ", rollData)
|
||||
}
|
||||
if (defenseMode == 'damage-without-armor') {
|
||||
rollData.finalDamage = rollData.damageTotal
|
||||
@@ -509,17 +503,9 @@ export class BoLUtility {
|
||||
}
|
||||
if (defenseMode == 'hero-reduce-damage') {
|
||||
let armorFormula = defender.getArmorFormula()
|
||||
if (armorFormula === "0") {
|
||||
rollData.armorProtect = 0
|
||||
} else {
|
||||
rollData.rollArmor = new Roll(armorFormula)
|
||||
await rollData.rollArmor.roll()
|
||||
let msg = await rollData.rollArmor.toMessage({ flavor: game.i18n.localize("BOL.chat.armorRoll") + " : " + armorFormula })
|
||||
if (game.dice3d && msg) {
|
||||
await game.dice3d.waitFor3DAnimationByMessageID(msg.id)
|
||||
}
|
||||
rollData.armorProtect = (rollData.rollArmor.total < 0) ? 0 : rollData.rollArmor.total
|
||||
}
|
||||
rollData.rollArmor = new Roll(armorFormula)
|
||||
await rollData.rollArmor.roll()
|
||||
rollData.armorProtect = (rollData.rollArmor.total < 0) ? 0 : rollData.rollArmor.total
|
||||
rollData.rollHero = new Roll("1d6")
|
||||
await rollData.rollHero.roll()
|
||||
rollData.finalDamage = rollData.damageTotal - rollData.rollHero.total - rollData.armorProtect
|
||||
@@ -554,13 +540,13 @@ export class BoLUtility {
|
||||
ChatMessage.create({
|
||||
alias: 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)
|
||||
ChatMessage.create({
|
||||
alias: defender.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({
|
||||
alias: 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,
|
||||
attacker: rollData.attacker,
|
||||
defender: defender,
|
||||
|
||||
@@ -188,25 +188,25 @@ BOL.rangeModifiers = {
|
||||
"-8": "BOL.dialog.utmost"
|
||||
}
|
||||
|
||||
BOL.difficultyModifiers = [
|
||||
{ value: "-12", label: "BOL.dialog.divine" },
|
||||
{ value: "-11", label: "BOL.dialog.mythic11" },
|
||||
{ value: "-10", label: "BOL.dialog.mythic" },
|
||||
{ value: "-9", label: "BOL.dialog.heroic9" },
|
||||
{ value: "-8", label: "BOL.dialog.heroic" },
|
||||
{ value: "-7", label: "BOL.dialog.formidable7" },
|
||||
{ value: "-6", label: "BOL.dialog.formidable" },
|
||||
{ value: "-5", label: "BOL.dialog.demanding5" },
|
||||
{ value: "-4", label: "BOL.dialog.demanding" },
|
||||
{ value: "-3", label: "BOL.dialog.tough3" },
|
||||
{ value: "-2", label: "BOL.dialog.tough" },
|
||||
{ value: "-1", label: "BOL.dialog.hard" },
|
||||
{ value: "0", label: "BOL.dialog.moderate" },
|
||||
{ value: "1", label: "BOL.dialog.easy" },
|
||||
{ value: "2", label: "BOL.dialog.veryeasy" },
|
||||
{ value: "3", label: "BOL.dialog.soeasy3" },
|
||||
{ value: "4", label: "BOL.dialog.soeasy" },
|
||||
]
|
||||
BOL.difficultyModifiers = {
|
||||
"4": "BOL.dialog.soeasy",
|
||||
"3": "BOL.dialog.soeasy3",
|
||||
"2": "BOL.dialog.veryeasy",
|
||||
"1": "BOL.dialog.easy",
|
||||
"0": "BOL.dialog.moderate",
|
||||
"-1": "BOL.dialog.hard",
|
||||
"-2": "BOL.dialog.tough",
|
||||
"-3": "BOL.dialog.tough3",
|
||||
"-4": "BOL.dialog.demanding",
|
||||
"-5": "BOL.dialog.demanding5",
|
||||
"-6": "BOL.dialog.formidable",
|
||||
"-7": "BOL.dialog.formidable7",
|
||||
"-8": "BOL.dialog.heroic",
|
||||
"-9": "BOL.dialog.heroic9",
|
||||
"-10": "BOL.dialog.mythic",
|
||||
"-11": "BOL.dialog.mythic11",
|
||||
"-12": "BOL.dialog.divine"
|
||||
}
|
||||
|
||||
BOL.alchemyModifiers = {
|
||||
"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/selected-horoscope-roll-card.hbs",
|
||||
"systems/bol/templates/chat/rolls/horoscope-roll-card.hbs",
|
||||
"systems/bol/templates/chat/chat-welcome.hbs",
|
||||
"systems/bol/templates/dialogs/aptitude-roll-part.hbs",
|
||||
"systems/bol/templates/dialogs/attribute-roll-part.hbs",
|
||||
"systems/bol/templates/dialogs/mod-roll-part.hbs",
|
||||
@@ -63,8 +62,7 @@ export const preloadHandlebarsTemplates = async function () {
|
||||
"systems/bol/templates/dialogs/flaws-roll-part.hbs",
|
||||
"systems/bol/templates/dialogs/total-roll-part.hbs",
|
||||
"systems/bol/templates/dialogs/fightoptions-roll-part.hbs",
|
||||
"systems/bol/templates/dialogs/horoscope-roll-part.hbs",
|
||||
"systems/bol/templates/apps/character-summary-template.html"
|
||||
"systems/bol/templates/dialogs/horoscope-roll-part.hbs"
|
||||
];
|
||||
|
||||
// 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/02/28-22:59:53.863099 7f56e3fff6c0 Delete type=3 #1072
|
||||
2026/02/28-22:59:53.863210 7f56e3fff6c0 Delete type=0 #1074
|
||||
2026/03/01-01:08:46.366409 7f54e37ef6c0 Level-0 table #1079: started
|
||||
2026/03/01-01:08:46.366440 7f54e37ef6c0 Level-0 table #1079: 0 bytes OK
|
||||
2026/03/01-01:08:46.372420 7f54e37ef6c0 Delete type=0 #1077
|
||||
2026/03/01-01:08:46.391669 7f54e37ef6c0 Manual compaction at level-0 from '!journal!3xJg1rCxnWvEmoxS' @ 72057594037927935 : 1 .. '!journal.pages!veAAxCtCKcFIsnln.0kUgZspxXO7VS8bd' @ 0 : 0; will stop at (end)
|
||||
2026/03/01-01:08:46.391720 7f54e37ef6c0 Manual compaction at level-1 from '!journal!3xJg1rCxnWvEmoxS' @ 72057594037927935 : 1 .. '!journal.pages!veAAxCtCKcFIsnln.0kUgZspxXO7VS8bd' @ 0 : 0; will stop at (end)
|
||||
2026/01/19-19:47:49.729596 7f14da7fc6c0 Recovering log #988
|
||||
2026/01/19-19:47:49.739434 7f14da7fc6c0 Delete type=3 #986
|
||||
2026/01/19-19:47:49.739512 7f14da7fc6c0 Delete type=0 #988
|
||||
2026/01/19-20:19:02.579851 7f1243fff6c0 Level-0 table #993: started
|
||||
2026/01/19-20:19:02.579872 7f1243fff6c0 Level-0 table #993: 0 bytes OK
|
||||
2026/01/19-20:19:02.585797 7f1243fff6c0 Delete type=0 #991
|
||||
2026/01/19-20:19:02.586018 7f1243fff6c0 Manual compaction at level-0 from '!journal!3xJg1rCxnWvEmoxS' @ 72057594037927935 : 1 .. '!journal.pages!veAAxCtCKcFIsnln.0kUgZspxXO7VS8bd' @ 0 : 0; will stop at (end)
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
2026/02/28-17:23:52.883622 7f56f93fe6c0 Recovering log #1070
|
||||
2026/02/28-17:23:52.893895 7f56f93fe6c0 Delete type=3 #1068
|
||||
2026/02/28-17:23:52.893967 7f56f93fe6c0 Delete type=0 #1070
|
||||
2026/02/28-22:59:43.750682 7f54e37ef6c0 Level-0 table #1075: started
|
||||
2026/02/28-22:59:43.750749 7f54e37ef6c0 Level-0 table #1075: 0 bytes OK
|
||||
2026/02/28-22:59:43.758241 7f54e37ef6c0 Delete type=0 #1073
|
||||
2026/02/28-22:59:43.758440 7f54e37ef6c0 Manual compaction at level-0 from '!journal!3xJg1rCxnWvEmoxS' @ 72057594037927935 : 1 .. '!journal.pages!veAAxCtCKcFIsnln.0kUgZspxXO7VS8bd' @ 0 : 0; will stop at (end)
|
||||
2026/02/28-22:59:43.758473 7f54e37ef6c0 Manual compaction at level-1 from '!journal!3xJg1rCxnWvEmoxS' @ 72057594037927935 : 1 .. '!journal.pages!veAAxCtCKcFIsnln.0kUgZspxXO7VS8bd' @ 0 : 0; will stop at (end)
|
||||
2026/01/18-20:07:47.845406 7f14d8ff96c0 Recovering log #984
|
||||
2026/01/18-20:07:47.861224 7f14d8ff96c0 Delete type=3 #982
|
||||
2026/01/18-20:07:47.861280 7f14d8ff96c0 Delete type=0 #984
|
||||
2026/01/18-20:13:44.130598 7f1243fff6c0 Level-0 table #989: started
|
||||
2026/01/18-20:13:44.130625 7f1243fff6c0 Level-0 table #989: 0 bytes OK
|
||||
2026/01/18-20:13:44.157241 7f1243fff6c0 Delete type=0 #987
|
||||
2026/01/18-20:13:44.192634 7f1243fff6c0 Manual compaction at level-0 from '!journal!3xJg1rCxnWvEmoxS' @ 72057594037927935 : 1 .. '!journal.pages!veAAxCtCKcFIsnln.0kUgZspxXO7VS8bd' @ 0 : 0; will stop at (end)
|
||||
|
||||
BIN
packs/aides-de-jeu/MANIFEST-000990
Normal file
BIN
packs/aides-de-jeu/MANIFEST-000990
Normal file
Binary file not shown.
Binary file not shown.
@@ -1 +1 @@
|
||||
MANIFEST-000981
|
||||
MANIFEST-000895
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
2026/02/28-22:59:53.826224 7f56f8bfd6c0 Recovering log #979
|
||||
2026/02/28-22:59:53.836758 7f56f8bfd6c0 Delete type=3 #977
|
||||
2026/02/28-22:59:53.836823 7f56f8bfd6c0 Delete type=0 #979
|
||||
2026/03/01-01:08:46.372471 7f54e37ef6c0 Level-0 table #984: started
|
||||
2026/03/01-01:08:46.372486 7f54e37ef6c0 Level-0 table #984: 0 bytes OK
|
||||
2026/03/01-01:08:46.378495 7f54e37ef6c0 Delete type=0 #982
|
||||
2026/03/01-01:08:46.391687 7f54e37ef6c0 Manual compaction at level-0 from '!items!G3dZTHIabA3LA1hY' @ 72057594037927935 : 1 .. '!items!xhEcsi3WHjbt2ro9' @ 0 : 0; will stop at (end)
|
||||
2026/03/01-01:08:46.391731 7f54e37ef6c0 Manual compaction at level-1 from '!items!G3dZTHIabA3LA1hY' @ 72057594037927935 : 1 .. '!items!xhEcsi3WHjbt2ro9' @ 0 : 0; will stop at (end)
|
||||
2026/01/19-19:47:49.702991 7f14d97fa6c0 Recovering log #893
|
||||
2026/01/19-19:47:49.714316 7f14d97fa6c0 Delete type=3 #891
|
||||
2026/01/19-19:47:49.714383 7f14d97fa6c0 Delete type=0 #893
|
||||
2026/01/19-20:19:02.560145 7f1243fff6c0 Level-0 table #898: started
|
||||
2026/01/19-20:19:02.560173 7f1243fff6c0 Level-0 table #898: 0 bytes OK
|
||||
2026/01/19-20:19:02.566093 7f1243fff6c0 Delete type=0 #896
|
||||
2026/01/19-20:19:02.585964 7f1243fff6c0 Manual compaction at level-0 from '!items!G3dZTHIabA3LA1hY' @ 72057594037927935 : 1 .. '!items!xhEcsi3WHjbt2ro9' @ 0 : 0; will stop at (end)
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
2026/02/28-17:23:52.858522 7f56e3fff6c0 Recovering log #975
|
||||
2026/02/28-17:23:52.869495 7f56e3fff6c0 Delete type=3 #973
|
||||
2026/02/28-17:23:52.869552 7f56e3fff6c0 Delete type=0 #975
|
||||
2026/02/28-22:59:43.737596 7f54e37ef6c0 Level-0 table #980: started
|
||||
2026/02/28-22:59:43.737635 7f54e37ef6c0 Level-0 table #980: 0 bytes OK
|
||||
2026/02/28-22:59:43.743801 7f54e37ef6c0 Delete type=0 #978
|
||||
2026/02/28-22:59:43.758414 7f54e37ef6c0 Manual compaction at level-0 from '!items!G3dZTHIabA3LA1hY' @ 72057594037927935 : 1 .. '!items!xhEcsi3WHjbt2ro9' @ 0 : 0; will stop at (end)
|
||||
2026/02/28-22:59:43.758457 7f54e37ef6c0 Manual compaction at level-1 from '!items!G3dZTHIabA3LA1hY' @ 72057594037927935 : 1 .. '!items!xhEcsi3WHjbt2ro9' @ 0 : 0; will stop at (end)
|
||||
2026/01/18-20:07:47.807797 7f14d9ffb6c0 Recovering log #889
|
||||
2026/01/18-20:07:47.824331 7f14d9ffb6c0 Delete type=3 #887
|
||||
2026/01/18-20:07:47.824381 7f14d9ffb6c0 Delete type=0 #889
|
||||
2026/01/18-20:13:44.157350 7f1243fff6c0 Level-0 table #894: started
|
||||
2026/01/18-20:13:44.157372 7f1243fff6c0 Level-0 table #894: 0 bytes OK
|
||||
2026/01/18-20:13:44.192480 7f1243fff6c0 Delete type=0 #892
|
||||
2026/01/18-20:13:44.192647 7f1243fff6c0 Manual compaction at level-0 from '!items!G3dZTHIabA3LA1hY' @ 72057594037927935 : 1 .. '!items!xhEcsi3WHjbt2ro9' @ 0 : 0; will stop at (end)
|
||||
|
||||
BIN
packs/armors/MANIFEST-000895
Normal file
BIN
packs/armors/MANIFEST-000895
Normal file
Binary file not shown.
Binary file not shown.
@@ -1 +1 @@
|
||||
MANIFEST-001075
|
||||
MANIFEST-000989
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
2026/02/28-22:59:53.718001 7f56f8bfd6c0 Recovering log #1073
|
||||
2026/02/28-22:59:53.729345 7f56f8bfd6c0 Delete type=3 #1071
|
||||
2026/02/28-22:59:53.729412 7f56f8bfd6c0 Delete type=0 #1073
|
||||
2026/03/01-01:08:46.321084 7f54e37ef6c0 Level-0 table #1078: started
|
||||
2026/03/01-01:08:46.321111 7f54e37ef6c0 Level-0 table #1078: 0 bytes OK
|
||||
2026/03/01-01:08:46.327221 7f54e37ef6c0 Delete type=0 #1076
|
||||
2026/03/01-01:08:46.339937 7f54e37ef6c0 Manual compaction at level-0 from '!items!039ZF3E3MtAGwbiX' @ 72057594037927935 : 1 .. '!items!zgspy1QKaxdEetEw' @ 0 : 0; will stop at (end)
|
||||
2026/03/01-01:08:46.339972 7f54e37ef6c0 Manual compaction at level-1 from '!items!039ZF3E3MtAGwbiX' @ 72057594037927935 : 1 .. '!items!zgspy1QKaxdEetEw' @ 0 : 0; will stop at (end)
|
||||
2026/01/19-19:47:49.594444 7f14d8ff96c0 Recovering log #987
|
||||
2026/01/19-19:47:49.605020 7f14d8ff96c0 Delete type=3 #985
|
||||
2026/01/19-19:47:49.605095 7f14d8ff96c0 Delete type=0 #987
|
||||
2026/01/19-20:19:02.521702 7f1243fff6c0 Level-0 table #992: started
|
||||
2026/01/19-20:19:02.521733 7f1243fff6c0 Level-0 table #992: 0 bytes OK
|
||||
2026/01/19-20:19:02.528339 7f1243fff6c0 Delete type=0 #990
|
||||
2026/01/19-20:19:02.534634 7f1243fff6c0 Manual compaction at level-0 from '!items!039ZF3E3MtAGwbiX' @ 72057594037927935 : 1 .. '!items!zgspy1QKaxdEetEw' @ 0 : 0; will stop at (end)
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
2026/02/28-17:23:52.757933 7f56f9bff6c0 Recovering log #1069
|
||||
2026/02/28-17:23:52.767692 7f56f9bff6c0 Delete type=3 #1067
|
||||
2026/02/28-17:23:52.767761 7f56f9bff6c0 Delete type=0 #1069
|
||||
2026/02/28-22:59:43.697108 7f54e37ef6c0 Level-0 table #1074: started
|
||||
2026/02/28-22:59:43.697152 7f54e37ef6c0 Level-0 table #1074: 0 bytes OK
|
||||
2026/02/28-22:59:43.704224 7f54e37ef6c0 Delete type=0 #1072
|
||||
2026/02/28-22:59:43.704461 7f54e37ef6c0 Manual compaction at level-0 from '!items!039ZF3E3MtAGwbiX' @ 72057594037927935 : 1 .. '!items!zgspy1QKaxdEetEw' @ 0 : 0; will stop at (end)
|
||||
2026/02/28-22:59:43.704511 7f54e37ef6c0 Manual compaction at level-1 from '!items!039ZF3E3MtAGwbiX' @ 72057594037927935 : 1 .. '!items!zgspy1QKaxdEetEw' @ 0 : 0; will stop at (end)
|
||||
2026/01/18-20:07:47.640110 7f14da7fc6c0 Recovering log #983
|
||||
2026/01/18-20:07:47.659075 7f14da7fc6c0 Delete type=3 #981
|
||||
2026/01/18-20:07:47.659147 7f14da7fc6c0 Delete type=0 #983
|
||||
2026/01/18-20:13:43.881522 7f1243fff6c0 Level-0 table #988: started
|
||||
2026/01/18-20:13:43.881548 7f1243fff6c0 Level-0 table #988: 0 bytes OK
|
||||
2026/01/18-20:13:43.921371 7f1243fff6c0 Delete type=0 #986
|
||||
2026/01/18-20:13:43.921513 7f1243fff6c0 Manual compaction at level-0 from '!items!039ZF3E3MtAGwbiX' @ 72057594037927935 : 1 .. '!items!zgspy1QKaxdEetEw' @ 0 : 0; will stop at (end)
|
||||
|
||||
BIN
packs/boons/MANIFEST-000989
Normal file
BIN
packs/boons/MANIFEST-000989
Normal file
Binary file not shown.
Binary file not shown.
@@ -1 +1 @@
|
||||
MANIFEST-001074
|
||||
MANIFEST-000988
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
2026/02/28-22:59:53.732583 7f56e3fff6c0 Recovering log #1072
|
||||
2026/02/28-22:59:53.742972 7f56e3fff6c0 Delete type=3 #1070
|
||||
2026/02/28-22:59:53.743061 7f56e3fff6c0 Delete type=0 #1072
|
||||
2026/03/01-01:08:46.313828 7f54e37ef6c0 Level-0 table #1077: started
|
||||
2026/03/01-01:08:46.313877 7f54e37ef6c0 Level-0 table #1077: 0 bytes OK
|
||||
2026/03/01-01:08:46.320973 7f54e37ef6c0 Delete type=0 #1075
|
||||
2026/03/01-01:08:46.339925 7f54e37ef6c0 Manual compaction at level-0 from '!items!CoqlfsDV1gL5swbK' @ 72057594037927935 : 1 .. '!items!yofwG0YrsL902G77' @ 0 : 0; will stop at (end)
|
||||
2026/03/01-01:08:46.339953 7f54e37ef6c0 Manual compaction at level-1 from '!items!CoqlfsDV1gL5swbK' @ 72057594037927935 : 1 .. '!items!yofwG0YrsL902G77' @ 0 : 0; will stop at (end)
|
||||
2026/01/19-19:47:49.609310 7f14da7fc6c0 Recovering log #986
|
||||
2026/01/19-19:47:49.619302 7f14da7fc6c0 Delete type=3 #984
|
||||
2026/01/19-19:47:49.619373 7f14da7fc6c0 Delete type=0 #986
|
||||
2026/01/19-20:19:02.515027 7f1243fff6c0 Level-0 table #991: started
|
||||
2026/01/19-20:19:02.515048 7f1243fff6c0 Level-0 table #991: 0 bytes OK
|
||||
2026/01/19-20:19:02.521555 7f1243fff6c0 Delete type=0 #989
|
||||
2026/01/19-20:19:02.534623 7f1243fff6c0 Manual compaction at level-0 from '!items!CoqlfsDV1gL5swbK' @ 72057594037927935 : 1 .. '!items!yofwG0YrsL902G77' @ 0 : 0; will stop at (end)
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
2026/02/28-17:23:52.769847 7f56f93fe6c0 Recovering log #1068
|
||||
2026/02/28-17:23:52.780583 7f56f93fe6c0 Delete type=3 #1066
|
||||
2026/02/28-17:23:52.780639 7f56f93fe6c0 Delete type=0 #1068
|
||||
2026/02/28-22:59:43.677524 7f54e37ef6c0 Level-0 table #1073: started
|
||||
2026/02/28-22:59:43.677620 7f54e37ef6c0 Level-0 table #1073: 0 bytes OK
|
||||
2026/02/28-22:59:43.684329 7f54e37ef6c0 Delete type=0 #1071
|
||||
2026/02/28-22:59:43.704401 7f54e37ef6c0 Manual compaction at level-0 from '!items!CoqlfsDV1gL5swbK' @ 72057594037927935 : 1 .. '!items!yofwG0YrsL902G77' @ 0 : 0; will stop at (end)
|
||||
2026/02/28-22:59:43.704474 7f54e37ef6c0 Manual compaction at level-1 from '!items!CoqlfsDV1gL5swbK' @ 72057594037927935 : 1 .. '!items!yofwG0YrsL902G77' @ 0 : 0; will stop at (end)
|
||||
2026/01/18-20:07:47.664234 7f14d8ff96c0 Recovering log #982
|
||||
2026/01/18-20:07:47.679427 7f14d8ff96c0 Delete type=3 #980
|
||||
2026/01/18-20:07:47.679484 7f14d8ff96c0 Delete type=0 #982
|
||||
2026/01/18-20:13:43.851971 7f1243fff6c0 Level-0 table #987: started
|
||||
2026/01/18-20:13:43.851994 7f1243fff6c0 Level-0 table #987: 0 bytes OK
|
||||
2026/01/18-20:13:43.881382 7f1243fff6c0 Delete type=0 #985
|
||||
2026/01/18-20:13:43.921506 7f1243fff6c0 Manual compaction at level-0 from '!items!CoqlfsDV1gL5swbK' @ 72057594037927935 : 1 .. '!items!yofwG0YrsL902G77' @ 0 : 0; will stop at (end)
|
||||
|
||||
BIN
packs/boonsflawscreatures/MANIFEST-000988
Normal file
BIN
packs/boonsflawscreatures/MANIFEST-000988
Normal file
Binary file not shown.
Binary file not shown.
@@ -1 +1 @@
|
||||
MANIFEST-001074
|
||||
MANIFEST-000988
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
2026/02/28-22:59:53.759689 7f56f8bfd6c0 Recovering log #1072
|
||||
2026/02/28-22:59:53.770229 7f56f8bfd6c0 Delete type=3 #1070
|
||||
2026/02/28-22:59:53.770305 7f56f8bfd6c0 Delete type=0 #1072
|
||||
2026/03/01-01:08:46.327327 7f54e37ef6c0 Level-0 table #1077: started
|
||||
2026/03/01-01:08:46.327354 7f54e37ef6c0 Level-0 table #1077: 0 bytes OK
|
||||
2026/03/01-01:08:46.333262 7f54e37ef6c0 Delete type=0 #1075
|
||||
2026/03/01-01:08:46.339946 7f54e37ef6c0 Manual compaction at level-0 from '!items!4S4xAfMXGnuU0O1a' @ 72057594037927935 : 1 .. '!items!zxY3sW0iCJBvwjOS' @ 0 : 0; will stop at (end)
|
||||
2026/03/01-01:08:46.339979 7f54e37ef6c0 Manual compaction at level-1 from '!items!4S4xAfMXGnuU0O1a' @ 72057594037927935 : 1 .. '!items!zxY3sW0iCJBvwjOS' @ 0 : 0; will stop at (end)
|
||||
2026/01/19-19:47:49.635172 7f14d8ff96c0 Recovering log #986
|
||||
2026/01/19-19:47:49.644889 7f14d8ff96c0 Delete type=3 #984
|
||||
2026/01/19-19:47:49.644941 7f14d8ff96c0 Delete type=0 #986
|
||||
2026/01/19-20:19:02.508864 7f1243fff6c0 Level-0 table #991: started
|
||||
2026/01/19-20:19:02.508913 7f1243fff6c0 Level-0 table #991: 0 bytes OK
|
||||
2026/01/19-20:19:02.514913 7f1243fff6c0 Delete type=0 #989
|
||||
2026/01/19-20:19:02.534608 7f1243fff6c0 Manual compaction at level-0 from '!items!4S4xAfMXGnuU0O1a' @ 72057594037927935 : 1 .. '!items!zxY3sW0iCJBvwjOS' @ 0 : 0; will stop at (end)
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
2026/02/28-17:23:52.796426 7f56f9bff6c0 Recovering log #1068
|
||||
2026/02/28-17:23:52.805920 7f56f9bff6c0 Delete type=3 #1066
|
||||
2026/02/28-17:23:52.805973 7f56f9bff6c0 Delete type=0 #1068
|
||||
2026/02/28-22:59:43.711333 7f54e37ef6c0 Level-0 table #1073: started
|
||||
2026/02/28-22:59:43.711370 7f54e37ef6c0 Level-0 table #1073: 0 bytes OK
|
||||
2026/02/28-22:59:43.717336 7f54e37ef6c0 Delete type=0 #1071
|
||||
2026/02/28-22:59:43.731041 7f54e37ef6c0 Manual compaction at level-0 from '!items!4S4xAfMXGnuU0O1a' @ 72057594037927935 : 1 .. '!items!zxY3sW0iCJBvwjOS' @ 0 : 0; will stop at (end)
|
||||
2026/02/28-22:59:43.731086 7f54e37ef6c0 Manual compaction at level-1 from '!items!4S4xAfMXGnuU0O1a' @ 72057594037927935 : 1 .. '!items!zxY3sW0iCJBvwjOS' @ 0 : 0; will stop at (end)
|
||||
2026/01/18-20:07:47.704039 7f14d8ff96c0 Recovering log #982
|
||||
2026/01/18-20:07:47.721242 7f14d8ff96c0 Delete type=3 #980
|
||||
2026/01/18-20:07:47.721902 7f14d8ff96c0 Delete type=0 #982
|
||||
2026/01/18-20:13:43.777269 7f1243fff6c0 Level-0 table #987: started
|
||||
2026/01/18-20:13:43.777312 7f1243fff6c0 Level-0 table #987: 0 bytes OK
|
||||
2026/01/18-20:13:43.819988 7f1243fff6c0 Delete type=0 #985
|
||||
2026/01/18-20:13:43.921486 7f1243fff6c0 Manual compaction at level-0 from '!items!4S4xAfMXGnuU0O1a' @ 72057594037927935 : 1 .. '!items!zxY3sW0iCJBvwjOS' @ 0 : 0; will stop at (end)
|
||||
|
||||
BIN
packs/careers/MANIFEST-000988
Normal file
BIN
packs/careers/MANIFEST-000988
Normal file
Binary file not shown.
Binary file not shown.
@@ -1 +1 @@
|
||||
MANIFEST-001072
|
||||
MANIFEST-000986
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
2026/02/28-22:59:53.948768 7f56f93fe6c0 Recovering log #1070
|
||||
2026/02/28-22:59:53.958702 7f56f93fe6c0 Delete type=3 #1068
|
||||
2026/02/28-22:59:53.958781 7f56f93fe6c0 Delete type=0 #1070
|
||||
2026/03/01-01:08:46.425514 7f54e37ef6c0 Level-0 table #1075: started
|
||||
2026/03/01-01:08:46.425561 7f54e37ef6c0 Level-0 table #1075: 0 bytes OK
|
||||
2026/03/01-01:08:46.431671 7f54e37ef6c0 Delete type=0 #1073
|
||||
2026/03/01-01:08:46.445290 7f54e37ef6c0 Manual compaction at level-0 from '!items!6fTZ6hOKR4pWbWOe' @ 72057594037927935 : 1 .. '!items!zwSNMO9HpiqUCMt8' @ 0 : 0; will stop at (end)
|
||||
2026/03/01-01:08:46.445328 7f54e37ef6c0 Manual compaction at level-1 from '!items!6fTZ6hOKR4pWbWOe' @ 72057594037927935 : 1 .. '!items!zwSNMO9HpiqUCMt8' @ 0 : 0; will stop at (end)
|
||||
2026/01/19-19:47:49.822315 7f14d9ffb6c0 Recovering log #984
|
||||
2026/01/19-19:47:49.833348 7f14d9ffb6c0 Delete type=3 #982
|
||||
2026/01/19-19:47:49.833401 7f14d9ffb6c0 Delete type=0 #984
|
||||
2026/01/19-20:19:02.619154 7f1243fff6c0 Level-0 table #989: started
|
||||
2026/01/19-20:19:02.619176 7f1243fff6c0 Level-0 table #989: 0 bytes OK
|
||||
2026/01/19-20:19:02.626822 7f1243fff6c0 Delete type=0 #987
|
||||
2026/01/19-20:19:02.639748 7f1243fff6c0 Manual compaction at level-0 from '!items!6fTZ6hOKR4pWbWOe' @ 72057594037927935 : 1 .. '!items!zwSNMO9HpiqUCMt8' @ 0 : 0; will stop at (end)
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
2026/02/28-17:23:52.970603 7f56f9bff6c0 Recovering log #1066
|
||||
2026/02/28-17:23:52.981835 7f56f9bff6c0 Delete type=3 #1064
|
||||
2026/02/28-17:23:52.981888 7f56f9bff6c0 Delete type=0 #1066
|
||||
2026/02/28-22:59:43.785498 7f54e37ef6c0 Level-0 table #1071: started
|
||||
2026/02/28-22:59:43.785523 7f54e37ef6c0 Level-0 table #1071: 0 bytes OK
|
||||
2026/02/28-22:59:43.792317 7f54e37ef6c0 Delete type=0 #1069
|
||||
2026/02/28-22:59:43.813749 7f54e37ef6c0 Manual compaction at level-0 from '!items!6fTZ6hOKR4pWbWOe' @ 72057594037927935 : 1 .. '!items!zwSNMO9HpiqUCMt8' @ 0 : 0; will stop at (end)
|
||||
2026/02/28-22:59:43.813808 7f54e37ef6c0 Manual compaction at level-1 from '!items!6fTZ6hOKR4pWbWOe' @ 72057594037927935 : 1 .. '!items!zwSNMO9HpiqUCMt8' @ 0 : 0; will stop at (end)
|
||||
2026/01/18-20:07:48.004635 7f14d9ffb6c0 Recovering log #980
|
||||
2026/01/18-20:07:48.021334 7f14d9ffb6c0 Delete type=3 #978
|
||||
2026/01/18-20:07:48.021403 7f14d9ffb6c0 Delete type=0 #980
|
||||
2026/01/18-20:13:44.336530 7f1243fff6c0 Level-0 table #985: started
|
||||
2026/01/18-20:13:44.336556 7f1243fff6c0 Level-0 table #985: 0 bytes OK
|
||||
2026/01/18-20:13:44.372711 7f1243fff6c0 Delete type=0 #983
|
||||
2026/01/18-20:13:44.502487 7f1243fff6c0 Manual compaction at level-0 from '!items!6fTZ6hOKR4pWbWOe' @ 72057594037927935 : 1 .. '!items!zwSNMO9HpiqUCMt8' @ 0 : 0; will stop at (end)
|
||||
|
||||
BIN
packs/effets-exemples/MANIFEST-000986
Normal file
BIN
packs/effets-exemples/MANIFEST-000986
Normal file
Binary file not shown.
Binary file not shown.
@@ -1 +1 @@
|
||||
MANIFEST-001075
|
||||
MANIFEST-000989
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
2026/02/28-22:59:53.798832 7f56f9bff6c0 Recovering log #1073
|
||||
2026/02/28-22:59:53.809449 7f56f9bff6c0 Delete type=3 #1071
|
||||
2026/02/28-22:59:53.809533 7f56f9bff6c0 Delete type=0 #1073
|
||||
2026/03/01-01:08:46.340100 7f54e37ef6c0 Level-0 table #1078: started
|
||||
2026/03/01-01:08:46.340139 7f54e37ef6c0 Level-0 table #1078: 0 bytes OK
|
||||
2026/03/01-01:08:46.346846 7f54e37ef6c0 Delete type=0 #1076
|
||||
2026/03/01-01:08:46.366221 7f54e37ef6c0 Manual compaction at level-0 from '!items!0ErhyqifZLDCmMfT' @ 72057594037927935 : 1 .. '!items!yE8UH6YAgNGjKDEu' @ 0 : 0; will stop at (end)
|
||||
2026/03/01-01:08:46.366278 7f54e37ef6c0 Manual compaction at level-1 from '!items!0ErhyqifZLDCmMfT' @ 72057594037927935 : 1 .. '!items!yE8UH6YAgNGjKDEu' @ 0 : 0; will stop at (end)
|
||||
2026/01/19-19:47:49.675978 7f14d8ff96c0 Recovering log #987
|
||||
2026/01/19-19:47:49.685972 7f14d8ff96c0 Delete type=3 #985
|
||||
2026/01/19-19:47:49.686034 7f14d8ff96c0 Delete type=0 #987
|
||||
2026/01/19-20:19:02.553787 7f1243fff6c0 Level-0 table #992: started
|
||||
2026/01/19-20:19:02.553814 7f1243fff6c0 Level-0 table #992: 0 bytes OK
|
||||
2026/01/19-20:19:02.559887 7f1243fff6c0 Delete type=0 #990
|
||||
2026/01/19-20:19:02.560019 7f1243fff6c0 Manual compaction at level-0 from '!items!0ErhyqifZLDCmMfT' @ 72057594037927935 : 1 .. '!items!yE8UH6YAgNGjKDEu' @ 0 : 0; will stop at (end)
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
2026/02/28-17:23:52.834261 7f56f9bff6c0 Recovering log #1069
|
||||
2026/02/28-17:23:52.843912 7f56f9bff6c0 Delete type=3 #1067
|
||||
2026/02/28-17:23:52.843969 7f56f9bff6c0 Delete type=0 #1069
|
||||
2026/02/28-22:59:43.704672 7f54e37ef6c0 Level-0 table #1074: started
|
||||
2026/02/28-22:59:43.704745 7f54e37ef6c0 Level-0 table #1074: 0 bytes OK
|
||||
2026/02/28-22:59:43.711212 7f54e37ef6c0 Delete type=0 #1072
|
||||
2026/02/28-22:59:43.731026 7f54e37ef6c0 Manual compaction at level-0 from '!items!0ErhyqifZLDCmMfT' @ 72057594037927935 : 1 .. '!items!yE8UH6YAgNGjKDEu' @ 0 : 0; will stop at (end)
|
||||
2026/02/28-22:59:43.731077 7f54e37ef6c0 Manual compaction at level-1 from '!items!0ErhyqifZLDCmMfT' @ 72057594037927935 : 1 .. '!items!yE8UH6YAgNGjKDEu' @ 0 : 0; will stop at (end)
|
||||
2026/01/18-20:07:47.766393 7f14d8ff96c0 Recovering log #983
|
||||
2026/01/18-20:07:47.781538 7f14d8ff96c0 Delete type=3 #981
|
||||
2026/01/18-20:07:47.781589 7f14d8ff96c0 Delete type=0 #983
|
||||
2026/01/18-20:13:43.983716 7f1243fff6c0 Level-0 table #988: started
|
||||
2026/01/18-20:13:43.983740 7f1243fff6c0 Level-0 table #988: 0 bytes OK
|
||||
2026/01/18-20:13:44.023789 7f1243fff6c0 Delete type=0 #986
|
||||
2026/01/18-20:13:44.053229 7f1243fff6c0 Manual compaction at level-0 from '!items!0ErhyqifZLDCmMfT' @ 72057594037927935 : 1 .. '!items!yE8UH6YAgNGjKDEu' @ 0 : 0; will stop at (end)
|
||||
|
||||
BIN
packs/equipment/MANIFEST-000989
Normal file
BIN
packs/equipment/MANIFEST-000989
Normal file
Binary file not shown.
Binary file not shown.
@@ -1 +1 @@
|
||||
MANIFEST-001074
|
||||
MANIFEST-000988
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
2026/02/28-22:59:53.895577 7f56f8bfd6c0 Recovering log #1072
|
||||
2026/02/28-22:59:53.906749 7f56f8bfd6c0 Delete type=3 #1070
|
||||
2026/02/28-22:59:53.906807 7f56f8bfd6c0 Delete type=0 #1072
|
||||
2026/03/01-01:08:46.391890 7f54e37ef6c0 Level-0 table #1077: started
|
||||
2026/03/01-01:08:46.391936 7f54e37ef6c0 Level-0 table #1077: 0 bytes OK
|
||||
2026/03/01-01:08:46.398187 7f54e37ef6c0 Delete type=0 #1075
|
||||
2026/03/01-01:08:46.417834 7f54e37ef6c0 Manual compaction at level-0 from '!items!AoT2c0af4lY6aBsx' @ 72057594037927935 : 1 .. '!items!vGydqADwTsHZ9B3j' @ 0 : 0; will stop at (end)
|
||||
2026/03/01-01:08:46.417875 7f54e37ef6c0 Manual compaction at level-1 from '!items!AoT2c0af4lY6aBsx' @ 72057594037927935 : 1 .. '!items!vGydqADwTsHZ9B3j' @ 0 : 0; will stop at (end)
|
||||
2026/01/19-19:47:49.769389 7f14d8ff96c0 Recovering log #986
|
||||
2026/01/19-19:47:49.779377 7f14d8ff96c0 Delete type=3 #984
|
||||
2026/01/19-19:47:49.779429 7f14d8ff96c0 Delete type=0 #986
|
||||
2026/01/19-20:19:02.593611 7f1243fff6c0 Level-0 table #991: started
|
||||
2026/01/19-20:19:02.593633 7f1243fff6c0 Level-0 table #991: 0 bytes OK
|
||||
2026/01/19-20:19:02.599673 7f1243fff6c0 Delete type=0 #989
|
||||
2026/01/19-20:19:02.612871 7f1243fff6c0 Manual compaction at level-0 from '!items!AoT2c0af4lY6aBsx' @ 72057594037927935 : 1 .. '!items!vGydqADwTsHZ9B3j' @ 0 : 0; will stop at (end)
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
2026/02/28-17:23:52.920377 7f56e3fff6c0 Recovering log #1068
|
||||
2026/02/28-17:23:52.930570 7f56e3fff6c0 Delete type=3 #1066
|
||||
2026/02/28-17:23:52.930642 7f56e3fff6c0 Delete type=0 #1068
|
||||
2026/02/28-22:59:43.758590 7f54e37ef6c0 Level-0 table #1073: started
|
||||
2026/02/28-22:59:43.758628 7f54e37ef6c0 Level-0 table #1073: 0 bytes OK
|
||||
2026/02/28-22:59:43.764731 7f54e37ef6c0 Delete type=0 #1071
|
||||
2026/02/28-22:59:43.785330 7f54e37ef6c0 Manual compaction at level-0 from '!items!AoT2c0af4lY6aBsx' @ 72057594037927935 : 1 .. '!items!vGydqADwTsHZ9B3j' @ 0 : 0; will stop at (end)
|
||||
2026/02/28-22:59:43.785372 7f54e37ef6c0 Manual compaction at level-1 from '!items!AoT2c0af4lY6aBsx' @ 72057594037927935 : 1 .. '!items!vGydqADwTsHZ9B3j' @ 0 : 0; will stop at (end)
|
||||
2026/01/18-20:07:47.909338 7f14d9ffb6c0 Recovering log #982
|
||||
2026/01/18-20:07:47.941648 7f14d9ffb6c0 Delete type=3 #980
|
||||
2026/01/18-20:07:47.941699 7f14d9ffb6c0 Delete type=0 #982
|
||||
2026/01/18-20:13:44.233085 7f1243fff6c0 Level-0 table #987: started
|
||||
2026/01/18-20:13:44.233108 7f1243fff6c0 Level-0 table #987: 0 bytes OK
|
||||
2026/01/18-20:13:44.259693 7f1243fff6c0 Delete type=0 #985
|
||||
2026/01/18-20:13:44.336426 7f1243fff6c0 Manual compaction at level-0 from '!items!AoT2c0af4lY6aBsx' @ 72057594037927935 : 1 .. '!items!vGydqADwTsHZ9B3j' @ 0 : 0; will stop at (end)
|
||||
|
||||
BIN
packs/fightoptions/MANIFEST-000988
Normal file
BIN
packs/fightoptions/MANIFEST-000988
Normal file
Binary file not shown.
Binary file not shown.
@@ -1 +1 @@
|
||||
MANIFEST-000557
|
||||
MANIFEST-000471
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
2026/02/28-22:59:53.909216 7f56f93fe6c0 Recovering log #555
|
||||
2026/02/28-22:59:53.919079 7f56f93fe6c0 Delete type=3 #553
|
||||
2026/02/28-22:59:53.919136 7f56f93fe6c0 Delete type=0 #555
|
||||
2026/03/01-01:08:46.411300 7f54e37ef6c0 Level-0 table #560: started
|
||||
2026/03/01-01:08:46.411339 7f54e37ef6c0 Level-0 table #560: 0 bytes OK
|
||||
2026/03/01-01:08:46.417727 7f54e37ef6c0 Delete type=0 #558
|
||||
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/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)
|
||||
2026/01/19-19:47:49.781873 7f14d9ffb6c0 Recovering log #469
|
||||
2026/01/19-19:47:49.791906 7f14d9ffb6c0 Delete type=3 #467
|
||||
2026/01/19-19:47:49.791963 7f14d9ffb6c0 Delete type=0 #469
|
||||
2026/01/19-20:19:02.599791 7f1243fff6c0 Level-0 table #474: started
|
||||
2026/01/19-20:19:02.599817 7f1243fff6c0 Level-0 table #474: 0 bytes OK
|
||||
2026/01/19-20:19:02.606216 7f1243fff6c0 Delete type=0 #472
|
||||
2026/01/19-20:19:02.612886 7f1243fff6c0 Manual compaction at level-0 from '!items!CLRp0k5qV8mD03pW' @ 72057594037927935 : 1 .. '!items!wYEpnhbyYaMkaNdL' @ 0 : 0; will stop at (end)
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
2026/02/28-17:23:52.933111 7f56f9bff6c0 Recovering log #551
|
||||
2026/02/28-17:23:52.944230 7f56f9bff6c0 Delete type=3 #549
|
||||
2026/02/28-17:23:52.944299 7f56f9bff6c0 Delete type=0 #551
|
||||
2026/02/28-22:59:43.771257 7f54e37ef6c0 Level-0 table #556: started
|
||||
2026/02/28-22:59:43.771301 7f54e37ef6c0 Level-0 table #556: 0 bytes OK
|
||||
2026/02/28-22:59:43.778711 7f54e37ef6c0 Delete type=0 #554
|
||||
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/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)
|
||||
2026/01/18-20:07:47.944158 7f14da7fc6c0 Recovering log #465
|
||||
2026/01/18-20:07:47.960589 7f14da7fc6c0 Delete type=3 #463
|
||||
2026/01/18-20:07:47.960660 7f14da7fc6c0 Delete type=0 #465
|
||||
2026/01/18-20:13:44.259805 7f1243fff6c0 Level-0 table #470: started
|
||||
2026/01/18-20:13:44.259831 7f1243fff6c0 Level-0 table #470: 0 bytes OK
|
||||
2026/01/18-20:13:44.295095 7f1243fff6c0 Delete type=0 #468
|
||||
2026/01/18-20:13:44.336439 7f1243fff6c0 Manual compaction at level-0 from '!items!CLRp0k5qV8mD03pW' @ 72057594037927935 : 1 .. '!items!wYEpnhbyYaMkaNdL' @ 0 : 0; will stop at (end)
|
||||
|
||||
BIN
packs/fightoptionsfanmade/MANIFEST-000471
Normal file
BIN
packs/fightoptionsfanmade/MANIFEST-000471
Normal file
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user