Compare commits

...

37 Commits

Author SHA1 Message Date
4722fdf4d6 Migration vers DataModels et appv2 2026-01-10 22:55:38 +01:00
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
1c7cf343b1 Update arts obscurs 2025-08-12 23:24:50 +02:00
d4b00e3508 Update arts obscurs 2025-08-12 23:20:51 +02:00
adc912e6cd Ajout/upgrade des arts obscurs 2025-08-11 22:53:23 +02:00
51a457ebf6 Foundry v13 migration 2025-05-02 08:34:22 +02:00
2e9c558027 Ajout arts obscurs 2024-11-17 22:46:52 +01:00
bcd0758328 Ajout arts obscurs 2024-11-17 22:45:48 +01:00
2b680a203f Fix jet avec prestance 2024-08-11 14:40:41 +02:00
e3d7874dce Fix masque/demaque + pouvoir passif avec point 2024-07-30 13:45:50 +02:00
ab6a5832c0 Various v12 fixes 2024-07-13 12:13:06 +02:00
d83a999974 Various v12 fixes 2024-07-13 12:12:38 +02:00
b83890a764 Add v12 support 2024-05-23 15:38:50 +02:00
5ad3c165e5 Add v12 support 2024-05-23 11:25:51 +02:00
2b3e774cbb Correction sur les pouvoirs des fiches de PNJ 2024-04-25 10:30:15 +02:00
96f8d2bceb Fix roll pouvoir + pouvoirs passifs 2024-04-11 12:36:50 +02:00
e288c90ee4 Bouton d'ajout d'items dans la fiche PNJ 2024-04-01 17:27:20 +02:00
8916de8613 Bouton d'ajout d'items dans la fiche 2024-03-31 17:53:56 +02:00
8598df5a57 Ajout de la gestion des Points d'usage 2024-03-23 11:37:15 +01:00
8781462c8d Correction sur competences à 0 + diverses ameliorations 2024-03-06 19:00:01 +01:00
8c38aead3e Correction sur competences à 0 + diverses ameliorations 2024-03-06 18:46:53 +01:00
67bf71e6c0 Fix competences 2024-03-01 13:39:32 +01:00
63d15e82bb Enhance stats 2024-02-08 12:56:25 +01:00
208 changed files with 19199 additions and 4680 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

BIN
assets/icons/sort.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 192 KiB

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;

View File

@@ -1,30 +1,24 @@
{
"ACTOR": {
"TypePersonnage": "Personnage",
"TypePNJ": "PNJ"
},
"ITEM": {
"TypeArtefact": "Artefact",
"TypeArme": "Arme",
"TypeTalent": "Talent",
"TypeHistorique": "Historique",
"TypeProfil": "Profil",
"TypeCompetence": "Compétence",
"TypeProtection": "Protection",
"TypeMonnaie": "Monnaie",
"TypeEquipement": "Equipement",
"TypeRessource": "Ressource",
"TypeContact": "Contact"
},
"HAWKMOON": {
"ui": {
"editContact": "Modifier le contact",
"deleteContact": "Supprimer le contact",
"editTrait": "Modifier le trait",
"deleteTrait": "Supprimer le trait"
"TYPES": {
"Actor": {
"personnage": "Personnage",
"pnj": "PNJ"
},
"Item": {
"accessoire": "Accessoire",
"arme": "Arme",
"atoutfeerique": "Atout féerique",
"avantage": "Avantage",
"capacitenaturelle": "Capacité naturelle",
"competence": "Compétence",
"contact": "Contact",
"desavantage": "Désavantage",
"equipement": "Equipement",
"fee": "e",
"pouvoir": "Pouvoir",
"profil": "Profil",
"protection": "Protection",
"sort": "Sort"
}
}
}

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 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,222 +0,0 @@
/**
* Extend the basic ActorSheet with some very simple modifications
* @extends {ActorSheet}
*/
import { HeritiersUtility } from "./heritiers-utility.js";
/* -------------------------------------------- */
export class HeritiersActorSheet extends ActorSheet {
/** @override */
static get defaultOptions() {
return 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 = 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"),
futileSkills :this.actor.organizeFutileSkills(),
contacts: this.actor.organizeContacts(),
armes: duplicate(this.actor.getWeapons()),
monnaies: duplicate(this.actor.getMonnaies()),
pouvoirs: duplicate(this.actor.getPouvoirs()),
fee: duplicate(this.actor.getFee() || {} ),
protections: duplicate(this.actor.getArmors()),
combat: this.actor.getCombatValues(),
equipements: duplicate(this.actor.getEquipments()),
avantages: duplicate(this.actor.getAvantages()),
atouts: duplicate(this.actor.getAtouts()),
capacites: duplicate(this.actor.getCapacites()),
desavantages: duplicate(this.actor.getDesavantages()),
profils: 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 TextEditor.enrichHTML(this.object.system.biodata.description, {async: true}),
revesetranges: await TextEditor.enrichHTML(this.object.system.biodata.revesetranges, {async: true}),
secretsdecouverts: await TextEditor.enrichHTML(this.object.system.biodata.secretsdecouverts, {async: true}),
questions: await TextEditor.enrichHTML(this.object.system.biodata.questions, {async: true}),
habitat: await TextEditor.enrichHTML(this.object.system.biodata.habitat, {async: true}),
playernotes: await TextEditor.enrichHTML(this.object.system.biodata.playernotes, {async: true}),
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;
}
/* -------------------------------------------- */
getCelluleTalents( ) {
let talents = []
for(let cellule of game.actors) {
if (cellule.type == "cellule") {
let found = cellule.system.members.find( it => it.id == this.actor.id)
if (found) {
talents = talents.concat( cellule.getTalents() )
}
}
}
return talents
}
/* -------------------------------------------- */
/** @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-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('.item-add').click((event) => {
const itemType = $(event.currentTarget).data("type")
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]
@@ -17,8 +17,8 @@ export class HeritiersActor extends Actor {
/**
* Override the create() function to provide additional SoS functionality.
*
* This overrided create() function adds initial items
* Namely: Basic skills, money,
* This overrided create() function adds initial items
* Namely: Basic skills, money,
*
* @param {Object} data Barebones actor data which this function adds onto.
* @param {Object} options (Unused) Additional options which customize the creation workflow.
@@ -41,7 +41,7 @@ export class HeritiersActor extends Actor {
const skills = await HeritiersUtility.loadCompendium("fvtt-les-heritiers.competences")
data.items = []
for (let skill of skills) {
if (skill.system.categorie == "utile") {
if (skill.system.categorie == "utile" && skill.system.profil != "magie") {
data.items.push(skill.toObject())
}
}
@@ -54,7 +54,7 @@ export class HeritiersActor extends Actor {
/* -------------------------------------------- */
prepareArme(arme) {
arme = duplicate(arme)
arme = foundry.utils.duplicate(arme)
arme.system.isMelee = HeritiersUtility.isArmeMelee(arme)
return arme
}
@@ -73,7 +73,7 @@ export class HeritiersActor extends Actor {
getOtherMeleeWeapons(excludeArme) {
let armes = []
for (let arme of this.items) {
if ( HeritiersUtility.isArmeMelee(arme) && arme.id != excludeArme._id) {
if (HeritiersUtility.isArmeMelee(arme) && arme.id != excludeArme._id) {
armes.push(this.prepareArme(arme))
}
}
@@ -86,7 +86,7 @@ export class HeritiersActor extends Actor {
/* ----------------------- --------------------- */
addMember(actorId) {
let members = duplicate(this.system.members)
let members = foundry.utils.duplicate(this.system.members)
members.push({ id: actorId })
this.update({ 'system.members': members })
}
@@ -135,13 +135,102 @@ export class HeritiersActor extends Actor {
return this.getItemSorted(["profil"])
}
getPouvoirs() {
return this.getItemSorted(["pouvoir"])
let pouvoirs = []
for (let item of this.items) {
if (item.type == "pouvoir") {
let itemObj = foundry.utils.duplicate(item)
itemObj.maxUsage = this.getPouvoirUsageMax(item)
pouvoirs.push(itemObj)
}
}
HeritiersUtility.sortArrayObjectsByName(pouvoirs)
return pouvoirs
}
getSorts() {
return this.getItemSorted(["sort"])
}
getCompetencesMagie() {
let comp = []
for (let item of this.items) {
if (item.type == "competence" && item.system.profil == "magie") {
let itemObj = foundry.utils.duplicate(item)
comp.push(itemObj)
}
}
HeritiersUtility.sortArrayObjectsByName(comp)
return comp
}
prepareMagie() {
let magieList = []
for (let item of this.items) {
if (item.type == "competence" && item.system.profil == "magie") {
let magie = {}
magie.name = item.name
magie.competence = foundry.utils.duplicate(item)
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 = {}
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)
}
}
return magieList
}
/* -------------------------------------------- */
getSkills() {
let comp = []
for (let item of this.items) {
item = duplicate(item)
item = foundry.utils.duplicate(item)
if (item.type == "competence") {
comp.push(item)
}
@@ -152,7 +241,7 @@ export class HeritiersActor extends Actor {
/* -------------------------------------------- */
prepareUtileSkill(item) {
let specList = []
if (item && item.system.categorie && item.system.categorie == "utile") {
if (item?.system?.categorie == "utile") {
for (let spec of item.system.specialites) {
specList.push(spec.name)
}
@@ -161,6 +250,28 @@ export class HeritiersActor extends Actor {
item.specList = specList.toString()
}
/* -------------------------------------------- */
organizeMagicSkills() {
let comp = {}
for (let key in game.system.lesheritiers.config.competenceProfil) {
if (game.system.lesheritiers.config.competenceProfil[key].kind == "magical")
comp[key] = { skills: [], niveau: 0 }
}
for (let item of this.items) {
if (item.type == "competence") {
if (item.system.categorie == "utile" && comp[item.system.profil]) {
this.prepareUtileSkill(item)
comp[item.system.profil].skills.push(item)
}
}
}
for (let key in comp) {
HeritiersUtility.sortArrayObjectsByName(comp[key].skills)
}
return Object.fromEntries(Object.entries(comp).sort())
}
/* -------------------------------------------- */
organizeUtileSkills(kind = "mental") {
let comp = {}
@@ -182,6 +293,7 @@ export class HeritiersActor extends Actor {
}
return Object.fromEntries(Object.entries(comp).sort())
}
/* -------------------------------------------- */
organizeContacts() {
let contactList = {}
@@ -251,8 +363,35 @@ export class HeritiersActor extends Actor {
super.prepareData();
}
/* -------------------------------------------- */
getMaxRangMagie() {
let niv = 0
let bestMagie
for (let comp of this.items) {
if (comp.type == "competence" && comp.system.profil == "magie") {
if (comp.system.niveau > niv) {
bestMagie = comp
niv = comp.system.niveau
}
}
}
if (bestMagie) {
return Math.round(bestMagie.system.niveau / 2)
}
return 0
}
/* -------------------------------------------- */
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') {
}
@@ -270,7 +409,7 @@ export class HeritiersActor extends Actor {
getItemById(id) {
let item = this.items.find(item => item.id == id);
if (item) {
item = duplicate(item)
item = foundry.utils.duplicate(item)
}
return item;
}
@@ -278,7 +417,7 @@ export class HeritiersActor extends Actor {
/* -------------------------------------------- */
async equipItem(itemId) {
let item = this.items.find(item => item.id == itemId)
if (item && item.system) {
if (item?.system) {
let update = { _id: item.id, "system.equipped": !item.system.equipped }
await this.updateEmbeddedDocuments('Item', [update]); // Updates one EmbeddedEntity
}
@@ -328,7 +467,7 @@ export class HeritiersActor extends Actor {
/* -------------------------------------------- */
getCarac(attrKey) {
return duplicate(this.system.caracteristiques)
return foundry.utils.duplicate(this.system.caracteristiques)
}
/* -------------------------------------------- */
@@ -339,7 +478,7 @@ export class HeritiersActor extends Actor {
/* -------------------------------------------- */
async equipGear(equipmentId) {
let item = this.items.find(item => item.id == equipmentId);
if (item && item.system.data) {
if (item?.system) {
let update = { _id: item.id, "system.equipped": !item.system.equipped };
await this.updateEmbeddedDocuments('Item', [update]); // Updates one EmbeddedEntity
}
@@ -349,13 +488,13 @@ export class HeritiersActor extends Actor {
getSubActors() {
let subActors = [];
for (let id of this.system.subactors) {
subActors.push(duplicate(game.actors.get(id)));
subActors.push(foundry.utils.duplicate(game.actors.get(id)));
}
return subActors;
}
/* -------------------------------------------- */
async addSubActor(subActorId) {
let subActors = duplicate(this.system.subactors);
let subActors = foundry.utils.duplicate(this.system.subactors);
subActors.push(subActorId);
await this.update({ 'system.subactors': subActors });
}
@@ -377,11 +516,12 @@ export class HeritiersActor extends Actor {
/* -------------------------------------------- */
async incDecAdversite(adv, incDec = 0) {
let adversite = duplicate(this.system.adversite)
let adversite = foundry.utils.duplicate(this.system.adversite)
adversite[adv] += Number(incDec)
adversite[adv] = Math.max(adversite[adv], 0)
this.update({ 'system.adversite': adversite })
}
/* -------------------------------------------- */
async incDecQuantity(objetId, incDec = 0) {
let objetQ = this.items.get(objetId)
@@ -424,7 +564,7 @@ export class HeritiersActor extends Actor {
/* -------------------------------------------- */
async setPredilectionUsed(compId, predIdx) {
let comp = this.items.get(compId)
let pred = duplicate(comp.system.predilections)
let pred = foundry.utils.duplicate(comp.system.predilections)
pred[predIdx].used = true
await this.updateEmbeddedDocuments('Item', [{ _id: compId, 'system.predilections': pred }])
}
@@ -446,7 +586,7 @@ export class HeritiersActor extends Actor {
}
if (arme.system.totalDefensif > maxDef) {
maxDef = arme.system.totalDefensif
bestArme = duplicate(arme)
bestArme = foundry.utils.duplicate(arme)
}
}
return bestArme
@@ -461,7 +601,7 @@ export class HeritiersActor extends Actor {
for (let auto of talent.system.automations) {
if (auto.eventtype === "prepare-roll") {
if (auto.competence.toLowerCase() == competence.name.toLowerCase()) {
talent = duplicate(talent)
talent = foundry.utils.duplicate(talent)
talent.system.bonus = auto.bonus
talent.system.baCost = auto.baCost
talents.push(talent)
@@ -501,7 +641,7 @@ export class HeritiersActor extends Actor {
incDecTricherie(value) {
let tricherie = this.system.rang.tricherie
tricherie.value += value
if ( tricherie.value < 0 || tricherie.value > tricherie.max) {
if (tricherie.value < 0 || tricherie.value > tricherie.max) {
ui.notifications.warn("Pas assez de points de Tricherie !")
return false
}
@@ -512,9 +652,9 @@ export class HeritiersActor extends Actor {
}
/* -------------------------------------------- */
getPireCompetence(compName1, compName2) {
let comp1 = this.items.find( it => it.name == compName1)
let comp2 = this.items.find( it => it.name == compName2)
if ( comp1 && comp2 ) {
let comp1 = this.items.find(it => it.name == compName1)
let comp2 = this.items.find(it => it.name == compName2)
if (comp1 && comp2) {
if (comp1.system.niveau > comp2.system.niveau) {
return comp1
} else {
@@ -523,6 +663,7 @@ export class HeritiersActor extends Actor {
}
return undefined
}
/* -------------------------------------------- */
getCommonRollData(compId = undefined, compName = undefined) {
let rollData = HeritiersUtility.getBasicRollData()
@@ -538,16 +679,17 @@ export class HeritiersActor extends Actor {
rollData.useTricherie = false
rollData.useSpecialite = false
rollData.useHeritage = false
rollData.pouvoirPointsUsage = 1
rollData.rulesMalus.push(this.getPvMalus())
if (compId) {
rollData.competence = duplicate(this.items.get(compId) || {})
rollData.competence = foundry.utils.duplicate(this.items.get(compId) || {})
this.prepareUtileSkill(rollData.competence)
rollData.actionImg = rollData.competence?.img
}
if (compName) {
rollData.competence = duplicate(this.items.find(item => item.name.toLowerCase() == compName.toLowerCase()) || {})
if (rollData.competence && rollData.competence.name) {
rollData.competence = foundry.utils.duplicate(this.items.find(item => item.name.toLowerCase() == compName.toLowerCase()) || {})
if (rollData.competence?.name) {
this.prepareUtileSkill(rollData.competence)
rollData.actionImg = rollData.competence?.img
} else {
@@ -568,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)
}
/* -------------------------------------------- */
@@ -578,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)
}
/* -------------------------------------------- */
@@ -588,18 +728,15 @@ 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) {
let rollData = this.getCommonRollData()
rollData.mode = "competence"
console.log("Compkey", compKey)
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)
}
/* -------------------------------------------- */
@@ -607,19 +744,91 @@ 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.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.rang)
this.update({ [`system.caracteristiques.${key}`]: carac })
return true
}
/* -------------------------------------------- */
async rollSort(sortId) {
let sort = this.items.get(sortId)
let comp = this.items.find(it => it.type == "competence" && it.name.toLowerCase() == sort.system.competence.toLowerCase())
if (!comp) {
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 <= 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}).`)
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) {
rollData.caracKey = sort.system.carac1
} else {
rollData.caracKey = sort.system.carac2
}
rollData.caracMessage = "Ce sort peut être lancé avec " + game.system.lesheritiers.config.caracList[sort.system.carac1] + " ou " + game.system.lesheritiers.config.caracList[sort.system.carac2] + ". La meilleure caractéristique a été selectionnée."
} else {
rollData.caracKey = sort.system.carac1
}
console.log("RollData", rollData)
await HeritiersRollDialog.create(this, rollData)
}
/* -------------------------------------------- */
async rollAttaqueArme(armeId) {
let arme = this.items.get(armeId)
if (arme) {
arme = duplicate(arme)
arme = foundry.utils.duplicate(arme)
arme.system.isMelee = HeritiersUtility.isArmeMelee(arme)
let competenceName = "Tir"
let key = "prec"
if ( arme.system.isMelee) {
if (arme.system.isMelee) {
competenceName = "Mêlée"
key = "agi"
}
@@ -628,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 ) {
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)
}
}
@@ -648,12 +857,12 @@ export class HeritiersActor extends Actor {
let rollData = this.getCommonRollData(undefined, competenceName)
rollData.carac = this.system.caracteristiques[key]
rollData.caracKey = key
rollData.arme = duplicate(arme)
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)
rollData.rulesMalus.push({ name: "Attaque brutale", value: -2 })
await HeritiersRollDialog.create(this, rollData)
}
}
/* -------------------------------------------- */
@@ -666,14 +875,14 @@ export class HeritiersActor extends Actor {
let rollData = this.getCommonRollData(undefined, pireCompetence.name)
rollData.carac = this.system.caracteristiques[key]
rollData.caracKey = key
rollData.arme = duplicate(arme)
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)
}
}
/* -------------------------------------------- */
async rollAssomerArme(armeId) {
let arme = this.items.get(armeId)
@@ -683,32 +892,162 @@ export class HeritiersActor extends Actor {
let rollData = this.getCommonRollData(undefined, competenceName)
rollData.carac = this.system.caracteristiques["agi"]
rollData.caracKey = "agi"
rollData.arme = duplicate(arme)
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)
}
}
/* -------------------------------------------- */
pouvoirPassifDialog(pouvoir) {
let rollData = this.getCommonRollData()
rollData.pouvoir = pouvoir
rollData.mode = "pouvoirpassif"
rollData.pouvoirPointsUsage = 0
rollData.noRoll = true
let d = new Dialog({
title: "Activer le pouvoir passif " + pouvoir.name,
content: "<p>Choisissez le nombre de Points d'Usage</p>",
buttons: {
one: {
icon: '<i class="fas fa-check"></i>',
label: "1 Point d'Usage",
callback: () => {
rollData.pouvoirPointsUsage = 1;
HeritiersUtility.rollHeritiers(rollData);
}
},
two: {
icon: '<i class="fas fa-check"></i>',
label: "2 Points d'Usage",
callback: () => {
rollData.pouvoirPointsUsage = 2;
HeritiersUtility.rollHeritiers(rollData);
}
},
three: {
icon: '<i class="fas fa-check"></i>',
label: "3 Points d'Usage",
callback: () => {
rollData.pouvoirPointsUsage = 3;
HeritiersUtility.rollHeritiers(rollData);
}
},
four: {
icon: '<i class="fas fa-check"></i>',
label: "4 Points d'Usage",
callback: () => {
rollData.pouvoirPointsUsage = 4;
HeritiersUtility.rollHeritiers(rollData);
}
},
close: {
icon: '<i class="fas fa-times"></i>',
label: "Annuler",
callback: () => {
}
}
},
default: "one",
render: html => console.log("Pouvoir passif"),
close: html => console.log("No option")
});
d.render(true);
}
/* -------------------------------------------- */
async rollPouvoir(pouvoirId) {
let pouvoir = this.items.get(pouvoirId)
if (pouvoir) {
let rollData = this.getCommonRollData(undefined, undefined)
if (pouvoir.system.feeriemasque != "autre") {
rollData.pouvoirBase = duplicate(this.system.rang[pouvoir.system.feeriemasque.toLowerCase()])
rollData.pouvoirBase.label = "Féerie"
rollData.carac = duplicate(this.system.caracteristiques[pouvoir.system.carac])
rollData.caracKey = pouvoir.system.carac
if (pouvoir.system.pouvoirtype == "passif") {
this.pouvoirPassifDialog(pouvoir)
return
}
rollData.pouvoir = duplicate(pouvoir)
let rollData = this.getCommonRollData(undefined, undefined)
rollData.pouvoirMaxUsage = this.getPouvoirUsageMax(pouvoir)
rollData.pouvoir = foundry.utils.duplicate(pouvoir)
rollData.mode = "pouvoir"
let rollDialog = await HeritiersRollDialog.create(this, rollData)
rollDialog.render(true)
if (pouvoir.system.feeriemasque != "autre") {
rollData.pouvoirBase = foundry.utils.duplicate(this.system.rang[pouvoir.system.feeriemasque.toLowerCase()])
rollData.pouvoirBase.label = "Féerie"
if (pouvoir.system.istest && !pouvoir.system.carac) {
ui.notifications.warn("Le pouvoir actif " + pouvoir.name + " n'a pas de caractéristique associée")
}
if (pouvoir.system.istest) {
rollData.carac = foundry.utils.duplicate(this.system.caracteristiques[pouvoir.system.carac])
rollData.caracKey = pouvoir.system.carac
} else {
rollData.noRoll = true
HeritiersUtility.rollHeritiers(rollData);
return;
//this.incDecPointsUsage(pouvoir.id, -rollData.pouvoirPointsUsage)
//ui.notifications.warn("Le pouvoir actif " + pouvoir.name + " a été utilisé, dépense de " + pouvoirPointsUsage + " points d'usage")
}
}
await HeritiersRollDialog.create(this, rollData)
}
}
/* -------------------------------------------- */
incDecPointsAme(value) {
let newValue = this.system.magie.pointsame.value + value
newValue = Math.max(newValue, 0)
newValue = Math.min(newValue, this.system.magie.pointsame.max)
this.update({ 'system.magie.pointsame.value': newValue })
}
/* -------------------------------------------- */
incDecPV(value) {
let newValue = this.system.pv.value + value
newValue = Math.max(newValue, 0)
newValue = Math.min(newValue, this.system.pv.max)
this.update({ 'system.pv.value': newValue })
}
/* -------------------------------------------- */
incDecPointsUsage(pouvoirId, value) {
let pouvoir = this.items.get(pouvoirId)
let newValue = pouvoir.system.pointsusagecourant + value
newValue = Math.max(newValue, 0)
newValue = Math.min(newValue, this.getPouvoirUsageMax(pouvoir))
this.updateEmbeddedDocuments('Item', [{ _id: pouvoirId, 'system.pointsusagecourant': newValue }])
}
/* -------------------------------------------- */
getPouvoirUsage(pouvoirId) {
let pouvoir = this.items.get(pouvoirId)
return pouvoir.system.pointsusagecourant
}
/* -------------------------------------------- */
getPouvoirUsageMax(pouvoir) {
if (pouvoir.system.masquetype == "masque") {
return this.system.rang.masque.value
}
return this.system.rang.feerie.value
}
/* -------------------------------------------- */
recupUsage(value) {
let updates = []
for (let pouvoir of this.items) {
if (pouvoir.type == "pouvoir") {
let newValue = pouvoir.system.pointsusagecourant + value
newValue = Math.max(newValue, 0)
newValue = Math.min(newValue, this.getPouvoirUsageMax(pouvoir))
updates.push({ _id: pouvoir.id, 'system.pointsusagecourant': newValue })
}
}
if (updates.length > 0) {
this.updateEmbeddedDocuments('Item', updates)
}
}
}

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

@@ -12,25 +12,26 @@ export const HERITIERS_CONFIG = {
"san": "Sang-Froid"
},
competenceCategorie : {
competenceCategorie: {
"utile": "Utile",
"futile": "Futile"
},
contactType: {
contact: "Contact",
contact: "Contact",
allie: "Allié",
ennemi: "Ennemi",
interet: "Personne d'interêt"
},
competenceProfil : {
"aventurier": {kind: "physical", name: "Aventurier"},
"roublard": {kind: "physical",name: "Roublard"},
"combattant": {kind: "physical",name:"Combattant"},
"erudit": {kind: "mental",name:"Erudit"},
"savant": {kind: "mental",name:"Savant"},
"gentleman": {kind: "mental",name:"Gentleman"}
competenceProfil: {
"aventurier": { kind: "physical", name: "Aventurier" },
"roublard": { kind: "physical", name: "Roublard" },
"combattant": { kind: "physical", name: "Combattant" },
"erudit": { kind: "mental", name: "Erudit" },
"savant": { kind: "mental", name: "Savant" },
"gentleman": { kind: "mental", name: "Gentleman" },
"magie": { kind: "magical", name: "Magie" },
},
baseTestPouvoir: {
"feerie": "Féerie",
@@ -52,7 +53,7 @@ export const HERITIERS_CONFIG = {
},
statutMasque: {
"masque": "Masqué",
"demasque":"Démasqué"
"demasque": "Démasqué"
},
niveauPouvoir: {
"normal": "Normal",
@@ -65,32 +66,32 @@ export const HERITIERS_CONFIG = {
},
seuilsDifficulte: {
"-1": "Aucun/Non applicable",
"5": "Enfantine",
"6": "Triviale",
"7": "Moins Triviale",
"8": "Aisée",
"7": "Moins Aisée",
"10": "Normale",
"11": "Moins Normale",
"12": "Compliquée",
"13": "Plus Compliquée",
"14": "Difficile",
"15": "Plus Difficile",
"16": "Très Difficile",
"17": "Très Très Difficile",
"18": "Critique",
"19": "Plus Critique",
"20": "Insurmontable",
"20": "Très Insurmontable",
"22": "Surhumaine",
"23": "Très Surhumaine",
"24": "Epique",
"25": "Plus Epique",
"26": "Légendaire",
"26": "Très Légendaire",
"28": "Mythique",
"29": "Plus Mythique",
"30": "Divine"
"5": "Enfantine (5)",
"6": "Triviale (6)",
"7": "Moins Triviale (7)",
"8": "Aisée (8)",
"9": "Moins Aisée (9)",
"10": "Normale (10)",
"11": "Moins Normale (11)",
"12": "Compliquée (12)",
"13": "Plus Compliquée (13)",
"14": "Difficile (14)",
"15": "Plus Difficile (15)",
"16": "Très Difficile (16)",
"17": "Très Très Difficile (17)",
"18": "Critique (18)",
"19": "Plus Critique (19)",
"20": "Insurmontable (20)",
"21": "Très Insurmontable (21)",
"22": "Surhumaine (22)",
"23": "Très Surhumaine (23)",
"24": "Epique (24)",
"25": "Plus Epique (25)",
"26": "Légendaire (26)",
"27": "Très Légendaire (27)",
"28": "Mythique (28)",
"29": "Plus Mythique (29)",
"30": "Divine (30)"
},
attaqueCible: {
@@ -99,8 +100,8 @@ export const HERITIERS_CONFIG = {
"main": "Main",
"tete": "Tête/Coeur"
},
categorieArme : {
categorieArme: {
"trait": "Arme de trait",
"poing": "Arme de poing",
"epaule": "Arme d'épaule",
@@ -108,7 +109,7 @@ export const HERITIERS_CONFIG = {
"blanche": "Arme blanche",
"improvise": "Arme improvisée",
"explosif": "Explosif"
},
},
typeArme: {
"naturelle": "Arme naturelle",
"trait": "Trait",
@@ -130,13 +131,13 @@ export const HERITIERS_CONFIG = {
"controlee": "Contrôlée (C)",
"prohibee": "Prohibée (P)"
},
armeDissimulation :{
armeDissimulation: {
"tresfacile": "Très facile (TF)",
"facile": "Facile (F)",
"difficile": "Difficile (D)",
"impossible": "Impossible (I)"
},
typeProtection : {
typeProtection: {
"balle": "Protège ds balles",
"melee": "Protège en mélée",
"tout": "Tout type de dégats"
@@ -145,7 +146,137 @@ export const HERITIERS_CONFIG = {
"traditionnelle": "Traditionnelle",
"moderne": "Moderne",
"orientale": "Orientale"
},
typeContact: {
"contact": "Contact",
"allie": "Allié",
"ennemi": "Ennemi",
"interet": "Personne d'interêt"
},
niveauContact: {
"1": "1",
"2": "2",
"3": "3",
},
pointsUsageList: {
"1": "1",
"2": "2",
"3": "3",
"4": "4",
},
attaquePlusieursList: {
"0": "0",
"1": "+1",
"2": "+2",
},
attaque2ArmesListe: [
{ value: "0", label: "Aucun" },
{ value: "-4", label: "Deux armes à 1 main" },
{ value: "-2", label: "Deux armes naturelles" },
{ value: "-2", label: "Avec spécialisation \"Mauvaise Main\"" }
],
typeProfil: {
"mineur": "Mineur",
"majeur": "Majeur",
},
bonusMalusContext: [
{ value: "-6", label: "-6" },
{ value: "-5", label: "-5" },
{ value: "-4", label: "-4" },
{ value: "-3", label: "-3" },
{ value: "-2", label: "-2" },
{ value: "-1", label: "-1" },
{ value: "0", label: "0" },
{ value: "1", label: "+1" },
{ value: "2", label: "+2" },
{ value: "3", label: "+3" },
{ value: "4", label: "+4" },
{ value: "5", label: "+5" },
{ value: "6", label: "+6" }
],
listNiveauSort: {
"1": "1",
"2": "2",
"3": "3",
"4": "4"
},
listRangSort: {
"1": "1",
"2": "2",
"3": "3",
"4": "4",
"5": "5",
"6": "6",
"7": "7"
},
listNiveau: {
"0": "0",
"1": "1",
"2": "2",
"3": "3",
"4": "4",
"5": "5",
"6": "6",
"7": "7",
"8": "8",
"9": "9",
"10": "10"
},
rangName: [
"Novice",
"Novice",
"Adepte",
"Maître",
"Grand Maître"
],
rangNameSpecific: {
"Druidisme": {
"Novice": "Eubage",
"Adepte": "Saronide",
"Maître": "Ovate",
"Grand Maître": "Archidruide"
},
"Faëomancie": {
"Novice": "Marmiton",
"Adepte": "Queux",
"Maître": "Chef",
"Grand Maître": "Maître-queux"
},
"Nécromancie": {
"Novice": "Inexpertus",
"Adepte": "Discipulus",
"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",
"Maître": "Maître",
"Grand Maître": "Éminence"
},
"Théurgie": {
"Novice": "Frère",
"Adepte": "Père",
"Maître": "Saint",
"Grand Maître": "Apôtre"
},
"Grand Langage": {
"Novice": "Éveillé",
"Adepte": "Initié",
"Maître": "Sage",
"Grand Maître": "Docteur"
}
},
soufflesMagieDuClan: {
"soufflecombat": "Souffle du Combat",
"soufflemouvement": "Souffle du Mouvement",
"souffleesprit": "Souffle de l'Esprit"
}
}

View File

@@ -1,25 +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 HeritiersCreatureSheet extends HeritiersActorSheet {
/** @override */
static get defaultOptions() {
return mergeObject(super.defaultOptions, {
classes: ["fvtt-les-heritiers", "sheet", "actor"],
template: "systems/fvtt-les-heritiers/templates/creature-sheet.html",
width: 640,
height: 720,
tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "stats" }],
dragDrop: [{ dragSelector: ".item-list .item", dropSelector: null }],
editScore: false
})
}
}

View File

@@ -1,201 +0,0 @@
import { HeritiersUtility } from "./heritiers-utility.js";
/**
* Extend the basic ItemSheet with some very simple modifications
* @extends {ItemSheet}
*/
export class HeritiersItemSheet extends ItemSheet {
/** @override */
static get defaultOptions() {
return 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 = 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 TextEditor.enrichHTML(this.object.system.description, {async: true}),
mr: (this.object.type == 'specialisation'),
isGM: game.user.isGM
}
//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 = 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 = duplicate(this.object.system.specialites)
spec.push( { name: "Nouvelle Spécialité", id: 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 = 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 = duplicate(this.object.system.specialites)
spec[index].name = ev.currentTarget.value
spec[index].id = spec[index].id || 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 = duplicate(this.object.system.specialites)
spec[index].description = ev.currentTarget.value
spec[index].id = spec[index].id || randomID(16)
this.object.update( { 'system.specialites': spec })
})
html.find('#add-automation').click(ev => {
let autom = duplicate(this.object.system.automations)
autom.push( { eventtype: "on-drop", name: "Automatisation 1", competence: "", minLevel: 0, id: 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 = 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 = duplicate(this.object.system.automations)
auto[index][field] = ev.currentTarget.value
auto[index].id = auto[index].id || 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

@@ -18,6 +18,7 @@ export const defaultItemImg = {
fee: "systems/fvtt-les-heritiers/assets/icons/faery_type.webp",
profil: "systems/fvtt-les-heritiers/assets/icons/profil.webp",
equipement: "systems/fvtt-les-heritiers/assets/icons/equipement.webp",
sort: "systems/fvtt-les-heritiers/assets/icons/sort.webp",
}
/**

View File

@@ -9,15 +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 { HeritiersCreatureSheet } from "./heritiers-creature-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 */
/* -------------------------------------------- */
@@ -31,7 +33,7 @@ Hooks.once("init", async function () {
HeritiersUtility.preloadHandlebarsTemplates()
/* -------------------------------------------- */
// Set an initiative formula for the system
// Set an initiative formula for the system
CONFIG.Combat.initiative = {
formula: "1d10",
decimals: 1
@@ -46,20 +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
Actors.unregisterSheet("core", ActorSheet);
Actors.registerSheet("fvtt-les-heritiers", HeritiersActorSheet, { types: ["personnage"], makeDefault: true })
Actors.registerSheet("fvtt-les-heritiers", HeritiersActorPNJSheet, { types: ["pnj"], makeDefault: true })
foundry.documents.collections.Actors.unregisterSheet("core", foundry.appv1.sheets.ActorSheet);
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 })
Items.unregisterSheet("core", ItemSheet);
Items.registerSheet("fvtt-les-heritiers", HeritiersItemSheet, { makeDefault: true })
// Register AppV2 Item Sheets
foundry.documents.collections.Items.unregisterSheet("core", foundry.appv1.sheets.ItemSheet);
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()
@@ -70,40 +114,52 @@ 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>
`
});
}
/* -------------------------------------------- */
// Register world usage statistics
function registerUsageCount(registerKey) {
if (game.user.isGM) {
game.settings.register(registerKey, "world-key", {
name: "Unique world key",
scope: "world",
config: false,
default: "",
type: String
});
let worldKey = game.settings.get(registerKey, "world-key")
if (worldKey == undefined || worldKey == "") {
worldKey = randomID(32)
game.settings.set(registerKey, "world-key", worldKey)
}
// Simple API counter
let regURL = `https://www.uberwald.me/fvtt_appcount/count.php?name="${registerKey}"&worldKey="${worldKey}"&version="${game.release.generation}.${game.release.build}"&system="${game.system.id}"&systemversion="${game.system.version}"`
//$.ajaxSetup({
//headers: { 'Access-Control-Allow-Origin': '*' }
//})
$.ajax(regURL)
async function importDefaultScene() {
let exists = game.scenes.find(j => j.name == "Accueil");
if (!exists) {
const scenes = await HeritiersUtility.loadCompendium("fvtt-les-heritiers.scenes")
let newDocuments = scenes.filter(i => i.name == "Accueil");
await game.scenes.documentClass.create(newDocuments);
game.scenes.find(i => i.name == "Accueil").activate();
}
}
/* -------------------------------------------- */
/* Foundry VTT Initialization */
/* -------------------------------------------- */
@@ -120,8 +176,14 @@ Hooks.once("ready", function () {
});
}
registerUsageCount(game.system.id)
welcomeMessage()
import("https://www.uberwald.me/fvtt_appcount/count-class-ready.js").then(moduleCounter => {
console.log("ClassCounter loaded", moduleCounter)
moduleCounter.ClassCounter.registerUsageCount()
}).catch(err =>
console.log("No stats available, giving up.")
)
welcomeMessage();
importDefaultScene();
});
@@ -132,10 +194,9 @@ Hooks.on("chatMessage", (html, content, msg) => {
if (content[0] == '/') {
let regExp = /(\S+)/g;
let commands = content.match(regExp);
if (game.system.mournblade.commands.processChatCommand(commands, content, msg)) {
if (game.system.lesheritiers.commands.processChatCommand(commands, content, msg)) {
return false;
}
}
return true;
});

View File

@@ -1,130 +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 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") }
},
rolld10: {
icon: '<i class="fas fa-check"></i>',
label: "Lancer 1d10",
callback: () => { this.roll("d10") }
},
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 -> 1d10
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);
var dialog = this;
function onLoad() {
}
$(function () { onLoad(); });
html.find('#sdValue').change(async (event) => {
this.rollData.sdValue = Number(event.currentTarget.value)
})
html.find('#caracKey').change(async (event) => {
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('#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

@@ -26,7 +26,7 @@ const __facesAdjacentes = {
10: [8, 4, 3, 7]
},
"d12": {
1:[2, 3, 4, 5, 6],
1: [2, 3, 4, 5, 6],
2: [1, 6, 8, 12, 3],
3: [1, 4, 11, 12, 2],
4: [1, 5, 10, 11, 3],
@@ -48,7 +48,7 @@ export class HeritiersUtility {
/* -------------------------------------------- */
static async init() {
Hooks.on('renderChatLog', (log, html, data) => HeritiersUtility.chatListeners(html))
Hooks.on("getChatLogEntryContext", (html, options) => HeritiersUtility.chatRollMenu(html, options))
/* Unused for Heitiers : Hooks.on("getChatMessageContextOptions", (html, options) => HeritiersUtility.chatRollMenu(html, options))*/
this.rollDataStore = {}
this.defenderStore = {}
@@ -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);
})
}
@@ -104,6 +108,8 @@ export class HeritiersUtility {
const skills = await HeritiersUtility.loadCompendium("fvtt-les-heritiers.competences")
this.skills = skills.map(i => i.toObject())
this.competencesMagie = this.skills.filter(s => s.system.profil == "magie")
game.settings.register("fvtt-les-heritiers", "heritiers-heritage", {
name: "Points d'héritage",
hint: "Points d'héritage du groupe",
@@ -114,6 +120,32 @@ export class HeritiersUtility {
})
}
/* -------------------------------------------- */
static getSDSortValue(niveau) {
if (niveau <= 1) return 12;
if (niveau == 2) return 14;
if (niveau == 3) return 16;
if (niveau > 3) return 18;
return 18;
}
/* -------------------------------------------- */
static getCompetencesMagie() {
return this.competencesMagie
}
/* -------------------------------------------- */
static buildCompetencesMagie() {
let competences = foundry.utils.duplicate(this.getCompetencesMagie())
for (let comp of competences) {
// Calcul du rang
let rang = Math.round(comp.system.niveau / 2);
competences.system.rang = rang;
competences.system.rangGenericName = game.system.lesheritiers.config.rangName[rang];
competences.system.rangSpecificName = game.system.lesheritiers.config.rangNameSpecific[comp.Name][competences.system.rangGenericName];
}
}
/* -------------------------------------------- */
static async loadCompendiumData(compendium) {
const pack = game.packs.get(compendium);
@@ -133,29 +165,29 @@ export class HeritiersUtility {
/* -------------------------------------------- */
static async chatListeners(html) {
html.on("click", '.predilection-reroll', async event => {
$(html).on("click", '.predilection-reroll', async event => {
let predIdx = $(event.currentTarget).data("predilection-index")
let messageId = HeritiersUtility.findChatMessageId(event.currentTarget)
let message = game.messages.get(messageId)
let rollData = message.getFlag("world", "heritiers-roll")
let actor = this.getActorFromRollData(rollData)
await actor.setPredilectionUsed(rollData.competence._id, predIdx)
rollData.competence = duplicate(actor.getCompetence(rollData.competence._id))
rollData.competence = foundry.utils.duplicate(actor.getCompetence(rollData.competence._id))
HeritiersUtility.rollHeritiers(rollData)
})
html.on("click", '.roll-tricherie-2', async event => {
$(html).on("click", '.roll-tricherie-2', async event => {
let messageId = HeritiersUtility.findChatMessageId(event.currentTarget)
let message = game.messages.get(messageId)
let rollData = message.getFlag("world", "heritiers-roll")
let actor = this.getActorFromRollData(rollData)
if ( await actor.incDecTricherie(-2) ) {
if (await actor.incDecTricherie(-2)) {
rollData.forcedValue = Number($(event.currentTarget).data("dice-value"))
HeritiersUtility.rollHeritiers(rollData)
HeritiersUtility.rollHeritiers(rollData)
}
})
html.on("click", '.roll-chat-degat', async event => {
$(html).on("click", '.roll-chat-degat', async event => {
let messageId = HeritiersUtility.findChatMessageId(event.currentTarget)
let message = game.messages.get(messageId)
let rollData = message.getFlag("world", "heritiers-roll")
@@ -168,14 +200,14 @@ 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/partial-list-niveau.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 loadTemplates(templatePaths);
return foundry.applications.handlebars.loadTemplates(templatePaths);
}
/* -------------------------------------------- */
@@ -252,14 +284,14 @@ export class HeritiersUtility {
let id = rollData.rollId;
let oldRollData = this.rollDataStore[id] || {};
let newRollData = mergeObject(oldRollData, rollData);
let newRollData = foundry.utils.mergeObject(oldRollData, rollData);
this.rollDataStore[id] = newRollData;
}
/* -------------------------------------------- */
static saveRollData(rollData) {
game.socket.emit("system.fvtt-les-heritiers", {
name: "msg_update_roll", data: rollData
}); // Notify all other clients of the roll
}); // Notify all other clients of the roll
this.updateRollData(rollData);
}
@@ -390,8 +422,8 @@ export class HeritiersUtility {
rollData.finalResult -= 5 + rollValue // Remove also the dice result has it has been added already
}
}
if ( !rollData.forcedValue) {
rollData.adjacentFaces = duplicate(__facesAdjacentes[rollData.mainDice][rollData.diceValue])
if (!rollData.forcedValue) {
rollData.adjacentFaces = foundry.utils.duplicate(__facesAdjacentes[rollData.mainDice][rollData.diceValue])
}
}
}
@@ -434,6 +466,10 @@ export class HeritiersUtility {
rollData.isSuccess = (rollData.finalResult >= seuil)
rollData.isCriticalSuccess = ((rollData.finalResult - seuil) >= 7)
rollData.isCriticalFailure = ((rollData.finalResult - seuil) <= -7)
// Si compétence > 0 et d8 -> echec critique impossible
if (rollData?.competence?.system.niveau > 0 && rollData?.mainDice == "d8") {
rollData.isCriticalFailure = false
}
}
}
@@ -447,7 +483,7 @@ export class HeritiersUtility {
this.computeArmeDegats(rollData, actor)
}
this.createChatWithRollMode(rollData.alias, {
content: await 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")
}
/* -------------------------------------------- */
@@ -459,7 +495,7 @@ export class HeritiersUtility {
this.computeMarge(rollData, valeurDefense)
rollData.dureeAssommer = (rollData.marge) ? rollData.marge * 2 : 1
this.createChatWithRollMode(rollData.alias, {
content: await 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")
}
/* -------------------------------------------- */
@@ -467,8 +503,14 @@ export class HeritiersUtility {
let actor = this.getActorFromRollData(rollData)
if (rollData.mode == "pouvoir" && actor.getPouvoirUsage(rollData.pouvoir._id) < rollData.pouvoirPointsUsage) {
ui.notifications.warn("Pas assez de points d'usage pour ce pouvoir.")
return
}
//rollData.actionImg = "systems/fvtt-les-heritiers/assets/icons/" + actor.system.attributs[rollData.attrKey].labelnorm + ".webp"
rollData.carac = duplicate(actor.system.caracteristiques[rollData.caracKey])
if (rollData.caracKey == "pre") rollData.caracKey = "pres"; // Patch tomanage wrong carac key
rollData.carac = foundry.utils.duplicate(actor.system.caracteristiques[rollData.caracKey])
if (rollData.forcedValue) {
rollData.diceFormula = rollData.forcedValue
@@ -477,7 +519,7 @@ export class HeritiersUtility {
rollData.diceFormula = "{1d8, 1d10, 1d12}"
} else {
rollData.diceFormula = "1" + rollData.mainDice + "kh1"
}
}
}
let rangValue = 0
@@ -485,7 +527,7 @@ export class HeritiersUtility {
rangValue = rollData.rang.value
}
if (rollData.competence) {
let compmod = (rollData.competence.system.niveau == 0) ? -3 : 0
let compmod = 0 // Bonus de compétence à 0 dans Les Heritiers
let specBonus = (rollData.useSpecialite) ? 1 : 0
rollData.diceFormula += `+${rollData.carac.value}+${rangValue}+${rollData.competence.system.niveau}+${specBonus}+${rollData.bonusMalusContext}+${compmod}`
} else if (rollData.pouvoirBase) {
@@ -526,20 +568,41 @@ export class HeritiersUtility {
}
}
let myRoll = new Roll(rollData.diceFormula).roll({ async: false })
await this.showDiceSoNice(myRoll, game.settings.get("core", "rollMode"))
rollData.roll = duplicate(myRoll)
console.log(">>>> ", myRoll)
this.computeResult(actor, rollData)
this.computeMarge(rollData, rollData.sdValue) // Calcul de la marge si seuil présent
if (!rollData.noRoll) {
let myRoll = await new Roll(rollData.diceFormula).roll()
await this.showDiceSoNice(myRoll, game.settings.get("core", "rollMode"))
rollData.roll = foundry.utils.duplicate(myRoll)
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") {
actor.setFlag("world", "last-initiative", rollData.finalResult)
}
// Gestion pouvoir et points d'usage
if (rollData.mode == "pouvoir" || rollData.mode == "pouvoirpassif") {
actor.incDecPointsUsage(rollData.pouvoir._id, -rollData.pouvoirPointsUsage)
}
// Gestion sort et points d'âme
if (rollData.mode == "sort") {
if (rollData.spendEsprit) {
actor.inDecCarac("esp", -rollData.totalEsprit)
} else {
actor.incDecPointsAme(-rollData.sortPointsAme)
if (rollData.sort.system.competence == "Magie du Clan") {
actor.incDecPV(-2)
}
}
}
this.createChatWithRollMode(rollData.alias, {
content: await 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
@@ -568,16 +631,16 @@ export class HeritiersUtility {
static async bonusRollHeritiers(rollData) {
rollData.bonusFormula = rollData.addedBonus
let bonusRoll = new Roll(rollData.bonusFormula).roll({ async: false })
let bonusRoll = await new Roll(rollData.bonusFormula).roll()
await this.showDiceSoNice(bonusRoll, game.settings.get("core", "rollMode"));
rollData.bonusRoll = duplicate(bonusRoll)
rollData.bonusRoll = foundry.utils.duplicate(bonusRoll)
rollData.finalResult += rollData.bonusRoll.total
this.computeResult(rollData)
this.createChatWithRollMode(rollData.alias, {
content: await 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)
}
@@ -589,7 +652,7 @@ export class HeritiersUtility {
/* -------------------------------------------- */
static isArmeMelee(arme) {
return (arme.type == "arme" && (arme.system.categorie == "lourde" || arme.system.categorie == "blanche" || arme.system.categorie == "improvise")) ? true : false
return (arme.type == "arme" && (arme.system.categorie == "lourde" || arme.system.categorie == "blanche" || arme.system.categorie == "improvise"))
}
/* -------------------------------------------- */
static getWhisperRecipients(rollMode, name) {
@@ -608,7 +671,7 @@ export class HeritiersUtility {
/* -------------------------------------------- */
static blindMessageToGM(chatOptions) {
let chatGM = duplicate(chatOptions);
let chatGM = foundry.utils.duplicate(chatOptions);
chatGM.whisper = this.getUsers(user => user.isGM);
chatGM.content = "Blinde message of " + game.user.name + "<br>" + chatOptions.content;
console.log("blindMessageToGM", chatGM);
@@ -672,7 +735,7 @@ export class HeritiersUtility {
/* -------------------------------------------- */
static getBasicRollData() {
let rollData = {
rollId: randomID(16),
rollId: foundry.utils.randomID(16),
rollMode: game.settings.get("core", "rollMode"),
sdList: game.system.lesheritiers.config.seuilsDifficulte,
sdValue: -1,
@@ -750,13 +813,13 @@ export class HeritiersUtility {
static chatRollMenu(html, options) {
let canApply = li => canvas.tokens.controlled.length && li.find(".heritiers-roll").length
let canApplyBA = function (li) {
let message = game.messages.get(li.attr("data-message-id"))
let message = game.messages.get($(li).attr("data-message-id"))
let rollData = message.getFlag("world", "heritiers-roll")
let actor = this.getActorFromRollData(rollData)
return (!rollData.isReroll && actor.getBonneAventure() > 0)
}
let canApplyPE = function (li) {
let message = game.messages.get(li.attr("data-message-id"))
let message = game.messages.get($(li).attr("data-message-id"))
let rollData = message.getFlag("world", "heritiers-roll")
let actor = this.getActorFromRollData(rollData)
return (!rollData.isReroll && actor.getEclat() > 0)
@@ -790,25 +853,30 @@ export class HeritiersUtility {
/* -------------------------------------------- */
static async confirmDelete(actorSheet, li) {
let itemId = li.data("item-id");
let msgTxt = "<p>Are you sure to remove this Item ?";
// 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: {
icon: '<i class="fas fa-check"></i>',
label: "Yes, remove it",
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: {
icon: '<i class="fas fa-times"></i>',
label: "Cancel"
label: "Non !"
}
}
msgTxt += "</p>";
let d = new Dialog({
title: "Confirm removal",
title: "Confirmer la suppression",
content: msgTxt,
buttons: buttons,
default: "cancel"
@@ -816,21 +884,56 @@ export class HeritiersUtility {
d.render(true);
}
/************************************************************************************/
static async __create_talents_table() {
let compName = "fvtt-les-heritiers.talents-cellule"
const compData = await HeritiersUtility.loadCompendium(compName)
let talents = compData.map(i => i.toObject())
let htmlTab = "<table border='1'><tbody>";
for (let entryData of talents) {
console.log(entryData)
htmlTab += `<tr><td>@UUID[Compendium.${compName}.${entryData._id}]{${entryData.name}}</td>`
htmlTab += `<td>${entryData.system.description}</td>`;
//htmlTab += `<td>${entryData.system.resumebonus}</td>`;
htmlTab += "</tr>\n";
static loadSort() {
// Create afolder in the item directory if it doesn't exist
if (!game.folders.getName("Magie du Clan")) {
Folder.create({
name: "Magie du Clan",
type: "Item",
color: "#3b1361"
});
}
htmlTab += "</table>";
await JournalEntry.create({ name: 'Liste des Talents de Cellule', content: htmlTab });
// Load the srcdata/sorts-druidisme.json file
return fetch("systems/fvtt-les-heritiers/srcdata/sort_magieduclan.json")
.then(response => response.json())
.then(data => {
console.log("Sorts Magie du Clan loaded:", data);
this.sortDruidisme = data;
// Loop through the spell and create the "sort "item based on the JSON content
data.forEach(spell => {
spell.name = spell.name;
spell.type = "sort";
spell.system = {
niveau: spell.niveau,
competence: spell.competence,
carac1: spell.carac1,
carac2: spell.carac2,
description: spell.description,
ingredients: spell.ingredients,
portee: spell.portee,
duree: spell.duree,
concentration: spell.concentration,
critique: spell.critique,
resistance: spell.resistance,
coutactivation: spell.coutactivation
};
spell.img = "systems/fvtt-les-heritiers/assets/icons/sort.webp";
spell.folder = game.folders.getName("Magie du Clan").id;
// Create the item in the world
Item.create(spell)
.then(item => {
console.log("Sort created:", item);
})
.catch(error => {
console.error("Error creating sort item:", error);
});
})
})
.catch(error => {
console.error("Error loading druidism spells:", error);
return [];
});
}
}

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"
}
}

Binary file not shown.

Binary file not shown.

View File

@@ -1 +1 @@
MANIFEST-000006
MANIFEST-000312

View File

@@ -1,8 +1,8 @@
2023/12/19-22:06:11.050257 7f33237fe6c0 Recovering log #4
2023/12/19-22:06:11.104534 7f33237fe6c0 Delete type=3 #2
2023/12/19-22:06:11.104875 7f33237fe6c0 Delete type=0 #4
2023/12/19-22:13:00.316854 7f33223ff6c0 Level-0 table #9: started
2023/12/19-22:13:00.316923 7f33223ff6c0 Level-0 table #9: 0 bytes OK
2023/12/19-22:13:00.490508 7f33223ff6c0 Delete type=0 #7
2023/12/19-22:13:00.624324 7f33223ff6c0 Manual compaction at level-0 from '!items!1NhJH4IJpxsGmLB8' @ 72057594037927935 : 1 .. '!items!y1yOenfAJTsb3r6e' @ 0 : 0; will stop at (end)
2023/12/19-22:13:00.624395 7f33223ff6c0 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,5 +1,8 @@
2023/12/19-21:28:12.654905 7f3323fff6c0 Delete type=3 #1
2023/12/19-21:34:54.787106 7f33223ff6c0 Level-0 table #5: started
2023/12/19-21:34:54.792294 7f33223ff6c0 Level-0 table #5: 75294 bytes OK
2023/12/19-21:34:54.798740 7f33223ff6c0 Delete type=0 #3
2023/12/19-21:34:54.828243 7f33223ff6c0 Manual compaction at level-0 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)

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -1 +1 @@
MANIFEST-000006
MANIFEST-000312

View File

@@ -1,8 +1,8 @@
2023/12/19-22:06:11.176247 7f3322ffd6c0 Recovering log #4
2023/12/19-22:06:11.233115 7f3322ffd6c0 Delete type=3 #2
2023/12/19-22:06:11.233244 7f3322ffd6c0 Delete type=0 #4
2023/12/19-22:13:00.722674 7f33223ff6c0 Level-0 table #9: started
2023/12/19-22:13:00.722715 7f33223ff6c0 Level-0 table #9: 0 bytes OK
2023/12/19-22:13:00.805532 7f33223ff6c0 Delete type=0 #7
2023/12/19-22:13:00.882637 7f33223ff6c0 Manual compaction at level-0 from '!items!1ETVaPBtjDtzelK1' @ 72057594037927935 : 1 .. '!items!zbsVCsWxRzkzzG1N' @ 0 : 0; will stop at (end)
2023/12/19-22:13:00.882686 7f33223ff6c0 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,5 +1,8 @@
2023/12/19-21:28:12.795275 7f3323fff6c0 Delete type=3 #1
2023/12/19-21:34:54.816711 7f33223ff6c0 Level-0 table #5: started
2023/12/19-21:34:54.820965 7f33223ff6c0 Level-0 table #5: 16828 bytes OK
2023/12/19-21:34:54.828050 7f33223ff6c0 Delete type=0 #3
2023/12/19-21:34:54.835440 7f33223ff6c0 Manual compaction at level-0 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)

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -1 +1 @@
MANIFEST-000006
MANIFEST-000312

View File

@@ -1,8 +1,8 @@
2023/12/19-22:06:10.985018 7f35b8bfa6c0 Recovering log #4
2023/12/19-22:06:11.046339 7f35b8bfa6c0 Delete type=3 #2
2023/12/19-22:06:11.046469 7f35b8bfa6c0 Delete type=0 #4
2023/12/19-22:13:00.177944 7f33223ff6c0 Level-0 table #9: started
2023/12/19-22:13:00.177984 7f33223ff6c0 Level-0 table #9: 0 bytes OK
2023/12/19-22:13:00.316506 7f33223ff6c0 Delete type=0 #7
2023/12/19-22:13:00.624302 7f33223ff6c0 Manual compaction at level-0 from '!items!0fPXtA5LkLgG8uDj' @ 72057594037927935 : 1 .. '!items!zvtBlG6KCIn0oCVk' @ 0 : 0; will stop at (end)
2023/12/19-22:13:00.624379 7f33223ff6c0 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,5 +1,8 @@
2023/12/19-21:28:12.601487 7f3322ffd6c0 Delete type=3 #1
2023/12/19-21:34:54.774727 7f33223ff6c0 Level-0 table #5: started
2023/12/19-21:34:54.779620 7f33223ff6c0 Level-0 table #5: 59886 bytes OK
2023/12/19-21:34:54.786884 7f33223ff6c0 Delete type=0 #3
2023/12/19-21:34:54.816678 7f33223ff6c0 Manual compaction at level-0 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)

Binary file not shown.

Binary file not shown.

BIN
packs/avantages/000179.ldb Normal file

Binary file not shown.

View File

@@ -1 +1 @@
MANIFEST-000006
MANIFEST-000312

View File

@@ -1,8 +1,8 @@
2023/12/19-22:06:10.801923 7f33237fe6c0 Recovering log #4
2023/12/19-22:06:10.856851 7f33237fe6c0 Delete type=3 #2
2023/12/19-22:06:10.857020 7f33237fe6c0 Delete type=0 #4
2023/12/19-22:12:59.901335 7f33223ff6c0 Level-0 table #9: started
2023/12/19-22:12:59.901390 7f33223ff6c0 Level-0 table #9: 0 bytes OK
2023/12/19-22:12:59.991239 7f33223ff6c0 Delete type=0 #7
2023/12/19-22:13:00.082181 7f33223ff6c0 Manual compaction at level-0 from '!items!0EAAt0qSzcD9VRBH' @ 72057594037927935 : 1 .. '!items!zfpjROW9LDAlXUkN' @ 0 : 0; will stop at (end)
2023/12/19-22:13:00.082266 7f33223ff6c0 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,5 +1,8 @@
2023/12/19-21:28:12.469210 7f3323fff6c0 Delete type=3 #1
2023/12/19-21:34:54.739813 7f33223ff6c0 Level-0 table #5: started
2023/12/19-21:34:54.744244 7f33223ff6c0 Level-0 table #5: 26203 bytes OK
2023/12/19-21:34:54.751692 7f33223ff6c0 Delete type=0 #3
2023/12/19-21:34:54.774674 7f33223ff6c0 Manual compaction at level-0 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)

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
packs/capacites/000179.ldb Normal file

Binary file not shown.

View File

@@ -1 +1 @@
MANIFEST-000006
MANIFEST-000312

View File

@@ -1,8 +1,8 @@
2023/12/19-22:06:10.924713 7f3322ffd6c0 Recovering log #4
2023/12/19-22:06:10.981248 7f3322ffd6c0 Delete type=3 #2
2023/12/19-22:06:10.981375 7f3322ffd6c0 Delete type=0 #4
2023/12/19-22:13:00.082384 7f33223ff6c0 Level-0 table #9: started
2023/12/19-22:13:00.082423 7f33223ff6c0 Level-0 table #9: 0 bytes OK
2023/12/19-22:13:00.177773 7f33223ff6c0 Delete type=0 #7
2023/12/19-22:13:00.624275 7f33223ff6c0 Manual compaction at level-0 from '!items!0cNSRJVPk3GbvxfD' @ 72057594037927935 : 1 .. '!items!yWDg2KlXEz33TSmZ' @ 0 : 0; will stop at (end)
2023/12/19-22:13:00.624363 7f33223ff6c0 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)

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