Compare commits

..

15 Commits

176 changed files with 12949 additions and 1391 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-hawkmoon-cyd/releases/download/latest/system.json
download: https://www.uberwald.me/gitea/${{gitea.repository}}/releases/download/${{github.event.release.tag_name}}/fvtt-hawkmoon-cyd.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-hawkmoon-cyd.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-hawkmoon-cyd.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-hawkmoon-cyd'
version: ${{github.event.release.tag_name}}
manifest: 'https://www.uberwald.me/gitea/public/fvtt-hawkmoon-cyd/releases/download/latest/system.json'
notes: 'https://www.uberwald.me/gitea/${{gitea.repository}}/releases/download/${{github.event.release.tag_name}}/fvtt-hawkmoon-cyd.zip'
compatibility-minimum: '13'
compatibility-verified: '13'

View File

@@ -40,7 +40,7 @@
{{selectOptions combativiteList selected=system.sante.etat valueAttr="value" nameAttr="value" labelAttr="label"}}
</select>
</li>
</ul>
</div>
</div>
@@ -55,6 +55,7 @@
<a class="item" data-tab="equipement">Equipement</a>
<a class="item" data-tab="biodata">Bio&Notes</a>
</nav>
<hr>
{{!-- Sheet Body --}}
<section class="sheet-body">
@@ -63,7 +64,7 @@
<div class="tab principal" data-group="primary" data-tab="principal">
<div class="flexcol">
<div class="grid grid-2col">
<div class="sheet-box color-bg-archetype">
@@ -86,7 +87,7 @@
<input type="text" class="padd-right numeric-input item-field-label-short" name="system.vitesse.value"
value="{{system.vitesse.value}}" data-dtype="Number" />
</li>
</ul>
</div>
@@ -236,17 +237,17 @@
{{#each skills as |skill key|}}
<li class="item flexrow " data-item-id="{{skill._id}}" data-item-type="competence">
<img class="item-name-img" src="{{skill.img}}" />
<div class="flexcol item-name-label">
<span class="item-name-label competence-name"><a class="roll-competence item-field-label-short"
<span class="item-name-label competence-name"><a class="roll-competence "
data-attr-key="tochoose">{{skill.name}}</a></span>
<span class="predilection-text">
{{#each skill.system.predilections as |pred key|}}
{{#if (and pred.acquise (not pred.used))}}
{{pred.name}},
{{/if}}
{{/if}}
{{/each}}
</span>
</div>
@@ -410,21 +411,21 @@
<div class="tab equipement" data-group="primary" data-tab="equipement">
<div class="flexcol">
<hr>
<div class="sheet-box color-bg-archetype">
<h4>
<label class="argent-total-text">
Argent Total : {{richesse.po}} PO - {{richesse.pa}} PA - {{richesse.sc}} SC (total {{richesse.valueSC}} SC)
</label>
</h4>
</h4>
</div>
<div class="sheet-box color-bg-archetype">
<ul class="item-list alternate-list">
<li class="item flexrow list-item items-title-bg">
<span class="item-name-label-header">
<h3><label class="items-title-text">Richesses et Argent</label></h3>
<h3><label class="items-title-text">Richesses et Argent</label></h3>
</span>
<span class="item-field-label-short">
<label class="short-label">Quantité</label>
@@ -440,7 +441,7 @@
<li class="item flexrow " data-item-id="{{monnaie._id}}" data-item-type="monnaie">
<img class="item-name-img" src="{{monnaie.img}}" />
<span class="item-name-label competence-name">{{monnaie.name}}</span>
<span class="item-name-label competence-name item-field-label-medium">{{monnaie.system.quantite}}
<span class="item-name-label competence-name item-field-label-medium">{{monnaie.system.quantite}}
<a class="quantity-modify plus-minus-button" data-quantite-value="-1">-</a>
<a class="quantity-modify plus-minus-button" data-quantite-value="+1">+</a>
</span>
@@ -460,7 +461,7 @@
<label class="argent-total-text">
Valeur Total Equipement : {{valeurEquipement.po}} PO - {{valeurEquipement.pa}} PA - {{valeurEquipement.sc}} SC (total {{valeurEquipement.valueSC}} SC)
</label>
</h4>
</h4>
</div>
<div class="sheet-box color-bg-archetype">
@@ -627,9 +628,6 @@
<span>
<h3>Description</h3>
</span>
<div class="medium-editor item-text-long-line">
{{editor description target="system.biodata.description" button=true owner=owner editable=editable}}
</div>
</div>

View File

@@ -0,0 +1,254 @@
<div class="hawkmoon-chat-result">
{{!-- Header avec acteur --}}
<div class="chat-result-header">
{{#if actorImg}}
<img class="actor-icon" src="{{actorImg}}" alt="{{alias}}" />
{{/if}}
<div class="header-info">
<h4 class="actor-name">{{alias}}</h4>
{{#if competence}}
<div class="action-title">
<i class="fas fa-dice-d20"></i>
{{competence.name}}
{{#if arme}}• {{arme.name}}{{/if}}
</div>
{{else if actionImg}}
<div class="action-title">
<i class="fas fa-dice-d20"></i>
{{attr.label}}{{#if attr2}} + {{attr2.label}}{{/if}}
</div>
{{/if}}
</div>
</div>
{{!-- Résultat principal --}}
<div class="result-main">
<div class="result-display">
<div class="dice-result">
<i class="fas fa-dice"></i>
<span class="dice-value">{{diceResult}}</span>
</div>
<div class="total-result">
<span class="total-label">Total</span>
<span class="total-value">{{finalResult}}</span>
</div>
{{#if difficulte}}
<div class="difficulty">
<span class="difficulty-label">SD</span>
<span class="difficulty-value">{{difficulte}}</span>
</div>
{{/if}}
</div>
{{!-- Badge de résultat --}}
{{#if difficulte}}
<div class="result-badge-container">
{{#if isHeroique}}
<div class="result-badge heroique">
<i class="fas fa-star"></i> HÉROÏQUE !
</div>
{{else if isDramatique}}
<div class="result-badge dramatique">
<i class="fas fa-skull"></i> DRAMATIQUE !
</div>
{{else if isSuccess}}
<div class="result-badge success">
<i class="fas fa-check"></i> Succès
</div>
{{else}}
<div class="result-badge failure">
<i class="fas fa-times"></i> Échec
</div>
{{/if}}
</div>
{{/if}}
</div>
{{!-- Détails du jet --}}
<div class="result-details">
<div class="details-section">
<div class="detail-row">
<span class="detail-label">Formule:</span>
<span class="detail-value">{{diceFormula}}</span>
</div>
<div class="detail-row">
<span class="detail-label">{{attr.label}}:</span>
<span class="detail-value">{{attr.value}}</span>
</div>
{{#if attr2}}
<div class="detail-row">
<span class="detail-label">{{attr2.label}}:</span>
<span class="detail-value">{{attr2.value}}</span>
</div>
{{/if}}
{{#if competence}}
<div class="detail-row">
<span class="detail-label">{{competence.name}}:</span>
<span class="detail-value">{{competence.system.niveau}}</span>
</div>
{{/if}}
{{#if selectedMaitrise}}
<div class="detail-row">
<span class="detail-label">Maîtrise:</span>
<span class="detail-value">{{selectedMaitrise.name}}</span>
</div>
{{/if}}
{{#if arme}}
<div class="detail-row">
<span class="detail-label">Arme:</span>
<span class="detail-value">{{arme.name}} (+{{arme.system.bonusmaniementoff}})</span>
</div>
{{/if}}
{{#if bonusRoll}}
<div class="detail-row bonus">
<span class="detail-label">{{textBonus}}:</span>
<span class="detail-value">+{{bonusRoll.total}}</span>
</div>
{{/if}}
</div>
</div>
{{!-- Effets et conséquences --}}
{{#if isSuccess}}
<div class="result-effects">
{{#if attaqueDesarme}}
<div class="effect-item">
<i class="fas fa-hand-sparkles"></i>
{{#if isHeroique}}
Vous récupérez l'arme de votre adversaire dans votre main !
{{else}}
Vous désarmez votre adversaire ! Son arme tombe hors de sa portée.
{{/if}}
</div>
{{/if}}
{{#if immobiliser}}
<div class="effect-item">
<i class="fas fa-lock"></i>
{{#if isHeroique}}
Votre cible est immobilisée, et vous pouvez faire une action complexe.
{{else}}
Votre cible est immobilisée.
{{/if}}
</div>
{{/if}}
{{#if desengager}}
<div class="effect-item">
<i class="fas fa-running"></i>
Vous vous désengagez de votre adversaire.
</div>
{{/if}}
{{#if repousser}}
<div class="effect-item">
<i class="fas fa-hand-rock"></i>
{{#if isHeroique}}
Votre cible est repoussée de 3 mètres et tombe au sol.
{{else}}
Votre cible tombe au sol.
{{/if}}
</div>
{{/if}}
{{#if assomer}}
<div class="effect-item">
<i class="fas fa-dizzy"></i>
{{#if isHeroique}}
Votre cible est assomée pour [[/r 1d10+10]] minutes.
{{else}}
Votre cible est assomée pour [[/r 1d10]] minutes.
{{/if}}
</div>
{{/if}}
{{#if coupBas}}
<div class="effect-item">
<i class="fas fa-shoe-prints"></i>
La cible a reçu 2 adversités bleues et a perdu 1 niveau de combativité.
{{#if isHeroique}}
<br><strong>Et votre cible perd sa prochaine action complexe.</strong>
{{/if}}
</div>
{{/if}}
{{#if arme}}
{{#if contenir}}
<div class="effect-item">
<i class="fas fa-shield-alt"></i>
{{#if isHeroique}}
Aucun dégât, mais tous les adversaires dont le SD + 10 est atteint ne peuvent déclarer d'attaque contre vous lors de leur prochaine action complexe.
{{else}}
Aucun dégât, mais la cible ne peut pas déclarer d'attaque contre vous lors de sa prochaine action complexe.
{{/if}}
</div>
{{else}}
{{#if (eq nbCombativitePerdu "vaincu")}}
<div class="effect-item victory">
<i class="fas fa-trophy"></i>
<strong>Votre adversaire est vaincu !</strong>
</div>
{{else}}
<div class="effect-item">
<i class="fas fa-heart-broken"></i>
Votre adversaire a perdu {{nbCombativitePerdu}} État de Combativité.
</div>
{{/if}}
{{#if (not arme.system.onlevelonly)}}
<div class="damage-buttons">
<button class="chat-card-button roll-chat-degat">
<i class="fas fa-burst"></i> Dégâts de l'arme
</button>
{{#if coupDevastateur}}
<button class="chat-card-button roll-chat-degat-devastateur">
<i class="fas fa-explosion"></i> Dégâts avec Coup Dévastateur
</button>
{{/if}}
</div>
{{/if}}
{{/if}}
{{/if}}
</div>
{{/if}}
{{!-- Avertissements --}}
{{#if attaqueCharge}}
<div class="result-warning">
<i class="fas fa-exclamation-triangle"></i>
Vous avez chargé : vos adversaires bénéficient de +3 pour vous attaquer.
</div>
{{/if}}
{{#if desengager}}
{{#if (not isSuccess)}}
<div class="result-warning">
<i class="fas fa-exclamation-triangle"></i>
Vous ne parvenez pas à vous désengager, votre adversaire a un bonus de +3 pour vous attaquer.
</div>
{{/if}}
{{/if}}
{{#if isInit}}
<div class="result-info">
<i class="fas fa-flag"></i> Initiative stockée !
</div>
{{/if}}
{{!-- Prédilections --}}
{{#each predilections as |pred key|}}
{{#if (and (and pred.acquise (not pred.maitrise)) (not pred.used))}}
<div class="predilection-section">
<button class="chat-card-button predilection-reroll" data-predilection-index="{{key}}">
<i class="fas fa-redo"></i> Prédilection : {{pred.name}}
</button>
</div>
{{/if}}
{{/each}}
</div>

View File

@@ -3,8 +3,8 @@
* @extends {ActorSheet}
*/
import { HawkmoonUtility } from "./hawkmoon-utility.js";
import { HawkmoonAutomation } from "./hawkmoon-automation.js";
import { HawkmoonUtility } from "../modules/hawkmoon-utility.js";
import { HawkmoonAutomation } from "../modules/hawkmoon-automation.js";
/* -------------------------------------------- */
export class HawkmoonActorSheet extends foundry.appv1.sheets.ActorSheet {
@@ -36,6 +36,7 @@ export class HawkmoonActorSheet extends foundry.appv1.sheets.ActorSheet {
editable: this.isEditable,
cssClass: this.isEditable ? "editable" : "locked",
system: objectData.system,
systemFields: this.document.system.schema.fields,
effects: this.object.effects.map(e => foundry.utils.deepClone(e.data)),
limited: this.object.limited,
skills: this.actor.getSkills(),
@@ -56,7 +57,7 @@ export class HawkmoonActorSheet extends foundry.appv1.sheets.ActorSheet {
nbCombativite: this.actor.system.sante.nbcombativite,
combativiteList: HawkmoonUtility.getCombativiteList(this.actor.system.sante.nbcombativite),
initiative: this.actor.getFlag("world", "last-initiative") || -1,
description: await foundry.applications.ux.TextEditor.implementation.enrichHTML(this.object.system.biodata.description, {async: true}),
enrichedDescription: await foundry.applications.ux.TextEditor.implementation.enrichHTML(this.object.system.biodata.description, {async: true}),
habitat: await foundry.applications.ux.TextEditor.implementation.enrichHTML(this.object.system.biodata.habitat, {async: true}),
options: this.options,
owner: this.document.isOwner,
@@ -66,7 +67,6 @@ export class HawkmoonActorSheet extends foundry.appv1.sheets.ActorSheet {
}
this.formData = formData;
console.log("PC : ", formData, this.object);
return formData;
}

View File

@@ -3,8 +3,8 @@
* @extends {ActorSheet}
*/
import { HawkmoonUtility } from "./hawkmoon-utility.js";
import { HawkmoonAutomation } from "./hawkmoon-automation.js";
import { HawkmoonUtility } from "../modules/hawkmoon-utility.js";
import { HawkmoonAutomation } from "../modules/hawkmoon-automation.js";
/* -------------------------------------------- */
const __ALLOWED_ITEM_CELLULE = { "talent": 1, "ressource": 1, "contact": 1, "equipement": 1, "protection": 1, "artefact": 1, "arme": 1, "monnaie": 1 }

View File

@@ -4,8 +4,8 @@
*/
import { HawkmoonActorSheet } from "./hawkmoon-actor-sheet.js";
import { HawkmoonUtility } from "./hawkmoon-utility.js";
import { HawkmoonAutomation } from "./hawkmoon-automation.js";
import { HawkmoonUtility } from "../modules/hawkmoon-utility.js";
import { HawkmoonAutomation } from "../modules/hawkmoon-automation.js";
/* -------------------------------------------- */
export class HawkmoonCreatureSheet extends HawkmoonActorSheet {

View File

@@ -1,14 +1,14 @@
import { HawkmoonUtility } from "./hawkmoon-utility.js";
import { HawkmoonUtility } from "../modules/hawkmoon-utility.js";
export class HawkmoonRollDialog extends Dialog {
/* -------------------------------------------- */
static async create(actor, rollData ) {
static async create(actor, rollData) {
let options = { classes: ["HawkmoonDialog"], width: 320, height: 'fit-content', 'z-index': 99999 };
let options = { classes: ["HawkmoonDialog"], width: 420, height: 'fit-content', 'z-index': 99999 };
let html = await foundry.applications.handlebars.renderTemplate('systems/fvtt-hawkmoon-cyd/templates/roll-dialog-generic.html', rollData);
return new HawkmoonRollDialog(actor, rollData, html, options );
return new HawkmoonRollDialog(actor, rollData, html, options);
}
/* -------------------------------------------- */
@@ -18,20 +18,21 @@ export class HawkmoonRollDialog extends Dialog {
content: html,
buttons: {
rolld10: {
icon: '<i class="fas fa-check"></i>',
label: "Lancer 1d10",
callback: () => { this.roll("d10") }
},
rolld20: {
icon: '<i class="fas fa-check"></i>',
label: "Lancer 1d20",
callback: () => { this.roll("d20") }
},
cancel: {
icon: '<i class="fas fa-times"></i>',
label: "Annuler",
callback: () => { this.close() }
} },
icon: '<i class="fas fa-check"></i>',
label: "Lancer 1d10",
callback: () => { this.roll("d10") }
},
rolld20: {
icon: '<i class="fas fa-check"></i>',
label: "Lancer 1d20",
callback: () => { this.roll("d20") }
},
cancel: {
icon: '<i class="fas fa-times"></i>',
label: "Annuler",
callback: () => { this.close() }
}
},
close: close
}
@@ -42,9 +43,9 @@ export class HawkmoonRollDialog extends Dialog {
}
/* -------------------------------------------- */
roll ( dice) {
roll(dice) {
this.rollData.mainDice = dice
HawkmoonUtility.rollHawkmoon( this.rollData )
HawkmoonUtility.rollHawkmoon(this.rollData)
}
@@ -57,20 +58,20 @@ export class HawkmoonRollDialog extends Dialog {
}
$(function () { onLoad(); });
html.find('#modificateur').change(async (event) => {
html.find('#modificateur').change(async (event) => {
this.rollData.modificateur = Number(event.currentTarget.value)
})
html.find('#difficulte').change( (event) => {
html.find('#difficulte').change((event) => {
console.log("Difficulte: " + event.currentTarget.value)
this.rollData.difficulte = Number(event.currentTarget.value)
})
html.find('#attrKey').change(async (event) => {
html.find('#attrKey').change(async (event) => {
this.rollData.attrKey = String(event.currentTarget.value)
})
html.find('#attrKey2').change(async (event) => {
html.find('#attrKey2').change(async (event) => {
this.rollData.attrKey2 = String(event.currentTarget.value)
})
html.find('#select-maitrise').change(async (event) => {
html.find('#select-maitrise').change(async (event) => {
this.rollData.maitriseId = String(event.currentTarget.value)
})
html.find('#competence-talents').change((event) => {

View File

@@ -0,0 +1,36 @@
<li
class="item flexrow list-item list-item-shadow"
data-item-id="{{equip._id}}"
>
<a class="item-edit item-name-img" title="Edit Item"
><img class="sheet-competence-img" src="{{equip.img}}"
/></a>
{{#if (eq level 1)}}
<span class="item-name-label">{{equip.name}}</span>
{{else}}
<span class="item-name-label-level2">{{equip.name}}</span>
{{/if}}
<span class="item-field-label-long"
><label>
{{equip.system.quantity}} (<a class="quantity-minus plus-minus-button">
-</a
>/<a class="quantity-plus plus-minus-button">+</a>)
</label>
</span>
<div class="item-filler">&nbsp;</div>
<div class="item-controls item-controls-fixed">
{{#if (eq level 1)}}
<a class="item-control item-equip" title="Worn"
>{{#if equip.system.equipped}}<i class="fas fa-circle"></i>{{else}}<i
class="fas fa-genderless"
></i
>{{/if}}</a
>
{{/if}}
<a class="item-control item-delete" title="Delete Item"
><i class="fas fa-trash"></i
></a>
</div>
</li>

View File

@@ -0,0 +1,334 @@
<form class="skill-roll-dialog">
<header class="roll-dialog-header">
{{#if img}}
<img class="actor-icon" src="{{img}}" data-edit="img" title="{{name}}" />
{{/if}}
<h1 class="dialog-roll-title roll-dialog-header">{{title}}</h1>
</header>
<div class="flexcol">
<div class="flexrow">
{{#if (eq attrKey "tochoose")}}
<span class="roll-dialog-label"><strong>Attribut</strong></span>
<select
class="status-small-label color-class-common"
id="attrKey"
type="text"
name="attrKey"
value="attrKey"
data-dtype="string"
>
{{selectOptions attributs selected=attrKey}}
</select>
{{else}}
<span class="roll-dialog-label"><strong>{{attr.label}}</strong></span>
<span class="small-label roll-dialog-label">{{attr.value}}</span>
{{/if}}
</div>
{{#if nbAdversites}}
<div class="flexrow">
<span class="roll-dialog-label"><strong>Malus d'adversités</strong></span>
<span class="small-label roll-dialog-label">- {{nbAdversites}}</span>
</div>
{{/if}} {{#if competence}}
<div class="flexrow">
<span class="roll-dialog-label"><strong>{{competence.name}}</strong></span>
<span class="small-label roll-dialog-label"><strong>{{competence.system.niveau}}</strong></span>
</div>
{{#if maitrises}}
<div class="flexrow">
<span class="roll-dialog-label"><strong>Maîtrise</strong></span>
<select
class="status-small-label color-class-common"
id="select-maitrise"
type="text"
name="select-maitrise"
value="maitriseId"
data-dtype="string"
>
{{selectOptions maitrises selected=maitriseId valueAttr="key"
nameAttr="key" labelAttr="label"}}
</select>
</div>
{{/if}} {{else}}
<div class="flexrow">
<span class="roll-dialog-label"><strong>Second Attribut</strong></span>
<select
class="status-small-label color-class-common"
id="attrKey2"
type="text"
name="attrKey2"
value="attrKey2"
data-dtype="string"
>
{{#select attrKey2}}
<option value="none">Aucun</option>
{{#each attributs as |attrLabel attrKey|}}
<option value="{{attrKey}}">{{attrLabel}}</option>
{{/each}} {{/select}}
</select>
</div>
{{/if}} {{#if (count talents)}}
<div class="flexrow">
<span class="roll-dialog-label"><strong></strong>Talents</strong></span>
<select
class="flex1"
name="competence-talents"
id="competence-talents"
data-type="String"
multiple
>
{{#each talents as |talent key|}}
<option value="{{talent._id}}">{{talent.name}}</option>
{{/each}}
</select>
</div>
{{/if}} {{#if conditionsCommunes}}
<div class="flexrow">
<span class="roll-dialog-label">En surplomb, défenseur au sol (+3)?</span>
<input type="checkbox" id="defenseur-au-sol" {{checked defenseurAuSol}} />
</div>
<div class="flexrow">
<span class="roll-dialog-label">Défenseur aveuglé (+10)?</span>
<input
type="checkbox"
id="defenseur-aveugle"
{{checked
defenseurAveugle}}
/>
</div>
<div class="flexrow">
<span class="roll-dialog-label">Défenseur de dos (+5)?</span>
<input type="checkbox" id="defenseur-de-dos" {{checked defenseurDeDos}} />
</div>
<div class="flexrow">
<span class="roll-dialog-label">Défenseur immobilisé (+5)?</span>
<input
type="checkbox"
id="defenseur-immobilise"
{{checked
defenseurImmobilise}}
/>
</div>
{{/if}} {{#if (or immobiliser repousser)}}
<div class="flexrow">
<span class="roll-dialog-label">Cible consciente?</span>
<input type="checkbox" id="cibleconsciente" {{checked cibleconsciente}} />
</div>
{{/if}} {{#if arme}} {{#if arme.system.isMelee}} {{#if bonusArmeNaturelle}}
<div class="flexrow">
<span class="roll-dialog-label">Arme naturelle/fortune en défense</span>
<span class="small-label roll-dialog-label">{{bonusArmeNaturelle}}</span>
</div>
{{/if}}
<div class="flexrow">
<span class="roll-dialog-label">En surplomb, défenseur au sol (+3)?</span>
<input type="checkbox" id="defenseur-au-sol" {{checked defenseurAuSol}} />
</div>
<div class="flexrow">
<span class="roll-dialog-label"
>Attaquants multiples (après le premier) (+3)?</span
>
<input
type="checkbox"
id="attaquants-multiple"
{{checked
attaquantsMultiples}}
/>
</div>
{{#if hasAmbidextre}}
<div class="flexrow">
<span class="roll-dialog-label"
>Première attaque avec deux armes (-3)?</span
>
<input type="checkbox" id="ambidextre-1" {{checked attaqueAmbidextre1}} />
</div>
<div class="flexrow">
<span class="roll-dialog-label"
>Seconde attaque avec deux armes (-6)?</span
>
<input type="checkbox" id="ambidextre-2" {{checked attaqueAmbidextre2}} />
</div>
{{/if}} {{#if hasFeinte}}
<div class="flexrow">
<span class="roll-dialog-label"
>Feinte (<strong>cout : 1 BA</strong>) ?</span
>
<input type="checkbox" id="feinte" {{checked feinte}} />
</div>
{{/if}}
<div class="flexrow">
<span class="roll-dialog-label"><strong></strong>Soutiens</strong></span>
<select
class="status-small-label color-class-common"
name="soutiens"
id="soutiens"
data-type="Number"
>
{{selectOptions config.optionsSoutiens selected=soutiens valueAttr="key"
nameAttr="key" labelAttr="label"}}
</select>
</div>
<div class="flexrow">
<span class="roll-dialog-label">Défenseur aveuglé (+10)?</span>
<input
type="checkbox"
id="defenseur-aveugle"
{{checked
defenseurAveugle}}
/>
</div>
<div class="flexrow">
<span class="roll-dialog-label">Défenseur de dos (+5)?</span>
<input type="checkbox" id="defenseur-de-dos" {{checked defenseurDeDos}} />
</div>
<div class="flexrow">
<span class="roll-dialog-label"
>Défenseur dans espace restreint (+3)?</span
>
<input
type="checkbox"
id="defenseur-restreint"
{{checked
defenseurRestreint}}
/>
</div>
<div class="flexrow">
<span class="roll-dialog-label">Défenseur immobilisé (+5)?</span>
<input
type="checkbox"
id="defenseur-immobilise"
{{checked
defenseurImmobilise}}
/>
</div>
<div class="flexrow">
<span class="roll-dialog-label">Charge ?</span>
<input type="checkbox" id="attaque-charge" {{checked attaqueCharge}} />
</div>
<div class="flexrow">
<span class="roll-dialog-label">Contenir?</span>
<input type="checkbox" id="contenir" {{checked contenir}} />
</div>
<div class="flexrow">
<span class="roll-dialog-label">Désarmer (SD+10)?</span>
<input type="checkbox" id="attaque-desarme" {{checked attaqueDesarme}} />
</div>
{{#if isMonte}}
<div class="flexrow">
<span class="roll-dialog-label">Charge de cavalerie?</span>
<input
type="checkbox"
id="charge-cavalerie"
{{checked
chargeCavalerie}}
/>
</div>
{{/if}} {{else}}
<div class="flexrow">
<span class="roll-dialog-label">Tireur en déplacement ?</span>
<select
class="item-field-label-long"
type="text"
id="tireur-deplacement"
data-dtype="string"
>
{{selectOptions config.optionsTireurDeplacement
selected=tireurDeplacement valueAttr="key" nameAttr="key"
labelAttr="label"}}
</select>
</div>
<div class="flexrow">
<span class="roll-dialog-label">Couvert de la cible ?</span>
<select
class="item-field-label-long"
type="text"
id="cible-couvert"
data-dtype="string"
>
{{selectOptions config.optionsCouvert selected=cibleCouvert
valueAttr="key" nameAttr="key" labelAttr="label"}}
</select>
</div>
<div class="flexrow">
<span class="roll-dialog-label">Cible se déplace vite (SD+3)?</span>
<input
type="checkbox"
id="tireur-cible-deplace"
{{checked
cibleDeplace}}
/>
</div>
<div class="flexrow">
<span class="roll-dialog-label">Cible corps à corps (SD+3)?</span>
<input type="checkbox" id="tireur-cible-cac" {{checked cibleCaC}} />
</div>
<div class="flexrow">
<span class="roll-dialog-label">Taille de la cible ?</span>
<select
class="item-field-label-long"
type="text"
id="taille-cible"
data-dtype="string"
>
{{selectOptions config.optionsTailleCible selected=tailleCible
valueAttr="key" nameAttr="key" labelAttr="label"}}
</select>
</div>
{{/if}} {{/if}}
<div class="flexrow">
<span class="roll-dialog-label">Bonus/Malus </span>
<select
class="roll-dialog-label"
id="bonus-malus-context"
type="text"
value="{{bonusMalusContext}}"
data-dtype="Number"
>
{{selectOptions config.optionsBonusMalus selected=bonusMalusContext
valueAttr="key" nameAttr="key" labelAttr="label"}}
</select>
</div>
{{#if (or armeDefense arme.system.isDistance)}} {{#if
arme.system.isDistance}}
<div class="flexrow">
<span class="roll-dialog-label">SD de distance</span>
<select
class="item-field-label-long"
type="text"
id="distance-tir"
data-dtype="string"
>
{{selectOptions config.optionsDistanceTir selected=distanceTir
valueAttr="key" nameAttr="key" labelAttr="label"}}
</select>
</div>
{{else}}
<div class="flexrow">
{{#if desengager}}
<span class="roll-dialog-label">C. Offensive adversaire </span>
{{else}}
<span class="roll-dialog-label">C. Défensive adversaire</span>
{{/if}}
<span class="roll-dialog-label"><strong>{{difficulte}}</strong> </span>
</div>
{{/if}} {{else}} {{#if isInit}} {{else}}
<div class="flexrow">
<span class="roll-dialog-label">Difficulté : </span>
<select
class="roll-dialog-label"
id="difficulte"
type="text"
name="difficulte"
data-dtype="String"
>
{{selectOptions config.optionsDifficulte selected=difficulte
valueAttr="key" nameAttr="key" labelAttr="label"}}
</select>
</div>
{{/if}} {{/if}}
</div>
</form>

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

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/hawkmoon.less')
.pipe(sourcemaps.init())
.pipe(less())
.pipe(sourcemaps.write('.'))
.pipe(gulp.dest(paths.styles.dest));
}
// Watch files
function watchFiles() {
gulp.watch(paths.styles.src, styles);
}
// Define complex tasks
const build = gulp.series(styles);
const watch = gulp.series(build, watchFiles);
// Export tasks
exports.styles = styles;
exports.build = build;
exports.watch = watch;
exports.default = build;

4
less/hawkmoon.less Normal file
View File

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

2713
less/simple-converted.less Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,177 @@
import { HawkmoonUtility } from "../hawkmoon-utility.js"
import { HAWKMOON_CONFIG } from "../hawkmoon-config.js"
/**
* Dialogue de jet de dé pour Hawkmoon - Version DialogV2
*/
export class HawkmoonRollDialog {
/**
* Create and display the roll dialog
* @param {HawkmoonActor} actor - The actor making the roll
* @param {Object} rollData - Data for the roll
* @returns {Promise<HawkmoonRollDialog>}
*/
static async create(actor, rollData) {
// Préparer le contexte pour le template
const context = {
...rollData,
difficulte: String(rollData.difficulte || 0), // Convertir en string pour matcher les options du select
img: actor.img,
name: actor.name,
config: HAWKMOON_CONFIG,
}
// Si attrKey est "tochoose", préparer la liste des attributs sélectionnables
if (rollData.attrKey === "tochoose") {
context.selectableAttributes = actor.system.attributs
// Ne pas changer attrKey ni attr - l'utilisateur doit choisir
}
// Rendre le template en HTML
const content = await foundry.applications.handlebars.renderTemplate(
"systems/fvtt-hawkmoon-cyd/templates/roll-dialog-generic.hbs",
context
)
// Utiliser DialogV2.wait avec le HTML rendu
return foundry.applications.api.DialogV2.wait({
window: { title: "Test de Capacité", icon: "fa-solid fa-dice-d20" },
classes: ["hawkmoon-roll-dialog"],
position: { width: 480 },
modal: false, // Permettre l'interaction avec le canvas pour garder la cible sélectionnée
content,
buttons: [
{
action: "rolld10",
label: "Lancer 1d10",
icon: "fa-solid fa-dice-d10",
default: true,
callback: (event, button, dialog) => {
this._updateRollDataFromForm(rollData, button.form.elements, actor)
rollData.mainDice = "d10"
HawkmoonUtility.rollHawkmoon(rollData)
}
},
{
action: "rolld20",
label: "Lancer 1d20",
icon: "fa-solid fa-dice-d20",
callback: (event, button, dialog) => {
this._updateRollDataFromForm(rollData, button.form.elements, actor)
rollData.mainDice = "d20"
HawkmoonUtility.rollHawkmoon(rollData)
}
},
],
rejectClose: false,
})
}
/**
* Mettre à jour rollData avec les valeurs du formulaire
* @param {Object} rollData - L'objet rollData à mettre à jour
* @param {HTMLFormControlsCollection} formElements - Les éléments du formulaire
* @param {HawkmoonActor} actor - L'acteur pour récupérer les attributs
* @private
*/
static _updateRollDataFromForm(rollData, formElements, actor) {
// Attributs
if (formElements.attrKey) {
rollData.attrKey = formElements.attrKey.value
// Si l'attribut a changé, mettre à jour rollData.attr
if (rollData.attrKey !== "tochoose" && rollData.attrKey !== "none" && actor) {
rollData.attr = foundry.utils.duplicate(actor.system.attributs[rollData.attrKey])
rollData.actionImg = "systems/fvtt-hawkmoon-cyd/assets/icons/" + actor.system.attributs[rollData.attrKey].labelnorm + ".webp"
}
}
if (formElements.attrKey2) {
rollData.attrKey2 = formElements.attrKey2.value
}
// Modificateurs de base
if (formElements.difficulte) {
rollData.difficulte = Number(formElements.difficulte.value)
}
if (formElements.modificateur) {
rollData.modificateur = Number(formElements.modificateur.value)
}
if (formElements.soutiens) {
rollData.soutiens = Number(formElements.soutiens.value)
}
// Compétence
if (formElements.maitrise) {
rollData.maitriseId = formElements.maitrise.value
}
if (formElements.talents) {
// Récupérer toutes les options sélectionnées (select multiple)
const selectedOptions = Array.from(formElements.talents.selectedOptions)
rollData.selectedTalents = selectedOptions.map(opt => opt.value)
}
// Modificateurs de tir
if (formElements.tailleCible) {
rollData.tailleCible = formElements.tailleCible.value
}
if (formElements.tireurDeplacement) {
rollData.tireurDeplacement = formElements.tireurDeplacement.value
}
if (formElements.cibleCouvert) {
rollData.cibleCouvert = formElements.cibleCouvert.value
}
if (formElements.distanceTir) {
rollData.distanceTir = formElements.distanceTir.value
}
if (formElements.cibleDeplace) {
rollData.cibleDeplace = formElements.cibleDeplace.checked
}
if (formElements.cibleCaC) {
rollData.cibleCaC = formElements.cibleCaC.checked
}
// Modificateurs de combat (checkboxes)
if (formElements.defenseurAuSol) {
rollData.defenseurAuSol = formElements.defenseurAuSol.checked
}
if (formElements.ambidextre1) {
rollData.ambidextre1 = formElements.ambidextre1.checked
}
if (formElements.ambidextre2) {
rollData.ambidextre2 = formElements.ambidextre2.checked
}
if (formElements.attaqueMonte) {
rollData.attaqueMonte = formElements.attaqueMonte.checked
}
if (formElements.defenseurAveugle) {
rollData.defenseurAveugle = formElements.defenseurAveugle.checked
}
if (formElements.defenseurDeDos) {
rollData.defenseurDeDos = formElements.defenseurDeDos.checked
}
if (formElements.defenseurRestreint) {
rollData.defenseurRestreint = formElements.defenseurRestreint.checked
}
if (formElements.defenseurImmobilise) {
rollData.defenseurImmobilise = formElements.defenseurImmobilise.checked
}
if (formElements.attaqueCharge) {
rollData.attaqueCharge = formElements.attaqueCharge.checked
}
if (formElements.chargeCavalerie) {
rollData.chargeCavalerie = formElements.chargeCavalerie.checked
}
if (formElements.attaquantsMultiple) {
rollData.attaquantsMultiple = formElements.attaquantsMultiple.checked
}
if (formElements.feinte) {
rollData.feinte = formElements.feinte.checked
}
if (formElements.contenir) {
rollData.contenir = formElements.contenir.checked
}
if (formElements.attaqueDesarme) {
rollData.attaqueDesarme = formElements.attaqueDesarme.checked
}
}
}

View File

@@ -0,0 +1,17 @@
export { default as HawkmoonTalentSheet } from "./talent-sheet.mjs"
export { default as HawkmoonCompetenceSheet } from "./competence-sheet.mjs"
export { default as HawkmoonArmeSheet } from "./arme-sheet.mjs"
export { default as HawkmoonProtectionSheet } from "./protection-sheet.mjs"
export { default as HawkmoonHistoriqueSheet } from "./historique-sheet.mjs"
export { default as HawkmoonProfilSheet } from "./profil-sheet.mjs"
export { default as HawkmoonEquipementSheet } from "./equipement-sheet.mjs"
export { default as HawkmoonMonnaieSheet } from "./monnaie-sheet.mjs"
export { default as HawkmoonArtefactSheet } from "./artefact-sheet.mjs"
export { default as HawkmoonRessourceSheet } from "./ressource-sheet.mjs"
export { default as HawkmoonContactSheet } from "./contact-sheet.mjs"
export { default as HawkmoonMutationSheet } from "./mutation-sheet.mjs"
// Actor sheets
export { default as HawkmoonPersonnageSheet } from "./personnage-sheet.mjs"
export { default as HawkmoonCreatureSheet } from "./creature-sheet.mjs"
export { default as HawkmoonCelluleSheet } from "./cellule-sheet.mjs"

View File

@@ -0,0 +1,21 @@
import HawkmoonItemSheet from "./base-item-sheet.mjs"
export default class HawkmoonArmeSheet extends HawkmoonItemSheet {
/** @override */
static DEFAULT_OPTIONS = {
classes: ["arme"],
position: {
width: 640,
},
window: {
contentClasses: ["arme-content"],
},
}
/** @override */
static PARTS = {
main: {
template: "systems/fvtt-hawkmoon-cyd/templates/item-arme-sheet.hbs",
},
}
}

View File

@@ -0,0 +1,21 @@
import HawkmoonItemSheet from "./base-item-sheet.mjs"
export default class HawkmoonArtefactSheet extends HawkmoonItemSheet {
/** @override */
static DEFAULT_OPTIONS = {
classes: ["artefact"],
position: {
width: 620,
},
window: {
contentClasses: ["artefact-content"],
},
}
/** @override */
static PARTS = {
main: {
template: "systems/fvtt-hawkmoon-cyd/templates/item-artefact-sheet.hbs",
},
}
}

View File

@@ -0,0 +1,547 @@
const { HandlebarsApplicationMixin } = foundry.applications.api
import { HawkmoonUtility } from "../../hawkmoon-utility.js"
import { HawkmoonAutomation } from "../../hawkmoon-automation.js"
export default class HawkmoonActorSheet 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 // Commencer en mode visualisation
}
#dragDrop
/** @override */
static DEFAULT_OPTIONS = {
classes: ["fvtt-hawkmoon-cyd", "sheet", "actor"],
position: {
width: 640,
height: 720,
},
window: {
resizable: true,
},
form: {
submitOnChange: true,
closeOnSubmit: false,
},
dragDrop: [{ dragSelector: ".item-list .item", dropSelector: "form" }],
actions: {
editImage: HawkmoonActorSheet.#onEditImage,
toggleSheet: HawkmoonActorSheet.#onToggleSheet,
editItem: HawkmoonActorSheet.#onEditItem,
deleteItem: HawkmoonActorSheet.#onDeleteItem,
createItem: HawkmoonActorSheet.#onCreateItem,
equipItem: HawkmoonActorSheet.#onEquipItem,
modifyQuantity: HawkmoonActorSheet.#onModifyQuantity,
modifyAdversite: HawkmoonActorSheet.#onModifyAdversite,
rollInitiative: HawkmoonActorSheet.#onRollInitiative,
rollAttribut: HawkmoonActorSheet.#onRollAttribut,
rollCompetence: HawkmoonActorSheet.#onRollCompetence,
rollArmeOffensif: HawkmoonActorSheet.#onRollArmeOffensif,
rollArmeDegats: HawkmoonActorSheet.#onRollArmeDegats,
rollAssommer: HawkmoonActorSheet.#onRollAssommer,
rollCoupBas: HawkmoonActorSheet.#onRollCoupBas,
rollImmobiliser: HawkmoonActorSheet.#onRollImmobiliser,
rollRepousser: HawkmoonActorSheet.#onRollRepousser,
rollDesengager: HawkmoonActorSheet.#onRollDesengager,
},
}
/**
* Is the sheet currently in 'Play' mode?
* @type {boolean}
*/
get isPlayMode() {
// Initialize if not set
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() {
// Initialize if not set
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: "principal" }
/** @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.HAWKMOON,
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 }),
}
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('a.item[data-tab]')
const tabContents = html.querySelectorAll('.tab[data-tab]')
// 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-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-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
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 HawkmoonUtility.searchItem(item)
}
const autoresult = HawkmoonAutomation.processAutomations("on-drop", item, this.actor)
if (autoresult.isValid) {
// In AppV2, we need to get the item data differently
const itemData = item.toObject ? item.toObject() : item
return this.actor.createEmbeddedDocuments("Item", [itemData])
} else {
ui.notifications.warn(autoresult.warningMessage)
return false
}
}
/**
* Handle dropping an Actor on the sheet
* @param {DragEvent} event
* @param {object} data
* @private
*/
async _onDropActor(event, data) {
// To be implemented by subclasses if needed
return false
}
/**
* Handle dropping an ActiveEffect on the sheet
* @param {DragEvent} event
* @param {object} data
* @private
*/
async _onDropActiveEffect(event, data) {
// To be implemented by subclasses if needed
return false
}
// #endregion
// #region Action Handlers
/**
* Toggle between edit and play mode
* @param {Event} event
* @param {HTMLElement} target
* @private
*/
static #onToggleSheet(event, target) {
console.log("Toggle sheet clicked", this)
const wasEditMode = this.isEditMode
console.log("Current mode:", this._sheetMode, "isEditMode:", wasEditMode, "isPlayMode:", this.isPlayMode)
this._sheetMode = wasEditMode ? this.constructor.SHEET_MODES.PLAY : this.constructor.SHEET_MODES.EDIT
console.log("New mode set to:", this._sheetMode, "(", wasEditMode ? "PLAY" : "EDIT", ")")
console.log("After change - isEditMode:", this.isEditMode, "isPlayMode:", this.isPlayMode)
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 HawkmoonUtility.confirmDelete(this, li)
}
/**
* Create a new item
* @param {Event} event
* @param {HTMLElement} target
* @private
*/
static async #onCreateItem(event, target) {
const itemType = target.dataset.type
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)
}
}
/**
* Modify adversité
* @param {Event} event
* @param {HTMLElement} target
* @private
*/
static async #onModifyAdversite(event, target) {
const li = target.closest(".item")
const adv = li?.dataset.adversite
const value = Number(target.dataset.adversiteValue)
if (adv) {
await this.actor.incDecAdversite(adv, value)
}
}
/**
* Roll initiative
* @param {Event} event
* @param {HTMLElement} target
* @private
*/
static async #onRollInitiative(event, target) {
await this.actor.rollAttribut("adr", true)
}
/**
* Roll attribut
* @param {Event} event
* @param {HTMLElement} target
* @private
*/
static async #onRollAttribut(event, target) {
const li = target.closest(".item")
const attrKey = li?.dataset.attrKey
if (attrKey) {
await this.actor.rollAttribut(attrKey, false)
}
}
/**
* Roll competence
* @param {Event} event
* @param {HTMLElement} target
* @private
*/
static async #onRollCompetence(event, target) {
const li = target.closest(".item")
const attrKey = target.dataset.attrKey
const compId = li?.dataset.itemId
if (attrKey && compId) {
await this.actor.rollCompetence(attrKey, compId)
}
}
/**
* Roll arme offensif
* @param {Event} event
* @param {HTMLElement} target
* @private
*/
static async #onRollArmeOffensif(event, target) {
const li = target.closest(".item")
const armeId = li?.dataset.itemId
if (armeId) {
await this.actor.rollArmeOffensif(armeId)
}
}
/**
* Roll arme degats
* @param {Event} event
* @param {HTMLElement} target
* @private
*/
static async #onRollArmeDegats(event, target) {
const li = target.closest(".item")
const armeId = li?.dataset.itemId
if (armeId) {
await this.actor.rollArmeDegats(armeId)
}
}
/**
* Roll assommer
* @param {Event} event
* @param {HTMLElement} target
* @private
*/
static async #onRollAssommer(event, target) {
await this.actor.rollAssommer()
}
/**
* Roll coup bas
* @param {Event} event
* @param {HTMLElement} target
* @private
*/
static async #onRollCoupBas(event, target) {
await this.actor.rollCoupBas()
}
/**
* Roll immobiliser
* @param {Event} event
* @param {HTMLElement} target
* @private
*/
static async #onRollImmobiliser(event, target) {
await this.actor.rollImmobiliser()
}
/**
* Roll repousser
* @param {Event} event
* @param {HTMLElement} target
* @private
*/
static async #onRollRepousser(event, target) {
await this.actor.rollRepousser()
}
/**
* Roll désengager
* @param {Event} event
* @param {HTMLElement} target
* @private
*/
static async #onRollDesengager(event, target) {
await this.actor.rollDesengager()
}
// #endregion
}

View File

@@ -0,0 +1,342 @@
const { HandlebarsApplicationMixin } = foundry.applications.api
export default class HawkmoonItemSheet extends HandlebarsApplicationMixin(foundry.applications.sheets.ItemSheetV2) {
constructor(options = {}) {
super(options)
this.#dragDrop = this.#createDragDropHandlers()
}
#dragDrop
/** @override */
static DEFAULT_OPTIONS = {
classes: ["fvtt-hawkmoon-cyd", "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: HawkmoonItemSheet.#onEditImage,
postItem: HawkmoonItemSheet.#onPostItem,
addPredilection: HawkmoonItemSheet.#onAddPredilection,
deletePredilection: HawkmoonItemSheet.#onDeletePredilection,
addAutomation: HawkmoonItemSheet.#onAddAutomation,
deleteAutomation: HawkmoonItemSheet.#onDeleteAutomation,
},
}
/**
* Tab groups state
* @type {object}
*/
tabGroups = { primary: "description" }
/**
* Is the sheet currently in 'Play' mode?
* @type {boolean}
*/
/** @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.HAWKMOON,
attributs: this.#getAttributs(),
}
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.implementation(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 = TextEditor.getDragEventData(event)
const item = await fromUuid(data.uuid)
if (!item) return
// Handle drop logic here if needed
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 foundry.applications.ui.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 = null
}
// JSON object for easy creation
chatData.jsondata = JSON.stringify({
compendium: "postedItem",
payload: chatData,
})
const html = await renderTemplate('systems/fvtt-hawkmoon-cyd/templates/post-item.hbs', chatData)
const chatOptions = {
user: game.user.id,
content: html,
}
ChatMessage.create(chatOptions)
}
/**
* Add a predilection
* @param {Event} event The triggering event
* @param {HTMLElement} target The target element
* @private
*/
static async #onAddPredilection(event, target) {
let pred = foundry.utils.duplicate(this.document.system.predilections || [])
pred.push({ name: "Nouvelle prédilection", id: foundry.utils.randomID(16), used: false, acquise: false, maitrise: false, description: "" })
await this.document.update({ 'system.predilections': pred })
}
/**
* Delete a predilection
* @param {Event} event The triggering event
* @param {HTMLElement} target The target element
* @private
*/
static async #onDeletePredilection(event, target) {
const index = parseInt(target.closest("[data-predilection-index]").dataset.predilectionIndex)
let pred = foundry.utils.duplicate(this.document.system.predilections)
pred.splice(index, 1)
await this.document.update({ 'system.predilections': pred })
}
/**
* Add an automation
* @param {Event} event The triggering event
* @param {HTMLElement} target The target element
* @private
*/
static async #onAddAutomation(event, target) {
let autom = foundry.utils.duplicate(this.document.system.automations || [])
autom.push({
eventtype: "on-drop",
name: "Automatisation 1",
bonusname: "vigueur",
bonus: 0,
competence: "",
minLevel: 0,
baCost: 0,
id: foundry.utils.randomID(16)
})
await this.document.update({ 'system.automations': autom })
}
/**
* Delete an automation
* @param {Event} event The triggering event
* @param {HTMLElement} target The target element
* @private
*/
static async #onDeleteAutomation(event, target) {
const index = parseInt(target.closest("[data-automation-index]").dataset.automationIndex)
let autom = foundry.utils.duplicate(this.document.system.automations)
autom.splice(index, 1)
await this.document.update({ 'system.automations': autom })
}
// #endregion
// #region Helper Methods
/**
* Get list of attributs
* @returns {Object}
* @private
*/
#getAttributs() {
return {
"adr": "Adresse",
"pui": "Puissance",
"cla": "Clairvoyance",
"pre": "Présence",
"tre": "Trempe"
}
}
// #endregion
/** @override */
_onChangeForm(formConfig, event) {
// Handle special form changes
const target = event.target
// Handle predilection field changes
if (target.classList.contains('edit-predilection') ||
target.classList.contains('edit-predilection-description') ||
target.classList.contains('predilection-acquise') ||
target.classList.contains('predilection-maitrise') ||
target.classList.contains('predilection-used')) {
const li = target.closest('.prediction-item')
if (li) {
const index = parseInt(li.dataset.predictionIndex)
const field = target.classList.contains('edit-predilection') ? 'name' :
target.classList.contains('edit-predilection-description') ? 'description' :
target.classList.contains('predilection-acquise') ? 'acquise' :
target.classList.contains('predilection-maitrise') ? 'maitrise' : 'used'
let pred = foundry.utils.duplicate(this.document.system.predilections)
if (target.type === 'checkbox') {
pred[index][field] = target.checked
} else {
pred[index][field] = target.value
}
pred[index].id = pred[index].id || foundry.utils.randomID(16)
this.document.update({ 'system.predilections': pred })
return
}
}
// Handle automation field changes
if (target.classList.contains('automation-edit-field')) {
const index = parseInt(target.dataset.automationIndex)
const field = target.dataset.automationField
let auto = foundry.utils.duplicate(this.document.system.automations)
auto[index][field] = target.value
auto[index].id = auto[index].id || foundry.utils.randomID(16)
this.document.update({ 'system.automations': auto })
return
}
super._onChangeForm(formConfig, event)
}
}

View File

@@ -0,0 +1,142 @@
import HawkmoonActorSheet from "./base-actor-sheet.mjs"
const __ALLOWED_ITEM_CELLULE = { talent: 1, ressource: 1, contact: 1, equipement: 1, protection: 1, artefact: 1, arme: 1, monnaie: 1 }
export default class HawkmoonCelluleSheet extends HawkmoonActorSheet {
/** @override */
static DEFAULT_OPTIONS = {
...super.DEFAULT_OPTIONS,
classes: [...super.DEFAULT_OPTIONS.classes],
window: {
...super.DEFAULT_OPTIONS.window,
title: "SHEETS.Actor.cellule",
},
actions: {
...super.DEFAULT_OPTIONS.actions,
editActor: HawkmoonCelluleSheet.#onEditActor,
deleteActor: HawkmoonCelluleSheet.#onDeleteActor,
},
}
/** @override */
static PARTS = {
sheet: {
template: "systems/fvtt-hawkmoon-cyd/templates/cellule-sheet.hbs",
},
}
/** @override */
tabGroups = { primary: "talents" }
/** @override */
async _prepareContext() {
const context = await super._prepareContext()
const actor = this.document
// Add cellule-specific data
context.talents = foundry.utils.duplicate(actor.getTalents() || {})
context.ressources = foundry.utils.duplicate(actor.getRessources ? actor.getRessources() : [])
context.contacts = foundry.utils.duplicate(actor.getContacts ? actor.getContacts() : [])
context.members = this.#getMembers()
context.equipements = foundry.utils.duplicate(actor.getEquipments ? actor.getEquipments() : [])
context.artefacts = foundry.utils.duplicate(actor.getArtefacts ? actor.getArtefacts() : [])
context.armes = foundry.utils.duplicate(actor.getWeapons ? actor.getWeapons() : [])
context.monnaies = foundry.utils.duplicate(actor.getMonnaies ? actor.getMonnaies() : [])
context.protections = foundry.utils.duplicate(actor.getArmors ? actor.getArmors() : [])
context.richesse = actor.computeRichesse ? actor.computeRichesse() : 0
context.valeurEquipement = actor.computeValeurEquipement ? actor.computeValeurEquipement() : 0
context.enrichedDescription = await foundry.applications.ux.TextEditor.implementation.enrichHTML(actor.system.description || "", { async: true })
return context
}
/**
* Get members of the cellule with full actor data
* @returns {Array}
* @private
*/
#getMembers() {
let membersFull = []
for (let memberId of this.actor.system.members) {
let actor = game.actors.get(memberId)
if (actor) {
membersFull.push({ name: actor.name, id: actor.id, img: actor.img })
}
}
return membersFull
}
/**
* Override _onDropItem to filter allowed item types for cellule
* @override
*/
async _onDropItem(event, data) {
const item = await fromUuid(data.uuid)
// Check if item type is allowed for cellule
if (!__ALLOWED_ITEM_CELLULE[item.type]) {
ui.notifications.warn(`Le type d'item ${item.type} n'est pas autorisé pour une cellule`)
return false
}
return super._onDropItem(event, data)
}
/**
* Override _onDropActor to handle adding members
* @override
*/
async _onDropActor(event, data) {
const droppedActor = await fromUuid(data.uuid)
if (droppedActor.type !== "personnage") {
ui.notifications.warn("Seuls les personnages peuvent être ajoutés à une cellule")
return false
}
// Check if already a member
const isMember = this.actor.system.members.includes(droppedActor.id)
if (isMember) {
ui.notifications.warn("Ce personnage est déjà membre de cette cellule")
return false
}
// Add member ID
const members = [...this.actor.system.members, droppedActor.id]
await this.actor.update({ "system.members": members })
return true
}
// #region Cellule-specific Actions
/**
* Edit an actor (member)
* @param {Event} event
* @param {HTMLElement} target
* @private
*/
static async #onEditActor(event, target) {
const li = target.closest(".item")
const actorId = li?.dataset.actorId
if (!actorId) return
const actor = game.actors.get(actorId)
if (actor) actor.sheet.render(true)
}
/**
* Delete an actor (remove member)
* @param {Event} event
* @param {HTMLElement} target
* @private
*/
static async #onDeleteActor(event, target) {
const li = target.closest(".item")
const actorId = li?.dataset.actorId
if (actorId) {
const members = this.actor.system.members.filter(id => id !== actorId)
await this.actor.update({ "system.members": members })
}
}
// #endregion
}

View File

@@ -0,0 +1,21 @@
import HawkmoonItemSheet from "./base-item-sheet.mjs"
export default class HawkmoonCompetenceSheet extends HawkmoonItemSheet {
/** @override */
static DEFAULT_OPTIONS = {
classes: ["competence"],
position: {
width: 620,
},
window: {
contentClasses: ["competence-content"],
},
}
/** @override */
static PARTS = {
main: {
template: "systems/fvtt-hawkmoon-cyd/templates/item-competence-sheet.hbs",
},
}
}

View File

@@ -0,0 +1,21 @@
import HawkmoonItemSheet from "./base-item-sheet.mjs"
export default class HawkmoonContactSheet extends HawkmoonItemSheet {
/** @override */
static DEFAULT_OPTIONS = {
classes: ["contact"],
position: {
width: 620,
},
window: {
contentClasses: ["contact-content"],
},
}
/** @override */
static PARTS = {
main: {
template: "systems/fvtt-hawkmoon-cyd/templates/item-contact-sheet.hbs",
},
}
}

View File

@@ -0,0 +1,60 @@
import HawkmoonActorSheet from "./base-actor-sheet.mjs"
import { HawkmoonUtility } from "../../hawkmoon-utility.js"
export default class HawkmoonCreatureSheet extends HawkmoonActorSheet {
/** @override */
static DEFAULT_OPTIONS = {
...super.DEFAULT_OPTIONS,
classes: [...super.DEFAULT_OPTIONS.classes],
window: {
...super.DEFAULT_OPTIONS.window,
title: "SHEETS.Actor.creature",
},
}
/** @override */
static PARTS = {
sheet: {
template: "systems/fvtt-hawkmoon-cyd/templates/creature-sheet.hbs",
},
}
/** @override */
tabGroups = { primary: "principal" }
/** @override */
async _prepareContext() {
const context = await super._prepareContext()
const actor = this.document
// Add creature-specific data
context.skills = actor.getSkills ? actor.getSkills() : []
context.armes = foundry.utils.duplicate(actor.getWeapons ? actor.getWeapons() : [])
context.protections = foundry.utils.duplicate(actor.getArmors ? actor.getArmors() : [])
context.combat = actor.getCombatValues ? actor.getCombatValues() : {}
context.equipements = foundry.utils.duplicate(actor.getEquipments ? actor.getEquipments() : [])
context.talents = foundry.utils.duplicate(actor.getTalents ? actor.getTalents() : [])
context.talentsCell = this.#getCelluleTalents()
context.nbCombativite = actor.system.sante?.nbcombativite || 0
context.combativiteList = HawkmoonUtility.getCombativiteList(actor.system.sante?.nbcombativite || 0)
context.initiative = actor.getFlag("world", "last-initiative") || -1
context.enrichedDescription = await foundry.applications.ux.TextEditor.implementation.enrichHTML(actor.system.biodata?.description || "", { async: true })
context.enrichedHabitat = await foundry.applications.ux.TextEditor.implementation.enrichHTML(actor.system.biodata?.habitat || "", { async: true })
return context
}
/**
* Get talents from attached cellule
* @private
*/
#getCelluleTalents() {
const celluleId = this.actor.system?.details?.celluleid
if (!celluleId) return []
const cellule = game.actors.get(celluleId)
if (!cellule) return []
return foundry.utils.duplicate(cellule.getTalents?.() || [])
}
}

View File

@@ -0,0 +1,21 @@
import HawkmoonItemSheet from "./base-item-sheet.mjs"
export default class HawkmoonEquipementSheet extends HawkmoonItemSheet {
/** @override */
static DEFAULT_OPTIONS = {
classes: ["equipement"],
position: {
width: 620,
},
window: {
contentClasses: ["equipement-content"],
},
}
/** @override */
static PARTS = {
main: {
template: "systems/fvtt-hawkmoon-cyd/templates/item-equipement-sheet.hbs",
},
}
}

View File

@@ -0,0 +1,21 @@
import HawkmoonItemSheet from "./base-item-sheet.mjs"
export default class HawkmoonHistoriqueSheet extends HawkmoonItemSheet {
/** @override */
static DEFAULT_OPTIONS = {
classes: ["historique"],
position: {
width: 620,
},
window: {
contentClasses: ["historique-content"],
},
}
/** @override */
static PARTS = {
main: {
template: "systems/fvtt-hawkmoon-cyd/templates/item-historique-sheet.hbs",
},
}
}

View File

@@ -0,0 +1,21 @@
import HawkmoonItemSheet from "./base-item-sheet.mjs"
export default class HawkmoonMonnaieSheet extends HawkmoonItemSheet {
/** @override */
static DEFAULT_OPTIONS = {
classes: ["monnaie"],
position: {
width: 620,
},
window: {
contentClasses: ["monnaie-content"],
},
}
/** @override */
static PARTS = {
main: {
template: "systems/fvtt-hawkmoon-cyd/templates/item-monnaie-sheet.hbs",
},
}
}

View File

@@ -0,0 +1,21 @@
import HawkmoonItemSheet from "./base-item-sheet.mjs"
export default class HawkmoonMutationSheet extends HawkmoonItemSheet {
/** @override */
static DEFAULT_OPTIONS = {
classes: ["mutation"],
position: {
width: 620,
},
window: {
contentClasses: ["mutation-content"],
},
}
/** @override */
static PARTS = {
main: {
template: "systems/fvtt-hawkmoon-cyd/templates/item-mutation-sheet.hbs",
},
}
}

View File

@@ -0,0 +1,104 @@
import HawkmoonActorSheet from "./base-actor-sheet.mjs"
import { HawkmoonUtility } from "../../hawkmoon-utility.js"
export default class HawkmoonPersonnageSheet extends HawkmoonActorSheet {
/** @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,
openCellule: HawkmoonPersonnageSheet.#onOpenCellule,
},
}
/** @override */
static PARTS = {
sheet: {
template: "systems/fvtt-hawkmoon-cyd/templates/actor-sheet.hbs",
},
}
/** @override */
tabGroups = { primary: "principal" }
/** @override */
async _prepareContext() {
const context = await super._prepareContext()
const actor = this.document
// Add personnage-specific data
context.skills = actor.getSkills()
context.armes = foundry.utils.duplicate(actor.getWeapons())
context.monnaies = foundry.utils.duplicate(actor.getMonnaies())
context.protections = foundry.utils.duplicate(actor.getArmors())
context.historiques = foundry.utils.duplicate(actor.getHistoriques() || [])
context.talents = foundry.utils.duplicate(actor.getTalents() || [])
context.mutations = foundry.utils.duplicate(actor.getMutations() || [])
context.talentsCell = this.#getCelluleTalents()
context.celluleId = this.#getCelluleId()
context.profils = foundry.utils.duplicate(actor.getProfils() || [])
context.combat = actor.getCombatValues()
context.equipements = foundry.utils.duplicate(actor.getEquipments())
context.artefacts = foundry.utils.duplicate(actor.getArtefacts())
context.richesse = actor.computeRichesse()
context.coupDevastateur = actor.items.find(it => it.type == "talent" && it.name.toLowerCase() == "coup devastateur" && !it.system.used)
context.valeurEquipement = actor.computeValeurEquipement()
context.nbCombativite = actor.system.sante.nbcombativite
context.combativiteList = HawkmoonUtility.getCombativiteList(actor.system.sante.nbcombativite)
context.initiative = actor.getFlag("world", "last-initiative") || -1
return context
}
/**
* Get talents from cellules this actor is a member of
* @returns {Array}
* @private
*/
#getCelluleTalents() {
let talents = []
for (let cellule of game.actors) {
if (cellule.type == "cellule") {
let found = cellule.system.members.includes(this.actor.id)
if (found) {
talents = talents.concat(cellule.getTalents())
}
}
}
return talents
}
/**
* Get the ID of the cellule this actor is a member of
* @returns {string|null}
* @private
*/
#getCelluleId() {
for (let cellule of game.actors) {
if (cellule.type == "cellule") {
if (cellule.system.members.includes(this.actor.id)) {
return cellule.id
}
}
}
return null
}
/**
* Open cellule sheet
* @param {Event} event
* @param {HTMLElement} target
* @private
*/
static async #onOpenCellule(event, target) {
const celluleId = target.dataset.celluleId
if (!celluleId) return
const cellule = game.actors.get(celluleId)
if (cellule) cellule.sheet.render(true)
}
}

View File

@@ -0,0 +1,21 @@
import HawkmoonItemSheet from "./base-item-sheet.mjs"
export default class HawkmoonProfilSheet extends HawkmoonItemSheet {
/** @override */
static DEFAULT_OPTIONS = {
classes: ["profil"],
position: {
width: 620,
},
window: {
contentClasses: ["profil-content"],
},
}
/** @override */
static PARTS = {
main: {
template: "systems/fvtt-hawkmoon-cyd/templates/item-profil-sheet.hbs",
},
}
}

View File

@@ -0,0 +1,21 @@
import HawkmoonItemSheet from "./base-item-sheet.mjs"
export default class HawkmoonProtectionSheet extends HawkmoonItemSheet {
/** @override */
static DEFAULT_OPTIONS = {
classes: ["protection"],
position: {
width: 620,
},
window: {
contentClasses: ["protection-content"],
},
}
/** @override */
static PARTS = {
main: {
template: "systems/fvtt-hawkmoon-cyd/templates/item-protection-sheet.hbs",
},
}
}

View File

@@ -0,0 +1,21 @@
import HawkmoonItemSheet from "./base-item-sheet.mjs"
export default class HawkmoonRessourceSheet extends HawkmoonItemSheet {
/** @override */
static DEFAULT_OPTIONS = {
classes: ["ressource"],
position: {
width: 620,
},
window: {
contentClasses: ["ressource-content"],
},
}
/** @override */
static PARTS = {
main: {
template: "systems/fvtt-hawkmoon-cyd/templates/item-ressource-sheet.hbs",
},
}
}

View File

@@ -0,0 +1,51 @@
import HawkmoonItemSheet from "./base-item-sheet.mjs"
export default class HawkmoonTalentSheet extends HawkmoonItemSheet {
/** @override */
static DEFAULT_OPTIONS = {
classes: ["talent"],
position: {
width: 620,
},
window: {
contentClasses: ["talent-content"],
},
}
/** @override */
static PARTS = {
main: {
template: "systems/fvtt-hawkmoon-cyd/templates/item-talent-sheet.hbs",
},
}
/** @override */
tabGroups = {
primary: "description",
}
/**
* Prepare an array of form header tabs.
* @returns {Record<string, Partial<ApplicationTab>>}
*/
#getTabs() {
const tabs = {
details: { id: "details", group: "primary", label: "Détails" },
description: { id: "description", group: "primary", label: "Description" }
}
for (const v of Object.values(tabs)) {
v.active = this.tabGroups[v.group] === v.id
v.cssClass = v.active ? "active" : ""
}
return tabs
}
/** @override */
async _prepareContext() {
const context = await super._prepareContext()
context.tabs = this.#getTabs()
context.enrichedDescription = await foundry.applications.ux.TextEditor.implementation.enrichHTML(this.document.system.description, { async: true })
return context
}
}

View File

@@ -1,6 +1,6 @@
/* -------------------------------------------- */
import { HawkmoonUtility } from "./hawkmoon-utility.js";
import { HawkmoonRollDialog } from "./hawkmoon-roll-dialog.js";
import { HawkmoonRollDialog } from "./applications/hawkmoon-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]
@@ -655,8 +655,7 @@ export class HawkmoonActor extends Actor {
let rollData = this.getCommonRollData(attrKey)
rollData.multiplier = (isInit) ? 1 : 2
rollData.isInit = isInit
let rollDialog = await HawkmoonRollDialog.create(this, rollData)
rollDialog.render(true)
await HawkmoonRollDialog.create(this, rollData)
}
/* -------------------------------------------- */
@@ -664,22 +663,30 @@ export class HawkmoonActor extends Actor {
let rollData = this.getCommonRollData(attrKey, compId)
rollData.multiplier = 1 // Attr multiplier, always 1 in competence mode
console.log("RollDatra", rollData)
let rollDialog = await HawkmoonRollDialog.create(this, rollData)
rollDialog.render(true)
await HawkmoonRollDialog.create(this, rollData)
}
/* -------------------------------------------- */
async rollArmeOffensif(armeId) {
let arme = this.items.get(armeId)
if (!arme.system.equipped) {
ui.notifications.warn("Cette arme doit être équipée pour pouvoir attaquer !")
return
}
if (arme.type == "arme") {
arme = this.prepareArme(arme)
}
if (!arme.system.competence) {
ui.notifications.warn("Aucune compétence trouvée pour cette arme !")
return
}
let rollData = this.getCommonRollData(arme.system.attrKey, arme.system.competence._id)
rollData.arme = arme
rollData.isCombat = true
rollData.isTir = arme.system.isDistance || false
HawkmoonUtility.updateWithTarget(rollData)
console.log("ARME!", rollData)
let rollDialog = await HawkmoonRollDialog.create(this, rollData)
rollDialog.render(true)
await HawkmoonRollDialog.create(this, rollData)
}
/* -------------------------------------------- */
async rollAssommer() {
@@ -687,8 +694,7 @@ export class HawkmoonActor extends Actor {
rollData.assomer = true
rollData.conditionsCommunes = true
HawkmoonUtility.updateWithTarget(rollData)
let rollDialog = await HawkmoonRollDialog.create(this, rollData)
rollDialog.render(true)
await HawkmoonRollDialog.create(this, rollData)
}
/* -------------------------------------------- */
async rollCoupBas() {
@@ -696,8 +702,7 @@ export class HawkmoonActor extends Actor {
rollData.coupBas = true
rollData.conditionsCommunes = true
HawkmoonUtility.updateWithTarget(rollData)
let rollDialog = await HawkmoonRollDialog.create(this, rollData)
rollDialog.render(true)
await HawkmoonRollDialog.create(this, rollData)
}
/* -------------------------------------------- */
async rollImmobiliser() {
@@ -706,8 +711,7 @@ export class HawkmoonActor extends Actor {
rollData.conditionsCommunes = true
rollData.cibleconsciente = true
HawkmoonUtility.updateWithTarget(rollData)
let rollDialog = await HawkmoonRollDialog.create(this, rollData)
rollDialog.render(true)
await HawkmoonRollDialog.create(this, rollData)
}
/* -------------------------------------------- */
async rollRepousser() {
@@ -716,8 +720,7 @@ export class HawkmoonActor extends Actor {
rollData.conditionsCommunes = true
rollData.cibleconsciente = true
HawkmoonUtility.updateWithTarget(rollData)
let rollDialog = await HawkmoonRollDialog.create(this, rollData)
rollDialog.render(true)
await HawkmoonRollDialog.create(this, rollData)
}
/* -------------------------------------------- */
async rollDesengager() {
@@ -725,13 +728,16 @@ export class HawkmoonActor extends Actor {
rollData.desengager = true
rollData.conditionsCommunes = true
HawkmoonUtility.updateWithTarget(rollData)
let rollDialog = await HawkmoonRollDialog.create(this, rollData)
rollDialog.render(true)
await HawkmoonRollDialog.create(this, rollData)
}
/* -------------------------------------------- */
async rollArmeDegats(armeId, targetVigueur = undefined, rollDataInput = undefined) {
let arme = this.items.get(armeId)
if (!arme.system.equipped) {
ui.notifications.warn("Cette arme doit être équipée pour pouvoir infliger des dégâts !")
return
}
if (arme.type == "arme") {
arme = this.prepareArme(arme)
}
@@ -782,7 +788,7 @@ export class HawkmoonActor extends Actor {
nbEtatPerdus: nbEtatPerdus
}
HawkmoonUtility.createChatWithRollMode(rollData.alias, {
content: await renderTemplate(`systems/fvtt-hawkmoon-cyd/templates/chat-degats-result.html`, rollData)
content: await foundry.applications.handlebars.renderTemplate(`systems/fvtt-hawkmoon-cyd/templates/chat-degats-result.hbs`, rollData)
})
if (rollDataInput?.defenderTokenId && nbEtatPerdus) {

View File

@@ -1,7 +1,7 @@
/* -------------------------------------------- */
import { HawkmoonUtility } from "./hawkmoon-utility.js";
import { HawkmoonRollDialog } from "./hawkmoon-roll-dialog.js";
import { HawkmoonRollDialog } from "./applications/hawkmoon-roll-dialog.mjs";
/* -------------------------------------------- */
export class HawkmoonCommands {
@@ -106,18 +106,17 @@ export class HawkmoonCommands {
static _chatAnswer(msg, content) {
msg.whisper = [game.user.id];
msg.content = content;
ChatMessage.create(msg);
ChatMessage.create(msg);
}
/* -------------------------------------------- */
async poolRoll( msg) {
let rollData = HawkmoonUtility.getBasicRollData()
rollData.alias = "Dice Pool Roll",
rollData.alias = "Dice Pool Roll",
rollData.mode = "generic"
rollData.title = `Dice Pool Roll`;
let rollDialog = await HawkmoonRollDialog.create( this, rollData);
rollDialog.render( true );
await HawkmoonRollDialog.create( this, rollData);
}
}

View File

@@ -24,7 +24,7 @@ export class HawkmoonTokenHud {
const controlIconActions = $(html).find('.control-icon[data-action=combat]');
// initiative
await HawkmoonTokenHud._configureSubMenu(controlIconActions, 'systems/fvtt-hawkmoon-cyd/templates/hud-adversites.html', hudData,
await HawkmoonTokenHud._configureSubMenu(controlIconActions, 'systems/fvtt-hawkmoon-cyd/templates/hud-adversites.hbs', hudData,
(event) => {
let adversite = event.currentTarget.attributes['data-action-index'].value
let value = Number(event.currentTarget.attributes['data-action-value'].value)

View File

@@ -9,10 +9,7 @@
/* -------------------------------------------- */
// Import Modules
import { HawkmoonActor } from "./hawkmoon-actor.js";
import { HawkmoonItemSheet } from "./hawkmoon-item-sheet.js";
import { HawkmoonActorSheet } from "./hawkmoon-actor-sheet.js";
import { HawkmoonCreatureSheet } from "./hawkmoon-creature-sheet.js";
import { HawkmoonCelluleSheet } from "./hawkmoon-cellule-sheet.js";
import { HawkmoonUtility } from "./hawkmoon-utility.js";
import { HawkmoonCombat } from "./hawkmoon-combat.js";
import { HawkmoonItem } from "./hawkmoon-item.js";
@@ -20,6 +17,12 @@ import { HawkmoonAutomation } from "./hawkmoon-automation.js";
import { HawkmoonTokenHud } from "./hawkmoon-hud.js";
import { HAWKMOON_CONFIG } from "./hawkmoon-config.js";
// Import DataModels
import * as models from "./models/index.mjs";
// Import AppV2 Item Sheets
import * as sheets from "./applications/sheets/_module.mjs";
/* -------------------------------------------- */
/* Foundry VTT Initialization */
/* -------------------------------------------- */
@@ -48,22 +51,59 @@ Hooks.once("init", async function () {
// Define custom Entity classes
CONFIG.Combat.documentClass = HawkmoonCombat
CONFIG.Actor.documentClass = HawkmoonActor
CONFIG.Actor.dataModels = {
personnage: models.PersonnageDataModel,
cellule: models.CelluleDataModel,
creature: models.CreatureDataModel
}
CONFIG.Item.documentClass = HawkmoonItem
CONFIG.Item.dataModels = {
talent: models.TalentDataModel,
historique: models.HistoriqueDataModel,
profil: models.ProfilDataModel,
competence: models.CompetenceDataModel,
arme: models.ArmeDataModel,
protection: models.ProtectionDataModel,
monnaie: models.MonnaieDataModel,
equipement: models.EquipementDataModel,
artefact: models.ArtefactDataModel,
ressource: models.RessourceDataModel,
contact: models.ContactDataModel,
mutation: models.MutationDataModel
}
CONFIG.HAWKMOON = HAWKMOON_CONFIG
game.system.hawkmoon = {
HawkmoonUtility,
HawkmoonAutomation,
config : HAWKMOON_CONFIG
config: HAWKMOON_CONFIG,
models,
sheets
}
/* -------------------------------------------- */
// Regster sheet application classes
// Register sheet application classes
foundry.documents.collections.Actors.unregisterSheet("core", foundry.appv1.sheets.ActorSheet);
foundry.documents.collections.Actors.registerSheet("fvtt-hawkmoon-cyd", HawkmoonActorSheet, { types: ["personnage"], makeDefault: true })
foundry.documents.collections.Actors.registerSheet("fvtt-hawkmoon-cyd", HawkmoonCreatureSheet, { types: ["creature"], makeDefault: true })
foundry.documents.collections.Actors.registerSheet("fvtt-hawkmoon-cyd", HawkmoonCelluleSheet, { types: ["cellule"], makeDefault: true });
foundry.documents.collections.Actors.registerSheet("fvtt-hawkmoon-cyd", sheets.HawkmoonPersonnageSheet, { types: ["personnage"], makeDefault: true })
foundry.documents.collections.Actors.registerSheet("fvtt-hawkmoon-cyd", sheets.HawkmoonCreatureSheet, { types: ["creature"], makeDefault: true })
foundry.documents.collections.Actors.registerSheet("fvtt-hawkmoon-cyd", sheets.HawkmoonCelluleSheet, { types: ["cellule"], makeDefault: true });
// Register AppV2 Item Sheets
foundry.documents.collections.Items.unregisterSheet("core", foundry.appv1.sheets.ItemSheet);
foundry.documents.collections.Items.registerSheet("fvtt-hawkmoon-cyd", HawkmoonItemSheet, { makeDefault: true })
foundry.documents.collections.Items.registerSheet("fvtt-hawkmoon-cyd", sheets.HawkmoonTalentSheet, { types: ["talent"], makeDefault: true })
foundry.documents.collections.Items.registerSheet("fvtt-hawkmoon-cyd", sheets.HawkmoonCompetenceSheet, { types: ["competence"], makeDefault: true })
foundry.documents.collections.Items.registerSheet("fvtt-hawkmoon-cyd", sheets.HawkmoonArmeSheet, { types: ["arme"], makeDefault: true })
foundry.documents.collections.Items.registerSheet("fvtt-hawkmoon-cyd", sheets.HawkmoonProtectionSheet, { types: ["protection"], makeDefault: true })
foundry.documents.collections.Items.registerSheet("fvtt-hawkmoon-cyd", sheets.HawkmoonHistoriqueSheet, { types: ["historique"], makeDefault: true })
foundry.documents.collections.Items.registerSheet("fvtt-hawkmoon-cyd", sheets.HawkmoonProfilSheet, { types: ["profil"], makeDefault: true })
foundry.documents.collections.Items.registerSheet("fvtt-hawkmoon-cyd", sheets.HawkmoonEquipementSheet, { types: ["equipement"], makeDefault: true })
foundry.documents.collections.Items.registerSheet("fvtt-hawkmoon-cyd", sheets.HawkmoonMonnaieSheet, { types: ["monnaie"], makeDefault: true })
foundry.documents.collections.Items.registerSheet("fvtt-hawkmoon-cyd", sheets.HawkmoonArtefactSheet, { types: ["artefact"], makeDefault: true })
foundry.documents.collections.Items.registerSheet("fvtt-hawkmoon-cyd", sheets.HawkmoonRessourceSheet, { types: ["ressource"], makeDefault: true })
foundry.documents.collections.Items.registerSheet("fvtt-hawkmoon-cyd", sheets.HawkmoonContactSheet, { types: ["contact"], makeDefault: true })
foundry.documents.collections.Items.registerSheet("fvtt-hawkmoon-cyd", sheets.HawkmoonMutationSheet, { types: ["mutation"], makeDefault: true })
HawkmoonUtility.init()
HawkmoonAutomation.init()
@@ -76,12 +116,39 @@ function welcomeMessage() {
ChatMessage.create({
user: game.user.id,
whisper: [game.user.id],
content: `<div id="welcome-message-Hawkmoon"><span class="rdd-roll-part">
<strong>Bienvenue dans Hawkmoon et le troisième Millénaire !</strong>
<p>Les livres de Hawkmoon sont nécessaires pour jouer : https://www.titam-france.fr</p>
<p>Hawkmoon 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="hawkmoon-chat-result">
<div class="chat-result-header">
<img class="actor-icon" src="systems/fvtt-hawkmoon-cyd/assets/logos/hawkmoon_logo.webp" alt="Hawkmoon" />
<div class="header-info">
<h4 class="actor-name">Bienvenue dans Hawkmoon !</h4>
<div class="action-title">
<i class="fas fa-book-open"></i>
Le Troisième Millénaire
</div>
</div>
</div>
<div class="result-details">
<div class="details-section">
<h5 class="section-title"><i class="fas fa-info-circle"></i> Informations importantes</h5>
<div class="description-content">
<p><strong>Les livres de Hawkmoon sont nécessaires pour jouer.</strong></p>
<p>Hawkmoon est un jeu de rôle publié par <strong>Titam France / Sombres projets</strong>, tous les droits leur appartiennent.</p>
</div>
</div>
<div class="details-section">
<h5 class="section-title"><i class="fas fa-users"></i> Support & Communauté</h5>
<div class="description-content">
<p>Système développé par <strong>LeRatierBretonnien</strong></p>
<p>Support disponible sur le <a href="https://discord.gg/pPSDNJk" target="_blank" style="color: #d4af37; text-decoration: underline;">Discord FR de Foundry VTT</a></p>
</div>
</div>
</div>
</div>
`
});
}
/* -------------------------------------------- */
@@ -113,10 +180,10 @@ Hooks.once("ready", function () {
});
}
import("https://www.uberwald.me/fvtt_appcount/count-class-ready.js").then(moduleCounter=>{
import("https://www.uberwald.me/fvtt_appcount/count-class-ready.js").then(moduleCounter => {
console.log("ClassCounter loaded", moduleCounter)
moduleCounter.ClassCounter.registerUsageCount()
}).catch(err=>
}).catch(err =>
console.log("No stats available, giving up.")
)

View File

@@ -104,15 +104,33 @@ export class HawkmoonUtility {
return this.skills
}
/* -------------------------------------------- */
static updatePauseLogo(html) {
let logoPause = "systems/fvtt-hawkmoon-cyd/assets/logos/" + game.settings.get("fvtt-hawkmoon-cyd", "hawkmoon-pause-logo") + ".webp"
console.log("Hawkmoon | Updating pause logo to:", logoPause)
// Supprimer l'ancien style s'il existe
let oldStyle = document.getElementById('hawkmoon-pause-logo-override')
if (oldStyle) {
oldStyle.remove()
}
// Injecter une règle CSS pour override le logo
let styleSheet = document.createElement('style')
styleSheet.id = 'hawkmoon-pause-logo-override'
styleSheet.textContent = `#pause>img { content: url(${logoPause}) !important; }`
document.head.appendChild(styleSheet)
console.log("Hawkmoon | Logo CSS rule injected")
}
/* -------------------------------------------- */
static async ready() {
const skills = await HawkmoonUtility.loadCompendium("fvtt-hawkmoon-cyd.skills")
this.skills = skills.map(i => i.toObject())
// Setup pause logo
let logoPause = "systems/fvtt-hawkmoon-cyd/assets/logos/" + game.settings.get("fvtt-hawkmoon-cyd", "hawkmoon-pause-logo") + ".webp"
let logoImg = document.querySelector('#pause').children[0]
logoImg.setAttribute('style', `content: url(${logoPause})`)
this.updatePauseLogo()
game.system.hawkmoon.config.listeNiveauSkill = this.createDirectOptionList(0, 10)
game.system.hawkmoon.config.listeNiveauCreature = this.createDirectOptionList(0, 35)
@@ -187,13 +205,13 @@ export class HawkmoonUtility {
static async preloadHandlebarsTemplates() {
const templatePaths = [
'systems/fvtt-hawkmoon-cyd/templates/editor-notes-gm.html',
'systems/fvtt-hawkmoon-cyd/templates/partial-item-header.html',
'systems/fvtt-hawkmoon-cyd/templates/partial-item-description.html',
'systems/fvtt-hawkmoon-cyd/templates/partial-item-nav.html',
'systems/fvtt-hawkmoon-cyd/templates/partial-item-prix.html',
'systems/fvtt-hawkmoon-cyd/templates/partial-automation.html',
'systems/fvtt-hawkmoon-cyd/templates/hud-adversites.html',
'systems/fvtt-hawkmoon-cyd/templates/editor-notes-gm.hbs',
'systems/fvtt-hawkmoon-cyd/templates/partial-item-header.hbs',
'systems/fvtt-hawkmoon-cyd/templates/partial-item-description.hbs',
'systems/fvtt-hawkmoon-cyd/templates/partial-item-nav.hbs',
'systems/fvtt-hawkmoon-cyd/templates/partial-item-prix.hbs',
'systems/fvtt-hawkmoon-cyd/templates/partial-automation.hbs',
'systems/fvtt-hawkmoon-cyd/templates/hud-adversites.hbs',
]
return foundry.applications.handlebars.loadTemplates(templatePaths);
}
@@ -247,11 +265,14 @@ export class HawkmoonUtility {
/* -------------------------------------------- */
static getTarget() {
if (game.user.targets && game.user.targets.size == 1) {
console.log("getTarget - targets size:", game.user.targets?.size)
if (game.user.targets && game.user.targets.size >= 1) {
for (let target of game.user.targets) {
return target;
console.log("getTarget - Returning target:", target.id)
return target; // Prendre la première cible si plusieurs
}
}
console.log("getTarget - No target found")
return undefined;
}
@@ -425,11 +446,10 @@ export class HawkmoonUtility {
}
}
}
rollData.diceFormula += `+${rollData.bonusMalusContext}`
} else if (rollData.attr2) {
rollData.diceFormula += `+${rollData.attr.value}+${rollData.attr2.value}+${rollData.modificateur}+${rollData.bonusMalusContext}`
rollData.diceFormula += `+${rollData.attr.value}+${rollData.attr2.value}+${rollData.modificateur}`
} else {
rollData.diceFormula += `+${rollData.attr.value}*${rollData.multiplier}+${rollData.modificateur}+${rollData.bonusMalusContext}`
rollData.diceFormula += `+${rollData.attr.value}*${rollData.multiplier}+${rollData.modificateur}`
}
// Bonus arme naturelle en défense
@@ -508,7 +528,7 @@ export class HawkmoonUtility {
}
this.createChatWithRollMode(rollData.alias, {
content: await foundry.applications.handlebars.renderTemplate(`systems/fvtt-hawkmoon-cyd/templates/chat-generic-result.html`, rollData)
content: await foundry.applications.handlebars.renderTemplate(`systems/fvtt-hawkmoon-cyd/templates/chat-generic-result.hbs`, rollData)
}, rollData)
if ((rollData.coupBas || rollData.arme) && rollData.isSuccess && rollData.defenderTokenId) {
@@ -550,7 +570,7 @@ export class HawkmoonUtility {
this.computeResultQuality(rollData)
this.createChatWithRollMode(rollData.alias, {
content: await foundry.applications.handlebars.renderTemplate(`systems/fvtt-hawkmoon-cyd/templates/chat-generic-result.html`, rollData)
content: await foundry.applications.handlebars.renderTemplate(`systems/fvtt-hawkmoon-cyd/templates/chat-generic-result.hbs`, rollData)
}, rollData)
}
@@ -633,9 +653,13 @@ export class HawkmoonUtility {
break;
}
chatOptions.alias = chatOptions.alias || name
// Ajouter le flag directement dans les options pour éviter les problèmes de timing
if (rollData) {
chatOptions.flags = { world: { "hawkmoon-roll": rollData } }
}
let msg = await ChatMessage.create(chatOptions)
console.log("=======>", rollData)
msg.setFlag("world", "hawkmoon-roll", rollData)
}
/* -------------------------------------------- */
@@ -646,8 +670,7 @@ export class HawkmoonUtility {
modificateursOptions: this.getModificateurOptions(),
pointAmeOptions: this.getPointAmeOptions(),
difficulte: 0,
modificateur: 0,
bonusMalusContext: 0,
modificateur: "0",
bonusArmeNaturelle: 0,
defenseurAveugle: false,
defenseurDeDos: false,
@@ -658,6 +681,8 @@ export class HawkmoonUtility {
tireurDeplacement: "immobile",
cibleCouvert: "aucun",
distanceTir: "porteemoyenne",
cibleDeplace: false,
cibleCaC: false,
attaqueCharge: false,
attaqueDesarme: false,
attaqueAmbidextre1: false,
@@ -672,10 +697,18 @@ export class HawkmoonUtility {
/* -------------------------------------------- */
static updateWithTarget(rollData) {
let target = HawkmoonUtility.getTarget()
console.log("updateWithTarget - Current target:", target)
console.log("updateWithTarget - Existing defenderTokenId:", rollData.defenderTokenId)
if (target) {
rollData.defenderTokenId = target.id
console.log("updateWithTarget - Set defenderTokenId to:", rollData.defenderTokenId)
}
// Utiliser la cible déjà enregistrée si aucune cible n'est actuellement sélectionnée
if (rollData.defenderTokenId) {
let defender = game.canvas.tokens.get(rollData.defenderTokenId).actor
console.log("updateWithTarget - Defender actor:", defender.name)
rollData.armeDefense = defender.getBestDefenseValue()
console.log("updateWithTarget - armeDefense:", rollData.armeDefense)
rollData.armeAttaqueDefenseur = defender.getBestAttackValue()
rollData.targetVigueur = defender.getVigueur()
rollData.protectionDefenseur = defender.getProtection()
@@ -691,14 +724,23 @@ export class HawkmoonUtility {
rollData.difficulte = rollData.armeAttaqueDefenseur?.system?.totalOffensif || 0;
} else if (rollData.armeDefense) {
rollData.difficulte = rollData.armeDefense.system.totalDefensif
if (!rollData.desengager && !rollData.arme.system.armenaturelle && !rollData.arme.system.armefortune) {
console.log("updateWithTarget - Calculated difficulte from armeDefense:", rollData.difficulte)
if (rollData.arme && !rollData.desengager && !rollData.arme.system.armenaturelle && !rollData.arme.system.armefortune) {
if (rollData.armeDefense.system.armenaturelle || rollData.armeDefense.system.armefortune) {
rollData.bonusArmeNaturelle = 3
}
}
} else if (rollData.arme?.system.isDistance) {
// Pour les armes à distance, calculer la difficulté de base (protection + distance par défaut)
const distanceValues = { "porteecourte": 5, "porteemoyenne": 9, "porteelongue": 14 }
rollData.difficulte = rollData.protectionDefenseur + distanceValues[rollData.distanceTir || "porteemoyenne"]
console.log("updateWithTarget - Calculated difficulte for ranged:", rollData.difficulte, "= protection", rollData.protectionDefenseur, "+ distance", distanceValues[rollData.distanceTir || "porteemoyenne"])
} else {
console.log("updateWithTarget - No armeDefense found!")
ui.notifications.warn("Aucune arme de défense équipée, difficulté manuelle à positionner.")
}
} else {
console.log("updateWithTarget - No defenderTokenId, skipping target calculations")
}
}
@@ -789,7 +831,7 @@ export class HawkmoonUtility {
/* -------------------------------------------- */
static async confirmDelete(actorSheet, li) {
let itemId = li.data("item-id");
let itemId = li.dataset.itemId;
let msgTxt = "<p>Etes vous certain de vouloir supprimer cet item ?";
let buttons = {
delete: {
@@ -797,7 +839,7 @@ export class HawkmoonUtility {
label: "Oui !",
callback: () => {
actorSheet.actor.deleteEmbeddedDocuments("Item", [itemId]);
li.slideUp(200, () => actorSheet.render(false));
actorSheet.render(false);
}
},
cancel: {

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

@@ -0,0 +1,31 @@
/**
* 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: "" }),
prixpo: new fields.NumberField({ initial: 0, integer: true }),
prixca: new fields.NumberField({ initial: 0, integer: true }),
prixsc: new fields.NumberField({ initial: 0, integer: true }),
rarete: new fields.NumberField({ initial: 0, integer: true }),
quantite: new fields.NumberField({ initial: 1, integer: true }),
equipped: new fields.BooleanField({ initial: false }),
typearme: new fields.StringField({ initial: "" }),
armenaturelle: new fields.BooleanField({ initial: false }),
armefortune: new fields.BooleanField({ initial: false }),
bonusmaniementoff: new fields.NumberField({ initial: 0, integer: true }),
seuildefense: new fields.NumberField({ initial: 0, integer: true }),
onlevelonly: new fields.BooleanField({ initial: false }),
degats: new fields.StringField({ initial: "" }),
deuxmains: new fields.BooleanField({ initial: false }),
percearmure: new fields.BooleanField({ initial: false }),
percearmurevalue: new fields.NumberField({ initial: 0, integer: true }),
courte: new fields.NumberField({ initial: 0, integer: true }),
moyenne: new fields.NumberField({ initial: 0, integer: true }),
longue: new fields.NumberField({ initial: 0, integer: true }),
tr: new fields.NumberField({ initial: 0, integer: true })
};
}
}

View File

@@ -0,0 +1,28 @@
/**
* Data model pour les artefacts
*/
export default class ArtefactDataModel extends foundry.abstract.TypeDataModel {
static defineSchema() {
const fields = foundry.data.fields;
return {
description: new fields.HTMLField({ initial: "" }),
prixpo: new fields.NumberField({ initial: 0, integer: true }),
prixca: new fields.NumberField({ initial: 0, integer: true }),
prixsc: new fields.NumberField({ initial: 0, integer: true }),
rarete: new fields.NumberField({ initial: 0, integer: true }),
quantite: new fields.NumberField({ initial: 1, integer: true }),
equipped: new fields.BooleanField({ initial: false }),
complexite: new fields.NumberField({ initial: 0, integer: true }),
branche: new fields.StringField({ initial: "" }),
branche2: new fields.StringField({ initial: "none" }),
dureerealisation: new fields.StringField({ initial: "" }),
tempsroute: new fields.StringField({ initial: "" }),
effetdejeu: new fields.StringField({ initial: "" }),
defautcourant: new fields.StringField({ initial: "" }),
autrescarac: new fields.StringField({ initial: "" }),
avantagespossibles: new fields.StringField({ initial: "" }),
avantages: new fields.StringField({ initial: "" }),
competences: new fields.StringField({ initial: "" })
};
}
}

View File

@@ -0,0 +1,53 @@
/**
* Template de base pour tous les items
*/
export class BaseItemModel extends foundry.abstract.TypeDataModel {
static defineSchema() {
const fields = foundry.data.fields;
return {
description: new fields.HTMLField({ initial: "" })
};
}
}
/**
* Template pour les équipements de base
*/
export class BaseEquipItemModel extends foundry.abstract.TypeDataModel {
static defineSchema() {
const fields = foundry.data.fields;
return {
prixpo: new fields.NumberField({ initial: 0, integer: true }),
prixca: new fields.NumberField({ initial: 0, integer: true }),
prixsc: new fields.NumberField({ initial: 0, integer: true }),
rarete: new fields.NumberField({ initial: 0, integer: true }),
quantite: new fields.NumberField({ initial: 1, integer: true }),
equipped: new fields.BooleanField({ initial: false })
};
}
}
/**
* Template pour l'automatisation
*/
export class AutomationItemModel extends foundry.abstract.TypeDataModel {
static defineSchema() {
const fields = foundry.data.fields;
return {
isautomated: new fields.BooleanField({ initial: false }),
automations: new fields.ArrayField(
new fields.SchemaField({
id: new fields.StringField({ initial: "" }),
eventtype: new fields.StringField({ initial: "on-drop" }),
name: new fields.StringField({ initial: "" }),
bonusname: new fields.StringField({ initial: "vigueur" }),
bonus: new fields.NumberField({ initial: 0, integer: true }),
competence: new fields.StringField({ initial: "" }),
minLevel: new fields.NumberField({ initial: 0, integer: true }),
baCost: new fields.NumberField({ initial: 0, integer: true })
}),
{ initial: [] }
)
};
}
}

View File

@@ -0,0 +1,15 @@
/**
* Data model pour les cellules
*/
export default class CelluleDataModel extends foundry.abstract.TypeDataModel {
static defineSchema() {
const fields = foundry.data.fields;
return {
notoriete: new fields.NumberField({ initial: 0, integer: true }),
resistance: new fields.NumberField({ initial: 0, integer: true }),
developpement: new fields.NumberField({ initial: 0, integer: true }),
members: new fields.ArrayField(new fields.StringField(), { initial: [] }),
description: new fields.HTMLField({ initial: "" })
};
}
}

View File

@@ -0,0 +1,27 @@
/**
* Data model pour les compétences
*/
export default class CompetenceDataModel extends foundry.abstract.TypeDataModel {
static defineSchema() {
const fields = foundry.data.fields;
return {
description: new fields.HTMLField({ initial: "" }),
niveau: new fields.NumberField({ initial: 0, integer: true }),
attribut1: new fields.StringField({ initial: "" }),
attribut2: new fields.StringField({ initial: "" }),
attribut3: new fields.StringField({ initial: "" }),
doublebonus: new fields.BooleanField({ initial: false }),
predilections: new fields.ArrayField(
new fields.SchemaField({
id: new fields.StringField({ initial: "" }),
name: new fields.StringField({ initial: "" }),
description: new fields.StringField({ initial: "" }),
acquise: new fields.BooleanField({ initial: false }),
maitrise: new fields.BooleanField({ initial: false }),
used: new fields.BooleanField({ initial: false })
}),
{ initial: [] }
)
};
}
}

View File

@@ -0,0 +1,14 @@
/**
* 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: "" }),
niveau: new fields.StringField({ initial: "" }),
pointdev: new fields.NumberField({ initial: 0, integer: true }),
description: new fields.HTMLField({ initial: "" })
};
}
}

View File

@@ -0,0 +1,97 @@
/**
* Data model pour les créatures
*/
export default class CreatureDataModel extends foundry.abstract.TypeDataModel {
static defineSchema() {
const fields = foundry.data.fields;
return {
// Template biodata
biodata: new fields.SchemaField({
name: 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: "" }),
habitat: new fields.HTMLField({ initial: "" }),
notes: new fields.HTMLField({ initial: "" }),
statut: new fields.StringField({ initial: "" }),
gmnotes: new fields.HTMLField({ initial: "" }),
statutresistant: new fields.StringField({ initial: "commun" })
}),
// Template core
subactors: new fields.ArrayField(new fields.StringField(), { initial: [] }),
attributs: new fields.SchemaField({
adr: new fields.SchemaField({
label: new fields.StringField({ initial: "Adresse" }),
labelnorm: new fields.StringField({ initial: "adresse" }),
abbrev: new fields.StringField({ initial: "adr" }),
value: new fields.NumberField({ initial: 1, integer: true })
}),
pui: new fields.SchemaField({
label: new fields.StringField({ initial: "Puissance" }),
labelnorm: new fields.StringField({ initial: "puissance" }),
abbrev: new fields.StringField({ initial: "pui" }),
value: new fields.NumberField({ initial: 1, integer: true })
}),
cla: new fields.SchemaField({
label: new fields.StringField({ initial: "Clairvoyance" }),
labelnorm: new fields.StringField({ initial: "clairvoyance" }),
abbrev: new fields.StringField({ initial: "cla" }),
value: new fields.NumberField({ initial: 1, integer: true })
}),
pre: new fields.SchemaField({
label: new fields.StringField({ initial: "Présence" }),
labelnorm: new fields.StringField({ initial: "presence" }),
abbrev: new fields.StringField({ initial: "pre" }),
value: new fields.NumberField({ initial: 0, integer: true })
}),
tre: new fields.SchemaField({
label: new fields.StringField({ initial: "Trempe" }),
labelnorm: new fields.StringField({ initial: "trempe" }),
abbrev: new fields.StringField({ initial: "tre" }),
value: new fields.NumberField({ initial: 0, integer: true })
})
}),
bonneaventure: new fields.SchemaField({
base: new fields.NumberField({ initial: 0, integer: true }),
actuelle: new fields.NumberField({ initial: 0, integer: true })
}),
experience: new fields.SchemaField({
value: new fields.NumberField({ initial: 0, integer: true })
}),
eclat: new fields.SchemaField({
value: new fields.NumberField({ initial: 0, integer: true })
}),
sante: new fields.SchemaField({
vigueur: new fields.NumberField({ initial: 0, integer: true }),
etat: new fields.NumberField({ initial: 0, integer: true }),
vigueurmodifier: new fields.NumberField({ initial: 0, integer: true }),
nbcombativite: new fields.NumberField({ initial: 5, integer: true })
}),
adversite: new fields.SchemaField({
bleue: new fields.NumberField({ initial: 0, integer: true }),
rouge: new fields.NumberField({ initial: 0, integer: true }),
noire: new fields.NumberField({ initial: 0, integer: true })
}),
vitesse: new fields.SchemaField({
value: new fields.NumberField({ initial: 0, integer: true })
}),
combat: new fields.SchemaField({
initbonus: new fields.NumberField({ initial: 0, integer: true }),
vitessebonus: new fields.NumberField({ initial: 0, integer: true }),
bonusdegats: new fields.NumberField({ initial: 0, integer: true }),
attaquebonus: new fields.NumberField({ initial: 0, integer: true }),
defensebonus: new fields.NumberField({ initial: 0, integer: true }),
defensetotale: new fields.BooleanField({ initial: false }),
monte: new fields.BooleanField({ initial: false })
}),
// Propriétés spécifiques aux créatures
ressources: new fields.SchemaField({
value: new fields.NumberField({ initial: 0, integer: true })
})
};
}
}

View File

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

View File

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

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

@@ -0,0 +1,23 @@
/**
* Index des DataModels pour Hawkmoon CYD
* Ce fichier centralise tous les exports des modèles de données
*/
// Modèles d'items
export { default as TalentDataModel } from './talent.mjs';
export { default as HistoriqueDataModel } from './historique.mjs';
export { default as ProfilDataModel } from './profil.mjs';
export { default as CompetenceDataModel } from './competence.mjs';
export { default as ArmeDataModel } from './arme.mjs';
export { default as ProtectionDataModel } from './protection.mjs';
export { default as MonnaieDataModel } from './monnaie.mjs';
export { default as EquipementDataModel } from './equipement.mjs';
export { default as ArtefactDataModel } from './artefact.mjs';
export { default as RessourceDataModel } from './ressource.mjs';
export { default as ContactDataModel } from './contact.mjs';
export { default as MutationDataModel } from './mutation.mjs';
// Modèles d'acteurs
export { default as PersonnageDataModel } from './personnage.mjs';
export { default as CelluleDataModel } from './cellule.mjs';
export { default as CreatureDataModel } from './creature.mjs';

View File

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

View File

@@ -0,0 +1,14 @@
/**
* Data model pour les mutations
*/
export default class MutationDataModel extends foundry.abstract.TypeDataModel {
static defineSchema() {
const fields = foundry.data.fields;
return {
description: new fields.HTMLField({ initial: "" }),
mutationcategorie: new fields.StringField({ initial: "tares_communes" }),
hascomplexite: new fields.BooleanField({ initial: false }),
complexite: new fields.NumberField({ initial: 0, integer: true })
};
}
}

View File

@@ -0,0 +1,93 @@
/**
* 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: "" }),
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: "" }),
habitat: new fields.HTMLField({ initial: "" }),
notes: new fields.HTMLField({ initial: "" }),
statut: new fields.StringField({ initial: "" }),
gmnotes: new fields.HTMLField({ initial: "" }),
statutresistant: new fields.StringField({ initial: "commun" })
}),
// Template core
subactors: new fields.ArrayField(new fields.StringField(), { initial: [] }),
attributs: new fields.SchemaField({
adr: new fields.SchemaField({
label: new fields.StringField({ initial: "Adresse" }),
labelnorm: new fields.StringField({ initial: "adresse" }),
abbrev: new fields.StringField({ initial: "adr" }),
value: new fields.NumberField({ initial: 1, integer: true })
}),
pui: new fields.SchemaField({
label: new fields.StringField({ initial: "Puissance" }),
labelnorm: new fields.StringField({ initial: "puissance" }),
abbrev: new fields.StringField({ initial: "pui" }),
value: new fields.NumberField({ initial: 1, integer: true })
}),
cla: new fields.SchemaField({
label: new fields.StringField({ initial: "Clairvoyance" }),
labelnorm: new fields.StringField({ initial: "clairvoyance" }),
abbrev: new fields.StringField({ initial: "cla" }),
value: new fields.NumberField({ initial: 1, integer: true })
}),
pre: new fields.SchemaField({
label: new fields.StringField({ initial: "Présence" }),
labelnorm: new fields.StringField({ initial: "presence" }),
abbrev: new fields.StringField({ initial: "pre" }),
value: new fields.NumberField({ initial: 0, integer: true })
}),
tre: new fields.SchemaField({
label: new fields.StringField({ initial: "Trempe" }),
labelnorm: new fields.StringField({ initial: "trempe" }),
abbrev: new fields.StringField({ initial: "tre" }),
value: new fields.NumberField({ initial: 0, integer: true })
})
}),
bonneaventure: new fields.SchemaField({
base: new fields.NumberField({ initial: 0, integer: true }),
actuelle: new fields.NumberField({ initial: 0, integer: true })
}),
experience: new fields.SchemaField({
value: new fields.NumberField({ initial: 0, integer: true })
}),
eclat: new fields.SchemaField({
value: new fields.NumberField({ initial: 0, integer: true })
}),
sante: new fields.SchemaField({
vigueur: new fields.NumberField({ initial: 0, integer: true }),
etat: new fields.NumberField({ initial: 0, integer: true }),
vigueurmodifier: new fields.NumberField({ initial: 0, integer: true }),
nbcombativite: new fields.NumberField({ initial: 5, integer: true })
}),
adversite: new fields.SchemaField({
bleue: new fields.NumberField({ initial: 0, integer: true }),
rouge: new fields.NumberField({ initial: 0, integer: true }),
noire: new fields.NumberField({ initial: 0, integer: true })
}),
vitesse: new fields.SchemaField({
value: new fields.NumberField({ initial: 0, integer: true })
}),
combat: new fields.SchemaField({
initbonus: new fields.NumberField({ initial: 0, integer: true }),
vitessebonus: new fields.NumberField({ initial: 0, integer: true }),
bonusdegats: new fields.NumberField({ initial: 0, integer: true }),
attaquebonus: new fields.NumberField({ initial: 0, integer: true }),
defensebonus: new fields.NumberField({ initial: 0, integer: true }),
defensetotale: new fields.BooleanField({ initial: false }),
monte: new fields.BooleanField({ initial: false })
})
};
}
}

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

@@ -0,0 +1,23 @@
/**
* Data model pour les profils
*/
export default class ProfilDataModel extends foundry.abstract.TypeDataModel {
static defineSchema() {
const fields = foundry.data.fields;
return {
description: new fields.HTMLField({ initial: "" }),
exemples: new fields.StringField({ initial: "" }),
attribut1: new fields.StringField({ initial: "" }),
attribut2: new fields.StringField({ initial: "" }),
attribut3: new fields.StringField({ initial: "" }),
competences: new fields.StringField({ initial: "" }),
talentsinitie: new fields.StringField({ initial: "" }),
prerequisaguerri: new fields.StringField({ initial: "" }),
talentsaguerri: new fields.StringField({ initial: "" }),
prerequismaitre: new fields.StringField({ initial: "" }),
talentsmaitre: new fields.StringField({ initial: "" }),
celluleinfo: new fields.StringField({ initial: "" }),
equipement: new fields.StringField({ initial: "" })
};
}
}

View File

@@ -0,0 +1,19 @@
/**
* 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: "" }),
prixpo: new fields.NumberField({ initial: 0, integer: true }),
prixca: new fields.NumberField({ initial: 0, integer: true }),
prixsc: new fields.NumberField({ initial: 0, integer: true }),
rarete: new fields.NumberField({ initial: 0, integer: true }),
quantite: new fields.NumberField({ initial: 1, integer: true }),
equipped: new fields.BooleanField({ initial: false }),
protection: new fields.NumberField({ initial: 0, integer: true }),
adversitepoids: new fields.NumberField({ initial: 0, integer: true })
};
}
}

View File

@@ -0,0 +1,12 @@
/**
* Data model pour les ressources
*/
export default class RessourceDataModel extends foundry.abstract.TypeDataModel {
static defineSchema() {
const fields = foundry.data.fields;
return {
pointdev: new fields.NumberField({ initial: 0, integer: true }),
description: new fields.HTMLField({ initial: "" })
};
}
}

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

@@ -0,0 +1,30 @@
/**
* Data model pour les talents
*/
export default class TalentDataModel extends foundry.abstract.TypeDataModel {
static defineSchema() {
const fields = foundry.data.fields;
return {
description: new fields.HTMLField({ initial: "" }),
isautomated: new fields.BooleanField({ initial: false }),
automations: new fields.ArrayField(
new fields.SchemaField({
id: new fields.StringField({ initial: "" }),
eventtype: new fields.StringField({ initial: "on-drop" }),
name: new fields.StringField({ initial: "" }),
bonusname: new fields.StringField({ initial: "vigueur" }),
bonus: new fields.NumberField({ initial: 0, integer: true }),
competence: new fields.StringField({ initial: "" }),
minLevel: new fields.NumberField({ initial: 0, integer: true }),
baCost: new fields.NumberField({ initial: 0, integer: true })
}),
{ initial: [] }
),
talenttype: new fields.StringField({ initial: "" }),
utilisation: new fields.StringField({ initial: "" }),
prerequis: new fields.StringField({ initial: "" }),
resumebonus: new fields.StringField({ initial: "" }),
used: new fields.BooleanField({ initial: false })
};
}
}

View File

@@ -1 +1 @@
MANIFEST-000309
MANIFEST-000377

View File

@@ -1,8 +1,8 @@
2025/08/24-16:39:04.800687 7f99ca7fc6c0 Recovering log #307
2025/08/24-16:39:04.811571 7f99ca7fc6c0 Delete type=3 #305
2025/08/24-16:39:04.811645 7f99ca7fc6c0 Delete type=0 #307
2025/08/24-16:59:15.773185 7f99c8ff96c0 Level-0 table #312: started
2025/08/24-16:59:15.773255 7f99c8ff96c0 Level-0 table #312: 0 bytes OK
2025/08/24-16:59:15.779965 7f99c8ff96c0 Delete type=0 #310
2025/08/24-16:59:15.786903 7f99c8ff96c0 Manual compaction at level-0 from '!journal!MUbViCE2PkVxlzqe' @ 72057594037927935 : 1 .. '!journal.pages!gVybbv17TFY8o3Y4.fQidyqfF1TbsZKHM' @ 0 : 0; will stop at (end)
2025/08/24-16:59:15.786956 7f99c8ff96c0 Manual compaction at level-1 from '!journal!MUbViCE2PkVxlzqe' @ 72057594037927935 : 1 .. '!journal.pages!gVybbv17TFY8o3Y4.fQidyqfF1TbsZKHM' @ 0 : 0; will stop at (end)
2026/01/09-17:40:07.997473 7f1c563fe6c0 Recovering log #375
2026/01/09-17:40:08.091717 7f1c563fe6c0 Delete type=0 #375
2026/01/09-17:40:08.091792 7f1c563fe6c0 Delete type=3 #373
2026/01/09-17:44:28.072757 7f1c54bfb6c0 Level-0 table #380: started
2026/01/09-17:44:28.072827 7f1c54bfb6c0 Level-0 table #380: 0 bytes OK
2026/01/09-17:44:28.079432 7f1c54bfb6c0 Delete type=0 #378
2026/01/09-17:44:28.105106 7f1c54bfb6c0 Manual compaction at level-0 from '!journal!MUbViCE2PkVxlzqe' @ 72057594037927935 : 1 .. '!journal.pages!gVybbv17TFY8o3Y4.fQidyqfF1TbsZKHM' @ 0 : 0; will stop at (end)
2026/01/09-17:44:28.117150 7f1c54bfb6c0 Manual compaction at level-1 from '!journal!MUbViCE2PkVxlzqe' @ 72057594037927935 : 1 .. '!journal.pages!gVybbv17TFY8o3Y4.fQidyqfF1TbsZKHM' @ 0 : 0; will stop at (end)

View File

@@ -1,8 +1,8 @@
2025/07/02-22:46:22.187484 7f0798bfa6c0 Recovering log #303
2025/07/02-22:46:22.198111 7f0798bfa6c0 Delete type=3 #301
2025/07/02-22:46:22.198158 7f0798bfa6c0 Delete type=0 #303
2025/07/02-22:48:09.734542 7f07923ff6c0 Level-0 table #308: started
2025/07/02-22:48:09.734569 7f07923ff6c0 Level-0 table #308: 0 bytes OK
2025/07/02-22:48:09.744356 7f07923ff6c0 Delete type=0 #306
2025/07/02-22:48:09.791085 7f07923ff6c0 Manual compaction at level-0 from '!journal!MUbViCE2PkVxlzqe' @ 72057594037927935 : 1 .. '!journal.pages!gVybbv17TFY8o3Y4.fQidyqfF1TbsZKHM' @ 0 : 0; will stop at (end)
2025/07/02-22:48:09.791154 7f07923ff6c0 Manual compaction at level-1 from '!journal!MUbViCE2PkVxlzqe' @ 72057594037927935 : 1 .. '!journal.pages!gVybbv17TFY8o3Y4.fQidyqfF1TbsZKHM' @ 0 : 0; will stop at (end)
2026/01/08-08:15:08.713116 7f93ea7fc6c0 Recovering log #371
2026/01/08-08:15:08.722804 7f93ea7fc6c0 Delete type=3 #369
2026/01/08-08:15:08.722873 7f93ea7fc6c0 Delete type=0 #371
2026/01/08-08:28:05.068912 7f93e9ffb6c0 Level-0 table #376: started
2026/01/08-08:28:05.068957 7f93e9ffb6c0 Level-0 table #376: 0 bytes OK
2026/01/08-08:28:05.106033 7f93e9ffb6c0 Delete type=0 #374
2026/01/08-08:28:05.217659 7f93e9ffb6c0 Manual compaction at level-0 from '!journal!MUbViCE2PkVxlzqe' @ 72057594037927935 : 1 .. '!journal.pages!gVybbv17TFY8o3Y4.fQidyqfF1TbsZKHM' @ 0 : 0; will stop at (end)
2026/01/08-08:28:05.217719 7f93e9ffb6c0 Manual compaction at level-1 from '!journal!MUbViCE2PkVxlzqe' @ 72057594037927935 : 1 .. '!journal.pages!gVybbv17TFY8o3Y4.fQidyqfF1TbsZKHM' @ 0 : 0; will stop at (end)

View File

@@ -1 +1 @@
MANIFEST-000308
MANIFEST-000376

View File

@@ -1,8 +1,8 @@
2025/08/24-16:39:04.657736 7f99ca7fc6c0 Recovering log #306
2025/08/24-16:39:04.668479 7f99ca7fc6c0 Delete type=3 #304
2025/08/24-16:39:04.668567 7f99ca7fc6c0 Delete type=0 #306
2025/08/24-16:59:15.720000 7f99c8ff96c0 Level-0 table #311: started
2025/08/24-16:59:15.720030 7f99c8ff96c0 Level-0 table #311: 0 bytes OK
2025/08/24-16:59:15.726074 7f99c8ff96c0 Delete type=0 #309
2025/08/24-16:59:15.733124 7f99c8ff96c0 Manual compaction at level-0 from '!items!0fit7HelSjaFtXcW' @ 72057594037927935 : 1 .. '!items!wxrzP3NyiHiYnAMJ' @ 0 : 0; will stop at (end)
2025/08/24-16:59:15.733174 7f99c8ff96c0 Manual compaction at level-1 from '!items!0fit7HelSjaFtXcW' @ 72057594037927935 : 1 .. '!items!wxrzP3NyiHiYnAMJ' @ 0 : 0; will stop at (end)
2026/01/09-17:40:07.215100 7f1c563fe6c0 Recovering log #374
2026/01/09-17:40:07.308808 7f1c563fe6c0 Delete type=0 #374
2026/01/09-17:40:07.308890 7f1c563fe6c0 Delete type=3 #372
2026/01/09-17:44:28.036990 7f1c54bfb6c0 Level-0 table #379: started
2026/01/09-17:44:28.037073 7f1c54bfb6c0 Level-0 table #379: 0 bytes OK
2026/01/09-17:44:28.043547 7f1c54bfb6c0 Delete type=0 #377
2026/01/09-17:44:28.043784 7f1c54bfb6c0 Manual compaction at level-0 from '!items!0fit7HelSjaFtXcW' @ 72057594037927935 : 1 .. '!items!wxrzP3NyiHiYnAMJ' @ 0 : 0; will stop at (end)
2026/01/09-17:44:28.043823 7f1c54bfb6c0 Manual compaction at level-1 from '!items!0fit7HelSjaFtXcW' @ 72057594037927935 : 1 .. '!items!wxrzP3NyiHiYnAMJ' @ 0 : 0; will stop at (end)

View File

@@ -1,8 +1,8 @@
2025/07/02-22:46:22.075956 7f07937fe6c0 Recovering log #302
2025/07/02-22:46:22.086980 7f07937fe6c0 Delete type=3 #300
2025/07/02-22:46:22.087033 7f07937fe6c0 Delete type=0 #302
2025/07/02-22:48:09.675327 7f07923ff6c0 Level-0 table #307: started
2025/07/02-22:48:09.675362 7f07923ff6c0 Level-0 table #307: 0 bytes OK
2025/07/02-22:48:09.686702 7f07923ff6c0 Delete type=0 #305
2025/07/02-22:48:09.686958 7f07923ff6c0 Manual compaction at level-0 from '!items!0fit7HelSjaFtXcW' @ 72057594037927935 : 1 .. '!items!wxrzP3NyiHiYnAMJ' @ 0 : 0; will stop at (end)
2025/07/02-22:48:09.686996 7f07923ff6c0 Manual compaction at level-1 from '!items!0fit7HelSjaFtXcW' @ 72057594037927935 : 1 .. '!items!wxrzP3NyiHiYnAMJ' @ 0 : 0; will stop at (end)
2026/01/08-08:15:08.609938 7f93eaffd6c0 Recovering log #370
2026/01/08-08:15:08.619765 7f93eaffd6c0 Delete type=3 #368
2026/01/08-08:15:08.619830 7f93eaffd6c0 Delete type=0 #370
2026/01/08-08:28:04.844266 7f93e9ffb6c0 Level-0 table #375: started
2026/01/08-08:28:04.844294 7f93e9ffb6c0 Level-0 table #375: 0 bytes OK
2026/01/08-08:28:04.883113 7f93e9ffb6c0 Delete type=0 #373
2026/01/08-08:28:04.919770 7f93e9ffb6c0 Manual compaction at level-0 from '!items!0fit7HelSjaFtXcW' @ 72057594037927935 : 1 .. '!items!wxrzP3NyiHiYnAMJ' @ 0 : 0; will stop at (end)
2026/01/08-08:28:04.919798 7f93e9ffb6c0 Manual compaction at level-1 from '!items!0fit7HelSjaFtXcW' @ 72057594037927935 : 1 .. '!items!wxrzP3NyiHiYnAMJ' @ 0 : 0; will stop at (end)

View File

@@ -1 +1 @@
MANIFEST-000308
MANIFEST-000376

View File

@@ -1,8 +1,8 @@
2025/08/24-16:39:04.627677 7f99c97fa6c0 Recovering log #306
2025/08/24-16:39:04.637852 7f99c97fa6c0 Delete type=3 #304
2025/08/24-16:39:04.637963 7f99c97fa6c0 Delete type=0 #306
2025/08/24-16:59:15.678161 7f99c8ff96c0 Level-0 table #311: started
2025/08/24-16:59:15.678292 7f99c8ff96c0 Level-0 table #311: 0 bytes OK
2025/08/24-16:59:15.685710 7f99c8ff96c0 Delete type=0 #309
2025/08/24-16:59:15.705541 7f99c8ff96c0 Manual compaction at level-0 from '!items!0nhTxujlIUB63Aqt' @ 72057594037927935 : 1 .. '!items!tFU5yISK6spdNWco' @ 0 : 0; will stop at (end)
2025/08/24-16:59:15.705635 7f99c8ff96c0 Manual compaction at level-1 from '!items!0nhTxujlIUB63Aqt' @ 72057594037927935 : 1 .. '!items!tFU5yISK6spdNWco' @ 0 : 0; will stop at (end)
2026/01/09-17:40:07.033899 7f1c55bfd6c0 Recovering log #374
2026/01/09-17:40:07.115529 7f1c55bfd6c0 Delete type=0 #374
2026/01/09-17:40:07.115669 7f1c55bfd6c0 Delete type=3 #372
2026/01/09-17:44:28.002424 7f1c54bfb6c0 Level-0 table #379: started
2026/01/09-17:44:28.002453 7f1c54bfb6c0 Level-0 table #379: 0 bytes OK
2026/01/09-17:44:28.008591 7f1c54bfb6c0 Delete type=0 #377
2026/01/09-17:44:28.016607 7f1c54bfb6c0 Manual compaction at level-0 from '!items!0nhTxujlIUB63Aqt' @ 72057594037927935 : 1 .. '!items!tFU5yISK6spdNWco' @ 0 : 0; will stop at (end)
2026/01/09-17:44:28.016651 7f1c54bfb6c0 Manual compaction at level-1 from '!items!0nhTxujlIUB63Aqt' @ 72057594037927935 : 1 .. '!items!tFU5yISK6spdNWco' @ 0 : 0; will stop at (end)

View File

@@ -1,8 +1,8 @@
2025/07/02-22:46:22.050017 7f0793fff6c0 Recovering log #302
2025/07/02-22:46:22.059979 7f0793fff6c0 Delete type=3 #300
2025/07/02-22:46:22.060037 7f0793fff6c0 Delete type=0 #302
2025/07/02-22:48:09.634420 7f07923ff6c0 Level-0 table #307: started
2025/07/02-22:48:09.634441 7f07923ff6c0 Level-0 table #307: 0 bytes OK
2025/07/02-22:48:09.644014 7f07923ff6c0 Delete type=0 #305
2025/07/02-22:48:09.644146 7f07923ff6c0 Manual compaction at level-0 from '!items!0nhTxujlIUB63Aqt' @ 72057594037927935 : 1 .. '!items!tFU5yISK6spdNWco' @ 0 : 0; will stop at (end)
2025/07/02-22:48:09.644167 7f07923ff6c0 Manual compaction at level-1 from '!items!0nhTxujlIUB63Aqt' @ 72057594037927935 : 1 .. '!items!tFU5yISK6spdNWco' @ 0 : 0; will stop at (end)
2026/01/08-08:15:08.584392 7f93eb7fe6c0 Recovering log #370
2026/01/08-08:15:08.595037 7f93eb7fe6c0 Delete type=3 #368
2026/01/08-08:15:08.595129 7f93eb7fe6c0 Delete type=0 #370
2026/01/08-08:28:04.658126 7f93e9ffb6c0 Level-0 table #375: started
2026/01/08-08:28:04.658154 7f93e9ffb6c0 Level-0 table #375: 0 bytes OK
2026/01/08-08:28:04.696322 7f93e9ffb6c0 Delete type=0 #373
2026/01/08-08:28:04.770719 7f93e9ffb6c0 Manual compaction at level-0 from '!items!0nhTxujlIUB63Aqt' @ 72057594037927935 : 1 .. '!items!tFU5yISK6spdNWco' @ 0 : 0; will stop at (end)
2026/01/08-08:28:04.770775 7f93e9ffb6c0 Manual compaction at level-1 from '!items!0nhTxujlIUB63Aqt' @ 72057594037927935 : 1 .. '!items!tFU5yISK6spdNWco' @ 0 : 0; will stop at (end)

View File

@@ -1 +1 @@
MANIFEST-000308
MANIFEST-000376

View File

@@ -1,8 +1,8 @@
2025/08/24-16:39:04.595109 7f99caffd6c0 Recovering log #306
2025/08/24-16:39:04.604941 7f99caffd6c0 Delete type=3 #304
2025/08/24-16:39:04.605009 7f99caffd6c0 Delete type=0 #306
2025/08/24-16:59:15.698867 7f99c8ff96c0 Level-0 table #311: started
2025/08/24-16:59:15.698952 7f99c8ff96c0 Level-0 table #311: 0 bytes OK
2025/08/24-16:59:15.705403 7f99c8ff96c0 Delete type=0 #309
2025/08/24-16:59:15.705617 7f99c8ff96c0 Manual compaction at level-0 from '!items!15IDGG6JoZnRCQtY' @ 72057594037927935 : 1 .. '!items!yI1zY5k8mAdx9wHK' @ 0 : 0; will stop at (end)
2025/08/24-16:59:15.705693 7f99c8ff96c0 Manual compaction at level-1 from '!items!15IDGG6JoZnRCQtY' @ 72057594037927935 : 1 .. '!items!yI1zY5k8mAdx9wHK' @ 0 : 0; will stop at (end)
2026/01/09-17:40:06.860640 7f1c553fc6c0 Recovering log #374
2026/01/09-17:40:06.945970 7f1c553fc6c0 Delete type=0 #374
2026/01/09-17:40:06.946049 7f1c553fc6c0 Delete type=3 #372
2026/01/09-17:44:27.995662 7f1c54bfb6c0 Level-0 table #379: started
2026/01/09-17:44:27.995696 7f1c54bfb6c0 Level-0 table #379: 0 bytes OK
2026/01/09-17:44:28.002283 7f1c54bfb6c0 Delete type=0 #377
2026/01/09-17:44:28.016595 7f1c54bfb6c0 Manual compaction at level-0 from '!items!15IDGG6JoZnRCQtY' @ 72057594037927935 : 1 .. '!items!yI1zY5k8mAdx9wHK' @ 0 : 0; will stop at (end)
2026/01/09-17:44:28.016641 7f1c54bfb6c0 Manual compaction at level-1 from '!items!15IDGG6JoZnRCQtY' @ 72057594037927935 : 1 .. '!items!yI1zY5k8mAdx9wHK' @ 0 : 0; will stop at (end)

View File

@@ -1,8 +1,8 @@
2025/07/02-22:46:22.022022 7f07937fe6c0 Recovering log #302
2025/07/02-22:46:22.031802 7f07937fe6c0 Delete type=3 #300
2025/07/02-22:46:22.031862 7f07937fe6c0 Delete type=0 #302
2025/07/02-22:48:09.604476 7f07923ff6c0 Level-0 table #307: started
2025/07/02-22:48:09.604540 7f07923ff6c0 Level-0 table #307: 0 bytes OK
2025/07/02-22:48:09.616123 7f07923ff6c0 Delete type=0 #305
2025/07/02-22:48:09.644121 7f07923ff6c0 Manual compaction at level-0 from '!items!15IDGG6JoZnRCQtY' @ 72057594037927935 : 1 .. '!items!yI1zY5k8mAdx9wHK' @ 0 : 0; will stop at (end)
2025/07/02-22:48:09.644157 7f07923ff6c0 Manual compaction at level-1 from '!items!15IDGG6JoZnRCQtY' @ 72057594037927935 : 1 .. '!items!yI1zY5k8mAdx9wHK' @ 0 : 0; will stop at (end)
2026/01/08-08:15:08.560342 7f93eaffd6c0 Recovering log #370
2026/01/08-08:15:08.570307 7f93eaffd6c0 Delete type=3 #368
2026/01/08-08:15:08.570398 7f93eaffd6c0 Delete type=0 #370
2026/01/08-08:28:04.883258 7f93e9ffb6c0 Level-0 table #375: started
2026/01/08-08:28:04.883283 7f93e9ffb6c0 Level-0 table #375: 0 bytes OK
2026/01/08-08:28:04.919585 7f93e9ffb6c0 Delete type=0 #373
2026/01/08-08:28:04.919781 7f93e9ffb6c0 Manual compaction at level-0 from '!items!15IDGG6JoZnRCQtY' @ 72057594037927935 : 1 .. '!items!yI1zY5k8mAdx9wHK' @ 0 : 0; will stop at (end)
2026/01/08-08:28:04.919805 7f93e9ffb6c0 Manual compaction at level-1 from '!items!15IDGG6JoZnRCQtY' @ 72057594037927935 : 1 .. '!items!yI1zY5k8mAdx9wHK' @ 0 : 0; will stop at (end)

View File

@@ -1 +1 @@
MANIFEST-000308
MANIFEST-000376

View File

@@ -1,8 +1,8 @@
2025/08/24-16:39:04.685664 7f99c9ffb6c0 Recovering log #306
2025/08/24-16:39:04.696583 7f99c9ffb6c0 Delete type=3 #304
2025/08/24-16:39:04.696664 7f99c9ffb6c0 Delete type=0 #306
2025/08/24-16:59:15.713614 7f99c8ff96c0 Level-0 table #311: started
2025/08/24-16:59:15.713701 7f99c8ff96c0 Level-0 table #311: 0 bytes OK
2025/08/24-16:59:15.719863 7f99c8ff96c0 Delete type=0 #309
2025/08/24-16:59:15.733110 7f99c8ff96c0 Manual compaction at level-0 from '!items!0BopmCu8vGK2923j' @ 72057594037927935 : 1 .. '!items!zYx0Ak2y1LNTcKlO' @ 0 : 0; will stop at (end)
2025/08/24-16:59:15.733164 7f99c8ff96c0 Manual compaction at level-1 from '!items!0BopmCu8vGK2923j' @ 72057594037927935 : 1 .. '!items!zYx0Ak2y1LNTcKlO' @ 0 : 0; will stop at (end)
2026/01/09-17:40:07.398683 7f1c55bfd6c0 Recovering log #374
2026/01/09-17:40:07.488253 7f1c55bfd6c0 Delete type=0 #374
2026/01/09-17:40:07.488337 7f1c55bfd6c0 Delete type=3 #372
2026/01/09-17:44:28.016766 7f1c54bfb6c0 Level-0 table #379: started
2026/01/09-17:44:28.016805 7f1c54bfb6c0 Level-0 table #379: 0 bytes OK
2026/01/09-17:44:28.023141 7f1c54bfb6c0 Delete type=0 #377
2026/01/09-17:44:28.043713 7f1c54bfb6c0 Manual compaction at level-0 from '!items!0BopmCu8vGK2923j' @ 72057594037927935 : 1 .. '!items!zYx0Ak2y1LNTcKlO' @ 0 : 0; will stop at (end)
2026/01/09-17:44:28.043764 7f1c54bfb6c0 Manual compaction at level-1 from '!items!0BopmCu8vGK2923j' @ 72057594037927935 : 1 .. '!items!zYx0Ak2y1LNTcKlO' @ 0 : 0; will stop at (end)

View File

@@ -1,8 +1,8 @@
2025/07/02-22:46:22.103691 7f0798bfa6c0 Recovering log #302
2025/07/02-22:46:22.113425 7f0798bfa6c0 Delete type=3 #300
2025/07/02-22:46:22.113488 7f0798bfa6c0 Delete type=0 #302
2025/07/02-22:48:09.644254 7f07923ff6c0 Level-0 table #307: started
2025/07/02-22:48:09.644276 7f07923ff6c0 Level-0 table #307: 0 bytes OK
2025/07/02-22:48:09.654757 7f07923ff6c0 Delete type=0 #305
2025/07/02-22:48:09.686905 7f07923ff6c0 Manual compaction at level-0 from '!items!0BopmCu8vGK2923j' @ 72057594037927935 : 1 .. '!items!zYx0Ak2y1LNTcKlO' @ 0 : 0; will stop at (end)
2025/07/02-22:48:09.686969 7f07923ff6c0 Manual compaction at level-1 from '!items!0BopmCu8vGK2923j' @ 72057594037927935 : 1 .. '!items!zYx0Ak2y1LNTcKlO' @ 0 : 0; will stop at (end)
2026/01/08-08:15:08.634608 7f93eb7fe6c0 Recovering log #370
2026/01/08-08:15:08.644771 7f93eb7fe6c0 Delete type=3 #368
2026/01/08-08:15:08.644849 7f93eb7fe6c0 Delete type=0 #370
2026/01/08-08:28:04.770939 7f93e9ffb6c0 Level-0 table #375: started
2026/01/08-08:28:04.770974 7f93e9ffb6c0 Level-0 table #375: 0 bytes OK
2026/01/08-08:28:04.807757 7f93e9ffb6c0 Delete type=0 #373
2026/01/08-08:28:04.919742 7f93e9ffb6c0 Manual compaction at level-0 from '!items!0BopmCu8vGK2923j' @ 72057594037927935 : 1 .. '!items!zYx0Ak2y1LNTcKlO' @ 0 : 0; will stop at (end)
2026/01/08-08:28:04.919789 7f93e9ffb6c0 Manual compaction at level-1 from '!items!0BopmCu8vGK2923j' @ 72057594037927935 : 1 .. '!items!zYx0Ak2y1LNTcKlO' @ 0 : 0; will stop at (end)

View File

@@ -1 +1 @@
MANIFEST-000308
MANIFEST-000376

View File

@@ -1,8 +1,8 @@
2025/08/24-16:39:04.642541 7f99c9ffb6c0 Recovering log #306
2025/08/24-16:39:04.652781 7f99c9ffb6c0 Delete type=3 #304
2025/08/24-16:39:04.652862 7f99c9ffb6c0 Delete type=0 #306
2025/08/24-16:59:15.685953 7f99c8ff96c0 Level-0 table #311: started
2025/08/24-16:59:15.686013 7f99c8ff96c0 Level-0 table #311: 0 bytes OK
2025/08/24-16:59:15.692263 7f99c8ff96c0 Delete type=0 #309
2025/08/24-16:59:15.705571 7f99c8ff96c0 Manual compaction at level-0 from '!items!15foLG7y3LUXNzkK' @ 72057594037927935 : 1 .. '!items!z1HtkvazCGHut7cz' @ 0 : 0; will stop at (end)
2025/08/24-16:59:15.705656 7f99c8ff96c0 Manual compaction at level-1 from '!items!15foLG7y3LUXNzkK' @ 72057594037927935 : 1 .. '!items!z1HtkvazCGHut7cz' @ 0 : 0; will stop at (end)
2026/01/09-17:40:07.118312 7f1c553fc6c0 Recovering log #374
2026/01/09-17:40:07.212316 7f1c553fc6c0 Delete type=0 #374
2026/01/09-17:40:07.212395 7f1c553fc6c0 Delete type=3 #372
2026/01/09-17:44:28.008871 7f1c54bfb6c0 Level-0 table #379: started
2026/01/09-17:44:28.008958 7f1c54bfb6c0 Level-0 table #379: 0 bytes OK
2026/01/09-17:44:28.016332 7f1c54bfb6c0 Delete type=0 #377
2026/01/09-17:44:28.016621 7f1c54bfb6c0 Manual compaction at level-0 from '!items!15foLG7y3LUXNzkK' @ 72057594037927935 : 1 .. '!items!z1HtkvazCGHut7cz' @ 0 : 0; will stop at (end)
2026/01/09-17:44:28.016661 7f1c54bfb6c0 Manual compaction at level-1 from '!items!15foLG7y3LUXNzkK' @ 72057594037927935 : 1 .. '!items!z1HtkvazCGHut7cz' @ 0 : 0; will stop at (end)

View File

@@ -1,8 +1,8 @@
2025/07/02-22:46:22.062411 7f0798bfa6c0 Recovering log #302
2025/07/02-22:46:22.072211 7f0798bfa6c0 Delete type=3 #300
2025/07/02-22:46:22.072276 7f0798bfa6c0 Delete type=0 #302
2025/07/02-22:48:09.625684 7f07923ff6c0 Level-0 table #307: started
2025/07/02-22:48:09.625708 7f07923ff6c0 Level-0 table #307: 0 bytes OK
2025/07/02-22:48:09.634315 7f07923ff6c0 Delete type=0 #305
2025/07/02-22:48:09.644139 7f07923ff6c0 Manual compaction at level-0 from '!items!15foLG7y3LUXNzkK' @ 72057594037927935 : 1 .. '!items!z1HtkvazCGHut7cz' @ 0 : 0; will stop at (end)
2025/07/02-22:48:09.644162 7f07923ff6c0 Manual compaction at level-1 from '!items!15foLG7y3LUXNzkK' @ 72057594037927935 : 1 .. '!items!z1HtkvazCGHut7cz' @ 0 : 0; will stop at (end)
2026/01/08-08:15:08.597802 7f93ea7fc6c0 Recovering log #370
2026/01/08-08:15:08.607783 7f93ea7fc6c0 Delete type=3 #368
2026/01/08-08:15:08.607847 7f93ea7fc6c0 Delete type=0 #370
2026/01/08-08:28:04.733376 7f93e9ffb6c0 Level-0 table #375: started
2026/01/08-08:28:04.733403 7f93e9ffb6c0 Level-0 table #375: 0 bytes OK
2026/01/08-08:28:04.770489 7f93e9ffb6c0 Delete type=0 #373
2026/01/08-08:28:04.770754 7f93e9ffb6c0 Manual compaction at level-0 from '!items!15foLG7y3LUXNzkK' @ 72057594037927935 : 1 .. '!items!z1HtkvazCGHut7cz' @ 0 : 0; will stop at (end)
2026/01/08-08:28:04.770794 7f93e9ffb6c0 Manual compaction at level-1 from '!items!15foLG7y3LUXNzkK' @ 72057594037927935 : 1 .. '!items!z1HtkvazCGHut7cz' @ 0 : 0; will stop at (end)

View File

@@ -1 +1 @@
MANIFEST-000218
MANIFEST-000286

View File

@@ -1,8 +1,8 @@
2025/08/24-16:39:04.611112 7f99ca7fc6c0 Recovering log #216
2025/08/24-16:39:04.621971 7f99ca7fc6c0 Delete type=3 #214
2025/08/24-16:39:04.622127 7f99ca7fc6c0 Delete type=0 #216
2025/08/24-16:59:15.692465 7f99c8ff96c0 Level-0 table #221: started
2025/08/24-16:59:15.692517 7f99c8ff96c0 Level-0 table #221: 0 bytes OK
2025/08/24-16:59:15.698622 7f99c8ff96c0 Delete type=0 #219
2025/08/24-16:59:15.705597 7f99c8ff96c0 Manual compaction at level-0 from '!folders!5d4Zn28TUcPxRyXd' @ 72057594037927935 : 1 .. '!items!zttESycGKltfwCzJ' @ 0 : 0; will stop at (end)
2025/08/24-16:59:15.705674 7f99c8ff96c0 Manual compaction at level-1 from '!folders!5d4Zn28TUcPxRyXd' @ 72057594037927935 : 1 .. '!items!zttESycGKltfwCzJ' @ 0 : 0; will stop at (end)
2026/01/09-17:40:06.948771 7f1c563fe6c0 Recovering log #284
2026/01/09-17:40:07.030884 7f1c563fe6c0 Delete type=0 #284
2026/01/09-17:40:07.030949 7f1c563fe6c0 Delete type=3 #282
2026/01/09-17:44:27.988602 7f1c54bfb6c0 Level-0 table #289: started
2026/01/09-17:44:27.988662 7f1c54bfb6c0 Level-0 table #289: 0 bytes OK
2026/01/09-17:44:27.995503 7f1c54bfb6c0 Delete type=0 #287
2026/01/09-17:44:28.016581 7f1c54bfb6c0 Manual compaction at level-0 from '!folders!5d4Zn28TUcPxRyXd' @ 72057594037927935 : 1 .. '!items!zttESycGKltfwCzJ' @ 0 : 0; will stop at (end)
2026/01/09-17:44:28.016631 7f1c54bfb6c0 Manual compaction at level-1 from '!folders!5d4Zn28TUcPxRyXd' @ 72057594037927935 : 1 .. '!items!zttESycGKltfwCzJ' @ 0 : 0; will stop at (end)

View File

@@ -1,8 +1,8 @@
2025/07/02-22:46:22.035824 7f0798bfa6c0 Recovering log #212
2025/07/02-22:46:22.046033 7f0798bfa6c0 Delete type=3 #210
2025/07/02-22:46:22.046089 7f0798bfa6c0 Delete type=0 #212
2025/07/02-22:48:09.616234 7f07923ff6c0 Level-0 table #217: started
2025/07/02-22:48:09.616258 7f07923ff6c0 Level-0 table #217: 0 bytes OK
2025/07/02-22:48:09.625537 7f07923ff6c0 Delete type=0 #215
2025/07/02-22:48:09.644131 7f07923ff6c0 Manual compaction at level-0 from '!folders!5d4Zn28TUcPxRyXd' @ 72057594037927935 : 1 .. '!items!zttESycGKltfwCzJ' @ 0 : 0; will stop at (end)
2025/07/02-22:48:09.644152 7f07923ff6c0 Manual compaction at level-1 from '!folders!5d4Zn28TUcPxRyXd' @ 72057594037927935 : 1 .. '!items!zttESycGKltfwCzJ' @ 0 : 0; will stop at (end)
2026/01/08-08:15:08.572263 7f93ebfff6c0 Recovering log #280
2026/01/08-08:15:08.581752 7f93ebfff6c0 Delete type=3 #278
2026/01/08-08:15:08.581804 7f93ebfff6c0 Delete type=0 #280
2026/01/08-08:28:04.623048 7f93e9ffb6c0 Level-0 table #285: started
2026/01/08-08:28:04.623109 7f93e9ffb6c0 Level-0 table #285: 0 bytes OK
2026/01/08-08:28:04.657992 7f93e9ffb6c0 Delete type=0 #283
2026/01/08-08:28:04.770699 7f93e9ffb6c0 Manual compaction at level-0 from '!folders!5d4Zn28TUcPxRyXd' @ 72057594037927935 : 1 .. '!items!zttESycGKltfwCzJ' @ 0 : 0; will stop at (end)
2026/01/08-08:28:04.770767 7f93e9ffb6c0 Manual compaction at level-1 from '!folders!5d4Zn28TUcPxRyXd' @ 72057594037927935 : 1 .. '!items!zttESycGKltfwCzJ' @ 0 : 0; will stop at (end)

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