Compare commits

...

15 Commits

Author SHA1 Message Date
dc3040df26 Migration vers DataModels et appv2
All checks were successful
Release Creation / build (release) Successful in 53s
2026-01-10 22:51:45 +01:00
b1bce86604 Migration vers DataModels et appv2 2026-01-10 22:49:38 +01:00
6066091d8d Fix after testing 2026-01-10 22:36:38 +01:00
287b6d83a7 Fix after testing 2026-01-10 22:36:26 +01:00
d8efba89a1 Fix after testing 2026-01-10 22:36:01 +01:00
936d525503 Fix after testing 2026-01-10 22:35:39 +01:00
b113f630bf Migration vers DataModels et appv2 2026-01-10 15:08:28 +01:00
939cfb1e86 Update compendiums 2025-09-15 22:23:25 +02:00
5f5e0e2a8c Update magie 2025-09-15 21:10:46 +02:00
c993a9a5b1 Update magie 2025-09-15 21:09:09 +02:00
cc7de0e53c Amelioration diverses pour la magie 2025-09-14 20:12:02 +02:00
4d41986c12 Ajout pour la magie 2025-09-13 00:24:58 +02:00
d04731f475 Ajout pour la magie 2025-09-13 00:24:08 +02:00
44a641a0ca Update arts obscurs 2025-08-13 09:39:04 +02:00
1ad022d193 Update arts obscurs 2025-08-13 09:38:35 +02:00
165 changed files with 14965 additions and 2511 deletions

View File

@@ -0,0 +1,63 @@
name: Release Creation
on:
release:
types: [published]
jobs:
build:
runs-on: ubuntu-latest
steps:
- run: echo "💡 The ${{ gitea.repository }} repository will cloned to the runner."
#- uses: actions/checkout@v3
- uses: RouxAntoine/checkout@v3.5.4
# 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
- name: Substitute Manifest and Download Links For Versioned Ones
id: sub_manifest_link_version
uses: microsoft/variable-substitution@v1
with:
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/fvtt-les-heritiers/releases/download/latest/system.json
download: https://www.uberwald.me/gitea/${{gitea.repository}}/releases/download/${{github.event.release.tag_name}}/fvtt-les-heritiers.zip
# Create a zip file with all files required by the module to add to the release
- run: |
apt update -y
apt install -y zip
- run: zip -r ./fvtt-les-heritiers.zip system.json README.md LICENCE.txt assets/ lang/ modules/ packs/ styles/ templates/
- name: setup go
uses: https://github.com/actions/setup-go@v4
with:
go-version: '>=1.20.1'
- name: Use Go Action
id: use-go-action
uses: https://gitea.com/actions/release-action@main
with:
files: |-
./fvtt-les-heritiers.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: 'fvtt-les-heritiers'
version: ${{github.event.release.tag_name}}
manifest: 'https://www.uberwald.me/gitea/public/fvtt-les-heritiers/releases/download/latest/system.json'
notes: 'https://www.uberwald.me/gitea/${{gitea.repository}}/releases/download/${{github.event.release.tag_name}}/fvtt-les-heritiers.zip'
compatibility-minimum: '13'
compatibility-verified: '13'

1
.gitignore vendored
View File

@@ -1 +1,2 @@
.history/
node_modules

35
gulpfile.js Normal file
View File

@@ -0,0 +1,35 @@
const gulp = require('gulp');
const less = require('gulp-less');
const sourcemaps = require('gulp-sourcemaps');
// Paths
const paths = {
styles: {
src: 'less/**/*.less',
dest: 'styles/'
}
};
// Compile LESS to CSS
function styles() {
return gulp.src('less/heritiers.less')
.pipe(sourcemaps.init())
.pipe(less())
.pipe(sourcemaps.write('.'))
.pipe(gulp.dest(paths.styles.dest));
}
// Watch files
function watchFiles() {
gulp.watch(paths.styles.src, styles);
}
// Define complex tasks
const build = gulp.series(styles);
const watch = gulp.series(build, watchFiles);
// Export tasks
exports.styles = styles;
exports.build = build;
exports.watch = watch;
exports.default = build;

4
less/heritiers.less Normal file
View File

@@ -0,0 +1,4 @@
// Main LESS file for Les Héritiers system
// Temporarily importing the full converted simple.css while we refactor
@import "simple-converted";

2809
less/simple-converted.less Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,213 @@
import { HeritiersUtility } from "../heritiers-utility.js"
/**
* Dialogue de jet de dé pour Les Héritiers - Version AppV2
*/
export class HeritiersRollDialog {
/**
* Create and display the roll dialog
* @param {HeritiersActor} actor - The actor making the roll
* @param {Object} rollData - Data for the roll
* @returns {Promise<Object>} - Returns a dialog-like object for compatibility
*/
static async create(actor, rollData) {
// Préparer le contexte pour le template
const context = {
...rollData,
img: actor.img,
name: actor.name,
config: game.system.lesheritiers.config,
}
// Rendre le template en HTML
const content = await foundry.applications.handlebars.renderTemplate(
"systems/fvtt-les-heritiers/templates/roll-dialog-generic.hbs",
context
)
// Préparer les boutons selon le mode et le niveau
const buttons = this._prepareButtons(rollData)
// Utiliser DialogV2.wait avec le HTML rendu
return foundry.applications.api.DialogV2.wait({
window: { title: "Test de Capacité", icon: "fa-solid fa-dice" },
classes: ["heritiers-roll-dialog"],
position: { width: 420 },
modal: false,
content,
buttons,
rejectClose: false
})
}
/**
* Préparer les boutons selon le mode et le niveau de compétence
* @param {Object} rollData - Data for the roll
* @returns {Array} - Array of button configurations
* @private
*/
static _prepareButtons(rollData) {
const buttons = []
// Bouton d8 toujours disponible
buttons.push({
action: "rolld8",
label: "1d8",
icon: "fa-solid fa-dice-d8",
default: true,
callback: (event, button, dialog) => {
this._updateRollDataFromForm(rollData, button.form.elements)
this._executeRoll(rollData, "d8")
}
})
// Bouton d10 si niveau > 0 ou pouvoir
const enableD10 = rollData.mode === "pouvoir" || rollData.competence?.system.niveau > 0
if (enableD10) {
buttons.push({
action: "rolld10",
label: "1d10",
icon: "fa-solid fa-dice-d10",
callback: (event, button, dialog) => {
this._updateRollDataFromForm(rollData, button.form.elements)
this._executeRoll(rollData, "d10")
}
})
}
// Bouton d12 si niveau > 1 ou pouvoir
const enableD12 = rollData.mode === "pouvoir" || rollData.competence?.system.niveau > 1
if (enableD12) {
buttons.push({
action: "rolld12",
label: "1d12",
icon: "fa-solid fa-dice-d12",
callback: (event, button, dialog) => {
this._updateRollDataFromForm(rollData, button.form.elements)
this._executeRoll(rollData, "d12")
}
})
}
// Bouton Tricherie si disponible
if (rollData.tricherie) {
buttons.push({
action: "rollTricherie",
label: "Lancer 1 Tricherie",
icon: "fa-solid fa-mask",
callback: (event, button, dialog) => {
this._updateRollDataFromForm(rollData, button.form.elements)
this._executeRoll(rollData, "tricherie")
}
})
}
// Bouton Héritage si disponible
if (rollData.heritage) {
buttons.push({
action: "rollHeritage",
label: "Lancer 1 Héritage",
icon: "fa-solid fa-crown",
callback: (event, button, dialog) => {
this._updateRollDataFromForm(rollData, button.form.elements)
this._executeRoll(rollData, "heritage")
}
})
}
// Si mode carac uniquement, on ne garde que d8
if (rollData.mode === "carac") {
return [
{
action: "rolld8",
label: "Lancer 1d8",
icon: "fa-solid fa-dice-d8",
default: true,
callback: (event, button, dialog) => {
this._updateRollDataFromForm(rollData, button.form.elements)
this._executeRoll(rollData, "d8")
}
}
]
}
return buttons
}
/**
* Mettre à jour rollData avec les valeurs du formulaire
* @param {Object} rollData - L'objet rollData à mettre à jour
* @param {HTMLFormControlsCollection} formElements - Les éléments du formulaire
* @private
*/
static _updateRollDataFromForm(rollData, formElements) {
// Seuil de Difficulté
if (formElements.sdValue) {
rollData.sdValue = Number(formElements.sdValue.value)
}
// Caractéristique
if (formElements.caracKey) {
rollData.caracKey = String(formElements.caracKey.value)
}
// Bonus/Malus contextuel
if (formElements['bonus-malus-context']) {
rollData.bonusMalusContext = Number(formElements['bonus-malus-context'].value)
}
// Attaque à plusieurs
if (formElements['bonus-attaque-plusieurs']) {
rollData.bonusAttaquePlusieurs = Number(formElements['bonus-attaque-plusieurs'].value)
}
// Spécialité
if (formElements.useSpecialite !== undefined) {
rollData.useSpecialite = formElements.useSpecialite.checked
}
// Points d'usage du pouvoir
if (formElements.pouvoirPointsUsage) {
rollData.pouvoirPointsUsage = Number(formElements.pouvoirPointsUsage.value)
}
// Attaque dans le dos
if (formElements.attaqueDos !== undefined) {
rollData.attaqueDos = formElements.attaqueDos.checked
}
// Seconde arme
if (formElements['bonus-attaque-seconde-arme']) {
rollData.secondeArme = String(formElements['bonus-attaque-seconde-arme'].value)
}
// Attaque ciblée
if (formElements['attaque-cible']) {
rollData.attaqueCible = String(formElements['attaque-cible'].value)
}
// Attaque à deux armes
if (formElements['bonus-attaque-deux-armes']) {
rollData.attaqueDeuxArmes = Number(formElements['bonus-attaque-deux-armes'].value)
}
}
/**
* Exécuter le jet de dés
* @param {Object} rollData - Data for the roll
* @param {String} dice - Type de dé (d8, d10, d12, tricherie, heritage)
* @private
*/
static _executeRoll(rollData, dice) {
if (dice === "heritage") {
rollData.useHeritage = true
} else if (dice === "tricherie") {
rollData.useTricherie = true
} else {
rollData.mainDice = dice
}
HeritiersUtility.rollHeritiers(rollData)
}
}

View File

@@ -0,0 +1,23 @@
/**
* Export all application sheets for Les Héritiers
*/
// Actor Sheets
export { default as HeritiersPersonnageSheet } from './personnage-sheet.mjs';
export { default as HeritiersPnjSheet } from './pnj-sheet.mjs';
// Item Sheets
export { default as HeritiersAccessoireSheet } from './accessoire-sheet.mjs';
export { default as HeritiersArmeSheet } from './arme-sheet.mjs';
export { default as HeritiersAtoutFeeriqueSheet } from './atoutfeerique-sheet.mjs';
export { default as HeritiersAvantageSheet } from './avantage-sheet.mjs';
export { default as HeritiersCapaciteNaturelleSheet } from './capacitenaturelle-sheet.mjs';
export { default as HeritiersCompetenceSheet } from './competence-sheet.mjs';
export { default as HeritiersContactSheet } from './contact-sheet.mjs';
export { default as HeritiersDesavantageSheet } from './desavantage-sheet.mjs';
export { default as HeritiersEquipementSheet } from './equipement-sheet.mjs';
export { default as HeritiersFeeSheet } from './fee-sheet.mjs';
export { default as HeritiersPouvoirSheet } from './pouvoir-sheet.mjs';
export { default as HeritiersProfilSheet } from './profil-sheet.mjs';
export { default as HeritiersProtectionSheet } from './protection-sheet.mjs';
export { default as HeritiersSortSheet } from './sort-sheet.mjs';

View File

@@ -0,0 +1,19 @@
import HeritiersItemSheet from "./base-item-sheet.mjs"
export default class HeritiersAccessoireSheet extends HeritiersItemSheet {
/** @override */
static DEFAULT_OPTIONS = {
...super.DEFAULT_OPTIONS,
window: {
...super.DEFAULT_OPTIONS.window,
title: "SHEETS.Item.accessoire",
},
}
/** @override */
static PARTS = {
sheet: {
template: "systems/fvtt-les-heritiers/templates/item-accessoire-sheet.hbs",
},
}
}

View File

@@ -0,0 +1,19 @@
import HeritiersItemSheet from "./base-item-sheet.mjs"
export default class HeritiersArmeSheet extends HeritiersItemSheet {
/** @override */
static DEFAULT_OPTIONS = {
...super.DEFAULT_OPTIONS,
window: {
...super.DEFAULT_OPTIONS.window,
title: "SHEETS.Item.arme",
},
}
/** @override */
static PARTS = {
sheet: {
template: "systems/fvtt-les-heritiers/templates/item-arme-sheet.hbs",
},
}
}

View File

@@ -0,0 +1,19 @@
import HeritiersItemSheet from "./base-item-sheet.mjs"
export default class HeritiersAtoutFeeriqueSheet extends HeritiersItemSheet {
/** @override */
static DEFAULT_OPTIONS = {
...super.DEFAULT_OPTIONS,
window: {
...super.DEFAULT_OPTIONS.window,
title: "SHEETS.Item.atoutfeerique",
},
}
/** @override */
static PARTS = {
sheet: {
template: "systems/fvtt-les-heritiers/templates/item-atoutfeerique-sheet.hbs",
},
}
}

View File

@@ -0,0 +1,19 @@
import HeritiersItemSheet from "./base-item-sheet.mjs"
export default class HeritiersAvantageSheet extends HeritiersItemSheet {
/** @override */
static DEFAULT_OPTIONS = {
...super.DEFAULT_OPTIONS,
window: {
...super.DEFAULT_OPTIONS.window,
title: "SHEETS.Item.avantage",
},
}
/** @override */
static PARTS = {
sheet: {
template: "systems/fvtt-les-heritiers/templates/item-avantage-sheet.hbs",
},
}
}

View File

@@ -0,0 +1,675 @@
const { HandlebarsApplicationMixin } = foundry.applications.api
import { HeritiersUtility } from "../../heritiers-utility.js"
export default class HeritiersActorSheet extends HandlebarsApplicationMixin(foundry.applications.sheets.ActorSheetV2) {
/**
* Different sheet modes.
* @enum {number}
*/
static SHEET_MODES = { EDIT: 0, PLAY: 1 }
constructor(options = {}) {
super(options)
this.#dragDrop = this.#createDragDropHandlers()
this._sheetMode = this.constructor.SHEET_MODES.PLAY
}
#dragDrop
/** @override */
static DEFAULT_OPTIONS = {
classes: ["fvtt-les-heritiers", "sheet", "actor"],
position: {
width: 780,
height: 840,
},
window: {
resizable: true,
},
form: {
submitOnChange: true,
closeOnSubmit: false,
},
dragDrop: [{ dragSelector: ".item-list .item", dropSelector: "form" }],
actions: {
editImage: HeritiersActorSheet.#onEditImage,
toggleSheet: HeritiersActorSheet.#onToggleSheet,
editItem: HeritiersActorSheet.#onEditItem,
deleteItem: HeritiersActorSheet.#onDeleteItem,
createItem: HeritiersActorSheet.#onCreateItem,
equipItem: HeritiersActorSheet.#onEquipItem,
modifyQuantity: HeritiersActorSheet.#onModifyQuantity,
quantityIncrease: HeritiersActorSheet.#onQuantityIncrease,
quantityDecrease: HeritiersActorSheet.#onQuantityDecrease,
pvIncrease: HeritiersActorSheet.#onPvIncrease,
pvDecrease: HeritiersActorSheet.#onPvDecrease,
rollInitiative: HeritiersActorSheet.#onRollInitiative,
rollCarac: HeritiersActorSheet.#onRollCarac,
rollRang: HeritiersActorSheet.#onRollRang,
rollRootCompetence: HeritiersActorSheet.#onRollRootCompetence,
rollCompetence: HeritiersActorSheet.#onRollCompetence,
rollSort: HeritiersActorSheet.#onRollSort,
rollAttaqueArme: HeritiersActorSheet.#onRollAttaqueArme,
rollAttaqueBrutaleArme: HeritiersActorSheet.#onRollAttaqueBrutaleArme,
rollAttaqueChargeArme: HeritiersActorSheet.#onRollAttaqueChargeArme,
rollAssomerArme: HeritiersActorSheet.#onRollAssomerArme,
rollPouvoir: HeritiersActorSheet.#onRollPouvoir,
toggleMasque: HeritiersActorSheet.#onToggleMasque,
dialogRecupUsage: HeritiersActorSheet.#onDialogRecupUsage,
},
}
/**
* Is the sheet currently in 'Play' mode?
* @type {boolean}
*/
get isPlayMode() {
if (this._sheetMode === undefined) this._sheetMode = this.constructor.SHEET_MODES.PLAY
return this._sheetMode === this.constructor.SHEET_MODES.PLAY
}
/**
* Is the sheet currently in 'Edit' mode?
* @type {boolean}
*/
get isEditMode() {
if (this._sheetMode === undefined) this._sheetMode = this.constructor.SHEET_MODES.PLAY
return this._sheetMode === this.constructor.SHEET_MODES.EDIT
}
/**
* Tab groups state
* @type {object}
*/
tabGroups = { primary: "competences" }
/** @override */
async _prepareContext() {
const actor = this.document
const context = {
actor: actor,
system: actor.system,
source: actor.toObject(),
fields: actor.schema.fields,
systemFields: actor.system.schema.fields,
isEditable: this.isEditable,
isEditMode: this.isEditMode,
isPlayMode: this.isPlayMode,
isGM: game.user.isGM,
config: CONFIG.HERITIERS,
enrichedDescription: await foundry.applications.ux.TextEditor.implementation.enrichHTML(actor.system.biodata?.description || "", { async: true }),
enrichedHabitat: await foundry.applications.ux.TextEditor.implementation.enrichHTML(actor.system.biodata?.habitat || "", { async: true }),
enrichedRevesetranges: await foundry.applications.ux.TextEditor.implementation.enrichHTML(actor.system.biodata?.revesetranges || "", { async: true }),
enrichedSecretsdecouverts: await foundry.applications.ux.TextEditor.implementation.enrichHTML(actor.system.biodata?.secretsdecouverts || "", { async: true }),
enrichedQuestions: await foundry.applications.ux.TextEditor.implementation.enrichHTML(actor.system.biodata?.questions || "", { async: true }),
enrichedPlayernotes: await foundry.applications.ux.TextEditor.implementation.enrichHTML(actor.system.biodata?.playernotes || "", { async: true }),
}
return context
}
/** @override */
_onRender(context, options) {
super._onRender(context, options)
// Activate drag & drop handlers
this.#dragDrop.forEach(d => d.bind(this.element))
// Manual tab navigation
const html = this.element
const tabLinks = html.querySelectorAll('.sheet-tabs a.item[data-tab]')
const tabContents = html.querySelectorAll('.sheet-body .tab[data-group="primary"]')
// Hide all tabs initially
tabContents.forEach(tab => {
tab.classList.remove('active')
tab.style.display = 'none'
})
// Show active tab
const activeTab = this.tabGroups.primary
const activeTabContent = html.querySelector(`.tab[data-group="primary"][data-tab="${activeTab}"]`)
if (activeTabContent) {
activeTabContent.classList.add('active')
activeTabContent.style.display = 'block'
}
// Activate the corresponding nav link
tabLinks.forEach(link => {
if (link.dataset.tab === activeTab) {
link.classList.add('active')
} else {
link.classList.remove('active')
}
})
// Tab click handler
tabLinks.forEach(link => {
link.addEventListener('click', (event) => {
event.preventDefault()
const tab = link.dataset.tab
// Update state
this.tabGroups.primary = tab
// Hide all tabs
tabContents.forEach(t => {
t.classList.remove('active')
t.style.display = 'none'
})
// Show selected tab
const selectedTab = html.querySelector(`.tab[data-group="primary"][data-tab="${tab}"]`)
if (selectedTab) {
selectedTab.classList.add('active')
selectedTab.style.display = 'block'
}
// Update nav links
tabLinks.forEach(l => {
if (l.dataset.tab === tab) {
l.classList.add('active')
} else {
l.classList.remove('active')
}
})
})
})
// Inline item editing
html.querySelectorAll('.edit-item-data').forEach(input => {
input.addEventListener('change', (event) => {
const li = event.target.closest('.item')
const itemId = li?.dataset.itemId
const itemType = li?.dataset.itemType
const itemField = event.target.dataset.itemField
const dataType = event.target.dataset.dtype
const value = event.target.value
if (itemId && itemType && itemField) {
this.actor.editItemField(itemId, itemType, itemField, dataType, value)
}
})
})
}
// #region Drag & Drop
/**
* Create drag-and-drop workflow handlers for this Application
* @returns {DragDrop[]} An array of DragDrop handlers
* @private
*/
#createDragDropHandlers() {
return this.options.dragDrop.map((d) => {
d.permissions = {
dragstart: this._canDragStart.bind(this),
drop: this._canDragDrop.bind(this),
}
d.callbacks = {
dragstart: this._onDragStart.bind(this),
drop: this._onDrop.bind(this),
}
return new foundry.applications.ux.DragDrop(d)
})
}
/**
* Define whether a user is able to begin a dragstart workflow for a given drag selector
* @param {string} selector The candidate HTML selector for dragging
* @returns {boolean} Can the current user drag this selector?
* @protected
*/
_canDragStart(selector) {
return this.isEditable
}
/**
* Define whether a user is able to conclude a drag-and-drop workflow for a given drop selector
* @param {string} selector The candidate HTML selector for the drop target
* @returns {boolean} Can the current user drop on this selector?
* @protected
*/
_canDragDrop(selector) {
return this.isEditable
}
/**
* Callback actions which occur at the beginning of a drag start workflow.
* @param {DragEvent} event The originating DragEvent
* @protected
*/
_onDragStart(event) {
const li = event.currentTarget.closest(".item")
if (!li?.dataset.itemId) return
const item = this.actor.items.get(li.dataset.itemId)
if (!item) return
const dragData = item.toDragData()
event.dataTransfer.setData("text/plain", JSON.stringify(dragData))
}
/**
* Callback actions which occur when a dragged element is dropped on a target.
* @param {DragEvent} event The originating DragEvent
* @protected
*/
async _onDrop(event) {
const data = foundry.applications.ux.TextEditor.implementation.getDragEventData(event)
const actor = this.actor
// Handle different data types
switch (data.type) {
case "Item":
return this._onDropItem(event, data)
case "Actor":
return this._onDropActor(event, data)
case "ActiveEffect":
return this._onDropActiveEffect(event, data)
}
}
/**
* Handle dropping an Item on the actor sheet
* @param {DragEvent} event
* @param {object} data
* @private
*/
async _onDropItem(event, data) {
if (!this.actor.isOwner) return false
let item = await fromUuid(data.uuid)
if (item.pack) {
item = await HeritiersUtility.searchItem(item)
}
const itemData = item.toObject ? item.toObject() : item
return this.actor.createEmbeddedDocuments("Item", [itemData])
}
/**
* Handle dropping an Actor on the sheet
* @param {DragEvent} event
* @param {object} data
* @private
*/
async _onDropActor(event, data) {
return false
}
/**
* Handle dropping an ActiveEffect on the sheet
* @param {DragEvent} event
* @param {object} data
* @private
*/
async _onDropActiveEffect(event, data) {
return false
}
// #endregion
// #region Action Handlers
/**
* Toggle between edit and play mode
* @param {Event} event
* @param {HTMLElement} target
* @private
*/
static #onToggleSheet(event, target) {
const wasEditMode = this.isEditMode
this._sheetMode = wasEditMode ? this.constructor.SHEET_MODES.PLAY : this.constructor.SHEET_MODES.EDIT
this.render({ force: true })
}
/**
* Edit the actor image
* @param {Event} event
* @param {HTMLElement} target
* @private
*/
static async #onEditImage(event, target) {
const fp = new FilePicker({
type: "image",
current: this.actor.img,
callback: (path) => {
this.actor.update({ img: path })
},
})
return fp.browse()
}
/**
* Edit an item
* @param {Event} event
* @param {HTMLElement} target
* @private
*/
static async #onEditItem(event, target) {
const li = target.closest(".item")
const itemId = li?.dataset.itemId
if (!itemId) return
const item = this.actor.items.get(itemId)
if (item) item.sheet.render(true)
}
/**
* Delete an item
* @param {Event} event
* @param {HTMLElement} target
* @private
*/
static async #onDeleteItem(event, target) {
const li = target.closest(".item")
await HeritiersUtility.confirmDelete(this, li)
}
/**
* Create a new item
* @param {Event} event
* @param {HTMLElement} target
* @private
*/
static async #onCreateItem(event, target) {
const itemType = target.dataset.type
// Cas spécial pour les sorts avec une compétence spécifique
if (itemType === "sort" && target.dataset.sortCompetence) {
const sortCompetence = target.dataset.sortCompetence
await this.actor.createEmbeddedDocuments('Item', [{
name: `Nouveau ${itemType} de ${sortCompetence}`,
type: itemType,
system: { competence: sortCompetence }
}], { renderSheet: true })
return
}
await this.actor.createEmbeddedDocuments("Item", [{ name: `Nouveau ${itemType}`, type: itemType }], { renderSheet: true })
}
/**
* Equip/unequip an item
* @param {Event} event
* @param {HTMLElement} target
* @private
*/
static async #onEquipItem(event, target) {
const li = target.closest(".item")
const itemId = li?.dataset.itemId
if (itemId) {
await this.actor.equipItem(itemId)
this.render()
}
}
/**
* Modify item quantity
* @param {Event} event
* @param {HTMLElement} target
* @private
*/
static async #onModifyQuantity(event, target) {
const li = target.closest(".item")
const itemId = li?.dataset.itemId
const value = Number(target.dataset.quantiteValue)
if (itemId) {
await this.actor.incDecQuantity(itemId, value)
}
}
/**
* Increase item quantity
* @param {Event} event
* @param {HTMLElement} target
* @private
*/
static async #onQuantityIncrease(event, target) {
const li = target.closest(".item")
const itemId = li?.dataset.itemId
if (itemId) {
await this.actor.incDecQuantity(itemId, 1)
}
}
/**
* Decrease item quantity
* @param {Event} event
* @param {HTMLElement} target
* @private
*/
static async #onQuantityDecrease(event, target) {
const li = target.closest(".item")
const itemId = li?.dataset.itemId
if (itemId) {
await this.actor.incDecQuantity(itemId, -1)
}
}
/**
* Increase PV
* @param {Event} event
* @param {HTMLElement} target
* @private
*/
static async #onPvIncrease(event, target) {
const currentPv = this.actor.system.pv.value || 0
const maxPv = this.actor.system.pv.max || 0
const newPv = Math.min(currentPv + 1, maxPv)
await this.actor.update({ 'system.pv.value': newPv })
}
/**
* Decrease PV
* @param {Event} event
* @param {HTMLElement} target
* @private
*/
static async #onPvDecrease(event, target) {
const currentPv = this.actor.system.pv.value || 0
const newPv = Math.max(currentPv - 1, 0)
await this.actor.update({ 'system.pv.value': newPv })
}
/**
* Roll initiative
* @param {Event} event
* @param {HTMLElement} target
* @private
*/
static async #onRollInitiative(event, target) {
await this.actor.rollInitiative()
}
/**
* Roll caractéristique
* @param {Event} event
* @param {HTMLElement} target
* @private
*/
static async #onRollCarac(event, target) {
const key = target.dataset.key
if (key) {
await this.actor.rollCarac(key, false)
}
}
/**
* Roll rang
* @param {Event} event
* @param {HTMLElement} target
* @private
*/
static async #onRollRang(event, target) {
const key = target.dataset.rangKey
if (key) {
await this.actor.rollRang(key)
}
}
/**
* Roll root competence
* @param {Event} event
* @param {HTMLElement} target
* @private
*/
static async #onRollRootCompetence(event, target) {
const compKey = target.dataset.attrKey
if (compKey) {
await this.actor.rollRootCompetence(compKey)
}
}
/**
* Roll competence
* @param {Event} event
* @param {HTMLElement} target
* @private
*/
static async #onRollCompetence(event, target) {
const li = target.closest(".item")
const compId = li?.dataset.itemId
if (compId) {
await this.actor.rollCompetence(compId)
}
}
/**
* Roll sort
* @param {Event} event
* @param {HTMLElement} target
* @private
*/
static async #onRollSort(event, target) {
const li = target.closest(".item")
const sortId = li?.dataset.itemId
if (sortId) {
await this.actor.rollSort(sortId)
}
}
/**
* Roll attaque arme
* @param {Event} event
* @param {HTMLElement} target
* @private
*/
static async #onRollAttaqueArme(event, target) {
const li = target.closest(".item")
const armeId = li?.dataset.itemId
if (armeId) {
await this.actor.rollAttaqueArme(armeId)
}
}
/**
* Roll attaque brutale arme
* @param {Event} event
* @param {HTMLElement} target
* @private
*/
static async #onRollAttaqueBrutaleArme(event, target) {
const li = target.closest(".item")
const armeId = li?.dataset.itemId
if (armeId) {
await this.actor.rollAttaqueBrutaleArme(armeId)
}
}
/**
* Roll attaque charge arme
* @param {Event} event
* @param {HTMLElement} target
* @private
*/
static async #onRollAttaqueChargeArme(event, target) {
const li = target.closest(".item")
const armeId = li?.dataset.itemId
if (armeId) {
await this.actor.rollAttaqueChargeArme(armeId)
}
}
/**
* Roll assomer arme
* @param {Event} event
* @param {HTMLElement} target
* @private
*/
static async #onRollAssomerArme(event, target) {
const li = target.closest(".item")
const armeId = li?.dataset.itemId
if (armeId) {
await this.actor.rollAssomerArme(armeId)
}
}
/**
* Roll pouvoir
* @param {Event} event
* @param {HTMLElement} target
* @private
*/
static async #onRollPouvoir(event, target) {
const li = target.closest(".item")
const pouvoirId = li?.dataset.itemId
if (pouvoirId) {
await this.actor.rollPouvoir(pouvoirId)
}
}
/**
* Toggle masque
* @param {Event} event
* @param {HTMLElement} target
* @private
*/
static async #onToggleMasque(event, target) {
await this.actor.toggleMasqueStatut()
this.render()
}
/**
* Dialog récupération usage
* @param {Event} event
* @param {HTMLElement} target
* @private
*/
static async #onDialogRecupUsage(event, target) {
new Dialog({
title: "Récupération des Points d'Usage",
content: "<p>Combien de Points d'Usage souhaitez-vous récupérer ?</p>",
buttons: {
one: {
icon: '<i class="fas fa-check"></i>',
label: "1 Point",
callback: () => {
this.actor.recupUsage(1)
}
},
two: {
icon: '<i class="fas fa-check"></i>',
label: "2 Points",
callback: () => {
this.actor.recupUsage(2)
}
},
three: {
icon: '<i class="fas fa-check"></i>',
label: "3 Points",
callback: () => {
this.actor.recupUsage(3)
}
},
cancel: {
icon: '<i class="fas fa-times"></i>',
label: "Annuler"
}
},
default: "one"
}).render(true)
}
// #endregion
}

View File

@@ -0,0 +1,212 @@
const { HandlebarsApplicationMixin } = foundry.applications.api
export default class HeritiersItemSheet extends HandlebarsApplicationMixin(foundry.applications.sheets.ItemSheetV2) {
constructor(options = {}) {
super(options)
this.#dragDrop = this.#createDragDropHandlers()
}
#dragDrop
/** @override */
static DEFAULT_OPTIONS = {
classes: ["fvtt-les-heritiers", "item"],
position: {
width: 620,
height: 600,
},
form: {
submitOnChange: true,
},
window: {
resizable: true,
},
tabs: [
{
navSelector: 'nav[data-group="primary"]',
contentSelector: "section.sheet-body",
initial: "description",
},
],
dragDrop: [{ dragSelector: "[data-drag]", dropSelector: null }],
actions: {
editImage: HeritiersItemSheet.#onEditImage,
postItem: HeritiersItemSheet.#onPostItem,
},
}
/**
* Tab groups state
* @type {object}
*/
tabGroups = { primary: "description" }
/** @override */
async _prepareContext() {
const context = {
fields: this.document.schema.fields,
systemFields: this.document.system.schema.fields,
item: this.document,
system: this.document.system,
source: this.document.toObject(),
enrichedDescription: await foundry.applications.ux.TextEditor.implementation.enrichHTML(this.document.system.description, { async: true }),
isEditMode: true,
isEditable: this.isEditable,
isGM: game.user.isGM,
config: CONFIG.HERITIERS,
}
return context
}
/** @override */
_onRender(context, options) {
super._onRender(context, options)
this.#dragDrop.forEach((d) => d.bind(this.element))
// Activate tab navigation manually
const nav = this.element.querySelector('nav.tabs[data-group]')
if (nav) {
const group = nav.dataset.group
// Activate the current tab
const activeTab = this.tabGroups[group] || "description"
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()
})
})
// Show/hide tab content
this.element.querySelectorAll('[data-group="' + group + '"][data-tab]').forEach(content => {
content.classList.toggle('active', content.dataset.tab === activeTab)
})
}
}
// #region Drag-and-Drop Workflow
/**
* Create drag-and-drop workflow handlers for this Application
* @returns {DragDrop[]} An array of DragDrop handlers
* @private
*/
#createDragDropHandlers() {
return this.options.dragDrop.map((d) => {
d.permissions = {
dragstart: this._canDragStart.bind(this),
drop: this._canDragDrop.bind(this),
}
d.callbacks = {
dragstart: this._onDragStart.bind(this),
dragover: this._onDragOver.bind(this),
drop: this._onDrop.bind(this),
}
return new foundry.applications.ux.DragDrop(d)
})
}
/**
* Can the User start a drag workflow for a given drag selector?
* @param {string} selector The candidate HTML selector for the drag event
* @returns {boolean} Can the current user drag this selector?
* @protected
*/
_canDragStart(selector) {
return this.isEditable
}
/**
* Can the User drop an entry at a given drop selector?
* @param {string} selector The candidate HTML selector for the drop event
* @returns {boolean} Can the current user drop on this selector?
* @protected
*/
_canDragDrop(selector) {
return this.isEditable
}
/**
* Callback for dragstart events.
* @param {DragEvent} event The drag start event
* @protected
*/
_onDragStart(event) {
const target = event.currentTarget
const dragData = { type: "Item", uuid: this.document.uuid }
event.dataTransfer.setData("text/plain", JSON.stringify(dragData))
}
/**
* Callback for dragover events.
* @param {DragEvent} event The drag over event
* @protected
*/
_onDragOver(event) {
// Default behavior is fine
}
/**
* Callback for drop events.
* @param {DragEvent} event The drop event
* @protected
*/
async _onDrop(event) {
const data = foundry.applications.ux.TextEditor.implementation.getDragEventData(event)
const item = await fromUuid(data.uuid)
if (!item) return
console.log("Item dropped:", item)
}
// #endregion
// #region Action Handlers
/**
* Edit the item image
* @param {Event} event The triggering event
* @param {HTMLElement} target The target element
* @private
*/
static async #onEditImage(event, target) {
const fp = new FilePicker({
type: "image",
current: this.document.img,
callback: (path) => {
this.document.update({ img: path })
},
})
return fp.browse()
}
/**
* Post item to chat
* @param {Event} event The triggering event
* @param {HTMLElement} target The target element
* @private
*/
static async #onPostItem(event, target) {
let chatData = foundry.utils.duplicate(this.document)
if (this.document.actor) {
chatData.actor = { id: this.document.actor.id }
}
// Don't post any image for the item if the default image is used
if (chatData.img.includes("/blank.png") || chatData.img.includes("/mystery-man")) {
chatData.img = null
}
// JSON object for easy creation
chatData.jsondata = JSON.stringify({
compendium: "postedItem",
payload: chatData,
})
const html = await renderTemplate('systems/fvtt-les-heritiers/templates/post-item.html', chatData)
const chatOptions = {
user: game.user.id,
content: html,
}
ChatMessage.create(chatOptions)
}
// #endregion
}

View File

@@ -0,0 +1,19 @@
import HeritiersItemSheet from "./base-item-sheet.mjs"
export default class HeritiersCapaciteNaturelleSheet extends HeritiersItemSheet {
/** @override */
static DEFAULT_OPTIONS = {
...super.DEFAULT_OPTIONS,
window: {
...super.DEFAULT_OPTIONS.window,
title: "SHEETS.Item.capacitenaturelle",
},
}
/** @override */
static PARTS = {
sheet: {
template: "systems/fvtt-les-heritiers/templates/item-capacitenaturelle-sheet.hbs",
},
}
}

View File

@@ -0,0 +1,65 @@
import HeritiersItemSheet from "./base-item-sheet.mjs"
export default class HeritiersCompetenceSheet extends HeritiersItemSheet {
/** @override */
static DEFAULT_OPTIONS = {
...super.DEFAULT_OPTIONS,
window: {
...super.DEFAULT_OPTIONS.window,
title: "SHEETS.Item.competence",
},
actions: {
addSpecialite: HeritiersCompetenceSheet.#onAddSpecialite,
deleteSpecialite: HeritiersCompetenceSheet.#onDeleteSpecialite,
editSpecialite: HeritiersCompetenceSheet.#onEditSpecialite,
editSpecialiteDescription: HeritiersCompetenceSheet.#onEditSpecialiteDescription,
}
}
/** @override */
static PARTS = {
sheet: {
template: "systems/fvtt-les-heritiers/templates/item-competence-sheet.hbs",
},
}
/* -------------------------------------------- */
/* Event Handlers */
/* -------------------------------------------- */
static async #onAddSpecialite(event, target) {
let spec = foundry.utils.duplicate(this.item.system.specialites) || []
spec.push({ name: "Nouvelle Spécialité", id: foundry.utils.randomID(16), used: false })
await this.item.update({ 'system.specialites': spec })
}
static async #onDeleteSpecialite(event, target) {
const li = target.closest(".specialite-item")
let index = parseInt(li.dataset.specialiteIndex)
let spec = foundry.utils.duplicate(this.item.system.specialites) || []
spec.splice(index, 1)
await this.item.update({ 'system.specialites': spec })
}
static async #onEditSpecialite(event, target) {
const li = target.closest(".specialite-item")
let index = parseInt(li.dataset.specialiteIndex)
let spec = foundry.utils.duplicate(this.item.system.specialites) || []
if (spec[index]) {
spec[index].name = target.value
spec[index].id = spec[index].id || foundry.utils.randomID(16)
await this.item.update({ 'system.specialites': spec })
}
}
static async #onEditSpecialiteDescription(event, target) {
const li = target.closest(".specialite-item")
let index = parseInt(li.dataset.specialiteIndex)
let spec = foundry.utils.duplicate(this.item.system.specialites) || []
if (spec[index]) {
spec[index].description = target.value
spec[index].id = spec[index].id || foundry.utils.randomID(16)
await this.item.update({ 'system.specialites': spec })
}
}
}

View File

@@ -0,0 +1,19 @@
import HeritiersItemSheet from "./base-item-sheet.mjs"
export default class HeritiersContactSheet extends HeritiersItemSheet {
/** @override */
static DEFAULT_OPTIONS = {
...super.DEFAULT_OPTIONS,
window: {
...super.DEFAULT_OPTIONS.window,
title: "SHEETS.Item.contact",
},
}
/** @override */
static PARTS = {
sheet: {
template: "systems/fvtt-les-heritiers/templates/item-contact-sheet.hbs",
},
}
}

View File

@@ -0,0 +1,19 @@
import HeritiersItemSheet from "./base-item-sheet.mjs"
export default class HeritiersDesavantageSheet extends HeritiersItemSheet {
/** @override */
static DEFAULT_OPTIONS = {
...super.DEFAULT_OPTIONS,
window: {
...super.DEFAULT_OPTIONS.window,
title: "SHEETS.Item.desavantage",
},
}
/** @override */
static PARTS = {
sheet: {
template: "systems/fvtt-les-heritiers/templates/item-desavantage-sheet.hbs",
},
}
}

View File

@@ -0,0 +1,19 @@
import HeritiersItemSheet from "./base-item-sheet.mjs"
export default class HeritiersEquipementSheet extends HeritiersItemSheet {
/** @override */
static DEFAULT_OPTIONS = {
...super.DEFAULT_OPTIONS,
window: {
...super.DEFAULT_OPTIONS.window,
title: "SHEETS.Item.equipement",
},
}
/** @override */
static PARTS = {
sheet: {
template: "systems/fvtt-les-heritiers/templates/item-equipement-sheet.hbs",
},
}
}

View File

@@ -0,0 +1,19 @@
import HeritiersItemSheet from "./base-item-sheet.mjs"
export default class HeritiersFeeSheet extends HeritiersItemSheet {
/** @override */
static DEFAULT_OPTIONS = {
...super.DEFAULT_OPTIONS,
window: {
...super.DEFAULT_OPTIONS.window,
title: "SHEETS.Item.fee",
},
}
/** @override */
static PARTS = {
sheet: {
template: "systems/fvtt-les-heritiers/templates/item-fee-sheet.hbs",
},
}
}

View File

@@ -0,0 +1,59 @@
import HeritiersActorSheet from "./base-actor-sheet.mjs"
export default class HeritiersPersonnageSheet extends HeritiersActorSheet {
/** @override */
static DEFAULT_OPTIONS = {
...super.DEFAULT_OPTIONS,
classes: [...super.DEFAULT_OPTIONS.classes],
window: {
...super.DEFAULT_OPTIONS.window,
title: "SHEETS.Actor.personnage",
},
actions: {
...super.DEFAULT_OPTIONS.actions,
},
}
/** @override */
static PARTS = {
sheet: {
template: "systems/fvtt-les-heritiers/templates/actor-sheet.hbs",
},
}
/** @override */
tabGroups = { primary: "competences" }
/** @override */
async _prepareContext() {
const context = await super._prepareContext()
const actor = this.document
// Add personnage-specific data
context.skills = actor.getSkills()
context.utileSkillsMental = actor.organizeUtileSkills("mental")
context.utileSkillsPhysical = actor.organizeUtileSkills("physical")
context.competencesMagie = game.system.lesheritiers.config.competencesMagie || []
context.futileSkills = actor.organizeFutileSkills()
context.contacts = actor.organizeContacts()
context.armes = foundry.utils.duplicate(actor.getWeapons())
context.monnaies = foundry.utils.duplicate(actor.getMonnaies())
context.pouvoirs = foundry.utils.duplicate(actor.getPouvoirs())
context.fee = foundry.utils.duplicate(actor.getFee() || {})
context.protections = foundry.utils.duplicate(actor.getArmors())
context.combat = actor.getCombatValues()
context.equipements = foundry.utils.duplicate(actor.getEquipments())
context.avantages = foundry.utils.duplicate(actor.getAvantages())
context.atouts = foundry.utils.duplicate(actor.getAtouts())
context.capacites = foundry.utils.duplicate(actor.getCapacites())
context.desavantages = foundry.utils.duplicate(actor.getDesavantages())
context.profils = foundry.utils.duplicate(actor.getProfils())
context.pvMalus = actor.getPvMalus()
context.heritage = game.settings.get("fvtt-les-heritiers", "heritiers-heritage")
context.initiative = actor.getFlag("world", "last-initiative") || -1
context.magieList = actor.prepareMagie()
context.isPNJ = false
return context
}
}

View File

@@ -0,0 +1,59 @@
import HeritiersActorSheet from "./base-actor-sheet.mjs"
export default class HeritiersPnjSheet extends HeritiersActorSheet {
/** @override */
static DEFAULT_OPTIONS = {
...super.DEFAULT_OPTIONS,
classes: [...super.DEFAULT_OPTIONS.classes],
window: {
...super.DEFAULT_OPTIONS.window,
title: "SHEETS.Actor.pnj",
},
actions: {
...super.DEFAULT_OPTIONS.actions,
},
}
/** @override */
static PARTS = {
sheet: {
template: "systems/fvtt-les-heritiers/templates/actor-pnj-sheet.hbs",
},
}
/** @override */
tabGroups = { primary: "competences" }
/** @override */
async _prepareContext() {
const context = await super._prepareContext()
const actor = this.document
// Add PNJ-specific data
context.skills = actor.getSkills()
context.utileSkillsMental = actor.organizeUtileSkills("mental")
context.utileSkillsPhysical = actor.organizeUtileSkills("physical")
context.competencesMagie = game.system.lesheritiers.config.competencesMagie || []
context.futileSkills = actor.organizeFutileSkills()
context.contacts = actor.organizeContacts()
context.armes = foundry.utils.duplicate(actor.getWeapons())
context.monnaies = foundry.utils.duplicate(actor.getMonnaies())
context.pouvoirs = foundry.utils.duplicate(actor.getPouvoirs())
context.fee = foundry.utils.duplicate(actor.getFee() || {})
context.protections = foundry.utils.duplicate(actor.getArmors())
context.combat = actor.getCombatValues()
context.equipements = foundry.utils.duplicate(actor.getEquipments())
context.avantages = foundry.utils.duplicate(actor.getAvantages())
context.atouts = foundry.utils.duplicate(actor.getAtouts())
context.capacites = foundry.utils.duplicate(actor.getCapacites())
context.desavantages = foundry.utils.duplicate(actor.getDesavantages())
context.profils = foundry.utils.duplicate(actor.getProfils())
context.pvMalus = actor.getPvMalus()
context.heritage = game.settings.get("fvtt-les-heritiers", "heritiers-heritage")
context.initiative = actor.getFlag("world", "last-initiative") || -1
context.magieList = actor.prepareMagie()
context.isPNJ = true
return context
}
}

View File

@@ -0,0 +1,19 @@
import HeritiersItemSheet from "./base-item-sheet.mjs"
export default class HeritiersPouvoirSheet extends HeritiersItemSheet {
/** @override */
static DEFAULT_OPTIONS = {
...super.DEFAULT_OPTIONS,
window: {
...super.DEFAULT_OPTIONS.window,
title: "SHEETS.Item.pouvoir",
},
}
/** @override */
static PARTS = {
sheet: {
template: "systems/fvtt-les-heritiers/templates/item-pouvoir-sheet.hbs",
},
}
}

View File

@@ -0,0 +1,19 @@
import HeritiersItemSheet from "./base-item-sheet.mjs"
export default class HeritiersProfilSheet extends HeritiersItemSheet {
/** @override */
static DEFAULT_OPTIONS = {
...super.DEFAULT_OPTIONS,
window: {
...super.DEFAULT_OPTIONS.window,
title: "SHEETS.Item.profil",
},
}
/** @override */
static PARTS = {
sheet: {
template: "systems/fvtt-les-heritiers/templates/item-profil-sheet.hbs",
},
}
}

View File

@@ -0,0 +1,19 @@
import HeritiersItemSheet from "./base-item-sheet.mjs"
export default class HeritiersProtectionSheet extends HeritiersItemSheet {
/** @override */
static DEFAULT_OPTIONS = {
...super.DEFAULT_OPTIONS,
window: {
...super.DEFAULT_OPTIONS.window,
title: "SHEETS.Item.protection",
},
}
/** @override */
static PARTS = {
sheet: {
template: "systems/fvtt-les-heritiers/templates/item-protection-sheet.hbs",
},
}
}

View File

@@ -0,0 +1,27 @@
import HeritiersItemSheet from "./base-item-sheet.mjs"
import { HeritiersUtility } from "../../heritiers-utility.js"
export default class HeritiersSortSheet extends HeritiersItemSheet {
/** @override */
static DEFAULT_OPTIONS = {
...super.DEFAULT_OPTIONS,
window: {
...super.DEFAULT_OPTIONS.window,
title: "SHEETS.Item.sort",
},
}
/** @override */
static PARTS = {
sheet: {
template: "systems/fvtt-les-heritiers/templates/item-sort-sheet.hbs",
},
}
/** @override */
async _prepareContext() {
const context = await super._prepareContext()
context.competencesMagie = HeritiersUtility.getCompetencesMagie() || []
return context
}
}

View File

@@ -1,26 +0,0 @@
/**
* Extend the basic ActorSheet with some very simple modifications
* @extends {ActorSheet}
*/
import { HeritiersActorSheet } from "./heritiers-actor-sheet.js";
import { HeritiersUtility } from "./heritiers-utility.js";
/* -------------------------------------------- */
export class HeritiersActorPNJSheet extends HeritiersActorSheet {
/** @override */
static get defaultOptions() {
return foundry.utils.mergeObject(super.defaultOptions, {
classes: ["fvtt-les-heritiers", "sheet", "actor"],
template: "systems/fvtt-les-heritiers/templates/actor-pnj-sheet.html",
width: 780,
height: 840,
tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "stats" }],
dragDrop: [{ dragSelector: ".item-list .item", dropSelector: null }],
editScore: false
})
}
}

View File

@@ -1,263 +0,0 @@
/**
* Extend the basic ActorSheet with some very simple modifications
* @extends {ActorSheet}
*/
import { HeritiersUtility } from "./heritiers-utility.js";
/* -------------------------------------------- */
export class HeritiersActorSheet extends foundry.appv1.sheets.ActorSheet {
/** @override */
static get defaultOptions() {
return foundry.utils.mergeObject(super.defaultOptions, {
classes: ["fvtt-les-heritiers", "sheet", "actor"],
template: "systems/fvtt-les-heritiers/templates/actor-sheet.html",
width: 780,
height: 840,
tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "stats" }],
dragDrop: [{ dragSelector: ".item-list .item", dropSelector: null }],
editScore: false
})
}
/* -------------------------------------------- */
async getData() {
const objectData = foundry.utils.duplicate(this.object)
let formData = {
title: this.title,
id: objectData.id,
type: objectData.type,
img: objectData.img,
name: objectData.name,
editable: this.isEditable,
cssClass: this.isEditable ? "editable" : "locked",
system: objectData.system,
effects: this.object.effects.map(e => foundry.utils.deepClone(e.data)),
limited: this.object.limited,
skills: this.actor.getSkills(),
utileSkillsMental: this.actor.organizeUtileSkills("mental"),
utileSkillsPhysical: this.actor.organizeUtileSkills("physical"),
competencesMagie: HeritiersUtility.getCompetencesMagie(),
futileSkills: this.actor.organizeFutileSkills(),
contacts: this.actor.organizeContacts(),
armes: foundry.utils.duplicate(this.actor.getWeapons()),
monnaies: foundry.utils.duplicate(this.actor.getMonnaies()),
pouvoirs: foundry.utils.duplicate(this.actor.getPouvoirs()),
fee: foundry.utils.duplicate(this.actor.getFee() || {}),
protections: foundry.utils.duplicate(this.actor.getArmors()),
combat: this.actor.getCombatValues(),
equipements: foundry.utils.duplicate(this.actor.getEquipments()),
avantages: foundry.utils.duplicate(this.actor.getAvantages()),
atouts: foundry.utils.duplicate(this.actor.getAtouts()),
capacites: foundry.utils.duplicate(this.actor.getCapacites()),
desavantages: foundry.utils.duplicate(this.actor.getDesavantages()),
profils: foundry.utils.duplicate(this.actor.getProfils()),
pvMalus: this.actor.getPvMalus(),
heritage: game.settings.get("fvtt-les-heritiers", "heritiers-heritage"),
initiative: this.actor.getFlag("world", "last-initiative") || -1,
description: await foundry.applications.ux.TextEditor.implementation.enrichHTML(this.object.system.biodata.description, { async: true }),
revesetranges: await foundry.applications.ux.TextEditor.implementation.enrichHTML(this.object.system.biodata.revesetranges, { async: true }),
secretsdecouverts: await foundry.applications.ux.TextEditor.implementation.enrichHTML(this.object.system.biodata.secretsdecouverts, { async: true }),
questions: await foundry.applications.ux.TextEditor.implementation.enrichHTML(this.object.system.biodata.questions, { async: true }),
habitat: await foundry.applications.ux.TextEditor.implementation.enrichHTML(this.object.system.biodata.habitat, { async: true }),
playernotes: await foundry.applications.ux.TextEditor.implementation.enrichHTML(this.object.system.biodata.playernotes, { async: true }),
magieList: this.actor.prepareMagie(),
options: this.options,
owner: this.document.isOwner,
editScore: this.options.editScore,
config: game.system.lesheritiers.config,
isGM: game.user.isGM,
isPNJ: (this.actor.type == "pnj")
}
this.formData = formData;
console.log("PC : ", formData, this.object);
return formData;
}
/* -------------------------------------------- */
dialogRecupUsage() {
new Dialog({
title: "Récupération des Points d'Usage",
content: "<p>Combien de Points d'Usage souhaitez-vous récupérer ?</p>",
buttons: {
one: {
icon: '<i class="fas fa-check"></i>',
label: "1 Point",
callback: () => {
this.actor.recupUsage(1)
}
},
two: {
icon: '<i class="fas fa-check"></i>',
label: "2 Points",
callback: () => {
this.actor.recupUsage(2)
}
},
four: {
icon: '<i class="fas fa-check"></i>',
label: "4 Points",
callback: () => {
this.actor.recupUsage(4)
}
},
all: {
icon: '<i class="fas fa-check"></i>',
label: "Tous les Points",
callback: () => {
this.actor.recupUsage(100)
}
}
}
}).render(true)
}
/* -------------------------------------------- */
/** @override */
activateListeners(html) {
super.activateListeners(html);
// Everything below here is only needed if the sheet is editable
if (!this.options.editable) return;
// Update Inventory Item
html.find('.item-edit').click(ev => {
const li = $(ev.currentTarget).parents(".item")
let itemId = li.data("item-id")
const item = this.actor.items.get(itemId)
item.sheet.render(true)
})
// Delete Inventory Item
html.find('.item-delete').click(ev => {
const li = $(ev.currentTarget).parents(".item");
HeritiersUtility.confirmDelete(this, li);
})
html.find('.edit-item-data').change(ev => {
const li = $(ev.currentTarget).parents(".item")
let itemId = li.data("item-id")
let itemType = li.data("item-type")
let itemField = $(ev.currentTarget).data("item-field")
let dataType = $(ev.currentTarget).data("dtype")
let value = ev.currentTarget.value
this.actor.editItemField(itemId, itemType, itemField, dataType, value)
})
html.find('.adversite-modify').click(event => {
const li = $(event.currentTarget).parents(".item")
let adv = li.data("adversite")
let value = Number($(event.currentTarget).data("adversite-value"))
this.actor.incDecAdversite(adv, value)
})
html.find('.quantity-modify').click(event => {
const li = $(event.currentTarget).parents(".item")
const value = Number($(event.currentTarget).data("quantite-value"))
this.actor.incDecQuantity(li.data("item-id"), value);
})
html.find('.roll-initiative').click((event) => {
this.actor.rollInitiative()
})
html.find('.roll-carac').click((event) => {
const key = $(event.currentTarget).data("key")
this.actor.rollCarac(key, false)
})
html.find('.roll-rang').click((event) => {
const key = $(event.currentTarget).data("rang-key")
this.actor.rollRang(key, false)
})
html.find('.roll-root-competence').click((event) => {
const compKey = $(event.currentTarget).data("attr-key")
this.actor.rollRootCompetence(compKey)
})
html.find('.roll-competence').click((event) => {
const li = $(event.currentTarget).parents(".item")
let compId = li.data("item-id")
this.actor.rollCompetence(compId)
})
html.find('.roll-sort').click((event) => {
const li = $(event.currentTarget).parents(".item")
let sortId = li.data("item-id")
this.actor.rollSort(sortId)
})
html.find('.roll-attaque-arme').click((event) => {
const li = $(event.currentTarget).parents(".item")
let armeId = li.data("item-id")
this.actor.rollAttaqueArme(armeId)
})
html.find('.roll-attaque-brutale-arme').click((event) => {
const li = $(event.currentTarget).parents(".item")
let armeId = li.data("item-id")
this.actor.rollAttaqueBrutaleArme(armeId)
})
html.find('.roll-attaque-charge-arme').click((event) => {
const li = $(event.currentTarget).parents(".item")
let armeId = li.data("item-id")
this.actor.rollAttaqueChargeArme(armeId)
})
html.find('.roll-assomer-arme').click((event) => {
const li = $(event.currentTarget).parents(".item")
let armeId = li.data("item-id")
this.actor.rollAssomerArme(armeId)
})
html.find('.roll-pouvoir').click((event) => {
const li = $(event.currentTarget).parents(".item")
let pouvoirId = li.data("item-id")
this.actor.rollPouvoir(pouvoirId)
})
html.find('.dialog-recup-usage').click((event) => {
this.dialogRecupUsage()
})
html.find('.item-add').click((event) => {
const itemType = $(event.currentTarget).data("type")
if (itemType == "sort") {
// Get data-sort-competence
let sortCompetence = $(event.currentTarget).data("sort-competence");
if (sortCompetence) {
this.actor.createEmbeddedDocuments('Item', [{ name: `Nouveau ${itemType} de ${sortCompetence}`, type: itemType, system: { competence: sortCompetence } }], { renderSheet: true })
return
}
}
this.actor.createEmbeddedDocuments('Item', [{ name: `Nouveau ${itemType}`, type: itemType }], { renderSheet: true })
})
html.find('.lock-unlock-sheet').click((event) => {
this.options.editScore = !this.options.editScore;
this.render(true);
});
html.find('.item-equip').click(ev => {
const li = $(ev.currentTarget).parents(".item");
this.actor.equipItem(li.data("item-id"));
this.render(true);
});
}
/* -------------------------------------------- */
/** @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;
}
/* -------------------------------------------- */
/*async _onDropItem(event, dragData) {
let data = event.dataTransfer.getData('text/plain')
let dataItem = JSON.parse( data)
let item = fromUuidSync(dataItem.uuid)
if (item.pack) {
item = await HeritiersUtility.searchItem(item)
}
super._onDropItem(event, dragData)
}*/
}

View File

@@ -1,6 +1,6 @@
/* -------------------------------------------- */
import { HeritiersUtility } from "./heritiers-utility.js";
import { HeritiersRollDialog } from "./heritiers-roll-dialog.js";
import { HeritiersRollDialog } from "./applications/heritiers-roll-dialog.mjs";
/* -------------------------------------------- */
const __degatsBonus = [-2, -2, -1, -1, 0, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 8, 8, 9, 9, 10, 10]
@@ -171,11 +171,53 @@ export class HeritiersActor extends Actor {
magie.rang = Math.round(item.system.niveau / 2);
magie.rangGenericName = game.system.lesheritiers.config.rangName[magie.rang];
console.log("Magie", item.name, item.system.niveau, magie.rang, magie.rangGenericName)
magie.rangSpecificName = game.system.lesheritiers.config.rangNameSpecific[item.name][magie.rangGenericName];
magie.sorts = []
for (let sort of this.items) {
if (sort.type == "sort" && sort.system.competence == item.name) {
magie.sorts.push(sort)
//magie.rangSpecificName = game.system.lesheritiers.config.rangNameSpecific[item.name][magie.rangGenericName];
magie.sorts = {}
if (item.name == "Magie du Clan") {
magie.sorts = {
"soufflecombat": {
1: { nomNiveau: magie.competence.system.nomniveausouffle.soufflecombat["1"], sorts: [] },
2: { nomNiveau: magie.competence.system.nomniveausouffle.soufflecombat["2"], sorts: [] },
3: { nomNiveau: magie.competence.system.nomniveausouffle.soufflecombat["3"], sorts: [] },
4: { nomNiveau: magie.competence.system.nomniveausouffle.soufflecombat["4"], sorts: [] }
},
"soufflemouvement": {
1: { nomNiveau: magie.competence.system.nomniveausouffle.soufflemouvement["1"], sorts: [] },
2: { nomNiveau: magie.competence.system.nomniveausouffle.soufflemouvement["2"], sorts: [] },
3: { nomNiveau: magie.competence.system.nomniveausouffle.soufflemouvement["3"], sorts: [] },
4: { nomNiveau: magie.competence.system.nomniveausouffle.soufflemouvement["4"], sorts: [] }
},
"souffleesprit": {
1: { nomNiveau: magie.competence.system.nomniveausouffle.souffleesprit["1"], sorts: [] },
2: { nomNiveau: magie.competence.system.nomniveausouffle.souffleesprit["2"], sorts: [] },
3: { nomNiveau: magie.competence.system.nomniveausouffle.souffleesprit["3"], sorts: [] },
4: { nomNiveau: magie.competence.system.nomniveausouffle.souffleesprit["4"], sorts: [] }
}
}
for (let sort of this.items) {
if (sort.type == "sort" && sort.system.competence == item.name) {
let sortObj = foundry.utils.duplicate(sort)
sortObj.sdValue = HeritiersUtility.getSDSortValue(Number(sort.system.niveau))
if (!magie.sorts[sort.system?.souffle]) {
console.warn("Sort with unknown souffle ", sort.system.souffle, sort)
continue
}
magie.sorts[sort.system.souffle][Number(sort.system.niveau)].sorts.push(sortObj)
}
}
} else {
magie.sorts = {
1: { nomNiveau: magie.competence.system.nomniveau["1"], sorts: [] },
2: { nomNiveau: magie.competence.system.nomniveau["2"], sorts: [] },
3: { nomNiveau: magie.competence.system.nomniveau["3"], sorts: [] },
4: { nomNiveau: magie.competence.system.nomniveau["4"], sorts: [] }
}
for (let sort of this.items) {
if (sort.type == "sort" && sort.system.competence == item.name) {
let sortObj = foundry.utils.duplicate(sort)
sortObj.sdValue = HeritiersUtility.getSDSortValue(Number(sort.system.niveau))
magie.sorts[Number(sort.system.niveau)].sorts.push(sortObj)
}
}
}
magieList.push(magie)
@@ -318,18 +360,6 @@ export class HeritiersActor extends Actor {
/* -------------------------------------------- */
async prepareData() {
let pvMax = (this.system.caracteristiques.con.rang * 3) + 9 + this.system.pv.mod
if (this.system.pv.max != pvMax) {
this.update({ 'system.pv.max': pvMax })
}
if (this.system.biodata.magie || this.type == "pnj") {
let pointsAmes = this.system.caracteristiques.esp.rang + this.system.caracteristiques.san.rang + this.getMaxRangMagie()
if (this.system.magie.pointsame.max != pointsAmes) {
this.update({ 'system.magie.pointsame.max': pointsAmes })
}
}
super.prepareData();
}
@@ -353,6 +383,15 @@ export class HeritiersActor extends Actor {
/* -------------------------------------------- */
prepareDerivedData() {
// Calculate derived PV max
let pvMax = (this.system.caracteristiques.con.rang * 3) + 9 + this.system.pv.mod
this.system.pv.max = pvMax
// Calculate derived Points d'Âme max
if (this.system.biodata.magie || this.type == "pnj") {
let pointsAmes = this.system.caracteristiques.esp.rang + this.system.caracteristiques.san.rang + this.getMaxRangMagie()
this.system.magie.pointsame.max = pointsAmes
}
if (this.type == 'personnage') {
}
@@ -671,8 +710,7 @@ export class HeritiersActor extends Actor {
rollData.caracKey = "per"
}
rollData.carac = this.system.caracteristiques[rollData.caracKey]
let rollDialog = await HeritiersRollDialog.create(this, rollData)
rollDialog.render(true)
await HeritiersRollDialog.create(this, rollData)
}
/* -------------------------------------------- */
@@ -681,8 +719,7 @@ export class HeritiersActor extends Actor {
rollData.mode = "carac"
rollData.carac = this.system.caracteristiques[key]
rollData.caracKey = key
let rollDialog = await HeritiersRollDialog.create(this, rollData)
rollDialog.render(true)
await HeritiersRollDialog.create(this, rollData)
}
/* -------------------------------------------- */
@@ -691,8 +728,7 @@ export class HeritiersActor extends Actor {
rollData.mode = "rang"
rollData.rang = this.system.rang[key]
rollData.rangKey = key
let rollDialog = await HeritiersRollDialog.create(this, rollData)
rollDialog.render(true)
await HeritiersRollDialog.create(this, rollData)
}
/* -------------------------------------------- */
async rollRootCompetence(compKey) {
@@ -700,8 +736,7 @@ export class HeritiersActor extends Actor {
rollData.mode = "competence"
rollData.competence = { name: this.system.competences[compKey].label, system: { niveau: this.system.competences[compKey].niveau } }
console.log("RollDatra", rollData)
let rollDialog = await HeritiersRollDialog.create(this, rollData)
rollDialog.render(true)
await HeritiersRollDialog.create(this, rollData)
}
/* -------------------------------------------- */
@@ -709,20 +744,19 @@ export class HeritiersActor extends Actor {
let rollData = this.getCommonRollData(compId)
rollData.mode = "competence"
console.log("RollDatra", rollData)
let rollDialog = await HeritiersRollDialog.create(this, rollData)
rollDialog.render(true)
await HeritiersRollDialog.create(this, rollData)
}
/* -------------------------------------------- */
inDecCarac(key, incDec) {
let carac = this.system.caracteristiques[key]
carac.value += incDec
if (carac.value < 0 || carac.value > carac.max) {
ui.notifications.warn("Pas assez de points dans cette caractéristique !")
if (carac.value < 0 || carac.value > carac.rang) {
ui.notifications.warn("Pas assez de points dans cette caractéristique ou rang max atteint !")
return false
}
carac.value = Math.max(carac.value, 0)
carac.value = Math.min(carac.value, carac.max)
carac.value = Math.min(carac.value, carac.rang)
this.update({ [`system.caracteristiques.${key}`]: carac })
return true
}
@@ -735,23 +769,41 @@ export class HeritiersActor extends Actor {
ui.notifications.warn("Compétence de magie associée non trouvée !")
return
}
if (sort.system.informatif) {
if (sort.system.texteinformatif) {
let chatData = { user: game.user.id, speaker: { actor: this, alias: this.name }, content: `<div class="heritiers-informatif-sort"><h4>Sort informatif !</h4>${sort.system.texteinformatif}</div>` }
ChatMessage.create(chatData)
} else {
ui.notifications.info("Ce sort est uniquement informatif et ne peut pas être lancé.")
}
return
}
let rollData = this.getCommonRollData(comp.id)
rollData.mode = "sort"
rollData.sort = foundry.utils.duplicate(sort)
rollData.sdValue = HeritiersUtility.getSDSortValue(Number(sort.system.niveau))
if (Number(sort.system.sdspecial) && Number(sort.system.sdspecial) > 0) {
rollData.sdValue = Number(sort.system.sdspecial)
}
rollData.sortPointsAme = Number(sort.system.niveau)
rollData.totalEsprit = 1
if (sort.system.competence == "Grand Langage") {
rollData.sortPointsAme *= 2
rollData.totalEsprit = Math.floor((rollData.sortPointsAme) / 3)
}
if (rollData.sortPointsAme > this.system.magie.pointsame.value) {
// Vérifier si au moins 1 point d'Esprit est disponible
if (this.system.caracteristiques.esp.value < 1) {
ui.notifications.warn("Pas assez de Points d'Esprit ni de Points d'Ame pour lancer ce sort (requis: 1, disponible: " + this.system.caracteristiques.esp.value + ")")
if (this.system.caracteristiques.esp.value <= rollData.totalEsprit) {
ui.notifications.warn(`Pas assez de Points d'Esprit ni de Points d'Ame pour lancer ce sort (requis: ${rollData.totalEsprit}, disponible: ${this.system.caracteristiques.esp.value})`)
return
} else {
rollData.spendEsprit = true
ui.notifications.warn(`Vous n'avez pas assez de Points d'Ame pour lancer ce sort (requis: ${rollData.sortPointsAme}, disponible: ${this.system.magie.pointsame.value}). Un Point d'Esprit sera utilisé à la place si vous effectuez le lancer.`)
ui.notifications.warn(`Vous n'avez pas assez de Points d'Ame pour lancer ce sort (requis: ${rollData.sortPointsAme}, disponible: ${this.system.magie.pointsame.value}).`)
ui.notifications.warn(`${rollData.totalEsprit} Points d'Esprit seront utilisés à la place si vous effectuez le lancer.`)
}
}
if (sort.system.carac2 != "none") {
// get the best carac between carac1 and carac2
if (this.system.caracteristiques[sort.system.carac1].value > this.system.caracteristiques[sort.system.carac2].value) {
@@ -764,8 +816,7 @@ export class HeritiersActor extends Actor {
rollData.caracKey = sort.system.carac1
}
console.log("RollData", rollData)
let rollDialog = await HeritiersRollDialog.create(this, rollData)
rollDialog.render(true)
await HeritiersRollDialog.create(this, rollData)
}
@@ -786,13 +837,13 @@ export class HeritiersActor extends Actor {
rollData.caracKey = key
rollData.arme = arme
rollData.mode = "arme"
rollData.attackType = "Attaque normale"
rollData.armes = this.getOtherMeleeWeapons(arme)
if (rollData.defenderTokenId && arme.system.isMelee) {
rollData.cacheDifficulte = true
}
console.log(">>>> ARME", rollData)
let rollDialog = await HeritiersRollDialog.create(this, rollData)
rollDialog.render(true)
await HeritiersRollDialog.create(this, rollData)
}
}
@@ -808,10 +859,10 @@ export class HeritiersActor extends Actor {
rollData.caracKey = key
rollData.arme = foundry.utils.duplicate(arme)
rollData.mode = "attaquebrutale"
rollData.attackType = "Attaque brutale"
rollData.armes = this.getOtherMeleeWeapons(arme)
rollData.rulesMalus.push({ name: "Attaque brutale", value: -2 })
let rollDialog = await HeritiersRollDialog.create(this, rollData)
rollDialog.render(true)
await HeritiersRollDialog.create(this, rollData)
}
}
/* -------------------------------------------- */
@@ -827,8 +878,8 @@ export class HeritiersActor extends Actor {
rollData.arme = foundry.utils.duplicate(arme)
rollData.armes = this.getOtherMeleeWeapons(arme)
rollData.mode = "attaquecharge"
let rollDialog = await HeritiersRollDialog.create(this, rollData)
rollDialog.render(true)
rollData.attackType = "Attaque en charge"
await HeritiersRollDialog.create(this, rollData)
}
}
@@ -843,11 +894,11 @@ export class HeritiersActor extends Actor {
rollData.caracKey = "agi"
rollData.arme = foundry.utils.duplicate(arme)
rollData.mode = "assommer"
rollData.attackType = "Assommer"
if (rollData.defenderTokenId) {
rollData.cacheDifficulte = true
}
let rollDialog = await HeritiersRollDialog.create(this, rollData)
rollDialog.render(true)
await HeritiersRollDialog.create(this, rollData)
}
}
@@ -941,8 +992,7 @@ export class HeritiersActor extends Actor {
//ui.notifications.warn("Le pouvoir actif " + pouvoir.name + " a été utilisé, dépense de " + pouvoirPointsUsage + " points d'usage")
}
}
let rollDialog = await HeritiersRollDialog.create(this, rollData)
rollDialog.render(true)
await HeritiersRollDialog.create(this, rollData)
}
}

View File

@@ -1,7 +1,7 @@
/* -------------------------------------------- */
import { HeritiersUtility } from "./heritiers-utility.js";
import { HeritiersRollDialog } from "./heritiers-roll-dialog.js";
import { HeritiersRollDialog } from "./applications/heritiers-roll-dialog.mjs";
/* -------------------------------------------- */
export class HeritiersCommands {

View File

@@ -200,6 +200,15 @@ export const HERITIERS_CONFIG = {
"3": "3",
"4": "4"
},
listRangSort: {
"1": "1",
"2": "2",
"3": "3",
"4": "4",
"5": "5",
"6": "6",
"7": "7"
},
listNiveau: {
"0": "0",
"1": "1",
@@ -239,6 +248,12 @@ export const HERITIERS_CONFIG = {
"Maître": "Dominus",
"Grand Maître": "Magister"
},
"Necromancie": {
"Novice": "Inexpertus",
"Adepte": "Discipulus",
"Maître": "Dominus",
"Grand Maître": "Magister"
},
"Magie du Clan": {
"Novice": "Apprenti",
"Adepte": "Disciple",
@@ -259,9 +274,9 @@ export const HERITIERS_CONFIG = {
}
},
soufflesMagieDuClan: {
"Souffle du Combat": "Souffle du Combat",
"Souffle du Mouvement": "Souffle du Mouvement",
"Souffle de l'Esprit": "Souffle de l'Esprit"
"soufflecombat": "Souffle du Combat",
"soufflemouvement": "Souffle du Mouvement",
"souffleesprit": "Souffle de l'Esprit"
}
}

View File

@@ -1,214 +0,0 @@
import { HeritiersUtility } from "./heritiers-utility.js";
/**
* Extend the basic ItemSheet with some very simple modifications
* @extends {ItemSheet}
*/
export class HeritiersItemSheet extends foundry.appv1.sheets.ItemSheet {
/** @override */
static get defaultOptions() {
return foundry.utils.mergeObject(super.defaultOptions, {
classes: ["fvtt-les-heritiers", "sheet", "item"],
template: "systems/fvtt-les-heritiers/templates/item-sheet.html",
dragDrop: [{ dragSelector: null, dropSelector: null }],
width: 620,
height: 550,
tabs: [{navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "description"}]
});
}
/* -------------------------------------------- */
_getHeaderButtons() {
let buttons = super._getHeaderButtons();
// Add "Post to chat" button
// We previously restricted this to GM and editable items only. If you ever find this comment because it broke something: eh, sorry!
buttons.unshift(
{
class: "post",
icon: "fas fa-comment",
onclick: ev => { }
})
return buttons
}
/* -------------------------------------------- */
/** @override */
setPosition(options = {}) {
const position = super.setPosition(options);
const sheetBody = this.element.find(".sheet-body");
const bodyHeight = position.height - 192;
sheetBody.css("height", bodyHeight);
if (this.item.type.includes('weapon')) {
position.width = 640;
}
return position;
}
/* -------------------------------------------- */
async getData() {
const objectData = foundry.utils.duplicate(this.object)
let formData = {
title: this.title,
id: this.id,
type: objectData.type,
img: objectData.img,
name: objectData.name,
editable: this.isEditable,
cssClass: this.isEditable ? "editable" : "locked",
system: objectData.system,
limited: this.object.limited,
options: this.options,
owner: this.document.isOwner,
config: game.system.lesheritiers.config,
isArmeMelee: HeritiersUtility.isArmeMelee(this.object),
description: await foundry.applications.ux.TextEditor.implementation.enrichHTML(this.object.system.description, {async: true}),
mr: (this.object.type == 'specialisation'),
isGM: game.user.isGM,
usageMax: -1
}
// Items specific data
if (this.object.type == 'pouvoir' && this.document.isOwner && this.actor) {
formData.usageMax = this.actor.getPouvoirUsageMax(this.object)
if (this.object.system.pointsusagecourant == -1) {
this.object.system.pointsusagecourant = formData.usageMax
}
}
if (this.object.type == 'sort' ) {
formData.competencesMagie = HeritiersUtility.getCompetencesMagie()
}
//this.options.editable = !(this.object.origin == "embeddedItem");
console.log("ITEM DATA", formData, this);
return formData;
}
/* -------------------------------------------- */
_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(HeritiersUtility.data(this.item));
if (this.actor) {
chatData.actor = { id: this.actor.id };
}
// Don't post any image for the item (which would leave a large gap) if the default image is used
if (chatData.img.includes("/blank.png")) {
chatData.img = null;
}
// JSON object for easy creation
chatData.jsondata = JSON.stringify(
{
compendium: "postedItem",
payload: chatData,
});
renderTemplate('systems/fvtt-Heritiers-rpg/templates/post-item.html', chatData).then(html => {
let chatOptions = HeritiersUtility.chatDataSetup(html);
ChatMessage.create(chatOptions)
});
}
/* -------------------------------------------- */
/** @override */
activateListeners(html) {
super.activateListeners(html);
// Everything below here is only needed if the sheet is editable
if (!this.options.editable) return;
// Update Inventory Item
html.find('.item-edit').click(ev => {
const li = $(ev.currentTarget).parents(".item")
const item = this.object.options.actor.getOwnedItem(li.data("item-id"))
item.sheet.render(true);
});
html.find('.delete-subitem').click(ev => {
this.deleteSubitem(ev);
})
html.find('#add-specialite').click(ev => {
let spec = foundry.utils.duplicate(this.object.system.specialites)
spec.push( { name: "Nouvelle Spécialité", id: foundry.utils.randomID(16), used: false })
this.object.update( { 'system.specialites': spec })
})
html.find('.delete-specialite').click(ev => {
const li = $(ev.currentTarget).parents(".specialite-item")
let index = li.data("specialite-index")
let spec = foundry.utils.duplicate(this.object.system.specialites)
spec.splice(index,1)
this.object.update( { 'system.specialites': spec })
})
html.find('.edit-specialite').change(ev => {
const li = $(ev.currentTarget).parents(".specialite-item")
let index = li.data("specialite-index")
let spec = foundry.utils.duplicate(this.object.system.specialites)
spec[index].name = ev.currentTarget.value
spec[index].id = spec[index].id || foundry.utils.randomID(16)
this.object.update( { 'system.specialites': spec })
})
html.find('.edit-specialite-description').change(ev => {
const li = $(ev.currentTarget).parents(".specialite-item")
let index = li.data("specialite-index")
let spec = foundry.utils.duplicate(this.object.system.specialites)
spec[index].description = ev.currentTarget.value
spec[index].id = spec[index].id || foundry.utils.randomID(16)
this.object.update( { 'system.specialites': spec })
})
html.find('#add-automation').click(ev => {
let autom = foundry.utils.duplicate(this.object.system.automations)
autom.push( { eventtype: "on-drop", name: "Automatisation 1", competence: "", minLevel: 0, id: foundry.utils.randomID(16) })
this.object.update( { 'system.automations': autom })
})
html.find('.delete-automation').click(ev => {
const li = $(ev.currentTarget).parents(".automation-item")
let index = li.data("automation-index")
let autom = foundry.utils.duplicate(this.object.system.automations)
autom.splice(index,1)
this.object.update( { 'system.automations': autom })
})
html.find('.automation-edit-field').change(ev => {
let index = $(ev.currentTarget).data("automation-index")
let field = $(ev.currentTarget).data("automation-field")
let auto = foundry.utils.duplicate(this.object.system.automations)
auto[index][field] = ev.currentTarget.value
auto[index].id = auto[index].id || foundry.utils.randomID(16)
this.object.update( { 'system.automations': auto })
})
// Update Inventory Item
html.find('.item-delete').click(ev => {
const li = $(ev.currentTarget).parents(".item");
let itemId = li.data("item-id");
let itemType = li.data("item-type");
});
}
/* -------------------------------------------- */
get template() {
let type = this.item.type;
return `systems/fvtt-les-heritiers/templates/item-${type}-sheet.html`;
}
/* -------------------------------------------- */
/** @override */
_updateObject(event, formData) {
return this.object.update(formData);
}
}

View File

@@ -9,14 +9,17 @@
/* -------------------------------------------- */
// Import Modules
import { HeritiersActor } from "./heritiers-actor.js";
import { HeritiersItemSheet } from "./heritiers-item-sheet.js";
import { HeritiersActorSheet } from "./heritiers-actor-sheet.js";
import { HeritiersActorPNJSheet } from "./heritiers-actor-pnj-sheet.js";
import { HeritiersItem } from "./heritiers-item.js";
import { HeritiersUtility } from "./heritiers-utility.js";
import { HeritiersCombat } from "./heritiers-combat.js";
import { HeritiersItem } from "./heritiers-item.js";
import { HERITIERS_CONFIG } from "./heritiers-config.js";
// Import DataModels
import * as models from "./models/index.mjs";
// Import AppV2 Sheets
import * as sheets from "./applications/sheets/_module.mjs";
/* -------------------------------------------- */
/* Foundry VTT Initialization */
/* -------------------------------------------- */
@@ -45,22 +48,62 @@ Hooks.once("init", async function () {
// Define custom Entity classes
CONFIG.Combat.documentClass = HeritiersCombat
CONFIG.Actor.documentClass = HeritiersActor
CONFIG.Actor.dataModels = {
personnage: models.PersonnageDataModel,
pnj: models.PnjDataModel
}
CONFIG.Item.documentClass = HeritiersItem
CONFIG.Item.dataModels = {
accessoire: models.AccessoireDataModel,
arme: models.ArmeDataModel,
atoutfeerique: models.AtoutFeeriqueDataModel,
avantage: models.AvantageDataModel,
capacitenaturelle: models.CapaciteNaturelleDataModel,
competence: models.CompetenceDataModel,
contact: models.ContactDataModel,
desavantage: models.DesavantageDataModel,
equipement: models.EquipementDataModel,
fee: models.FeeDataModel,
pouvoir: models.PouvoirDataModel,
profil: models.ProfilDataModel,
protection: models.ProtectionDataModel,
sort: models.SortDataModel
}
// Create an object of bonus/malus from -6 to +6 signed
HERITIERS_CONFIG.bonusMalus = Array.from({ length: 7 }, (v, k) => toString(k - 6))
CONFIG.HERITIERS = HERITIERS_CONFIG
game.system.lesheritiers = {
HeritiersUtility,
config: HERITIERS_CONFIG
config: HERITIERS_CONFIG,
models,
sheets
}
/* -------------------------------------------- */
// Register sheet application classes
foundry.documents.collections.Actors.unregisterSheet("core", foundry.appv1.sheets.ActorSheet);
foundry.documents.collections.Actors.registerSheet("fvtt-les-heritiers", HeritiersActorSheet, { types: ["personnage"], makeDefault: true })
foundry.documents.collections.Actors.registerSheet("fvtt-les-heritiers", HeritiersActorPNJSheet, { types: ["pnj"], makeDefault: true })
foundry.documents.collections.Actors.registerSheet("fvtt-les-heritiers", sheets.HeritiersPersonnageSheet, { types: ["personnage"], makeDefault: true })
foundry.documents.collections.Actors.registerSheet("fvtt-les-heritiers", sheets.HeritiersPnjSheet, { types: ["pnj"], makeDefault: true })
// Register AppV2 Item Sheets
foundry.documents.collections.Items.unregisterSheet("core", foundry.appv1.sheets.ItemSheet);
foundry.documents.collections.Items.registerSheet("fvtt-les-heritiers", HeritiersItemSheet, { makeDefault: true })
foundry.documents.collections.Items.registerSheet("fvtt-les-heritiers", sheets.HeritiersAccessoireSheet, { types: ["accessoire"], makeDefault: true })
foundry.documents.collections.Items.registerSheet("fvtt-les-heritiers", sheets.HeritiersArmeSheet, { types: ["arme"], makeDefault: true })
foundry.documents.collections.Items.registerSheet("fvtt-les-heritiers", sheets.HeritiersAtoutFeeriqueSheet, { types: ["atoutfeerique"], makeDefault: true })
foundry.documents.collections.Items.registerSheet("fvtt-les-heritiers", sheets.HeritiersAvantageSheet, { types: ["avantage"], makeDefault: true })
foundry.documents.collections.Items.registerSheet("fvtt-les-heritiers", sheets.HeritiersCapaciteNaturelleSheet, { types: ["capacitenaturelle"], makeDefault: true })
foundry.documents.collections.Items.registerSheet("fvtt-les-heritiers", sheets.HeritiersCompetenceSheet, { types: ["competence"], makeDefault: true })
foundry.documents.collections.Items.registerSheet("fvtt-les-heritiers", sheets.HeritiersContactSheet, { types: ["contact"], makeDefault: true })
foundry.documents.collections.Items.registerSheet("fvtt-les-heritiers", sheets.HeritiersDesavantageSheet, { types: ["desavantage"], makeDefault: true })
foundry.documents.collections.Items.registerSheet("fvtt-les-heritiers", sheets.HeritiersEquipementSheet, { types: ["equipement"], makeDefault: true })
foundry.documents.collections.Items.registerSheet("fvtt-les-heritiers", sheets.HeritiersFeeSheet, { types: ["fee"], makeDefault: true })
foundry.documents.collections.Items.registerSheet("fvtt-les-heritiers", sheets.HeritiersPouvoirSheet, { types: ["pouvoir"], makeDefault: true })
foundry.documents.collections.Items.registerSheet("fvtt-les-heritiers", sheets.HeritiersProfilSheet, { types: ["profil"], makeDefault: true })
foundry.documents.collections.Items.registerSheet("fvtt-les-heritiers", sheets.HeritiersProtectionSheet, { types: ["protection"], makeDefault: true })
foundry.documents.collections.Items.registerSheet("fvtt-les-heritiers", sheets.HeritiersSortSheet, { types: ["sort"], makeDefault: true })
HeritiersUtility.init()
@@ -71,12 +114,38 @@ function welcomeMessage() {
ChatMessage.create({
user: game.user.id,
whisper: [game.user.id],
content: `<div id="welcome-message-heritiers"><span class="rdd-roll-part">
<strong>Bienvenue dans Les Heritiers et la Belle Epoque !</strong>
<p>Les livres du JDR Les Heritiers sont nécessaires pour jouer : https://www.titam-france.fr</p>
<p>Les Heritiers est jeu de rôle publié par Titam France/Sombres projets, tout les droits leur appartiennent.</p>
<p>Système développé par LeRatierBretonnien, support sur le <a href="https://discord.gg/pPSDNJk">Discord FR de Foundry</a>.</p>
` });
content: `
<div class="heritiers-chat-card heritiers-welcome-card">
<div class="chat-card-header welcome-header">
<div class="welcome-icon-wrapper">
<i class="fas fa-book-open welcome-icon"></i>
</div>
<div class="chat-actor-info">
<h3 class="chat-actor-name">Bienvenue dans Les Héritiers !</h3>
<div class="chat-action-name">et la Belle Époque</div>
</div>
</div>
<div class="chat-card-content welcome-content">
<div class="welcome-section">
<i class="fas fa-info-circle"></i>
<p>Les livres du JDR <strong>Les Héritiers</strong> sont nécessaires pour jouer.</p>
</div>
<div class="welcome-section">
<i class="fas fa-copyright"></i>
<p><em>Les Héritiers</em> est un jeu de rôle publié par <strong>Titam France / Sombres Projets</strong>. Tous les droits leur appartiennent.</p>
</div>
<div class="welcome-section">
<i class="fas fa-code"></i>
<p>Système développé par <strong>LeRatierBretonnien</strong></p>
<p>Support sur le <a href="https://discord.gg/pPSDNJk" target="_blank"><i class="fab fa-discord"></i> Discord FR de Foundry</a></p>
</div>
</div>
</div>
`
});
}
/* -------------------------------------------- */

View File

@@ -1,146 +0,0 @@
import { HeritiersUtility } from "./heritiers-utility.js";
export class HeritiersRollDialog extends Dialog {
/* -------------------------------------------- */
static async create(actor, rollData) {
let options = { classes: ["HeritiersDialog"], width: 420, height: 'fit-content', 'z-index': 99999 };
let html = await foundry.applications.handlebars.renderTemplate('systems/fvtt-les-heritiers/templates/roll-dialog-generic.html', rollData);
return new HeritiersRollDialog(actor, rollData, html, options);
}
/* -------------------------------------------- */
constructor(actor, rollData, html, options, close = undefined) {
let buttons = {
rolld8: {
icon: '<i class="fas fa-check"></i>',
label: "Lancer 1d8",
callback: () => { this.roll("d8") }
}
}
let enableD10 = false
let enableD12 = false
if (rollData.mode == "pouvoir" || rollData.competence?.system.niveau > 0) {
enableD10 = true
}
if (rollData.mode == "pouvoir" || rollData.competence?.system.niveau > 1) {
enableD12 = true
}
if (enableD10) {
buttons.rolld10 = {
icon: '<i class="fas fa-check"></i>',
label: "Lancer 1d10",
callback: () => { this.roll("d10") }
}
}
if (enableD12) {
buttons.rolld12 = {
icon: '<i class="fas fa-check"></i>',
label: "Lancer 1d12",
callback: () => { this.roll("d12") }
}
}
if (rollData.tricherie) {
buttons["rollTricherie"] = {
icon: '<i class="fas fa-check"></i>',
label: "Lancer avec 1 Point de Tricherie",
callback: () => { this.roll("tricherie") }
}
}
if (rollData.heritage) {
buttons["rollHeritage"] = {
icon: '<i class="fas fa-check"></i>',
label: "Lancer avec 1 Point d'Héritage",
callback: () => { this.roll("heritage") }
}
}
buttons["Cancel"] = {
icon: '<i class="fas fa-times"></i>',
label: "Annuler",
callback: () => { this.close() }
}
let conf = {
title: "Test de Capacité",
content: html,
buttons: buttons,
close: close
}
// Overwrite in case of carac only -> 1d8
if (rollData.mode == "carac") {
conf.buttons = {
rolld8: {
icon: '<i class="fas fa-check"></i>',
label: "Lancer 1d8",
callback: () => { this.roll("d8") }
},
cancel: {
icon: '<i class="fas fa-times"></i>',
label: "Annuler",
callback: () => { this.close() }
}
}
}
super(conf, options);
this.actor = actor
this.rollData = rollData
}
/* -------------------------------------------- */
roll(dice) {
if (dice == "heritage") {
this.rollData.useHeritage = true
}
else {
if (dice == "tricherie") {
this.rollData.useTricherie = true
} else {
this.rollData.mainDice = dice
}
}
HeritiersUtility.rollHeritiers(this.rollData)
}
/* -------------------------------------------- */
activateListeners(html) {
super.activateListeners(html);
function onLoad() {
}
$(function () { onLoad(); });
html.find('#sdValue').change(async (event) => {
this.rollData.sdValue = Number(event.currentTarget.value)
})
html.find('#caracKey').change(async (event) => {
//console.log("caracKey", event.currentTarget.value)
this.rollData.caracKey = String(event.currentTarget.value)
})
html.find('#bonus-malus-context').change((event) => {
this.rollData.bonusMalusContext = Number(event.currentTarget.value)
})
html.find('#bonus-attaque-plusieurs').change((event) => {
this.rollData.bonusAttaquePlusieurs = Number(event.currentTarget.value)
})
html.find('#useSpecialite').change((event) => {
this.rollData.useSpecialite = event.currentTarget.checked
})
html.find('#pouvoirPointsUsage').change((event) => {
this.rollData.pouvoirPointsUsage = Number(event.currentTarget.value)
})
html.find('#attaqueDos').change((event) => {
this.rollData.attaqueDos = event.currentTarget.checked
})
html.find('#bonus-attaque-seconde-arme').change((event) => {
this.rollData.secondeArme = String(event.currentTarget.value)
})
html.find('#attaque-cible').change((event) => {
this.rollData.attaqueCible = String(event.currentTarget.value)
})
}
}

View File

@@ -76,6 +76,10 @@ export class HeritiersUtility {
Handlebars.registerHelper('mul', function (a, b) {
return parseInt(a) * parseInt(b);
})
Handlebars.registerHelper('and', function (...args) {
// Last argument is Handlebars options object, ignore it
return args.slice(0, -1).every(Boolean);
})
}
@@ -196,11 +200,12 @@ export class HeritiersUtility {
static async preloadHandlebarsTemplates() {
const templatePaths = [
'systems/fvtt-les-heritiers/templates/editor-notes-gm.html',
'systems/fvtt-les-heritiers/templates/partial-item-header.html',
'systems/fvtt-les-heritiers/templates/partial-item-description.html',
'systems/fvtt-les-heritiers/templates/partial-item-nav.html',
'systems/fvtt-les-heritiers/templates/partial-utile-skills.html'
'systems/fvtt-les-heritiers/templates/editor-notes-gm.hbs',
'systems/fvtt-les-heritiers/templates/partial-item-header.hbs',
'systems/fvtt-les-heritiers/templates/partial-item-description.hbs',
'systems/fvtt-les-heritiers/templates/partial-item-nav.hbs',
'systems/fvtt-les-heritiers/templates/partial-utile-skills.hbs',
'systems/fvtt-les-heritiers/templates/partial-actor-equipment.hbs'
]
return foundry.applications.handlebars.loadTemplates(templatePaths);
}
@@ -478,7 +483,7 @@ export class HeritiersUtility {
this.computeArmeDegats(rollData, actor)
}
this.createChatWithRollMode(rollData.alias, {
content: await foundry.applications.handlebars.renderTemplate(`systems/fvtt-les-heritiers/templates/chat-cc-result.html`, rollData)
content: await foundry.applications.handlebars.renderTemplate(`systems/fvtt-les-heritiers/templates/chat-cc-result.hbs`, rollData)
}, rollData, "selfroll")
}
/* -------------------------------------------- */
@@ -490,7 +495,7 @@ export class HeritiersUtility {
this.computeMarge(rollData, valeurDefense)
rollData.dureeAssommer = (rollData.marge) ? rollData.marge * 2 : 1
this.createChatWithRollMode(rollData.alias, {
content: await foundry.applications.handlebars.renderTemplate(`systems/fvtt-les-heritiers/templates/chat-assommer-result.html`, rollData)
content: await foundry.applications.handlebars.renderTemplate(`systems/fvtt-les-heritiers/templates/chat-assommer-result.hbs`, rollData)
}, rollData, "selfroll")
}
/* -------------------------------------------- */
@@ -570,6 +575,10 @@ export class HeritiersUtility {
console.log(">>>> ", myRoll)
this.computeResult(actor, rollData)
this.computeMarge(rollData, rollData.sdValue) // Calcul de la marge si seuil présent
// Compute weapon damage for successful attacks
if (rollData.arme && rollData.isSuccess) {
this.computeArmeDegats(rollData, actor)
}
}
if (rollData.mode == "init") {
@@ -583,7 +592,7 @@ export class HeritiersUtility {
// Gestion sort et points d'âme
if (rollData.mode == "sort") {
if (rollData.spendEsprit) {
actor.inDecCarac("esp", -1)
actor.inDecCarac("esp", -rollData.totalEsprit)
} else {
actor.incDecPointsAme(-rollData.sortPointsAme)
if (rollData.sort.system.competence == "Magie du Clan") {
@@ -593,7 +602,7 @@ export class HeritiersUtility {
}
this.createChatWithRollMode(rollData.alias, {
content: await foundry.applications.handlebars.renderTemplate(`systems/fvtt-les-heritiers/templates/chat-generic-result.html`, rollData)
content: await foundry.applications.handlebars.renderTemplate(`systems/fvtt-les-heritiers/templates/chat-generic-result.hbs`, rollData)
}, rollData)
// Gestion attaque standard
@@ -631,7 +640,7 @@ export class HeritiersUtility {
this.computeResult(rollData)
this.createChatWithRollMode(rollData.alias, {
content: await foundry.applications.handlebars.renderTemplate(`systems/fvtt-les-heritiers/templates/chat-generic-result.html`, rollData)
content: await foundry.applications.handlebars.renderTemplate(`systems/fvtt-les-heritiers/templates/chat-generic-result.hbs`, rollData)
}, rollData)
}
@@ -844,7 +853,8 @@ export class HeritiersUtility {
/* -------------------------------------------- */
static async confirmDelete(actorSheet, li) {
let itemId = li.data("item-id");
// Support both jQuery and native elements
let itemId = li.dataset ? li.dataset.itemId : li.data("item-id");
let msgTxt = "<p>Certain de supprimer cet item ?";
let buttons = {
delete: {
@@ -852,7 +862,11 @@ export class HeritiersUtility {
label: "Oui !",
callback: () => {
actorSheet.actor.deleteEmbeddedDocuments("Item", [itemId]);
li.slideUp(200, () => actorSheet.render(false));
if (li.slideUp) {
li.slideUp(200, () => actorSheet.render(false));
} else {
actorSheet.render(false);
}
}
},
cancel: {

View File

@@ -0,0 +1,16 @@
/**
* Data model pour les accessoires
*/
export default class AccessoireDataModel extends foundry.abstract.TypeDataModel {
static defineSchema() {
const fields = foundry.data.fields;
return {
description: new fields.HTMLField({ initial: "" }),
rarete: new fields.NumberField({ initial: 0, integer: true }),
quantite: new fields.NumberField({ initial: 0, integer: true }),
prix: new fields.NumberField({ initial: 0, integer: true }),
equipped: new fields.BooleanField({ initial: false }),
lieu: new fields.NumberField({ initial: 0, integer: true })
};
}
}

30
modules/models/arme.mjs Normal file
View File

@@ -0,0 +1,30 @@
/**
* Data model pour les armes
*/
export default class ArmeDataModel extends foundry.abstract.TypeDataModel {
static defineSchema() {
const fields = foundry.data.fields;
return {
description: new fields.HTMLField({ initial: "" }),
rarete: new fields.NumberField({ initial: 0, integer: true }),
quantite: new fields.NumberField({ initial: 0, integer: true }),
prix: new fields.NumberField({ initial: 0, integer: true }),
equipped: new fields.BooleanField({ initial: false }),
categorie: new fields.StringField({ initial: "" }),
armetype: new fields.StringField({ initial: "" }),
degats: new fields.NumberField({ initial: 0, integer: true }),
precision: new fields.NumberField({ initial: 0, integer: true }),
cadence: new fields.StringField({ initial: "" }),
enraiement: new fields.StringField({ initial: "" }),
magasin: new fields.NumberField({ initial: 0, integer: true }),
charge: new fields.NumberField({ initial: 0, integer: true }),
portee: new fields.StringField({ initial: "" }),
legalite: new fields.StringField({ initial: "" }),
dissimulation: new fields.StringField({ initial: "" }),
zone: new fields.NumberField({ initial: 0, integer: true }),
temps: new fields.StringField({ initial: "" }),
allumage: new fields.StringField({ initial: "" }),
special: new fields.StringField({ initial: "" })
};
}
}

View File

@@ -0,0 +1,11 @@
/**
* Data model pour les atouts féériques
*/
export default class AtoutFeeriqueDataModel extends foundry.abstract.TypeDataModel {
static defineSchema() {
const fields = foundry.data.fields;
return {
description: new fields.HTMLField({ initial: "" })
};
}
}

View File

@@ -0,0 +1,11 @@
/**
* Data model pour les avantages
*/
export default class AvantageDataModel extends foundry.abstract.TypeDataModel {
static defineSchema() {
const fields = foundry.data.fields;
return {
description: new fields.HTMLField({ initial: "" })
};
}
}

View File

@@ -0,0 +1,11 @@
/**
* Base data model pour les items
*/
export default class BaseItemDataModel extends foundry.abstract.TypeDataModel {
static defineSchema() {
const fields = foundry.data.fields;
return {
description: new fields.HTMLField({ initial: "" })
};
}
}

View File

@@ -0,0 +1,21 @@
/**
* Data model pour les capacités naturelles
*/
export default class CapaciteNaturelleDataModel extends foundry.abstract.TypeDataModel {
static defineSchema() {
const fields = foundry.data.fields;
return {
pouvoirtype: new fields.StringField({ initial: "" }),
activation: new fields.StringField({ initial: "" }),
cibles: new fields.StringField({ initial: "" }),
effet: new fields.StringField({ initial: "" }),
duree: new fields.StringField({ initial: "" }),
portee: new fields.StringField({ initial: "" }),
resistance: new fields.StringField({ initial: "" }),
resistanceautre: new fields.StringField({ initial: "" }),
isvirulence: new fields.BooleanField({ initial: false }),
virulence: new fields.StringField({ initial: "" }),
description: new fields.HTMLField({ initial: "" })
};
}
}

View File

@@ -0,0 +1,43 @@
/**
* Data model pour les compétences
*/
export default class CompetenceDataModel extends foundry.abstract.TypeDataModel {
static defineSchema() {
const fields = foundry.data.fields;
return {
categorie: new fields.StringField({ initial: "" }),
profil: new fields.StringField({ initial: "" }),
niveau: new fields.NumberField({ initial: 0, integer: true }),
nomniveau: new fields.SchemaField({
1: new fields.StringField({ initial: "" }),
2: new fields.StringField({ initial: "" }),
3: new fields.StringField({ initial: "" }),
4: new fields.StringField({ initial: "" })
}),
nomniveausouffle: new fields.SchemaField({
soufflecombat: new fields.SchemaField({
1: new fields.StringField({ initial: "" }),
2: new fields.StringField({ initial: "" }),
3: new fields.StringField({ initial: "" }),
4: new fields.StringField({ initial: "" })
}),
soufflemouvement: new fields.SchemaField({
1: new fields.StringField({ initial: "" }),
2: new fields.StringField({ initial: "" }),
3: new fields.StringField({ initial: "" }),
4: new fields.StringField({ initial: "" })
}),
souffleesprit: new fields.SchemaField({
1: new fields.StringField({ initial: "" }),
2: new fields.StringField({ initial: "" }),
3: new fields.StringField({ initial: "" }),
4: new fields.StringField({ initial: "" })
})
}),
predilection: new fields.BooleanField({ initial: false }),
specialites: new fields.ArrayField(new fields.ObjectField(), { initial: [] }),
ismagie: new fields.BooleanField({ initial: false }),
description: new fields.HTMLField({ initial: "" })
};
}
}

View File

@@ -0,0 +1,12 @@
/**
* Data model pour les contacts
*/
export default class ContactDataModel extends foundry.abstract.TypeDataModel {
static defineSchema() {
const fields = foundry.data.fields;
return {
contacttype: new fields.StringField({ initial: "contact" }),
description: new fields.HTMLField({ initial: "" })
};
}
}

View File

@@ -0,0 +1,11 @@
/**
* Data model pour les désavantages
*/
export default class DesavantageDataModel extends foundry.abstract.TypeDataModel {
static defineSchema() {
const fields = foundry.data.fields;
return {
description: new fields.HTMLField({ initial: "" })
};
}
}

View File

@@ -0,0 +1,15 @@
/**
* Data model pour les équipements
*/
export default class EquipementDataModel extends foundry.abstract.TypeDataModel {
static defineSchema() {
const fields = foundry.data.fields;
return {
description: new fields.HTMLField({ initial: "" }),
rarete: new fields.NumberField({ initial: 0, integer: true }),
quantite: new fields.NumberField({ initial: 0, integer: true }),
prix: new fields.NumberField({ initial: 0, integer: true }),
equipped: new fields.BooleanField({ initial: false })
};
}
}

19
modules/models/fee.mjs Normal file
View File

@@ -0,0 +1,19 @@
/**
* Data model pour les fées
*/
export default class FeeDataModel extends foundry.abstract.TypeDataModel {
static defineSchema() {
const fields = foundry.data.fields;
return {
feetype: new fields.NumberField({ initial: 0, integer: true }),
avantages: new fields.StringField({ initial: "" }),
desavantages: new fields.StringField({ initial: "" }),
pouvoirsfeeriquesmasque: new fields.StringField({ initial: "" }),
pouvoirsfeeriquesdemasque: new fields.StringField({ initial: "" }),
atoutsfeeriques: new fields.StringField({ initial: "" }),
competences: new fields.StringField({ initial: "" }),
capacitenaturelles: new fields.StringField({ initial: "" }),
description: new fields.HTMLField({ initial: "" })
};
}
}

24
modules/models/index.mjs Normal file
View File

@@ -0,0 +1,24 @@
/**
* Index des DataModels pour Les Héritiers
* Ce fichier centralise tous les exports des modèles de données
*/
// Modèles d'acteurs
export { default as PersonnageDataModel } from './personnage.mjs';
export { default as PnjDataModel } from './pnj.mjs';
// Modèles d'items
export { default as AccessoireDataModel } from './accessoire.mjs';
export { default as ArmeDataModel } from './arme.mjs';
export { default as AtoutFeeriqueDataModel } from './atoutfeerique.mjs';
export { default as AvantageDataModel } from './avantage.mjs';
export { default as CapaciteNaturelleDataModel } from './capacitenaturelle.mjs';
export { default as CompetenceDataModel } from './competence.mjs';
export { default as ContactDataModel } from './contact.mjs';
export { default as DesavantageDataModel } from './desavantage.mjs';
export { default as EquipementDataModel } from './equipement.mjs';
export { default as FeeDataModel } from './fee.mjs';
export { default as PouvoirDataModel } from './pouvoir.mjs';
export { default as ProfilDataModel } from './profil.mjs';
export { default as ProtectionDataModel } from './protection.mjs';
export { default as SortDataModel } from './sort.mjs';

View File

@@ -0,0 +1,234 @@
/**
* Data model pour les personnages
*/
export default class PersonnageDataModel extends foundry.abstract.TypeDataModel {
static defineSchema() {
const fields = foundry.data.fields;
return {
// Template biodata
biodata: new fields.SchemaField({
name: new fields.StringField({ initial: "" }),
activite: new fields.StringField({ initial: "" }),
nomhumain: new fields.StringField({ initial: "" }),
activites: new fields.StringField({ initial: "" }),
fortune: new fields.NumberField({ initial: 0, integer: true }),
traitscaracteres: new fields.StringField({ initial: "" }),
tailledemasquee: new fields.StringField({ initial: "" }),
taillemasquee: new fields.StringField({ initial: "" }),
poidsmasquee: new fields.StringField({ initial: "" }),
poidsdemasquee: new fields.StringField({ initial: "" }),
apparencemasquee: new fields.StringField({ initial: "" }),
apparencedemasquee: new fields.StringField({ initial: "" }),
titrefamille: new fields.StringField({ initial: "" }),
langues: new fields.StringField({ initial: "" }),
factionfeerique: new fields.StringField({ initial: "" }),
typetaille: new fields.StringField({ initial: "" }),
age: new fields.NumberField({ initial: 0, integer: true }),
poids: new fields.StringField({ initial: "" }),
taille: new fields.StringField({ initial: "" }),
cheveux: new fields.StringField({ initial: "" }),
sexe: new fields.StringField({ initial: "" }),
yeux: new fields.StringField({ initial: "" }),
description: new fields.HTMLField({ initial: "" }),
revesetranges: new fields.HTMLField({ initial: "" }),
secretsdecouverts: new fields.HTMLField({ initial: "" }),
questions: new fields.HTMLField({ initial: "" }),
habitat: new fields.HTMLField({ initial: "" }),
notes: new fields.HTMLField({ initial: "" }),
statut: new fields.StringField({ initial: "" }),
playernotes: new fields.HTMLField({ initial: "" }),
gmnotes: new fields.HTMLField({ initial: "" }),
magie: new fields.BooleanField({ initial: false })
}),
// Template core
subactors: new fields.ArrayField(new fields.StringField(), { initial: [] }),
caracteristiques: new fields.SchemaField({
agi: new fields.SchemaField({
label: new fields.StringField({ initial: "Agilité" }),
labelnorm: new fields.StringField({ initial: "agilite" }),
abbrev: new fields.StringField({ initial: "agi" }),
kind: new fields.StringField({ initial: "physical" }),
value: new fields.NumberField({ initial: 1, integer: true }),
rang: new fields.NumberField({ initial: 0, integer: true }),
max: new fields.NumberField({ initial: 1, integer: true })
}),
con: new fields.SchemaField({
label: new fields.StringField({ initial: "Constitution" }),
labelnorm: new fields.StringField({ initial: "constitution" }),
abbrev: new fields.StringField({ initial: "con" }),
kind: new fields.StringField({ initial: "physical" }),
value: new fields.NumberField({ initial: 1, integer: true }),
rang: new fields.NumberField({ initial: 0, integer: true }),
max: new fields.NumberField({ initial: 1, integer: true })
}),
for: new fields.SchemaField({
label: new fields.StringField({ initial: "Force" }),
labelnorm: new fields.StringField({ initial: "force" }),
abbrev: new fields.StringField({ initial: "for" }),
kind: new fields.StringField({ initial: "physical" }),
value: new fields.NumberField({ initial: 1, integer: true }),
rang: new fields.NumberField({ initial: 0, integer: true }),
max: new fields.NumberField({ initial: 1, integer: true })
}),
prec: new fields.SchemaField({
label: new fields.StringField({ initial: "Précision" }),
labelnorm: new fields.StringField({ initial: "precision" }),
abbrev: new fields.StringField({ initial: "prec" }),
kind: new fields.StringField({ initial: "physical" }),
value: new fields.NumberField({ initial: 1, integer: true }),
rang: new fields.NumberField({ initial: 0, integer: true }),
max: new fields.NumberField({ initial: 1, integer: true })
}),
esp: new fields.SchemaField({
label: new fields.StringField({ initial: "Esprit" }),
labelnorm: new fields.StringField({ initial: "esprit" }),
abbrev: new fields.StringField({ initial: "esp" }),
kind: new fields.StringField({ initial: "mental" }),
value: new fields.NumberField({ initial: 1, integer: true }),
rang: new fields.NumberField({ initial: 0, integer: true }),
max: new fields.NumberField({ initial: 1, integer: true })
}),
per: new fields.SchemaField({
label: new fields.StringField({ initial: "Perception" }),
labelnorm: new fields.StringField({ initial: "perception" }),
abbrev: new fields.StringField({ initial: "per" }),
kind: new fields.StringField({ initial: "mental" }),
value: new fields.NumberField({ initial: 1, integer: true }),
rang: new fields.NumberField({ initial: 0, integer: true }),
max: new fields.NumberField({ initial: 1, integer: true })
}),
pres: new fields.SchemaField({
label: new fields.StringField({ initial: "Prestance" }),
labelnorm: new fields.StringField({ initial: "pres" }),
abbrev: new fields.StringField({ initial: "pres" }),
kind: new fields.StringField({ initial: "mental" }),
value: new fields.NumberField({ initial: 1, integer: true }),
rang: new fields.NumberField({ initial: 0, integer: true }),
max: new fields.NumberField({ initial: 1, integer: true })
}),
san: new fields.SchemaField({
label: new fields.StringField({ initial: "Sang-Froid" }),
labelnorm: new fields.StringField({ initial: "sangfroid" }),
abbrev: new fields.StringField({ initial: "san" }),
kind: new fields.StringField({ initial: "mental" }),
value: new fields.NumberField({ initial: 1, integer: true }),
rang: new fields.NumberField({ initial: 0, integer: true }),
max: new fields.NumberField({ initial: 1, integer: true })
})
}),
statutmasque: new fields.StringField({ initial: "masque" }),
rang: new fields.SchemaField({
tricherie: new fields.SchemaField({
label: new fields.StringField({ initial: "Tricherie" }),
value: new fields.NumberField({ initial: 0, integer: true }),
max: new fields.NumberField({ initial: 0, integer: true })
}),
feerie: new fields.SchemaField({
label: new fields.StringField({ initial: "Féerie" }),
value: new fields.NumberField({ initial: 0, integer: true }),
max: new fields.NumberField({ initial: 0, integer: true })
}),
masque: new fields.SchemaField({
label: new fields.StringField({ initial: "Masque" }),
value: new fields.NumberField({ initial: 0, integer: true }),
max: new fields.NumberField({ initial: 0, integer: true })
}),
heritage: new fields.SchemaField({
label: new fields.StringField({ initial: "Héritage" }),
value: new fields.NumberField({ initial: 0, integer: true }),
max: new fields.NumberField({ initial: 0, integer: true }),
scenarios: new fields.NumberField({ initial: 0, integer: true })
})
}),
pv: new fields.SchemaField({
value: new fields.NumberField({ initial: 0, integer: true }),
max: new fields.NumberField({ initial: 0, integer: true }),
mod: new fields.NumberField({ initial: 0, integer: true })
}),
competences: new fields.SchemaField({
aventurier: new fields.SchemaField({
label: new fields.StringField({ initial: "Aventurier" }),
niveau: new fields.NumberField({ initial: 0, integer: true }),
rang: new fields.NumberField({ initial: 0, integer: true }),
pp: new fields.NumberField({ initial: 0, integer: true })
}),
combattant: new fields.SchemaField({
label: new fields.StringField({ initial: "Combattant" }),
niveau: new fields.NumberField({ initial: 0, integer: true }),
rang: new fields.NumberField({ initial: 0, integer: true }),
pp: new fields.NumberField({ initial: 0, integer: true })
}),
erudit: new fields.SchemaField({
label: new fields.StringField({ initial: "Erudit" }),
niveau: new fields.NumberField({ initial: 0, integer: true }),
rang: new fields.NumberField({ initial: 0, integer: true }),
pp: new fields.NumberField({ initial: 0, integer: true })
}),
gentleman: new fields.SchemaField({
label: new fields.StringField({ initial: "Gentleman" }),
niveau: new fields.NumberField({ initial: 0, integer: true }),
rang: new fields.NumberField({ initial: 0, integer: true }),
pp: new fields.NumberField({ initial: 0, integer: true })
}),
roublard: new fields.SchemaField({
label: new fields.StringField({ initial: "Roublard" }),
niveau: new fields.NumberField({ initial: 0, integer: true }),
rang: new fields.NumberField({ initial: 0, integer: true }),
pp: new fields.NumberField({ initial: 0, integer: true })
}),
savant: new fields.SchemaField({
label: new fields.StringField({ initial: "Savant" }),
niveau: new fields.NumberField({ initial: 0, integer: true }),
rang: new fields.NumberField({ initial: 0, integer: true }),
pp: new fields.NumberField({ initial: 0, integer: true })
})
}),
magie: new fields.SchemaField({
pointsame: new fields.SchemaField({
value: new fields.NumberField({ initial: 0, integer: true }),
max: new fields.NumberField({ initial: 0, integer: true })
})
}),
experience: new fields.SchemaField({
value: new fields.NumberField({ initial: 0, integer: true }),
pourtricher: new fields.NumberField({ initial: 0, integer: true })
}),
combat: new fields.SchemaField({
esquive: new fields.SchemaField({
masquee: new fields.NumberField({ initial: 0, integer: true }),
demasquee: new fields.NumberField({ initial: 0, integer: true })
}),
parade: new fields.SchemaField({
masquee: new fields.NumberField({ initial: 0, integer: true }),
demasquee: new fields.NumberField({ initial: 0, integer: true }),
value: new fields.NumberField({ initial: 0, integer: true })
}),
resistancephysique: new fields.SchemaField({
value: new fields.NumberField({ initial: 0, integer: true })
}),
resistancepsychique: new fields.SchemaField({
value: new fields.NumberField({ initial: 0, integer: true })
}),
protection: new fields.SchemaField({
value: new fields.NumberField({ initial: 0, integer: true })
}),
effetssecondaires: new fields.StringField({ initial: "" }),
dissimulation: new fields.SchemaField({
value: new fields.NumberField({ initial: 0, integer: true })
}),
initiative: new fields.SchemaField({
masquee: new fields.NumberField({ initial: 0, integer: true }),
demasquee: new fields.NumberField({ initial: 0, integer: true })
}),
corpsacorps: new fields.SchemaField({
masquee: new fields.NumberField({ initial: 0, integer: true }),
demasquee: new fields.NumberField({ initial: 0, integer: true })
}),
tir: new fields.SchemaField({
masquee: new fields.NumberField({ initial: 0, integer: true }),
demasquee: new fields.NumberField({ initial: 0, integer: true })
})
})
};
}
}

10
modules/models/pnj.mjs Normal file
View File

@@ -0,0 +1,10 @@
/**
* Data model pour les PNJ
* Utilise le même schéma que les personnages
*/
import PersonnageDataModel from './personnage.mjs';
export default class PnjDataModel extends PersonnageDataModel {
// Les PNJ utilisent exactement le même schéma que les personnages
// On hérite simplement de PersonnageDataModel
}

View File

@@ -0,0 +1,29 @@
/**
* Data model pour les pouvoirs
*/
export default class PouvoirDataModel extends foundry.abstract.TypeDataModel {
static defineSchema() {
const fields = foundry.data.fields;
return {
pouvoirtype: new fields.StringField({ initial: "" }),
masquetype: new fields.StringField({ initial: "" }),
niveau: new fields.StringField({ initial: "" }),
activation: new fields.StringField({ initial: "" }),
istest: new fields.BooleanField({ initial: false }),
feeriemasque: new fields.StringField({ initial: "feerie" }),
zoneffet: new fields.StringField({ initial: "" }),
testautre: new fields.StringField({ initial: "" }),
carac: new fields.StringField({ initial: "pre" }),
duree: new fields.StringField({ initial: "" }),
cibles: new fields.StringField({ initial: "" }),
effet: new fields.StringField({ initial: "" }),
portee: new fields.StringField({ initial: "" }),
resistance: new fields.StringField({ initial: "" }),
resistanceautre: new fields.StringField({ initial: "" }),
pointsusagecourant: new fields.NumberField({ initial: -1, integer: true }),
isvirulence: new fields.BooleanField({ initial: false }),
virulence: new fields.StringField({ initial: "" }),
description: new fields.HTMLField({ initial: "" })
};
}
}

12
modules/models/profil.mjs Normal file
View File

@@ -0,0 +1,12 @@
/**
* Data model pour les profils
*/
export default class ProfilDataModel extends foundry.abstract.TypeDataModel {
static defineSchema() {
const fields = foundry.data.fields;
return {
profiltype: new fields.StringField({ initial: "majeur" }),
description: new fields.HTMLField({ initial: "" })
};
}
}

View File

@@ -0,0 +1,20 @@
/**
* Data model pour les protections
*/
export default class ProtectionDataModel extends foundry.abstract.TypeDataModel {
static defineSchema() {
const fields = foundry.data.fields;
return {
description: new fields.HTMLField({ initial: "" }),
rarete: new fields.NumberField({ initial: 0, integer: true }),
quantite: new fields.NumberField({ initial: 0, integer: true }),
prix: new fields.NumberField({ initial: 0, integer: true }),
equipped: new fields.BooleanField({ initial: false }),
points: new fields.NumberField({ initial: 0, integer: true }),
protectiontype: new fields.StringField({ initial: "" }),
effetsecondaire: new fields.StringField({ initial: "" }),
malusagilite: new fields.NumberField({ initial: 0, integer: true }),
dissimulation: new fields.StringField({ initial: "" })
};
}
}

27
modules/models/sort.mjs Normal file
View File

@@ -0,0 +1,27 @@
/**
* Data model pour les sorts
*/
export default class SortDataModel extends foundry.abstract.TypeDataModel {
static defineSchema() {
const fields = foundry.data.fields;
return {
niveau: new fields.StringField({ initial: "1" }),
rang: new fields.StringField({ initial: "1" }),
competence: new fields.StringField({ initial: "Druidisme" }),
carac1: new fields.StringField({ initial: "esp" }),
carac2: new fields.StringField({ initial: "none" }),
sdspecial: new fields.StringField({ initial: "" }),
duree: new fields.StringField({ initial: "" }),
portee: new fields.StringField({ initial: "" }),
concentration: new fields.StringField({ initial: "" }),
informatif: new fields.BooleanField({ initial: false }),
texteinformatif: new fields.StringField({ initial: "" }),
critique: new fields.StringField({ initial: "" }),
ingredients: new fields.StringField({ initial: "" }),
resistance: new fields.StringField({ initial: "" }),
coutactivation: new fields.StringField({ initial: "" }),
souffle: new fields.StringField({ initial: "" }),
description: new fields.HTMLField({ initial: "" })
};
}
}

4971
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

16
package.json Normal file
View File

@@ -0,0 +1,16 @@
{
"name": "fvtt-les-heritiers",
"version": "13.0.7",
"description": "Les Héritiers RPG for FoundryVTT (French)",
"scripts": {
"build": "gulp build",
"watch": "gulp watch"
},
"author": "Uberwald/LeRatierBretonnien",
"license": "SEE LICENSE IN LICENCE.txt",
"devDependencies": {
"gulp": "^4.0.2",
"gulp-less": "^5.0.0",
"gulp-sourcemaps": "^3.0.0"
}
}

View File

@@ -1 +1 @@
MANIFEST-000216
MANIFEST-000312

View File

@@ -1,8 +1,8 @@
2025/08/12-23:22:09.841305 7f12eeffd6c0 Recovering log #214
2025/08/12-23:22:09.894721 7f12eeffd6c0 Delete type=3 #212
2025/08/12-23:22:09.894801 7f12eeffd6c0 Delete type=0 #214
2025/08/12-23:24:44.447479 7f12edffb6c0 Level-0 table #219: started
2025/08/12-23:24:44.447513 7f12edffb6c0 Level-0 table #219: 0 bytes OK
2025/08/12-23:24:44.453775 7f12edffb6c0 Delete type=0 #217
2025/08/12-23:24:44.453928 7f12edffb6c0 Manual compaction at level-0 from '!items!1NhJH4IJpxsGmLB8' @ 72057594037927935 : 1 .. '!items!y1yOenfAJTsb3r6e' @ 0 : 0; will stop at (end)
2025/08/12-23:24:44.453962 7f12edffb6c0 Manual compaction at level-1 from '!items!1NhJH4IJpxsGmLB8' @ 72057594037927935 : 1 .. '!items!y1yOenfAJTsb3r6e' @ 0 : 0; will stop at (end)
2026/01/10-22:45:42.655574 7fd463fff6c0 Recovering log #310
2026/01/10-22:45:42.666271 7fd463fff6c0 Delete type=0 #310
2026/01/10-22:45:42.666327 7fd463fff6c0 Delete type=3 #308
2026/01/10-22:49:23.124832 7fd4627fc6c0 Level-0 table #315: started
2026/01/10-22:49:23.124856 7fd4627fc6c0 Level-0 table #315: 0 bytes OK
2026/01/10-22:49:23.132096 7fd4627fc6c0 Delete type=0 #313
2026/01/10-22:49:23.151717 7fd4627fc6c0 Manual compaction at level-0 from '!items!1NhJH4IJpxsGmLB8' @ 72057594037927935 : 1 .. '!items!y1yOenfAJTsb3r6e' @ 0 : 0; will stop at (end)
2026/01/10-22:49:23.151765 7fd4627fc6c0 Manual compaction at level-1 from '!items!1NhJH4IJpxsGmLB8' @ 72057594037927935 : 1 .. '!items!y1yOenfAJTsb3r6e' @ 0 : 0; will stop at (end)

View File

@@ -1,8 +1,8 @@
2025/08/12-22:03:12.134639 7f12ef7fe6c0 Recovering log #210
2025/08/12-22:03:12.178916 7f12ef7fe6c0 Delete type=3 #208
2025/08/12-22:03:12.178963 7f12ef7fe6c0 Delete type=0 #210
2025/08/12-23:20:29.693131 7f12edffb6c0 Level-0 table #215: started
2025/08/12-23:20:29.693153 7f12edffb6c0 Level-0 table #215: 0 bytes OK
2025/08/12-23:20:29.699501 7f12edffb6c0 Delete type=0 #213
2025/08/12-23:20:29.716914 7f12edffb6c0 Manual compaction at level-0 from '!items!1NhJH4IJpxsGmLB8' @ 72057594037927935 : 1 .. '!items!y1yOenfAJTsb3r6e' @ 0 : 0; will stop at (end)
2025/08/12-23:20:29.716949 7f12edffb6c0 Manual compaction at level-1 from '!items!1NhJH4IJpxsGmLB8' @ 72057594037927935 : 1 .. '!items!y1yOenfAJTsb3r6e' @ 0 : 0; will stop at (end)
2026/01/10-17:13:21.499762 7fd462ffd6c0 Recovering log #306
2026/01/10-17:13:21.510831 7fd462ffd6c0 Delete type=3 #304
2026/01/10-17:13:21.511011 7fd462ffd6c0 Delete type=0 #306
2026/01/10-22:35:10.944218 7fd4627fc6c0 Level-0 table #311: started
2026/01/10-22:35:10.944249 7fd4627fc6c0 Level-0 table #311: 0 bytes OK
2026/01/10-22:35:10.950116 7fd4627fc6c0 Delete type=0 #309
2026/01/10-22:35:10.963623 7fd4627fc6c0 Manual compaction at level-0 from '!items!1NhJH4IJpxsGmLB8' @ 72057594037927935 : 1 .. '!items!y1yOenfAJTsb3r6e' @ 0 : 0; will stop at (end)
2026/01/10-22:35:10.963688 7fd4627fc6c0 Manual compaction at level-1 from '!items!1NhJH4IJpxsGmLB8' @ 72057594037927935 : 1 .. '!items!y1yOenfAJTsb3r6e' @ 0 : 0; will stop at (end)

View File

@@ -1 +1 @@
MANIFEST-000216
MANIFEST-000312

View File

@@ -1,8 +1,8 @@
2025/08/12-23:22:09.953525 7f12ef7fe6c0 Recovering log #214
2025/08/12-23:22:09.999140 7f12ef7fe6c0 Delete type=3 #212
2025/08/12-23:22:09.999193 7f12ef7fe6c0 Delete type=0 #214
2025/08/12-23:24:44.461664 7f12edffb6c0 Level-0 table #219: started
2025/08/12-23:24:44.461699 7f12edffb6c0 Level-0 table #219: 0 bytes OK
2025/08/12-23:24:44.467731 7f12edffb6c0 Delete type=0 #217
2025/08/12-23:24:44.481357 7f12edffb6c0 Manual compaction at level-0 from '!items!1ETVaPBtjDtzelK1' @ 72057594037927935 : 1 .. '!items!zbsVCsWxRzkzzG1N' @ 0 : 0; will stop at (end)
2025/08/12-23:24:44.481393 7f12edffb6c0 Manual compaction at level-1 from '!items!1ETVaPBtjDtzelK1' @ 72057594037927935 : 1 .. '!items!zbsVCsWxRzkzzG1N' @ 0 : 0; will stop at (end)
2026/01/10-22:45:42.682529 7fd478fff6c0 Recovering log #310
2026/01/10-22:45:42.692944 7fd478fff6c0 Delete type=0 #310
2026/01/10-22:45:42.692994 7fd478fff6c0 Delete type=3 #308
2026/01/10-22:49:23.158820 7fd4627fc6c0 Level-0 table #315: started
2026/01/10-22:49:23.158855 7fd4627fc6c0 Level-0 table #315: 0 bytes OK
2026/01/10-22:49:23.164806 7fd4627fc6c0 Delete type=0 #313
2026/01/10-22:49:23.178845 7fd4627fc6c0 Manual compaction at level-0 from '!items!1ETVaPBtjDtzelK1' @ 72057594037927935 : 1 .. '!items!zbsVCsWxRzkzzG1N' @ 0 : 0; will stop at (end)
2026/01/10-22:49:23.178875 7fd4627fc6c0 Manual compaction at level-1 from '!items!1ETVaPBtjDtzelK1' @ 72057594037927935 : 1 .. '!items!zbsVCsWxRzkzzG1N' @ 0 : 0; will stop at (end)

View File

@@ -1,8 +1,8 @@
2025/08/12-22:03:12.234213 7f12eeffd6c0 Recovering log #210
2025/08/12-22:03:12.274961 7f12eeffd6c0 Delete type=3 #208
2025/08/12-22:03:12.275015 7f12eeffd6c0 Delete type=0 #210
2025/08/12-23:20:29.728859 7f12edffb6c0 Level-0 table #215: started
2025/08/12-23:20:29.728889 7f12edffb6c0 Level-0 table #215: 0 bytes OK
2025/08/12-23:20:29.734828 7f12edffb6c0 Delete type=0 #213
2025/08/12-23:20:29.748366 7f12edffb6c0 Manual compaction at level-0 from '!items!1ETVaPBtjDtzelK1' @ 72057594037927935 : 1 .. '!items!zbsVCsWxRzkzzG1N' @ 0 : 0; will stop at (end)
2025/08/12-23:20:29.758780 7f12edffb6c0 Manual compaction at level-1 from '!items!1ETVaPBtjDtzelK1' @ 72057594037927935 : 1 .. '!items!zbsVCsWxRzkzzG1N' @ 0 : 0; will stop at (end)
2026/01/10-17:13:21.528896 7fd478fff6c0 Recovering log #306
2026/01/10-17:13:21.539812 7fd478fff6c0 Delete type=3 #304
2026/01/10-17:13:21.539902 7fd478fff6c0 Delete type=0 #306
2026/01/10-22:35:10.963778 7fd4627fc6c0 Level-0 table #311: started
2026/01/10-22:35:10.963855 7fd4627fc6c0 Level-0 table #311: 0 bytes OK
2026/01/10-22:35:10.969945 7fd4627fc6c0 Delete type=0 #309
2026/01/10-22:35:10.989919 7fd4627fc6c0 Manual compaction at level-0 from '!items!1ETVaPBtjDtzelK1' @ 72057594037927935 : 1 .. '!items!zbsVCsWxRzkzzG1N' @ 0 : 0; will stop at (end)
2026/01/10-22:35:10.989967 7fd4627fc6c0 Manual compaction at level-1 from '!items!1ETVaPBtjDtzelK1' @ 72057594037927935 : 1 .. '!items!zbsVCsWxRzkzzG1N' @ 0 : 0; will stop at (end)

View File

@@ -1 +1 @@
MANIFEST-000216
MANIFEST-000312

View File

@@ -1,8 +1,8 @@
2025/08/12-23:22:09.739184 7f12ef7fe6c0 Recovering log #214
2025/08/12-23:22:09.787438 7f12ef7fe6c0 Delete type=3 #212
2025/08/12-23:22:09.787511 7f12ef7fe6c0 Delete type=0 #214
2025/08/12-23:24:44.402280 7f12edffb6c0 Level-0 table #219: started
2025/08/12-23:24:44.402330 7f12edffb6c0 Level-0 table #219: 0 bytes OK
2025/08/12-23:24:44.408548 7f12edffb6c0 Delete type=0 #217
2025/08/12-23:24:44.427555 7f12edffb6c0 Manual compaction at level-0 from '!items!0fPXtA5LkLgG8uDj' @ 72057594037927935 : 1 .. '!items!zvtBlG6KCIn0oCVk' @ 0 : 0; will stop at (end)
2025/08/12-23:24:44.427616 7f12edffb6c0 Manual compaction at level-1 from '!items!0fPXtA5LkLgG8uDj' @ 72057594037927935 : 1 .. '!items!zvtBlG6KCIn0oCVk' @ 0 : 0; will stop at (end)
2026/01/10-22:45:42.628622 7fd462ffd6c0 Recovering log #310
2026/01/10-22:45:42.638290 7fd462ffd6c0 Delete type=0 #310
2026/01/10-22:45:42.638350 7fd462ffd6c0 Delete type=3 #308
2026/01/10-22:49:23.132234 7fd4627fc6c0 Level-0 table #315: started
2026/01/10-22:49:23.132271 7fd4627fc6c0 Level-0 table #315: 0 bytes OK
2026/01/10-22:49:23.138271 7fd4627fc6c0 Delete type=0 #313
2026/01/10-22:49:23.151732 7fd4627fc6c0 Manual compaction at level-0 from '!items!0fPXtA5LkLgG8uDj' @ 72057594037927935 : 1 .. '!items!zvtBlG6KCIn0oCVk' @ 0 : 0; will stop at (end)
2026/01/10-22:49:23.151774 7fd4627fc6c0 Manual compaction at level-1 from '!items!0fPXtA5LkLgG8uDj' @ 72057594037927935 : 1 .. '!items!zvtBlG6KCIn0oCVk' @ 0 : 0; will stop at (end)

View File

@@ -1,8 +1,8 @@
2025/08/12-22:03:12.046235 7f12effff6c0 Recovering log #210
2025/08/12-22:03:12.089332 7f12effff6c0 Delete type=3 #208
2025/08/12-22:03:12.089400 7f12effff6c0 Delete type=0 #210
2025/08/12-23:20:29.686986 7f12edffb6c0 Level-0 table #215: started
2025/08/12-23:20:29.687016 7f12edffb6c0 Level-0 table #215: 0 bytes OK
2025/08/12-23:20:29.693011 7f12edffb6c0 Delete type=0 #213
2025/08/12-23:20:29.716900 7f12edffb6c0 Manual compaction at level-0 from '!items!0fPXtA5LkLgG8uDj' @ 72057594037927935 : 1 .. '!items!zvtBlG6KCIn0oCVk' @ 0 : 0; will stop at (end)
2025/08/12-23:20:29.716935 7f12edffb6c0 Manual compaction at level-1 from '!items!0fPXtA5LkLgG8uDj' @ 72057594037927935 : 1 .. '!items!zvtBlG6KCIn0oCVk' @ 0 : 0; will stop at (end)
2026/01/10-17:13:21.469395 7fd4637fe6c0 Recovering log #306
2026/01/10-17:13:21.479611 7fd4637fe6c0 Delete type=3 #304
2026/01/10-17:13:21.479687 7fd4637fe6c0 Delete type=0 #306
2026/01/10-22:35:10.919012 7fd4627fc6c0 Level-0 table #311: started
2026/01/10-22:35:10.919040 7fd4627fc6c0 Level-0 table #311: 0 bytes OK
2026/01/10-22:35:10.924958 7fd4627fc6c0 Delete type=0 #309
2026/01/10-22:35:10.937993 7fd4627fc6c0 Manual compaction at level-0 from '!items!0fPXtA5LkLgG8uDj' @ 72057594037927935 : 1 .. '!items!zvtBlG6KCIn0oCVk' @ 0 : 0; will stop at (end)
2026/01/10-22:35:10.938027 7fd4627fc6c0 Manual compaction at level-1 from '!items!0fPXtA5LkLgG8uDj' @ 72057594037927935 : 1 .. '!items!zvtBlG6KCIn0oCVk' @ 0 : 0; will stop at (end)

View File

@@ -1 +1 @@
MANIFEST-000216
MANIFEST-000312

View File

@@ -1,8 +1,8 @@
2025/08/12-23:22:09.532032 7f12ef7fe6c0 Recovering log #214
2025/08/12-23:22:09.583613 7f12ef7fe6c0 Delete type=3 #212
2025/08/12-23:22:09.583679 7f12ef7fe6c0 Delete type=0 #214
2025/08/12-23:24:44.414597 7f12edffb6c0 Level-0 table #219: started
2025/08/12-23:24:44.414620 7f12edffb6c0 Level-0 table #219: 0 bytes OK
2025/08/12-23:24:44.420650 7f12edffb6c0 Delete type=0 #217
2025/08/12-23:24:44.427592 7f12edffb6c0 Manual compaction at level-0 from '!items!0EAAt0qSzcD9VRBH' @ 72057594037927935 : 1 .. '!items!zfpjROW9LDAlXUkN' @ 0 : 0; will stop at (end)
2025/08/12-23:24:44.427633 7f12edffb6c0 Manual compaction at level-1 from '!items!0EAAt0qSzcD9VRBH' @ 72057594037927935 : 1 .. '!items!zfpjROW9LDAlXUkN' @ 0 : 0; will stop at (end)
2026/01/10-22:45:42.589327 7fd4637fe6c0 Recovering log #310
2026/01/10-22:45:42.598987 7fd4637fe6c0 Delete type=0 #310
2026/01/10-22:45:42.599056 7fd4637fe6c0 Delete type=3 #308
2026/01/10-22:49:23.105824 7fd4627fc6c0 Level-0 table #315: started
2026/01/10-22:49:23.105875 7fd4627fc6c0 Level-0 table #315: 0 bytes OK
2026/01/10-22:49:23.111837 7fd4627fc6c0 Delete type=0 #313
2026/01/10-22:49:23.124673 7fd4627fc6c0 Manual compaction at level-0 from '!items!0EAAt0qSzcD9VRBH' @ 72057594037927935 : 1 .. '!items!zfpjROW9LDAlXUkN' @ 0 : 0; will stop at (end)
2026/01/10-22:49:23.124705 7fd4627fc6c0 Manual compaction at level-1 from '!items!0EAAt0qSzcD9VRBH' @ 72057594037927935 : 1 .. '!items!zfpjROW9LDAlXUkN' @ 0 : 0; will stop at (end)

View File

@@ -1,8 +1,8 @@
2025/08/12-22:03:11.912233 7f12effff6c0 Recovering log #210
2025/08/12-22:03:11.957119 7f12effff6c0 Delete type=3 #208
2025/08/12-22:03:11.957180 7f12effff6c0 Delete type=0 #210
2025/08/12-23:20:29.661087 7f12edffb6c0 Level-0 table #215: started
2025/08/12-23:20:29.661131 7f12edffb6c0 Level-0 table #215: 0 bytes OK
2025/08/12-23:20:29.667177 7f12edffb6c0 Delete type=0 #213
2025/08/12-23:20:29.686825 7f12edffb6c0 Manual compaction at level-0 from '!items!0EAAt0qSzcD9VRBH' @ 72057594037927935 : 1 .. '!items!zfpjROW9LDAlXUkN' @ 0 : 0; will stop at (end)
2025/08/12-23:20:29.686871 7f12edffb6c0 Manual compaction at level-1 from '!items!0EAAt0qSzcD9VRBH' @ 72057594037927935 : 1 .. '!items!zfpjROW9LDAlXUkN' @ 0 : 0; will stop at (end)
2026/01/10-17:13:21.429229 7fd463fff6c0 Recovering log #306
2026/01/10-17:13:21.439355 7fd463fff6c0 Delete type=3 #304
2026/01/10-17:13:21.439437 7fd463fff6c0 Delete type=0 #306
2026/01/10-22:35:10.925075 7fd4627fc6c0 Level-0 table #311: started
2026/01/10-22:35:10.925115 7fd4627fc6c0 Level-0 table #311: 0 bytes OK
2026/01/10-22:35:10.931575 7fd4627fc6c0 Delete type=0 #309
2026/01/10-22:35:10.938004 7fd4627fc6c0 Manual compaction at level-0 from '!items!0EAAt0qSzcD9VRBH' @ 72057594037927935 : 1 .. '!items!zfpjROW9LDAlXUkN' @ 0 : 0; will stop at (end)
2026/01/10-22:35:10.938039 7fd4627fc6c0 Manual compaction at level-1 from '!items!0EAAt0qSzcD9VRBH' @ 72057594037927935 : 1 .. '!items!zfpjROW9LDAlXUkN' @ 0 : 0; will stop at (end)

View File

@@ -1 +1 @@
MANIFEST-000216
MANIFEST-000312

View File

@@ -1,8 +1,8 @@
2025/08/12-23:22:09.678492 7f12eeffd6c0 Recovering log #214
2025/08/12-23:22:09.736918 7f12eeffd6c0 Delete type=3 #212
2025/08/12-23:22:09.737004 7f12eeffd6c0 Delete type=0 #214
2025/08/12-23:24:44.408642 7f12edffb6c0 Level-0 table #219: started
2025/08/12-23:24:44.408666 7f12edffb6c0 Level-0 table #219: 0 bytes OK
2025/08/12-23:24:44.414489 7f12edffb6c0 Delete type=0 #217
2025/08/12-23:24:44.427576 7f12edffb6c0 Manual compaction at level-0 from '!items!0cNSRJVPk3GbvxfD' @ 72057594037927935 : 1 .. '!items!yWDg2KlXEz33TSmZ' @ 0 : 0; will stop at (end)
2025/08/12-23:24:44.427625 7f12edffb6c0 Manual compaction at level-1 from '!items!0cNSRJVPk3GbvxfD' @ 72057594037927935 : 1 .. '!items!yWDg2KlXEz33TSmZ' @ 0 : 0; will stop at (end)
2026/01/10-22:45:42.615071 7fd463fff6c0 Recovering log #310
2026/01/10-22:45:42.625822 7fd463fff6c0 Delete type=0 #310
2026/01/10-22:45:42.625885 7fd463fff6c0 Delete type=3 #308
2026/01/10-22:49:23.098421 7fd4627fc6c0 Level-0 table #315: started
2026/01/10-22:49:23.098464 7fd4627fc6c0 Level-0 table #315: 0 bytes OK
2026/01/10-22:49:23.105653 7fd4627fc6c0 Delete type=0 #313
2026/01/10-22:49:23.124661 7fd4627fc6c0 Manual compaction at level-0 from '!items!0cNSRJVPk3GbvxfD' @ 72057594037927935 : 1 .. '!items!yWDg2KlXEz33TSmZ' @ 0 : 0; will stop at (end)
2026/01/10-22:49:23.124699 7fd4627fc6c0 Manual compaction at level-1 from '!items!0cNSRJVPk3GbvxfD' @ 72057594037927935 : 1 .. '!items!yWDg2KlXEz33TSmZ' @ 0 : 0; will stop at (end)

View File

@@ -1,8 +1,8 @@
2025/08/12-22:03:12.004614 7f12ef7fe6c0 Recovering log #210
2025/08/12-22:03:12.044171 7f12ef7fe6c0 Delete type=3 #208
2025/08/12-22:03:12.044244 7f12ef7fe6c0 Delete type=0 #210
2025/08/12-23:20:29.673446 7f12edffb6c0 Level-0 table #215: started
2025/08/12-23:20:29.673471 7f12edffb6c0 Level-0 table #215: 0 bytes OK
2025/08/12-23:20:29.680450 7f12edffb6c0 Delete type=0 #213
2025/08/12-23:20:29.686854 7f12edffb6c0 Manual compaction at level-0 from '!items!0cNSRJVPk3GbvxfD' @ 72057594037927935 : 1 .. '!items!yWDg2KlXEz33TSmZ' @ 0 : 0; will stop at (end)
2025/08/12-23:20:29.686885 7f12edffb6c0 Manual compaction at level-1 from '!items!0cNSRJVPk3GbvxfD' @ 72057594037927935 : 1 .. '!items!yWDg2KlXEz33TSmZ' @ 0 : 0; will stop at (end)
2026/01/10-17:13:21.456371 7fd462ffd6c0 Recovering log #306
2026/01/10-17:13:21.466637 7fd462ffd6c0 Delete type=3 #304
2026/01/10-17:13:21.466715 7fd462ffd6c0 Delete type=0 #306
2026/01/10-22:35:10.912772 7fd4627fc6c0 Level-0 table #311: started
2026/01/10-22:35:10.912830 7fd4627fc6c0 Level-0 table #311: 0 bytes OK
2026/01/10-22:35:10.918894 7fd4627fc6c0 Delete type=0 #309
2026/01/10-22:35:10.937977 7fd4627fc6c0 Manual compaction at level-0 from '!items!0cNSRJVPk3GbvxfD' @ 72057594037927935 : 1 .. '!items!yWDg2KlXEz33TSmZ' @ 0 : 0; will stop at (end)
2026/01/10-22:35:10.938019 7fd4627fc6c0 Manual compaction at level-1 from '!items!0cNSRJVPk3GbvxfD' @ 72057594037927935 : 1 .. '!items!yWDg2KlXEz33TSmZ' @ 0 : 0; will stop at (end)

View File

@@ -1 +1 @@
MANIFEST-000219
MANIFEST-000318

View File

@@ -1,8 +1,8 @@
2025/08/12-23:22:09.475992 7f12effff6c0 Recovering log #217
2025/08/12-23:22:09.530135 7f12effff6c0 Delete type=3 #215
2025/08/12-23:22:09.530186 7f12effff6c0 Delete type=0 #217
2025/08/12-23:24:44.420774 7f12edffb6c0 Level-0 table #222: started
2025/08/12-23:24:44.420800 7f12edffb6c0 Level-0 table #222: 0 bytes OK
2025/08/12-23:24:44.427391 7f12edffb6c0 Delete type=0 #220
2025/08/12-23:24:44.427605 7f12edffb6c0 Manual compaction at level-0 from '!folders!FBCujRu055QLePB2' @ 72057594037927935 : 1 .. '!items!zEl2NQsnCpELVWzh' @ 0 : 0; will stop at (end)
2025/08/12-23:24:44.427641 7f12edffb6c0 Manual compaction at level-1 from '!folders!FBCujRu055QLePB2' @ 72057594037927935 : 1 .. '!items!zEl2NQsnCpELVWzh' @ 0 : 0; will stop at (end)
2026/01/10-22:45:42.576270 7fd462ffd6c0 Recovering log #316
2026/01/10-22:45:42.587079 7fd462ffd6c0 Delete type=0 #316
2026/01/10-22:45:42.587154 7fd462ffd6c0 Delete type=3 #314
2026/01/10-22:49:23.111938 7fd4627fc6c0 Level-0 table #321: started
2026/01/10-22:49:23.111961 7fd4627fc6c0 Level-0 table #321: 0 bytes OK
2026/01/10-22:49:23.117915 7fd4627fc6c0 Delete type=0 #319
2026/01/10-22:49:23.124683 7fd4627fc6c0 Manual compaction at level-0 from '!folders!FBCujRu055QLePB2' @ 72057594037927935 : 1 .. '!items!zEl2NQsnCpELVWzh' @ 0 : 0; will stop at (end)
2026/01/10-22:49:23.124711 7fd4627fc6c0 Manual compaction at level-1 from '!folders!FBCujRu055QLePB2' @ 72057594037927935 : 1 .. '!items!zEl2NQsnCpELVWzh' @ 0 : 0; will stop at (end)

View File

@@ -1,8 +1,8 @@
2025/08/12-22:03:11.864963 7f12ee7fc6c0 Recovering log #213
2025/08/12-22:03:11.909538 7f12ee7fc6c0 Delete type=3 #211
2025/08/12-22:03:11.909606 7f12ee7fc6c0 Delete type=0 #213
2025/08/12-23:20:29.667307 7f12edffb6c0 Level-0 table #218: started
2025/08/12-23:20:29.667339 7f12edffb6c0 Level-0 table #218: 0 bytes OK
2025/08/12-23:20:29.673335 7f12edffb6c0 Delete type=0 #216
2025/08/12-23:20:29.686842 7f12edffb6c0 Manual compaction at level-0 from '!folders!FBCujRu055QLePB2' @ 72057594037927935 : 1 .. '!items!zEl2NQsnCpELVWzh' @ 0 : 0; will stop at (end)
2025/08/12-23:20:29.686878 7f12edffb6c0 Manual compaction at level-1 from '!folders!FBCujRu055QLePB2' @ 72057594037927935 : 1 .. '!items!zEl2NQsnCpELVWzh' @ 0 : 0; will stop at (end)
2026/01/10-17:13:21.415001 7fd4637fe6c0 Recovering log #312
2026/01/10-17:13:21.425375 7fd4637fe6c0 Delete type=3 #310
2026/01/10-17:13:21.425467 7fd4637fe6c0 Delete type=0 #312
2026/01/10-22:35:10.931688 7fd4627fc6c0 Level-0 table #317: started
2026/01/10-22:35:10.931718 7fd4627fc6c0 Level-0 table #317: 0 bytes OK
2026/01/10-22:35:10.937843 7fd4627fc6c0 Delete type=0 #315
2026/01/10-22:35:10.938011 7fd4627fc6c0 Manual compaction at level-0 from '!folders!FBCujRu055QLePB2' @ 72057594037927935 : 1 .. '!items!zEl2NQsnCpELVWzh' @ 0 : 0; will stop at (end)
2026/01/10-22:35:10.938033 7fd4627fc6c0 Manual compaction at level-1 from '!folders!FBCujRu055QLePB2' @ 72057594037927935 : 1 .. '!items!zEl2NQsnCpELVWzh' @ 0 : 0; will stop at (end)

Binary file not shown.

Binary file not shown.

View File

@@ -1 +1 @@
MANIFEST-000216
MANIFEST-000312

View File

@@ -1,8 +1,8 @@
2025/08/12-23:22:09.585932 7f12ee7fc6c0 Recovering log #214
2025/08/12-23:22:09.675400 7f12ee7fc6c0 Delete type=3 #212
2025/08/12-23:22:09.675482 7f12ee7fc6c0 Delete type=0 #214
2025/08/12-23:24:44.434363 7f12edffb6c0 Level-0 table #219: started
2025/08/12-23:24:44.434400 7f12edffb6c0 Level-0 table #219: 0 bytes OK
2025/08/12-23:24:44.440785 7f12edffb6c0 Delete type=0 #217
2025/08/12-23:24:44.453906 7f12edffb6c0 Manual compaction at level-0 from '!items!2QqvtClSVnh5ejXu' @ 72057594037927935 : 1 .. '!items!xzRJ6JP1HqoqxLdj' @ 0 : 0; will stop at (end)
2025/08/12-23:24:44.453946 7f12edffb6c0 Manual compaction at level-1 from '!items!2QqvtClSVnh5ejXu' @ 72057594037927935 : 1 .. '!items!xzRJ6JP1HqoqxLdj' @ 0 : 0; will stop at (end)
2026/01/10-22:45:42.601653 7fd478fff6c0 Recovering log #310
2026/01/10-22:45:42.612222 7fd478fff6c0 Delete type=0 #310
2026/01/10-22:45:42.612283 7fd478fff6c0 Delete type=3 #308
2026/01/10-22:49:23.118089 7fd4627fc6c0 Level-0 table #315: started
2026/01/10-22:49:23.118123 7fd4627fc6c0 Level-0 table #315: 0 bytes OK
2026/01/10-22:49:23.124530 7fd4627fc6c0 Delete type=0 #313
2026/01/10-22:49:23.124693 7fd4627fc6c0 Manual compaction at level-0 from '!items!2QqvtClSVnh5ejXu' @ 72057594037927935 : 1 .. '!items!xzRJ6JP1HqoqxLdj' @ 0 : 0; will stop at (end)
2026/01/10-22:49:23.124717 7fd4627fc6c0 Manual compaction at level-1 from '!items!2QqvtClSVnh5ejXu' @ 72057594037927935 : 1 .. '!items!xzRJ6JP1HqoqxLdj' @ 0 : 0; will stop at (end)

View File

@@ -1,8 +1,8 @@
2025/08/12-22:03:11.960107 7f12eeffd6c0 Recovering log #210
2025/08/12-22:03:12.002183 7f12eeffd6c0 Delete type=3 #208
2025/08/12-22:03:12.002239 7f12eeffd6c0 Delete type=0 #210
2025/08/12-23:20:29.680595 7f12edffb6c0 Level-0 table #215: started
2025/08/12-23:20:29.680637 7f12edffb6c0 Level-0 table #215: 0 bytes OK
2025/08/12-23:20:29.686672 7f12edffb6c0 Delete type=0 #213
2025/08/12-23:20:29.686864 7f12edffb6c0 Manual compaction at level-0 from '!items!2QqvtClSVnh5ejXu' @ 72057594037927935 : 1 .. '!items!xzRJ6JP1HqoqxLdj' @ 0 : 0; will stop at (end)
2025/08/12-23:20:29.686893 7f12edffb6c0 Manual compaction at level-1 from '!items!2QqvtClSVnh5ejXu' @ 72057594037927935 : 1 .. '!items!xzRJ6JP1HqoqxLdj' @ 0 : 0; will stop at (end)
2026/01/10-17:13:21.442425 7fd478fff6c0 Recovering log #306
2026/01/10-17:13:21.453357 7fd478fff6c0 Delete type=3 #304
2026/01/10-17:13:21.453438 7fd478fff6c0 Delete type=0 #306
2026/01/10-22:35:10.950222 7fd4627fc6c0 Level-0 table #311: started
2026/01/10-22:35:10.950248 7fd4627fc6c0 Level-0 table #311: 0 bytes OK
2026/01/10-22:35:10.957326 7fd4627fc6c0 Delete type=0 #309
2026/01/10-22:35:10.963639 7fd4627fc6c0 Manual compaction at level-0 from '!items!2QqvtClSVnh5ejXu' @ 72057594037927935 : 1 .. '!items!xzRJ6JP1HqoqxLdj' @ 0 : 0; will stop at (end)
2026/01/10-22:35:10.963675 7fd4627fc6c0 Manual compaction at level-1 from '!items!2QqvtClSVnh5ejXu' @ 72057594037927935 : 1 .. '!items!xzRJ6JP1HqoqxLdj' @ 0 : 0; will stop at (end)

BIN
packs/journaux/000005.ldb Normal file

Binary file not shown.

1
packs/journaux/CURRENT Normal file
View File

@@ -0,0 +1 @@
MANIFEST-000030

8
packs/journaux/LOG Normal file
View File

@@ -0,0 +1,8 @@
2026/01/10-22:45:42.723038 7fd4637fe6c0 Recovering log #28
2026/01/10-22:45:42.733325 7fd4637fe6c0 Delete type=0 #28
2026/01/10-22:45:42.733393 7fd4637fe6c0 Delete type=3 #26
2026/01/10-22:49:23.164915 7fd4627fc6c0 Level-0 table #33: started
2026/01/10-22:49:23.164944 7fd4627fc6c0 Level-0 table #33: 0 bytes OK
2026/01/10-22:49:23.170895 7fd4627fc6c0 Delete type=0 #31
2026/01/10-22:49:23.178857 7fd4627fc6c0 Manual compaction at level-0 from '!journal!QZDy8zwSVh7t4meA' @ 72057594037927935 : 1 .. '!journal.pages!QZDy8zwSVh7t4meA.gdXBDBkPlBjfmTy7' @ 0 : 0; will stop at (end)
2026/01/10-22:49:23.178898 7fd4627fc6c0 Manual compaction at level-1 from '!journal!QZDy8zwSVh7t4meA' @ 72057594037927935 : 1 .. '!journal.pages!QZDy8zwSVh7t4meA.gdXBDBkPlBjfmTy7' @ 0 : 0; will stop at (end)

8
packs/journaux/LOG.old Normal file
View File

@@ -0,0 +1,8 @@
2026/01/10-17:13:21.571878 7fd462ffd6c0 Recovering log #24
2026/01/10-17:13:21.582771 7fd462ffd6c0 Delete type=3 #22
2026/01/10-17:13:21.582857 7fd462ffd6c0 Delete type=0 #24
2026/01/10-22:35:10.976802 7fd4627fc6c0 Level-0 table #29: started
2026/01/10-22:35:10.976847 7fd4627fc6c0 Level-0 table #29: 0 bytes OK
2026/01/10-22:35:10.983280 7fd4627fc6c0 Delete type=0 #27
2026/01/10-22:35:10.989948 7fd4627fc6c0 Manual compaction at level-0 from '!journal!QZDy8zwSVh7t4meA' @ 72057594037927935 : 1 .. '!journal.pages!QZDy8zwSVh7t4meA.gdXBDBkPlBjfmTy7' @ 0 : 0; will stop at (end)
2026/01/10-22:35:10.989976 7fd4627fc6c0 Manual compaction at level-1 from '!journal!QZDy8zwSVh7t4meA' @ 72057594037927935 : 1 .. '!journal.pages!QZDy8zwSVh7t4meA.gdXBDBkPlBjfmTy7' @ 0 : 0; will stop at (end)

Binary file not shown.

Binary file not shown.

Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More