Compare commits

..

8 Commits

Author SHA1 Message Date
e7a6c15bf7 Remove node_modules from repository
All checks were successful
Release Creation / build (release) Successful in 56s
2026-01-09 17:25:00 +01:00
1909ff443d Remove node_modules from repository 2026-01-09 17:24:36 +01:00
c72c9d8b02 Upgrade to auto-release 2026-01-09 17:23:02 +01:00
536812e871 Upgrade to auto-release 2026-01-09 17:22:52 +01:00
66fe1418f0 Migration datamodels ! 2026-01-09 17:11:12 +01:00
901df5b395 Enhance CSS+fonts 2025-10-26 21:41:25 +01:00
f5d84832f3 CSS/Font enhancements 2025-10-26 15:08:45 +01:00
216360e0d8 Correction sur usage BA sur un jet impair au D20 2025-06-24 22:11:57 +02:00
204 changed files with 17218 additions and 3746 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-mournblade/releases/download/latest/system.json
download: https://www.uberwald.me/gitea/${{gitea.repository}}/releases/download/${{github.event.release.tag_name}}/fvtt-mournblade.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-mournblade.zip system.json README.md LICENSE assets/ lang/ modules/ packs/ styles/ templates/ template.json
- 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-mournblade.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-mournblade'
version: ${{github.event.release.tag_name}}
manifest: 'https://www.uberwald.me/gitea/public/fvtt-mournblade/releases/download/latest/system.json'
notes: 'https://www.uberwald.me/gitea/${{gitea.repository}}/releases/download/${{github.event.release.tag_name}}/fvtt-mournblade.zip'
compatibility-minimum: '13'
compatibility-verified: '13'

1
.gitignore vendored
View File

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

35
gulpfile.js Normal file
View File

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

View File

@@ -169,6 +169,8 @@
"MNBL.weaponscapacities": "Weapons/Abilities",
"MNBL.weapontype": "Weapon Type",
"MNBL.weight": "Weight",
"MNBL.total": "Total",
"Présence": "Presence",
"Puissance": "Might",
"Trempe": "Mettle",

View File

@@ -141,7 +141,7 @@
"MNBL.hair": "Cheveux",
"MNBL.eyes": "Yeux",
"MNBL.preferredhand": "Main Préférée",
"MNBL.weight": "Weight",
"MNBL.weight": "Poids",
"MNBL.soulmultiplier": "Multiplicateur d'âme",
"MNBL.ignorehealthmalus": "Ignore le malus de santé",
"MNBL.ignoresoulmalus": "Ignore le malus d'âme",
@@ -213,6 +213,12 @@
"MNBL.attribute": "Attribut",
"MNBL.Protections": "Protections",
"MNBL.rune": "Rune"
"MNBL.rune": "Rune",
"MNBL.total": "Total",
"MNBL.description": "Description",
"MNBL.details": "Détails",
"MNBL.sacrifice": "Sacrifice",
"MNBL.identity": "Identité",
"MNBL.gmtools": "Outils MJ"
}

874
less/actor-styles.less Normal file
View File

@@ -0,0 +1,874 @@
/* ==================== Actor Sheet Styles ==================== */
// NOTE: Ce fichier surcharge certaines règles de simple-converted.less
// Les sélecteurs .fvtt-mournblade.actor sont plus spécifiques et prennent priorité
.fvtt-mournblade.actor {
// Background pour toute la fiche d'acteur
background: url("../assets/ui/pc_sheet_bg.webp") repeat;
// AppV2 - Structure flex pour permettre le scroll
.window-content {
height: 100%;
padding: 0;
margin: 0;
display: flex;
flex-direction: column;
overflow: hidden;
}
// Main form structure
form,
.sheet-form-layout {
height: 100%;
background: url("../assets/ui/pc_sheet_bg.webp") repeat-y;
color: black;
display: flex;
flex-direction: column;
flex: 1;
min-height: 0;
overflow: hidden;
padding: 0;
margin: 0;
// La section racine du template (if nested inside form, or simple direct children handling)
> section {
height: 100%;
display: flex;
flex-direction: column;
flex: 1;
min-height: 0;
overflow: hidden;
}
}
// SURCHARGE: simple-converted.less définit flex: 0 0 210px
.sheet-header {
background: url("../assets/ui/pc_sheet_bg.webp") repeat;
padding: 0.5rem;
margin: 0;
flex: 0 0 auto !important; // Override simple-converted
overflow: visible !important; // Override simple-converted
.background-sheet-header {
background: transparent;
}
.header-main-content {
flex: 1;
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.header-stats-grid {
display: grid;
grid-template-columns: 2fr 1fr 1fr;
gap: 0.75rem;
padding: 0.5rem;
background: rgba(0, 0, 0, 0.15);
border: 2px solid rgba(139, 69, 19, 0.5);
border-radius: 4px;
}
.stat-group {
display: flex;
flex-direction: column;
gap: 0.3rem;
padding: 0.35rem 0.6rem;
background: rgba(0, 0, 0, 0.2);
border: 1px solid rgba(139, 69, 19, 0.4);
border-radius: 3px;
&.stat-group-health {
border-left: 3px solid rgba(200, 0, 0, 0.6);
background: rgba(40, 0, 0, 0.15);
}
}
.stat-title {
font-size: 0.75rem;
font-weight: bold;
color: #f5e6d3;
margin: 0;
padding: 0 0 0.3rem 0;
border-bottom: 1px solid rgba(139, 69, 19, 0.5);
text-transform: uppercase;
letter-spacing: 0.5px;
font-family: "CentaurMT", serif;
text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.8);
}
.stat-values {
display: flex;
flex-direction: row;
gap: 0.5rem;
flex-wrap: wrap;
justify-content: center;
}
.stat-item {
display: flex;
flex-direction: column;
gap: 0.2rem;
align-items: center;
flex: 1;
min-width: 0;
}
.stat-label {
font-size: 0.7rem;
color: #d4c5b0;
margin: 0;
font-weight: 600;
text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.7);
}
.stat-value {
font-size: 0.85rem;
font-weight: bold;
color: #fff;
padding: 0.25rem 0.5rem;
background: rgba(0, 0, 0, 0.4);
border: 1px solid rgba(139, 69, 19, 0.6);
border-radius: 3px;
min-width: 2.5rem;
text-align: center;
text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.9);
width: 100%;
}
.stat-input {
font-size: 0.8rem;
font-weight: 600;
padding: 0.25rem 0.4rem;
background: rgba(40, 30, 20, 0.7);
border: 1px solid rgba(139, 69, 19, 0.7);
color: #fff;
border-radius: 3px;
text-align: center;
min-width: 2.5rem;
max-width: 100%;
width: 100%;
text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.9);
box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.3);
&.stat-input-single {
min-width: 3.5rem;
}
&.stat-input-damage {
border-color: rgba(200, 0, 0, 0.8);
background: rgba(80, 0, 0, 0.5);
}
&:hover {
background: rgba(60, 45, 30, 0.8);
border-color: rgba(255, 102, 0, 0.6);
}
&:focus {
outline: none;
border-color: rgba(255, 102, 0, 1);
box-shadow: 0 0 6px rgba(255, 102, 0, 0.5), inset 0 1px 3px rgba(0, 0, 0, 0.3);
background: rgba(70, 50, 35, 0.9);
}
}
.header-fields {
h4.item-name-label.competence-name {
font-size: 0.75rem;
padding-top: 3px;
}
.item-name-label.competence-name {
font-size: 0.75rem;
}
label.item-name-label.competence-name {
font-size: 0.7rem;
}
.item-field-label-short {
font-size: 0.8rem;
}
.status-small-label {
font-size: 0.8rem;
}
}
}
// Sheet navigation tabs
// SURCHARGE: simple-converted.less définit flex: 0
.sheet-tabs {
margin: 0;
padding: 0 0.5rem;
flex: 0 0 auto !important; // Override simple-converted
}
// Sheet body - section scrollable
// SURCHARGE CRITIQUE: simple-converted.less définit height: auto sur .sheet-body et .tab
// Ces surcharges permettent le scroll vertical
.sheet-body {
margin: 0;
padding: 0.5rem;
flex: 1 !important; // Override simple-converted
min-height: 0 !important; // Critique pour le scroll
overflow-y: auto !important; // Override simple-converted
.tab {
padding: 0;
height: auto !important; // Override simple-converted qui met height: auto
&:not(.active) {
display: none;
}
// Assurer que les grilles peuvent scroller
.grid, .grid-2col {
height: auto;
overflow: visible;
}
.sheet-box {
height: auto;
}
}
// Listes compactes dans les sections
.compact-list {
list-style: none;
margin: 0;
padding: 0;
li.item {
padding: 0.2rem 0.4rem;
margin-bottom: 0.15rem;
background: rgba(0, 0, 0, 0.1);
border: 1px solid rgba(139, 69, 19, 0.3);
border-radius: 3px;
&:hover {
background: rgba(0, 0, 0, 0.15);
}
&.items-title-bg {
background: rgba(0, 0, 0, 0.3);
border-color: rgba(139, 69, 19, 0.5);
font-weight: 600;
margin-bottom: 0.3rem;
.item-name-label-header {
color: #f5e6d3;
text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.7);
}
}
}
}
// Contrôles d'items (edit, delete, equip, etc.)
.item-controls {
display: flex;
align-items: center;
gap: 0.3rem;
justify-content: flex-end;
.item-control {
display: inline-flex;
align-items: center;
justify-content: center;
width: 20px;
height: 20px;
color: #5a3a1a;
text-decoration: none;
cursor: pointer;
border-radius: 3px;
transition: all 0.2s;
&:hover {
color: #2a1a0a;
background: rgba(139, 69, 19, 0.2);
transform: scale(1.1);
}
i {
font-size: 0.85rem;
}
&.item-edit {
color: #4a7c59;
&:hover {
color: #2d5a3a;
background: rgba(74, 124, 89, 0.2);
}
}
&.item-delete {
color: #a04040;
&:hover {
color: #802020;
background: rgba(160, 64, 64, 0.2);
}
}
&.item-equip {
color: #6b5b3a;
&:hover {
color: #4a3a1a;
background: rgba(107, 91, 58, 0.2);
}
i.fa-circle {
color: #4a7c59;
}
i.fa-genderless {
color: #8a6a4a;
}
}
&.item-add {
color: #4a7c59;
&:hover {
color: #2d5a3a;
background: rgba(74, 124, 89, 0.2);
}
}
}
}
.item-controls-fixed {
min-width: 3.2rem;
max-width: 3.2rem;
}
// Couleurs pour les labels et textes dans les onglets
h4, h3, label, span.item-name-label, span.competence-name,
.label-name, .generic-label, .item-field-label-short,
.item-field-label-medium, .item-field-label-long,
.short-label, .items-title-text {
color: #3a2a1a !important;
text-shadow: 0px 0px 1px rgba(255, 255, 255, 0.3);
}
// Inputs dans le corps
input[type="text"], input[type="number"], select {
color: #2a1a0a;
background: rgba(255, 250, 240, 0.8);
border: 1px solid rgba(139, 69, 19, 0.5);
height: 24px;
padding: 0.15rem 0.3rem;
line-height: 1.2;
&:focus {
background: rgba(255, 255, 245, 0.95);
border-color: rgba(139, 69, 19, 0.8);
}
}
// Titres de sections
h3, h4 {
font-weight: bold;
color: #2a1a0a !important;
}
// Titres de sections Santé, Âme, Combat
h4.item-name-label.competence-name {
font-size: 0.85rem;
margin-top: 0.2rem;
margin-bottom: 0.3rem;
padding-top: 0;
}
// Section grids pour Santé, Âme, Combat
.section-grid {
display: flex;
flex-direction: column;
gap: 0.2rem;
padding: 0.3rem 0.4rem;
margin-bottom: 0.3rem;
background: rgba(0, 0, 0, 0.15);
border: 2px solid rgba(139, 69, 19, 0.5);
border-radius: 4px;
.section-title {
font-size: 0.85rem;
font-weight: bold;
color: #f5e6d3;
text-transform: uppercase;
letter-spacing: 0.5px;
margin: 0 0 0.2rem 0;
padding: 0.2rem 0.4rem;
background: rgba(0, 0, 0, 0.3);
border-left: 3px solid rgba(139, 69, 19, 0.8);
border-radius: 2px;
text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.9);
}
.grid-row {
display: grid;
grid-template-columns: 1fr 1fr;
align-items: center;
gap: 0.4rem;
padding: 0.25rem 0.4rem;
background: rgba(0, 0, 0, 0.2);
border: 1px solid rgba(139, 69, 19, 0.4);
border-radius: 3px;
input {
width: 60px;
min-width: 60px;
}
&.attr-row {
grid-template-columns: 40px 1fr auto;
gap: 0.5rem;
.item-name-img {
width: 32px;
height: 32px;
border-radius: 3px;
border: 1px solid rgba(139, 69, 19, 0.5);
}
.label-name {
display: flex;
align-items: center;
a {
color: #f5e6d3;
text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.7);
font-weight: 600;
cursor: pointer;
&:hover {
color: #fff;
text-shadow: 0 0 4px rgba(255, 200, 100, 0.8);
}
}
}
select {
width: 80px;
}
}
.label-name {
font-weight: 600;
font-size: 0.9rem;
color: #d4c5b0;
text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.7);
}
.stat-label {
font-weight: 600;
font-size: 0.9rem;
color: #d4c5b0;
text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.7);
}
.value-display {
text-align: center;
font-weight: bold;
font-size: 1rem;
color: #fff;
background: rgba(0, 0, 0, 0.4);
padding: 0.2rem 0.4rem;
border-radius: 3px;
border: 1px solid rgba(139, 69, 19, 0.6);
text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.9);
}
.malus-value {
text-align: center;
font-weight: bold;
font-size: 1rem;
color: #ff9999;
background: rgba(0, 0, 0, 0.4);
padding: 0.2rem 0.4rem;
border-radius: 3px;
border: 1px solid rgba(200, 50, 50, 0.6);
text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.9);
}
&.damage-row {
grid-template-columns: 120px 1fr;
.damage-label {
font-size: 0.95rem;
font-weight: 600;
}
.damage-controls {
display: flex;
align-items: center;
justify-content: center;
gap: 0.4rem;
input {
width: 60px;
min-width: 60px;
flex-shrink: 0;
text-align: center;
font-size: 1.1rem;
font-weight: bold;
}
.plus-minus-button {
width: 30px;
height: 30px;
display: flex;
align-items: center;
justify-content: center;
font-size: 1.2rem;
font-weight: bold;
border-radius: 4px;
border: 2px solid rgba(139, 69, 19, 0.5);
background: linear-gradient(to bottom, rgba(210, 180, 140, 0.9), rgba(180, 150, 110, 0.9));
color: #2a1a0a;
cursor: pointer;
transition: all 0.15s;
&:hover {
background: linear-gradient(to bottom, rgba(230, 200, 160, 0.95), rgba(200, 170, 130, 0.95));
border-color: rgba(139, 69, 19, 0.8);
transform: scale(1.08);
}
&:active {
transform: scale(0.95);
}
}
}
}
&.soul-consumed-row {
grid-template-columns: 120px 1fr;
}
&.soul-malus-row {
grid-template-columns: 90px 1fr;
gap: 0.4rem;
.label-name {
font-size: 0.85rem;
}
.malus-value {
font-size: 0.9rem;
padding: 0.2rem 0.3rem;
}
}
&.malus-row {
grid-template-columns: 55px 60px 75px 50px;
gap: 0.3rem;
.label-name {
font-size: 0.85rem;
}
input {
width: 100%;
min-width: unset;
}
.malus-value {
font-size: 0.9rem;
padding: 0.2rem 0.3rem;
}
}
}
&.combat-grid {
.grid-row.combat-stat {
grid-template-columns: 85px 50px 60px 55px;
gap: 0.4rem;
.stat-label {
font-size: 0.85rem;
}
.stat-base {
text-align: center;
font-weight: bold;
font-size: 0.85rem;
color: #fff;
background: rgba(0, 0, 0, 0.4);
padding: 0.2rem 0.3rem;
border-radius: 3px;
border: 1px solid rgba(139, 69, 19, 0.6);
text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.9);
}
input {
width: 50px;
min-width: 50px;
text-align: center;
}
.stat-total {
text-align: center;
font-weight: bold;
font-size: 0.85rem;
color: #fff;
background: rgba(0, 0, 0, 0.4);
padding: 0.2rem 0.3rem;
border-radius: 3px;
border: 1px solid rgba(139, 69, 19, 0.6);
text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.9);
}
}
.grid-row.protection-row {
grid-template-columns: 1fr 1fr;
.protection-value {
text-align: center;
font-weight: bold;
font-size: 1.2rem;
color: #fff;
background: rgba(0, 0, 0, 0.4);
padding: 0.25rem 0.4rem;
border-radius: 3px;
border: 1px solid rgba(139, 69, 19, 0.6);
text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.9);
}
}
}
}
// Boutons d'actions spéciales
.action-buttons {
display: flex;
flex-direction: column;
gap: 0.3rem;
padding: 0.3rem 0;
button {
margin: 0;
}
}
.action-buttons-row {
display: flex;
flex-direction: row;
align-items: center;
gap: 0.5rem;
padding: 0.3rem 0;
button {
margin: 0;
flex: 1;
}
.mounted-checkbox {
display: flex;
align-items: center;
gap: 0.4rem;
padding: 0.3rem 0.6rem;
white-space: nowrap;
label {
margin: 0;
font-size: 0.9rem;
}
input[type="checkbox"] {
margin: 0;
cursor: pointer;
}
}
}
}
}
/* ==================== Creature Sheet Specific Styles ==================== */
.fvtt-mournblade.actor.creature-sheet {
// Variant background pour creatures - teinte légèrement différente
.background-sheet-header-creature {
background: linear-gradient(135deg, rgba(0, 60, 0, 0.15) 0%, rgba(20, 80, 20, 0.1) 100%);
border: 2px solid rgba(34, 139, 34, 0.5);
border-radius: 4px;
padding: 0;
}
// Légère teinte verte pour les sections
.sheet-box {
&.color-bg-archetype {
background: linear-gradient(135deg, rgba(0, 40, 0, 0.08) 0%, rgba(20, 60, 20, 0.05) 100%);
}
}
// Header simplifié pour creatures
.sheet-header {
flex: 0 0 auto !important;
padding: 0;
}
.profile-img {
width: 80px;
height: 80px;
border-radius: 8px;
border: 2px solid rgba(34, 139, 34, 0.6);
object-fit: cover;
cursor: pointer;
flex-shrink: 0;
}
// Tabs avec teinte verte
nav.tabs {
.item.active {
border-bottom-color: rgba(34, 139, 34, 0.8);
color: #228b22;
}
}
// Section titles avec teinte verte
.section-title {
color: #1a5a1a;
border-bottom-color: rgba(34, 139, 34, 0.3);
}
// Items headers
.items-title-bg {
background: linear-gradient(135deg, rgba(0, 60, 0, 0.15) 0%, rgba(20, 80, 20, 0.1) 100%);
border-bottom: 1px solid rgba(34, 139, 34, 0.3);
}
}
// PNJ Sheet - Orange/Copper theme for visual distinction
.fvtt-mournblade.actor.pnj-sheet {
// Variant background pour PNJs - teinte orange/cuivre
.background-sheet-header-creature {
background: linear-gradient(135deg, rgba(80, 40, 0, 0.15) 0%, rgba(100, 50, 0, 0.1) 100%);
border: 2px solid rgba(205, 127, 50, 0.5);
border-radius: 4px;
padding: 0;
}
// Légère teinte orange/cuivre pour les sections
.sheet-box {
&.color-bg-archetype {
background: linear-gradient(135deg, rgba(60, 30, 0, 0.08) 0%, rgba(80, 40, 0, 0.05) 100%);
}
}
// Header simplifié pour PNJs
.sheet-header {
flex: 0 0 auto !important;
padding: 0;
}
.profile-img {
width: 80px;
height: 80px;
border-radius: 8px;
border: 2px solid rgba(205, 127, 50, 0.6);
object-fit: cover;
cursor: pointer;
flex-shrink: 0;
}
// Tabs avec teinte orange/cuivre
nav.tabs {
.item.active {
border-bottom-color: rgba(205, 127, 50, 0.8);
color: #cd7f32;
}
}
// Section titles avec teinte orange/cuivre
.section-title {
color: #b8734d;
border-bottom-color: rgba(205, 127, 50, 0.3);
}
// Items headers
.items-title-bg {
background: linear-gradient(135deg, rgba(80, 40, 0, 0.15) 0%, rgba(100, 50, 0, 0.1) 100%);
border-bottom: 1px solid rgba(205, 127, 50, 0.3);
}
}
// GM Tools section - labels plus larges
.gm-tools-section {
.grid {
.item-list .flexrow.item {
.label-name {
flex: 1;
min-width: 12rem;
}
}
}
}
// Alignment group in header
.stat-group-alignment {
.stat-values.alignment-values {
display: flex;
flex-direction: column;
gap: 0.3rem;
}
.alignment-row {
display: flex;
align-items: center;
gap: 0.3rem;
.alignment-label {
font-weight: bold;
min-width: 4rem;
font-size: 0.85rem;
}
.alignment-inputs {
display: flex;
align-items: center;
gap: 0.2rem;
flex: 1;
}
.stat-label-mini {
font-size: 0.7rem;
min-width: 2.5rem;
}
.stat-input-mini {
width: 2.5rem;
height: 1.5rem;
padding: 0.1rem 0.2rem;
font-size: 0.8rem;
}
select.stat-input-mini {
width: 3rem;
}
}
.alignment-info {
display: flex;
justify-content: space-around;
margin-top: 0.2rem;
padding-top: 0.2rem;
border-top: 1px solid rgba(139, 69, 19, 0.3);
.info-label {
font-size: 0.75rem;
color: #f5e6d3;
strong {
color: #ffd700;
}
}
}
}

299
less/item-styles.less Normal file
View File

@@ -0,0 +1,299 @@
/* ==================== Item Sheet Styles ==================== */
/* Item header with image and name */
.fvtt-mournblade.item {
/* Background pour toute la fiche d'item */
background: url("../assets/ui/pc_sheet_bg.webp") repeat;
display: flex;
flex-direction: column;
height: 100%;
padding: 0;
margin: 0;
/* AppV2 - Remove window content padding */
.window-content {
padding: 0;
margin: 0;
}
/* AppV2 - Main section structure */
section {
background: url("../assets/ui/pc_sheet_bg.webp") repeat-y;
color: black;
display: flex;
flex-direction: column;
height: 100%;
overflow: hidden;
padding: 0;
margin: 0;
}
/* AppV2 Item Sheets - Disabled inputs readability */
input:disabled,
select:disabled {
color: #000000;
opacity: 0.8;
background-color: rgba(255, 255, 255, 0.5);
}
/* Inputs and selects styling */
input[type="text"],
input[type="number"],
select {
color: #000000;
background-color: rgba(255, 255, 255, 0.7);
border: 1px solid #999999;
margin: 0;
padding: 2px 4px;
font-family: "CentaurMT", serif;
font-size: 0.85rem;
}
textarea {
margin: 0;
padding: 2px 4px;
}
input[type="checkbox"] {
width: auto;
height: auto;
margin: 0 4px;
align-self: center;
}
.header {
flex: 0 0 auto;
border-bottom: 1px solid #999;
margin: 0;
}
.sheet-header {
display: flex;
flex-direction: row;
align-items: center;
gap: 1rem;
padding: 0.5rem;
background: url("../assets/ui/pc_sheet_bg.webp") repeat;
flex: 0 0 auto;
}
.item-sheet-img {
flex: 0 0 64px;
width: 64px;
height: 64px;
object-fit: cover;
border: 1px solid #999;
border-radius: 4px;
cursor: pointer;
&:hover {
box-shadow: 0 0 8px rgba(255, 102, 0, 0.8);
}
}
.header-fields {
flex: 1;
display: flex;
flex-direction: column;
gap: 0.25rem;
}
.header-actions {
flex: 0 0 auto;
display: flex;
align-items: center;
gap: 0.5rem;
button {
background: rgba(0, 0, 0, 0.1);
border: 1px solid #999;
padding: 0.25rem 0.5rem;
cursor: pointer;
font-family: "CentaurMT", serif;
&:hover {
background: rgba(255, 102, 0, 0.2);
box-shadow: 0 0 5px rgba(255, 102, 0, 0.5);
}
}
.chat-card-button {
background: linear-gradient(to bottom, #21374afc 5%, #152833ab 100%);
border: 2px ridge #846109;
color: #d4b5a8;
padding: 0.3rem 0.5rem;
transition: all 0.2s ease;
i {
font-size: 0.9rem;
}
&:hover {
background: linear-gradient(to bottom, #800000 5%, #3e0101 100%);
color: #ffffff;
box-shadow: 0 0 8px rgba(128, 0, 0, 0.6);
}
&:active {
position: relative;
top: 1px;
}
}
}
.sheet-header h1.charname {
height: 50px;
padding: 0;
margin: 5px 0;
border-bottom: 0;
font-weight: bold;
font-size: 2rem;
font-family: "CentaurMT";
}
.sheet-header h1.charname input {
width: 100%;
height: 100%;
margin: 0;
font-weight: bold;
font-family: "CentaurMT";
font-size: 2rem;
text-align: left;
border: 0 none;
&:focus {
outline: 1px solid #ff6600;
}
}
/* Tabs - Modern style matching actor sheets */
nav.tabs {
display: flex;
border-bottom: 1px solid #7a7971;
margin: 0;
padding: 4px;
background-color: #1c1c1c;
flex: 0 0 auto;
}
nav.tabs a.item {
padding: 6px 12px;
color: #d4af37;
text-decoration: none;
border: 1px solid transparent;
border-radius: 4px 4px 0 0;
margin-right: 4px;
transition: all 0.2s;
i {
display: none; // Hide icons to match actor sheets
}
&:hover {
background-color: rgba(212, 175, 55, 0.1);
}
&.active {
background-color: #2a2a2a;
border-bottom-color: #d4af37;
color: #f5f5f5;
}
}
/* Tab content */
.tab {
display: none;
padding: 4px 8px;
overflow-y: auto;
flex: 1 1 auto;
&.active {
display: block;
}
}
/* Item list in details tab */
.item-list {
list-style: none;
margin: 0;
padding: 0;
li.item {
display: flex;
align-items: center;
margin-bottom: 2px;
padding: 2px 4px;
min-height: 24px;
border-bottom: none;
&.flexrow {
display: flex;
flex-direction: row;
align-items: center;
gap: 4px;
}
}
}
/* Labels */
.generic-label {
display: inline-block;
white-space: nowrap;
font-weight: 700;
color: #464331c4;
font-size: 0.9rem;
font-family: "CentaurMT", serif;
margin: 0;
padding: 0 4px 0 0;
}
/* Field labels */
.item-field-label-short {
flex: 0 0 60px;
max-width: 60px;
}
.item-field-label-medium {
flex: 0 0 100px;
max-width: 100px;
}
.item-field-label-long {
flex: 1;
min-width: 150px;
}
.item-field-label-long1 {
flex: 1;
min-width: 200px;
}
.item-field-label-long2 {
flex: 1;
min-width: 250px;
max-width: 250px;
}
.item-field-label-long3 {
flex: 1;
min-width: 350px;
max-width: 350px;
}
.numeric-input {
text-align: center;
width: 60px;
}
/* Editor fields */
.editor {
height: 300px;
border: 1px solid #999;
background: rgba(255, 255, 255, 0.9);
.editor-content {
height: 100%;
padding: 0.5rem;
color: #000;
}
}
}

6
less/mournblade.less Normal file
View File

@@ -0,0 +1,6 @@
// Main LESS file for Mournblade system
// Importing base styles and component-specific styles
@import "simple-converted";
@import "item-styles";
@import "actor-styles";

2476
less/simple-converted.less Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,13 +1,13 @@
/**
* Extend the basic ActorSheet with some very simple modifications
* @extends {ActorSheet}
* @extends {ActorSheetV2}
*/
import { MournbladeUtility } from "./mournblade-utility.js";
import { MournbladeRollDialog } from "./mournblade-roll-dialog.js";
/* -------------------------------------------- */
export class MournbladeActorSheet extends foundry.appv1.sheets.ActorSheet {
export class MournbladeActorSheet extends foundry.applications.sheets.ActorSheetV2 {
/** @override */
static get defaultOptions() {

View File

@@ -0,0 +1,158 @@
import { MournbladeUtility } from "../mournblade-utility.js"
/**
* Dialogue de jet de dé pour Mournblade - Version DialogV2
*/
export class MournbladeRollDialog {
/**
* Create and display the roll dialog
* @param {MournbladeActor} actor - The actor making the roll
* @param {Object} rollData - Data for the roll
* @returns {Promise<MournbladeRollDialog>}
*/
static async create(actor, rollData) {
// Préparer le contexte pour le template
const context = {
...rollData,
difficulte: String(rollData.difficulte || 0),
img: actor.img,
name: actor.name,
config: game.system.mournblade.config,
}
// Si attrKey est "tochoose", préparer la liste des attributs sélectionnables
if (rollData.attrKey === "tochoose") {
context.selectableAttributes = actor.system.attributs
}
// Rendre le template en HTML
const content = await foundry.applications.handlebars.renderTemplate(
"systems/fvtt-mournblade/templates/roll-dialog-v2.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: ["mournblade-roll-dialog"],
position: { width: 500 },
modal: false,
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 = "1d10"
MournbladeUtility.rollMournblade(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 = "1d20"
MournbladeUtility.rollMournblade(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 {MournbladeActor} actor - L'acteur pour récupérer les attributs
* @private
*/
static _updateRollDataFromForm(rollData, formElements, actor) {
// Attributs
if (formElements.attrKey) {
rollData.attrKey = formElements.attrKey.value
if (rollData.attrKey !== "tochoose" && actor) {
rollData.attr = foundry.utils.duplicate(actor.system.attributs[rollData.attrKey])
rollData.actionImg = "systems/fvtt-mournblade/assets/icons/" + actor.system.attributs[rollData.attrKey].labelnorm + ".webp"
}
}
// Modificateurs de base
if (formElements.difficulte) {
rollData.difficulte = Number(formElements.difficulte.value)
}
if (formElements.modificateur) {
rollData.modificateur = Number(formElements.modificateur.value)
}
// Runes
if (formElements.runemode) {
rollData.runemode = String(formElements.runemode.value)
}
if (formElements.runeame) {
rollData.runeame = Number(formElements.runeame.value)
}
// Combat mêlée
if (formElements.typeAttaque) {
rollData.typeAttaque = String(formElements.typeAttaque.value)
}
if (formElements.isMonte !== undefined) {
rollData.isMonte = formElements.isMonte.checked
}
// Combat distance
if (formElements.visee !== undefined) {
rollData.visee = formElements.visee.checked
}
if (formElements.cibleconsciente !== undefined) {
rollData.cibleconsciente = formElements.cibleconsciente.checked
}
if (formElements.ciblecourt !== undefined) {
rollData.ciblecourt = formElements.ciblecourt.checked
}
if (formElements.typeCouvert) {
rollData.typeCouvert = String(formElements.typeCouvert.value)
}
// Désavantages
if (!rollData.desavantages) rollData.desavantages = {}
if (formElements.cibleausol !== undefined) {
rollData.desavantages.cibleausol = formElements.cibleausol.checked
}
if (formElements.cibledesarmee !== undefined) {
rollData.desavantages.cibledesarmee = formElements.cibledesarmee.checked
}
if (formElements.ciblerestreint !== undefined) {
rollData.desavantages.ciblerestreint = formElements.ciblerestreint.checked
}
if (formElements.cibleimmobilisée !== undefined) {
rollData.desavantages.cibleimmobilisée = formElements.cibleimmobilisée.checked
}
if (formElements.ciblesurplomb !== undefined) {
rollData.desavantages.ciblesurplomb = formElements.ciblesurplomb.checked
}
// Double D20
if (formElements.doubleD20 !== undefined) {
rollData.doubleD20 = formElements.doubleD20.checked
}
// Modifiers
if (rollData.modifiers) {
rollData.modifiers.forEach((modifier, idx) => {
const checkbox = formElements[`apply-modifier-${idx}`]
if (checkbox) {
modifier.system.apply = checkbox.checked
}
})
}
}
}

View File

@@ -0,0 +1,29 @@
/**
* Index des applications AppV2 pour Mournblade
* Ce fichier centralise tous les exports des applications
*/
// Applications de feuilles d'acteurs
export { default as MournbladePersonnageSheet } from './mournblade-personnage-sheet.mjs';
export { default as MournbladeCreatureSheet } from './mournblade-creature-sheet.mjs';
export { default as MournbladePnjSheet } from './mournblade-pnj-sheet.mjs';
// Applications de feuilles d'items
export { default as MournbladeArmeSheet } from './mournblade-arme-sheet.mjs';
export { default as MournbladeBouclierSheet } from './mournblade-bouclier-sheet.mjs';
export { default as MournbladeCapaciteSheet } from './mournblade-capacite-sheet.mjs';
export { default as MournbladeCompetenceSheet } from './mournblade-competence-sheet.mjs';
export { default as MournbladeDonSheet } from './mournblade-don-sheet.mjs';
export { default as MournbladeEquipementSheet } from './mournblade-equipement-sheet.mjs';
export { default as MournbladeHeritageSheet } from './mournblade-heritage-sheet.mjs';
export { default as MournbladeMetierSheet } from './mournblade-metier-sheet.mjs';
export { default as MournbladeModifierSheet } from './mournblade-modifier-sheet.mjs';
export { default as MournbladeMonnaieSheet } from './mournblade-monnaie-sheet.mjs';
export { default as MournbladeOrigineSheet } from './mournblade-origine-sheet.mjs';
export { default as MournbladePacteSheet } from './mournblade-pacte-sheet.mjs';
export { default as MournbladeProtectionSheet } from './mournblade-protection-sheet.mjs';
export { default as MournbladeRuneSheet } from './mournblade-rune-sheet.mjs';
export { default as MournbladeRuneEffectSheet } from './mournblade-runeeffect-sheet.mjs';
export { default as MournbladeTendanceSheet } from './mournblade-tendance-sheet.mjs';
export { default as MournbladeTraitChaotiqueSheet } from './mournblade-traitchaotique-sheet.mjs';
export { default as MournbladeTraitEspeceSheet } from './mournblade-traitespece-sheet.mjs';

View File

@@ -0,0 +1,406 @@
const { HandlebarsApplicationMixin } = foundry.applications.api
import { MournbladeUtility } from "../../mournblade-utility.js"
export default class MournbladeActorSheet 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-mournblade", "sheet", "actor"],
position: {
width: 650,
height: 720,
},
form: {
submitOnChange: true,
closeOnSubmit: false,
},
window: {
resizable: true,
},
tabs: [
{
navSelector: 'nav[data-group="primary"]',
contentSelector: "section.sheet-body",
initial: "stats",
},
],
dragDrop: [{ dragSelector: ".item-list .item", dropSelector: null }],
actions: {
editImage: MournbladeActorSheet.#onEditImage,
toggleSheet: MournbladeActorSheet.#onToggleSheet,
editItem: MournbladeActorSheet.#onEditItem,
deleteItem: MournbladeActorSheet.#onDeleteItem,
createItem: MournbladeActorSheet.#onCreateItem,
equipItem: MournbladeActorSheet.#onEquipItem,
modifyQuantity: MournbladeActorSheet.#onModifyQuantity,
modifySante: MournbladeActorSheet.#onModifySante,
modifyAme: MournbladeActorSheet.#onModifyAme,
rollAttribut: MournbladeActorSheet.#onRollAttribut,
rollCompetence: MournbladeActorSheet.#onRollCompetence,
rollRune: MournbladeActorSheet.#onRollRune,
rollArmeOffensif: MournbladeActorSheet.#onRollArmeOffensif,
rollArmeSpecial: MournbladeActorSheet.#onRollArmeSpecial,
rollArmeDegats: MournbladeActorSheet.#onRollArmeDegats,
rollAssommer: MournbladeActorSheet.#onRollAssommer,
rollImmobiliser: MournbladeActorSheet.#onRollImmobiliser,
rollFuir: MournbladeActorSheet.#onRollFuir,
},
}
/**
* Is the sheet currently in 'Play' mode?
* @type {boolean}
*/
get isPlayMode() {
if (this._sheetMode === undefined) this._sheetMode = this.constructor.SHEET_MODES.PLAY
return this._sheetMode === this.constructor.SHEET_MODES.PLAY
}
/**
* Is the sheet currently in 'Edit' mode?
* @type {boolean}
*/
get isEditMode() {
if (this._sheetMode === undefined) this._sheetMode = this.constructor.SHEET_MODES.PLAY
return this._sheetMode === this.constructor.SHEET_MODES.EDIT
}
/**
* Tab groups state
* @type {object}
*/
tabGroups = { primary: "stats" }
/** @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: game.system.mournblade.config,
enrichedDescription: await foundry.applications.ux.TextEditor.implementation.enrichHTML(actor.system.biodata?.description || "", { async: true }),
}
return context
}
/** @override */
_onRender(context, options) {
super._onRender(context, options)
this.#dragDrop.forEach((d) => d.bind(this.element))
// Handle edit-item-data changes
this.element.querySelectorAll('.edit-item-data').forEach(element => {
element.addEventListener('change', async (event) => {
const target = event.currentTarget
const itemElement = target.closest('[data-item-id]')
if (!itemElement) return
const itemId = itemElement.dataset.itemId
const itemType = itemElement.dataset.itemType
const itemField = target.dataset.itemField
const dataType = target.dataset.dtype
const value = target.value
await this.document.editItemField(itemId, itemType, itemField, dataType, value)
})
})
// 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] || "stats"
nav.querySelectorAll('[data-tab]').forEach(link => {
const tab = link.dataset.tab
link.classList.toggle('active', tab === activeTab)
link.addEventListener('click', (event) => {
event.preventDefault()
this.tabGroups[group] = tab
this.render()
})
})
// 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
*/
#createDragDropHandlers() {
return []
}
// #region Actions
/** @override */
static ACTIONS = {
editImage: MournbladeActorSheet.#onEditImage,
toggleSheet: MournbladeActorSheet.#onToggleSheet,
editItem: MournbladeActorSheet.#onEditItem,
deleteItem: MournbladeActorSheet.#onDeleteItem,
createItem: MournbladeActorSheet.#onCreateItem,
equipItem: MournbladeActorSheet.#onEquipItem,
modifyQuantity: MournbladeActorSheet.#onModifyQuantity,
rollAttribut: MournbladeActorSheet.#onRollAttribut,
rollCompetence: MournbladeActorSheet.#onRollCompetence,
rollArmeOffensif: MournbladeActorSheet.#onRollArmeOffensif,
rollArmeDegats: MournbladeActorSheet.#onRollArmeDegats,
rollAssommer: MournbladeActorSheet.#onRollAssommer,
rollImmobiliser: MournbladeActorSheet.#onRollImmobiliser,
rollFuir: MournbladeActorSheet.#onRollFuir,
}
/**
* Handle editing the actor image
* @param {Event} event - The triggering event
*/
static async #onEditImage(event) {
event.preventDefault()
const sheet = this
const filePicker = new FilePicker({
type: "image",
current: sheet.document.img,
callback: (path) => {
sheet.document.update({ img: path })
},
})
filePicker.browse()
}
/**
* Handle toggling the sheet mode
* @param {Event} event - The triggering event
*/
static async #onToggleSheet(event) {
event.preventDefault()
const sheet = this
sheet._sheetMode = sheet._sheetMode === sheet.constructor.SHEET_MODES.PLAY ? sheet.constructor.SHEET_MODES.EDIT : sheet.constructor.SHEET_MODES.PLAY
sheet.render()
}
/**
* Handle editing an item
* @param {Event} event - The triggering event
* @param {HTMLElement} target - The target element
*/
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)
}
/**
* Handle deleting an item
* @param {Event} event - The triggering event
* @param {HTMLElement} target - The target element
*/
static async #onDeleteItem(event, target) {
const li = target.closest(".item")
await MournbladeUtility.confirmDelete(this, li)
}
/**
* Handle creating an item
* @param {Event} event - The triggering event
* @param {HTMLElement} target - The target element
*/
static async #onCreateItem(event, target) {
const itemType = target.dataset.type
await this.actor.createEmbeddedDocuments("Item", [{ name: `Nouveau ${itemType}`, type: itemType }], { renderSheet: true })
}
/**
* Handle equipping an item
* @param {Event} event - The triggering event
* @param {HTMLElement} target - The target element
*/
static async #onEquipItem(event, target) {
const li = target.closest(".item")
const itemId = li?.dataset.itemId
if (!itemId) return
const item = this.actor.items.get(itemId)
if (item) {
await item.update({ "system.equipped": !item.system.equipped })
}
}
/**
* Handle modifying the quantity of an item
* @param {Event} event - The triggering event
* @param {HTMLElement} target - The target element
*/
static async #onModifyQuantity(event, target) {
const li = target.closest('[data-item-id]')
const itemId = li?.dataset.itemId
const value = Number.parseInt(target.dataset.quantiteValue)
const item = this.document.items.get(itemId)
if (item) {
const newQuantity = Math.max(0, (item.system.quantite || 0) + value)
await item.update({ "system.quantite": newQuantity })
}
}
/**
* Handle modifying santé (health) values
* @param {Event} event - The triggering event
* @param {HTMLElement} target - The target element
*/
static async #onModifySante(event, target) {
const type = target.dataset.type
const value = Number.parseInt(target.dataset.value)
const actor = this.document
const currentValue = actor.system.sante[type] || 0
const newValue = Math.max(0, currentValue + value)
await actor.update({ [`system.sante.${type}`]: newValue })
}
/**
* Handle modifying âme (soul) value
* @param {Event} event - The triggering event
* @param {HTMLElement} target - The target element
*/
static async #onModifyAme(event, target) {
const value = Number.parseInt(target.dataset.value)
const actor = this.document
const currentValue = actor.system.ame.value || 0
const newValue = Math.max(0, currentValue + value)
await actor.update({ "system.ame.value": newValue })
}
/**
* Handle rolling an attribut
* @param {Event} event - The triggering event
*/
static async #onRollAttribut(event, target) {
event.preventDefault()
const sheet = this
const attrKey = target.dataset.attrKey
const actor = sheet.document
await actor.rollAttribut(attrKey)
}
/**
* Handle rolling a competence
* @param {Event} event - The triggering event
*/
static async #onRollCompetence(event, target) {
event.preventDefault()
const sheet = this
const attrKey = target.dataset.attrKey
const li = target.closest('[data-item-id]')
const compId = li?.dataset.itemId
const actor = sheet.document
await actor.rollCompetence(attrKey, compId)
}
/**
* Handle rolling a rune
* @param {Event} event - The triggering event
*/
static async #onRollRune(event, target) {
event.preventDefault()
const sheet = this
const li = target.closest('[data-item-id]')
const runeId = li?.dataset.itemId
const actor = sheet.document
await actor.rollRune(runeId)
}
/**
* Handle rolling an arme offensif
* @param {Event} event - The triggering event
*/
static async #onRollArmeOffensif(event, target) {
event.preventDefault()
const sheet = this
const armeId = target.dataset.armeId
const actor = sheet.document
await actor.rollArmeOffensif(armeId)
}
/**
* Handle rolling an arme degats
* @param {Event} event - The triggering event
*/
static async #onRollArmeDegats(event, target) {
event.preventDefault()
const sheet = this
const armeId = target.dataset.armeId
const actor = sheet.document
await actor.rollArmeDegats(armeId)
}
/**
* Handle rolling an arme special
* @param {Event} event - The triggering event
*/
static async #onRollArmeSpecial(event, target) {
event.preventDefault()
const sheet = this
const armeId = target.dataset.armeId
const actor = sheet.document
await actor.rollArmeSpecial(armeId)
}
/**
* Handle rolling an assommer
* @param {Event} event - The triggering event
*/
static async #onRollAssommer(event, target) {
event.preventDefault()
const sheet = this
const actor = sheet.document
await actor.rollAssomer()
}
/**
* Handle rolling an immobiliser
* @param {Event} event - The triggering event
*/
static async #onRollImmobiliser(event, target) {
event.preventDefault()
const sheet = this
const actor = sheet.document
await actor.rollImmobiliser()
}
/**
* Handle rolling a fuir
* @param {Event} event - The triggering event
*/
static async #onRollFuir(event, target) {
event.preventDefault()
const sheet = this
const actor = sheet.document
await actor.rollFuir()
}
}

View File

@@ -0,0 +1,142 @@
const { HandlebarsApplicationMixin } = foundry.applications.api
export default class MournbladeItemSheet extends HandlebarsApplicationMixin(foundry.applications.sheets.ItemSheetV2) {
constructor(options = {}) {
super(options)
this.#dragDrop = this.#createDragDropHandlers()
}
#dragDrop
/** @override */
static DEFAULT_OPTIONS = {
classes: ["fvtt-mournblade", "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: MournbladeItemSheet.#onEditImage,
postItem: MournbladeItemSheet.#onPostItem,
},
}
/**
* Tab groups state
* @type {object}
*/
tabGroups = { primary: "description" }
/** @override */
async _prepareContext() {
const context = {
fields: this.document.schema.fields,
systemFields: this.document.system.schema.fields,
item: this.document,
system: this.document.system,
source: this.document.toObject(),
enrichedDescription: await foundry.applications.ux.TextEditor.implementation.enrichHTML(this.document.system.description, { async: true }),
isEditMode: true,
isEditable: this.isEditable,
isGM: game.user.isGM,
config: game.system.mournblade.config,
}
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
*/
#createDragDropHandlers() {
return []
}
// #region Actions
/**
* Handle editing the item image
* @param {Event} event - The triggering event
*/
static async #onEditImage(event) {
event.preventDefault()
const filePicker = new FilePicker({
type: "image",
current: this.document.img,
callback: (path) => {
this.document.update({ img: path })
},
})
filePicker.browse()
}
/**
* Handle posting the item to chat
* @param {Event} event - The triggering event
*/
static async #onPostItem(event) {
event.preventDefault()
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-mournblade/templates/post-item.hbs', chatData)
const chatOptions = {
user: game.user.id,
content: html,
}
ChatMessage.create(chatOptions)
}
}

View File

@@ -0,0 +1,49 @@
import MournbladeItemSheet from "./base-item-sheet.mjs"
export default class MournbladeArmeSheet extends MournbladeItemSheet {
/** @override */
static DEFAULT_OPTIONS = {
classes: ["arme"],
position: {
width: 620,
},
window: {
contentClasses: ["arme-content"],
},
}
/** @override */
static PARTS = {
main: {
template: "systems/fvtt-mournblade/templates/item-arme-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()
return context
}
}

View File

@@ -0,0 +1,49 @@
import MournbladeItemSheet from "./base-item-sheet.mjs"
export default class MournbladeBouclierSheet extends MournbladeItemSheet {
/** @override */
static DEFAULT_OPTIONS = {
classes: ["bouclier"],
position: {
width: 620,
},
window: {
contentClasses: ["bouclier-content"],
},
}
/** @override */
static PARTS = {
main: {
template: "systems/fvtt-mournblade/templates/item-bouclier-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()
return context
}
}

View File

@@ -0,0 +1,49 @@
import MournbladeItemSheet from "./base-item-sheet.mjs"
export default class MournbladeCapaciteSheet extends MournbladeItemSheet {
/** @override */
static DEFAULT_OPTIONS = {
classes: ["capacite"],
position: {
width: 620,
},
window: {
contentClasses: ["capacite-content"],
},
}
/** @override */
static PARTS = {
main: {
template: "systems/fvtt-mournblade/templates/item-capacite-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()
return context
}
}

View File

@@ -0,0 +1,49 @@
import MournbladeItemSheet from "./base-item-sheet.mjs"
export default class MournbladeCompetenceSheet extends MournbladeItemSheet {
/** @override */
static DEFAULT_OPTIONS = {
classes: ["competence"],
position: {
width: 620,
},
window: {
contentClasses: ["competence-content"],
},
}
/** @override */
static PARTS = {
main: {
template: "systems/fvtt-mournblade/templates/item-competence-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()
return context
}
}

View File

@@ -0,0 +1,43 @@
import MournbladeActorSheet from "./base-actor-sheet.mjs"
export default class MournbladeCreatureSheet extends MournbladeActorSheet {
/** @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-mournblade/templates/creature-sheet.hbs",
},
}
/** @override */
tabGroups = {
primary: "stats",
}
/** @override */
async _prepareContext() {
const context = await super._prepareContext()
const actor = this.document
// Add creature-specific data
context.skills = actor.getSkills()
context.armes = foundry.utils.duplicate(actor.getWeapons())
context.protections = foundry.utils.duplicate(actor.getArmors())
context.runes = foundry.utils.duplicate(actor.getRunes())
context.combat = actor.getCombatValues()
context.equipements = foundry.utils.duplicate(actor.getEquipments())
context.protectionTotal = actor.getProtectionTotal()
context.santeMalus = actor.getStatusMalus()
context.ameMalus = actor.getAmeMalus()
return context
}
}

View File

@@ -0,0 +1,50 @@
import MournbladeItemSheet from "./base-item-sheet.mjs"
export default class MournbladeDonSheet extends MournbladeItemSheet {
/** @override */
static DEFAULT_OPTIONS = {
classes: ["don"],
position: {
width: 620,
},
window: {
contentClasses: ["don-content"],
},
}
/** @override */
static PARTS = {
main: {
template: "systems/fvtt-mournblade/templates/item-don-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.enrichedSacrifice = await foundry.applications.ux.TextEditor.implementation.enrichHTML(this.document.system.sacrifice, { async: true })
return context
}
}

View File

@@ -0,0 +1,49 @@
import MournbladeItemSheet from "./base-item-sheet.mjs"
export default class MournbladeEquipementSheet extends MournbladeItemSheet {
/** @override */
static DEFAULT_OPTIONS = {
classes: ["equipement"],
position: {
width: 620,
},
window: {
contentClasses: ["equipement-content"],
},
}
/** @override */
static PARTS = {
main: {
template: "systems/fvtt-mournblade/templates/item-equipement-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()
return context
}
}

View File

@@ -0,0 +1,49 @@
import MournbladeItemSheet from "./base-item-sheet.mjs"
export default class MournbladeHeritageSheet extends MournbladeItemSheet {
/** @override */
static DEFAULT_OPTIONS = {
classes: ["heritage"],
position: {
width: 620,
},
window: {
contentClasses: ["heritage-content"],
},
}
/** @override */
static PARTS = {
main: {
template: "systems/fvtt-mournblade/templates/item-heritage-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()
return context
}
}

View File

@@ -0,0 +1,49 @@
import MournbladeItemSheet from "./base-item-sheet.mjs"
export default class MournbladeMetierSheet extends MournbladeItemSheet {
/** @override */
static DEFAULT_OPTIONS = {
classes: ["metier"],
position: {
width: 620,
},
window: {
contentClasses: ["metier-content"],
},
}
/** @override */
static PARTS = {
main: {
template: "systems/fvtt-mournblade/templates/item-metier-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()
return context
}
}

View File

@@ -0,0 +1,49 @@
import MournbladeItemSheet from "./base-item-sheet.mjs"
export default class MournbladeModifierSheet extends MournbladeItemSheet {
/** @override */
static DEFAULT_OPTIONS = {
classes: ["modifier"],
position: {
width: 620,
},
window: {
contentClasses: ["modifier-content"],
},
}
/** @override */
static PARTS = {
main: {
template: "systems/fvtt-mournblade/templates/item-modifier-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()
return context
}
}

View File

@@ -0,0 +1,49 @@
import MournbladeItemSheet from "./base-item-sheet.mjs"
export default class MournbladeMonnaieSheet extends MournbladeItemSheet {
/** @override */
static DEFAULT_OPTIONS = {
classes: ["monnaie"],
position: {
width: 620,
},
window: {
contentClasses: ["monnaie-content"],
},
}
/** @override */
static PARTS = {
main: {
template: "systems/fvtt-mournblade/templates/item-monnaie-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()
return context
}
}

View File

@@ -0,0 +1,49 @@
import MournbladeItemSheet from "./base-item-sheet.mjs"
export default class MournbladeOrigineSheet extends MournbladeItemSheet {
/** @override */
static DEFAULT_OPTIONS = {
classes: ["origine"],
position: {
width: 620,
},
window: {
contentClasses: ["origine-content"],
},
}
/** @override */
static PARTS = {
main: {
template: "systems/fvtt-mournblade/templates/item-origine-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()
return context
}
}

View File

@@ -0,0 +1,49 @@
import MournbladeItemSheet from "./base-item-sheet.mjs"
export default class MournbladePacteSheet extends MournbladeItemSheet {
/** @override */
static DEFAULT_OPTIONS = {
classes: ["pacte"],
position: {
width: 620,
},
window: {
contentClasses: ["pacte-content"],
},
}
/** @override */
static PARTS = {
main: {
template: "systems/fvtt-mournblade/templates/item-pacte-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()
return context
}
}

View File

@@ -0,0 +1,57 @@
import MournbladeActorSheet from "./base-actor-sheet.mjs"
export default class MournbladePersonnageSheet extends MournbladeActorSheet {
/** @override */
static DEFAULT_OPTIONS = {
...super.DEFAULT_OPTIONS,
classes: [...super.DEFAULT_OPTIONS.classes],
window: {
...super.DEFAULT_OPTIONS.window,
title: "SHEETS.Actor.personnage",
},
}
/** @override */
static PARTS = {
sheet: {
template: "systems/fvtt-mournblade/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.protections = foundry.utils.duplicate(actor.getArmors())
context.dons = foundry.utils.duplicate(actor.getDons())
context.pactes = foundry.utils.duplicate(actor.getPactes())
context.alignement = actor.getAlignement()
context.aspect = actor.getAspect()
context.marge = actor.getMarge()
context.tendances = foundry.utils.duplicate(actor.getTendances())
context.runes = foundry.utils.duplicate(actor.getRunes())
context.traitsChaotiques = foundry.utils.duplicate(actor.getTraitsChaotiques())
context.traitsEspeces = foundry.utils.duplicate(actor.getTraitsEspeces())
context.origine = foundry.utils.duplicate(actor.getOrigine() || {})
context.heritage = foundry.utils.duplicate(actor.getHeritage() || {})
context.metier = foundry.utils.duplicate(actor.getMetier() || {})
context.combat = actor.getCombatValues()
context.equipements = foundry.utils.duplicate(actor.getEquipments())
context.modifiers = foundry.utils.duplicate(actor.getModifiers())
context.monnaies = foundry.utils.duplicate(actor.getMonnaies())
context.runeEffects = foundry.utils.duplicate(actor.getRuneEffects())
context.protectionTotal = actor.getProtectionTotal()
context.santeMalus = actor.getStatusMalus()
context.ameMalus = actor.getAmeMalus()
return context
}
}

View File

@@ -0,0 +1,47 @@
/**
* Application de feuille de PNJ pour Mournblade
*/
import MournbladeActorSheet from "./base-actor-sheet.mjs"
export default class MournbladePnjSheet extends MournbladeActorSheet {
/** @override */
static DEFAULT_OPTIONS = {
...super.DEFAULT_OPTIONS,
classes: [...super.DEFAULT_OPTIONS.classes],
window: {
...super.DEFAULT_OPTIONS.window,
title: "SHEETS.Actor.pnj",
},
}
/** @override */
static PARTS = {
sheet: {
template: "systems/fvtt-mournblade/templates/actor-sheet.hbs",
},
}
/** @override */
tabGroups = {
primary: "principal",
}
/** @override */
async _prepareContext() {
const context = await super._prepareContext()
const actor = this.document
// Add pnj-specific data
context.skills = actor.getSkills()
context.armes = foundry.utils.duplicate(actor.getWeapons())
context.protections = foundry.utils.duplicate(actor.getArmors())
context.dons = foundry.utils.duplicate(actor.getDons())
context.pactes = foundry.utils.duplicate(actor.getPactes())
context.combat = actor.getCombatValues()
context.equipements = foundry.utils.duplicate(actor.getEquipments())
context.protectionTotal = actor.getProtectionTotal()
context.santeMalus = actor.getStatusMalus()
context.ameMalus = actor.getAmeMalus()
return context
}
}

View File

@@ -0,0 +1,49 @@
import MournbladeItemSheet from "./base-item-sheet.mjs"
export default class MournbladeProtectionSheet extends MournbladeItemSheet {
/** @override */
static DEFAULT_OPTIONS = {
classes: ["protection"],
position: {
width: 620,
},
window: {
contentClasses: ["protection-content"],
},
}
/** @override */
static PARTS = {
main: {
template: "systems/fvtt-mournblade/templates/item-protection-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()
return context
}
}

View File

@@ -0,0 +1,49 @@
import MournbladeItemSheet from "./base-item-sheet.mjs"
export default class MournbladeRuneSheet extends MournbladeItemSheet {
/** @override */
static DEFAULT_OPTIONS = {
classes: ["rune"],
position: {
width: 620,
},
window: {
contentClasses: ["rune-content"],
},
}
/** @override */
static PARTS = {
main: {
template: "systems/fvtt-mournblade/templates/item-rune-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()
return context
}
}

View File

@@ -0,0 +1,49 @@
import MournbladeItemSheet from "./base-item-sheet.mjs"
export default class MournbladeRuneEffectSheet extends MournbladeItemSheet {
/** @override */
static DEFAULT_OPTIONS = {
classes: ["runeeffect"],
position: {
width: 620,
},
window: {
contentClasses: ["runeeffect-content"],
},
}
/** @override */
static PARTS = {
main: {
template: "systems/fvtt-mournblade/templates/item-runeeffect-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()
return context
}
}

View File

@@ -0,0 +1,49 @@
import MournbladeItemSheet from "./base-item-sheet.mjs"
export default class MournbladeTendanceSheet extends MournbladeItemSheet {
/** @override */
static DEFAULT_OPTIONS = {
classes: ["tendance"],
position: {
width: 620,
},
window: {
contentClasses: ["tendance-content"],
},
}
/** @override */
static PARTS = {
main: {
template: "systems/fvtt-mournblade/templates/item-tendance-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()
return context
}
}

View File

@@ -0,0 +1,49 @@
import MournbladeItemSheet from "./base-item-sheet.mjs"
export default class MournbladeTraitChaotiqueSheet extends MournbladeItemSheet {
/** @override */
static DEFAULT_OPTIONS = {
classes: ["traitchaotique"],
position: {
width: 620,
},
window: {
contentClasses: ["traitchaotique-content"],
},
}
/** @override */
static PARTS = {
main: {
template: "systems/fvtt-mournblade/templates/item-traitchaotique-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()
return context
}
}

View File

@@ -0,0 +1,49 @@
import MournbladeItemSheet from "./base-item-sheet.mjs"
export default class MournbladeTraitEspeceSheet extends MournbladeItemSheet {
/** @override */
static DEFAULT_OPTIONS = {
classes: ["traitespece"],
position: {
width: 620,
},
window: {
contentClasses: ["traitespece-content"],
},
}
/** @override */
static PARTS = {
main: {
template: "systems/fvtt-mournblade/templates/item-traitespece-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()
return context
}
}

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

@@ -0,0 +1,27 @@
/**
* 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: "" }),
typearme: new fields.StringField({ initial: "" }),
isdefense: new fields.BooleanField({ initial: false }),
bonusmaniementoff: new fields.NumberField({ initial: 0, integer: true }),
bonusmaniementdef: new fields.NumberField({ initial: 0, integer: true }),
ignorearmure: new fields.BooleanField({ initial: false }),
nbressources: new fields.NumberField({ initial: 0, integer: true }),
degats: new fields.StringField({ initial: "" }),
nonletaux: new fields.BooleanField({ initial: false }),
deuxmains: new fields.BooleanField({ initial: false }),
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 }),
rarete: new fields.NumberField({ initial: 0, integer: true }),
prix: new fields.NumberField({ initial: 0, integer: true }),
equipped: new fields.BooleanField({ initial: false })
};
}
}

View File

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

View File

@@ -0,0 +1,17 @@
/**
* Data model pour les boucliers
*/
export default class BouclierDataModel extends foundry.abstract.TypeDataModel {
static defineSchema() {
const fields = foundry.data.fields;
return {
description: new fields.HTMLField({ initial: "" }),
bonusdefense: new fields.NumberField({ initial: 0, integer: true }),
degats: new fields.StringField({ initial: "" }),
nonletaux: new fields.BooleanField({ initial: false }),
rarete: new fields.NumberField({ initial: 0, integer: true }),
prix: new fields.NumberField({ initial: 0, integer: true }),
equipped: new fields.BooleanField({ initial: false })
};
}
}

View File

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

View File

@@ -0,0 +1,17 @@
/**
* 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.StringField(), { initial: [] })
};
}
}

103
modules/models/creature.mjs Normal file
View File

@@ -0,0 +1,103 @@
/**
* 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 }),
alignement: new fields.StringField({ initial: "" }),
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: "" }),
amemultiplier: new fields.NumberField({ initial: 2, integer: true }),
ignoreamemalus: new fields.BooleanField({ initial: false }),
ignoresantemalus: new fields.BooleanField({ initial: false }),
notes: new fields.HTMLField({ initial: "" }),
gmnotes: new fields.HTMLField({ initial: "" })
}),
// 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({
base: new fields.NumberField({ initial: 0, integer: true }),
bonus: new fields.NumberField({ initial: 0, integer: true }),
nonletaux: new fields.NumberField({ initial: 0, integer: true }),
letaux: new fields.NumberField({ initial: 0, integer: true }),
malusmanuel: new fields.NumberField({ initial: 0, integer: true }),
sequelles: new fields.StringField({ initial: "" })
}),
ame: new fields.SchemaField({
fullmax: new fields.NumberField({ initial: 0, integer: true }),
currentmax: new fields.NumberField({ initial: 0, integer: true }),
value: new fields.NumberField({ initial: 0, integer: true }),
traumatismes: new fields.StringField({ initial: "" })
}),
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 }),
defensebonus: new fields.NumberField({ initial: 0, integer: true }),
monte: new fields.BooleanField({ initial: false })
}),
balance: new fields.SchemaField({
loi: new fields.NumberField({ initial: 0, integer: true }),
chaos: new fields.NumberField({ initial: 0, integer: true }),
aspect: new fields.NumberField({ initial: 0, integer: true }),
marge: new fields.NumberField({ initial: 0, integer: true }),
pointschaos: new fields.NumberField({ initial: 0, integer: true }),
pointsloi: new fields.NumberField({ initial: 0, integer: true })
}),
ressources: new fields.SchemaField({
value: new fields.NumberField({ initial: 0, integer: true })
})
};
}
}

14
modules/models/don.mjs Normal file
View File

@@ -0,0 +1,14 @@
/**
* Data model pour les dons
*/
export default class DonDataModel extends foundry.abstract.TypeDataModel {
static defineSchema() {
const fields = foundry.data.fields;
return {
description: new fields.HTMLField({ initial: "" }),
allegeance: new fields.StringField({ initial: "" }),
prerequis: new fields.StringField({ initial: "" }),
sacrifice: new fields.HTMLField({ initial: "" })
};
}
}

View File

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

View File

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

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

@@ -0,0 +1,28 @@
/**
* Index des DataModels pour Mournblade
* Ce fichier centralise tous les exports des modèles de données
*/
// Modèles d'items
export { default as ArmeDataModel } from './arme.mjs';
export { default as BouclierDataModel } from './bouclier.mjs';
export { default as CapaciteDataModel } from './capacite.mjs';
export { default as CompetenceDataModel } from './competence.mjs';
export { default as DonDataModel } from './don.mjs';
export { default as EquipementDataModel } from './equipement.mjs';
export { default as HeritageDataModel } from './heritage.mjs';
export { default as MetierDataModel } from './metier.mjs';
export { default as ModifierDataModel } from './modifier.mjs';
export { default as MonnaieDataModel } from './monnaie.mjs';
export { default as OrigineDataModel } from './origine.mjs';
export { default as PacteDataModel } from './pacte.mjs';
export { default as ProtectionDataModel } from './protection.mjs';
export { default as RuneDataModel } from './rune.mjs';
export { default as RuneEffectDataModel } from './runeeffect.mjs';
export { default as TendanceDataModel } from './tendance.mjs';
export { default as TraitChaotiqueDataModel } from './traitchaotique.mjs';
export { default as TraitEspeceDataModel } from './traitespece.mjs';
// Modèles d'acteurs
export { default as PersonnageDataModel } from './personnage.mjs';
export { default as CreatureDataModel } from './creature.mjs';

11
modules/models/metier.mjs Normal file
View File

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

View File

@@ -0,0 +1,18 @@
/**
* Data model pour les modificateurs
*/
export default class ModifierDataModel extends foundry.abstract.TypeDataModel {
static defineSchema() {
const fields = foundry.data.fields;
return {
description: new fields.HTMLField({ initial: "" }),
modifiertype: new fields.StringField({ initial: "roll" }),
value: new fields.NumberField({ initial: 0, integer: true }),
attribut: new fields.StringField({ initial: "aucun" }),
competence: new fields.StringField({ initial: "aucun" }),
permanent: new fields.BooleanField({ initial: true }),
once: new fields.BooleanField({ initial: false }),
duree: new fields.StringField({ initial: "" })
};
}
}

View File

@@ -0,0 +1,13 @@
/**
* 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: "" }),
quantite: new fields.NumberField({ initial: 0, integer: true }),
unite: new fields.StringField({ initial: "" })
};
}
}

View File

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

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

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

View File

@@ -0,0 +1,100 @@
/**
* 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 }),
alignement: new fields.StringField({ initial: "" }),
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: "" }),
amemultiplier: new fields.NumberField({ initial: 2, integer: true }),
ignoreamemalus: new fields.BooleanField({ initial: false }),
ignoresantemalus: new fields.BooleanField({ initial: false }),
notes: new fields.HTMLField({ initial: "" }),
gmnotes: new fields.HTMLField({ initial: "" })
}),
// 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({
base: new fields.NumberField({ initial: 0, integer: true }),
bonus: new fields.NumberField({ initial: 0, integer: true }),
nonletaux: new fields.NumberField({ initial: 0, integer: true }),
letaux: new fields.NumberField({ initial: 0, integer: true }),
malusmanuel: new fields.NumberField({ initial: 0, integer: true }),
sequelles: new fields.StringField({ initial: "" })
}),
ame: new fields.SchemaField({
fullmax: new fields.NumberField({ initial: 0, integer: true }),
currentmax: new fields.NumberField({ initial: 0, integer: true }),
value: new fields.NumberField({ initial: 0, integer: true }),
traumatismes: new fields.StringField({ initial: "" })
}),
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 }),
defensebonus: new fields.NumberField({ initial: 0, integer: true }),
monte: new fields.BooleanField({ initial: false })
}),
balance: new fields.SchemaField({
loi: new fields.NumberField({ initial: 0, integer: true }),
chaos: new fields.NumberField({ initial: 0, integer: true }),
aspect: new fields.NumberField({ initial: 0, integer: true }),
marge: new fields.NumberField({ initial: 0, integer: true }),
pointschaos: new fields.NumberField({ initial: 0, integer: true }),
pointsloi: new fields.NumberField({ initial: 0, integer: true })
})
};
}
}

View File

@@ -0,0 +1,17 @@
/**
* 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: "" }),
typeprotection: new fields.StringField({ initial: "" }),
protection: new fields.NumberField({ initial: 0, integer: true }),
degats: new fields.StringField({ initial: "" }),
rarete: new fields.NumberField({ initial: 0, integer: true }),
prix: new fields.NumberField({ initial: 0, integer: true }),
equipped: new fields.BooleanField({ initial: false })
};
}
}

15
modules/models/rune.mjs Normal file
View File

@@ -0,0 +1,15 @@
/**
* Data model pour les runes
*/
export default class RuneDataModel extends foundry.abstract.TypeDataModel {
static defineSchema() {
const fields = foundry.data.fields;
return {
description: new fields.HTMLField({ initial: "" }),
formule: new fields.StringField({ initial: "" }),
seuil: new fields.NumberField({ initial: 0, integer: true }),
prononcee: new fields.StringField({ initial: "" }),
tracee: new fields.StringField({ initial: "" })
};
}
}

View File

@@ -0,0 +1,15 @@
/**
* Data model pour les effets de runes
*/
export default class RuneEffectDataModel extends foundry.abstract.TypeDataModel {
static defineSchema() {
const fields = foundry.data.fields;
return {
description: new fields.HTMLField({ initial: "" }),
rune: new fields.StringField({ initial: "" }),
mode: new fields.StringField({ initial: "" }),
duree: new fields.StringField({ initial: "" }),
pointame: new fields.NumberField({ initial: 0, integer: true })
};
}
}

View File

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

View File

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

View File

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

View File

@@ -1,6 +1,6 @@
/* -------------------------------------------- */
import { MournbladeUtility } from "./mournblade-utility.js";
import { MournbladeRollDialog } from "./mournblade-roll-dialog.js";
import { MournbladeRollDialog } from "./applications/mournblade-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]
@@ -12,6 +12,28 @@ const __vitesseBonus = [-2, -2, -1, -1, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6
* @extends {Actor}
*/
export class MournbladeActor extends Actor {
prepareData() {
super.prepareData();
// Calculate derived attributes
const data = this.system;
// Calculate total health
data.sante.total = data.sante.base + data.sante.bonus;
// Calculate current health
data.sante.current = data.sante.total - data.sante.nonletaux - data.sante.letaux;
// Calculate total ame
data.ame.total = data.ame.fullmax;
// Calculate balance
data.balance.total = data.balance.loi + data.balance.chaos;
}
prepareDerivedData() {
this.prepareData();
}
/* -------------------------------------------- */
/**
@@ -64,22 +86,38 @@ export class MournbladeActor extends Actor {
let combat = this.getCombatValues()
if (arme.system.typearme == "contact" || arme.system.typearme == "contactjet") {
arme.system.isMelee = true
arme.system.competence = foundry.utils.duplicate(this.items.find(item => item.type == "competence" && item.name.toLowerCase() == "mêlée"))
arme.system.attrKey = "pui"
arme.system.totalDegats = arme.system.degats + "+" + combat.bonusDegatsTotal
arme.system.totalOffensif = this.system.attributs.pui.value + arme.system.competence.system.niveau + arme.system.bonusmaniementoff + combat.attaqueModifier
if (arme.system.isdefense) {
arme.system.totalDefensif = combat.defenseTotal + arme.system.competence.system.niveau + arme.system.bonusmaniementdef
let competence = this.items.find(item => item.type == "competence" && item.name.toLowerCase() == "mêlée")
if (competence) {
arme.system.competence = foundry.utils.duplicate(competence)
arme.system.attrKey = "pui"
arme.system.totalDegats = arme.system.degats + "+" + combat.bonusDegatsTotal
arme.system.totalOffensif = this.system.attributs.pui.value + arme.system.competence.system.niveau + arme.system.bonusmaniementoff + combat.attaqueModifier
if (arme.system.isdefense) {
arme.system.totalDefensif = combat.defenseTotal + arme.system.competence.system.niveau + arme.system.bonusmaniementdef
}
} else {
arme.system.competence = null
arme.system.totalOffensif = 0
arme.system.totalDegats = arme.system.degats
arme.system.totalDefensif = 0
}
}
if (arme.system.typearme == "jet" || arme.system.typearme == "tir") {
arme.system.isDistance = true
arme.system.competence = foundry.utils.duplicate(this.items.find(item => item.type == "competence" && item.name.toLowerCase() == "armes à distance"))
arme.system.attrKey = "adr"
arme.system.totalOffensif = this.system.attributs.adr.value + arme.system.competence.system.niveau + arme.system.bonusmaniementoff + combat.attaqueModifier
arme.system.totalDegats = arme.system.degats
if (arme.system.isdefense) {
arme.system.totalDefensif = combat.defenseTotal + arme.system.competence.system.niveau + arme.system.bonusmaniementdef
let competence = this.items.find(item => item.type == "competence" && item.name.toLowerCase() == "armes à distance")
if (competence) {
arme.system.competence = foundry.utils.duplicate(competence)
arme.system.attrKey = "adr"
arme.system.totalOffensif = this.system.attributs.adr.value + arme.system.competence.system.niveau + arme.system.bonusmaniementoff + combat.attaqueModifier
arme.system.totalDegats = arme.system.degats
if (arme.system.isdefense) {
arme.system.totalDefensif = combat.defenseTotal + arme.system.competence.system.niveau + arme.system.bonusmaniementdef
}
} else {
arme.system.competence = null
arme.system.totalOffensif = 0
arme.system.totalDegats = arme.system.degats
arme.system.totalDefensif = 0
}
}
return arme
@@ -88,13 +126,21 @@ export class MournbladeActor extends Actor {
prepareBouclier(bouclier) {
bouclier = foundry.utils.duplicate(bouclier)
let combat = this.getCombatValues()
bouclier.system.competence = foundry.utils.duplicate(this.items.find(item => item.type == "competence" && item.name.toLowerCase() == "mêlée"))
bouclier.system.attrKey = "pui"
bouclier.system.totalDegats = bouclier.system.degats + "+" + combat.bonusDegatsTotal
bouclier.system.totalOffensif = this.system.attributs.pui.value + bouclier.system.competence.system.niveau
bouclier.system.isdefense = true
bouclier.system.bonusmaniementoff = 0
bouclier.system.totalDefensif = combat.defenseTotal + bouclier.system.competence.system.niveau + bouclier.system.bonusdefense
let competence = this.items.find(item => item.type == "competence" && item.name.toLowerCase() == "mêlée")
if (competence) {
bouclier.system.competence = foundry.utils.duplicate(competence)
bouclier.system.attrKey = "pui"
bouclier.system.totalDegats = bouclier.system.degats + "+" + combat.bonusDegatsTotal
bouclier.system.totalOffensif = this.system.attributs.pui.value + bouclier.system.competence.system.niveau
bouclier.system.isdefense = true
bouclier.system.bonusmaniementoff = 0
bouclier.system.totalDefensif = combat.defenseTotal + bouclier.system.competence.system.niveau + bouclier.system.bonusdefense
} else {
bouclier.system.competence = null
bouclier.system.totalOffensif = 0
bouclier.system.totalDegats = bouclier.system.degats
bouclier.system.totalDefensif = 0
}
return bouclier
}
@@ -258,11 +304,13 @@ export class MournbladeActor extends Actor {
if (this.type == 'personnage') {
let newSante = this.system.sante.bonus + (this.system.attributs.pui.value + this.system.attributs.tre.value) * 2 + 5
if (this.system.sante.base != newSante) {
if (this.system.sante.base != newSante && this._id) {
// Only update if the actor already exists (has an _id)
this.update({ 'system.sante.base': newSante })
}
let newAme = (this.system.attributs.cla.value + this.system.attributs.tre.value) * this.system.biodata.amemultiplier + 5
if (this.system.ame.fullmax != newAme) {
if (this.system.ame.fullmax != newAme && this._id) {
// Only update if the actor already exists (has an _id)
this.update({ 'system.ame.fullmax': newAme })
}
}
@@ -589,16 +637,14 @@ export class MournbladeActor extends Actor {
/* -------------------------------------------- */
async rollAttribut(attrKey) {
let rollData = this.getCommonRollData(attrKey)
let rollDialog = await MournbladeRollDialog.create(this, rollData)
rollDialog.render(true)
await MournbladeRollDialog.create(this, rollData)
}
/* -------------------------------------------- */
async rollCompetence(attrKey, compId) {
let rollData = this.getCommonRollData(attrKey, compId)
console.log("RollDatra", rollData)
let rollDialog = await MournbladeRollDialog.create(this, rollData)
rollDialog.render(true)
await MournbladeRollDialog.create(this, rollData)
}
/* -------------------------------------------- */
@@ -614,8 +660,7 @@ export class MournbladeActor extends Actor {
rollData.runemode = "prononcer"
rollData.runeame = 1
console.log("runeData", rollData)
let rollDialog = await MournbladeRollDialog.create(this, rollData)
rollDialog.render(true)
await MournbladeRollDialog.create(this, rollData)
}
/* -------------------------------------------- */
@@ -642,8 +687,7 @@ export class MournbladeActor extends Actor {
}
console.log("ARME!", rollData)
this.depenseRessources(arme)
let rollDialog = await MournbladeRollDialog.create(this, rollData)
rollDialog.render(true)
await MournbladeRollDialog.create(this, rollData)
}
/* -------------------------------------------- */
@@ -657,8 +701,7 @@ export class MournbladeActor extends Actor {
rollData.difficulte = rollData.defender.system.attributs.tre.value * 2
}
console.log("Assomer!", rollData)
let rollDialog = await MournbladeRollDialog.create(this, rollData)
rollDialog.render(true)
await MournbladeRollDialog.create(this, rollData)
}
/* -------------------------------------------- */
async rollFuir() {
@@ -672,8 +715,7 @@ export class MournbladeActor extends Actor {
rollData.difficulte = rollData.defender.system.attributs.adr.value + ((comp) ? comp.system.niveau : rollData.defender.system.attributs.adr.value)
}
console.log("Fuir!", rollData)
let rollDialog = await MournbladeRollDialog.create(this, rollData)
rollDialog.render(true)
await MournbladeRollDialog.create(this, rollData)
}
/* -------------------------------------------- */
async rollImmobiliser() {
@@ -686,15 +728,14 @@ export class MournbladeActor extends Actor {
rollData.difficulte = rollData.defenderCombatValues.defenseTotal
}
console.log("Immobiliser!", rollData)
let rollDialog = await MournbladeRollDialog.create(this, rollData)
rollDialog.render(true)
await MournbladeRollDialog.create(this, rollData)
}
/* -------------------------------------------- */
async rollArmeSpecial(armeId) {
let arme = this.items.get(armeId)
if (arme) {
MournbladeUtility.createChatWithRollMode("GM", {
content: await renderTemplate(`systems/fvtt-mournblade/templates/chat-display-description.html`, arme)
content: await renderTemplate(`systems/fvtt-mournblade/templates/chat-display-description.hbs`, arme)
}, arme)
this.depenseRessources(arme)
}
@@ -722,7 +763,7 @@ export class MournbladeActor extends Actor {
actionImg: arme.img,
}
MournbladeUtility.createChatWithRollMode(rollData.alias, {
content: await foundry.applications.handlebars.renderTemplate(`systems/fvtt-mournblade/templates/chat-degats-result.html`, rollData)
content: await foundry.applications.handlebars.renderTemplate(`systems/fvtt-mournblade/templates/chat-degats-result-v2.hbs`, rollData)
})
}

View File

@@ -116,8 +116,7 @@ export class MournbladeCommands {
rollData.mode = "generic"
rollData.title = `Dice Pool Roll`;
let rollDialog = await MournbladeRollDialog.create( this, rollData);
rollDialog.render( true );
await MournbladeRollDialog.create( this, rollData);
}
}

View File

@@ -11,7 +11,7 @@ export class MournbladeItemSheet extends foundry.appv1.sheets.ItemSheet {
return foundry.utils.mergeObject(super.defaultOptions, {
classes: ["fvtt-mournblade", "sheet", "item"],
template: "systems/fvtt-mournblade/templates/item-sheet.html",
template: "systems/fvtt-mournblade/templates/item-sheet.hbs",
dragDrop: [{ dragSelector: null, dropSelector: null }],
width: 620,
height: 550
@@ -106,7 +106,7 @@ export class MournbladeItemSheet extends foundry.appv1.sheets.ItemSheet {
payload: chatData,
});
renderTemplate('systems/fvtt-Mournblade-rpg/templates/post-item.html', chatData).then(html => {
renderTemplate('systems/fvtt-mournblade/templates/post-item.hbs', chatData).then(html => {
let chatOptions = MournbladeUtility.chatDataSetup(html);
ChatMessage.create(chatOptions)
});
@@ -169,7 +169,7 @@ export class MournbladeItemSheet extends foundry.appv1.sheets.ItemSheet {
/* -------------------------------------------- */
get template() {
let type = this.item.type;
return `systems/fvtt-mournblade/templates/item-${type}-sheet.html`;
return `systems/fvtt-mournblade/templates/item-${type}-sheet.hbs`;
}
/* -------------------------------------------- */

View File

@@ -10,13 +10,20 @@
// Import Modules
import { MournbladeActor } from "./mournblade-actor.js";
import { MournbladeItemSheet } from "./mournblade-item-sheet.js";
import { MournbladeActorSheet } from "./mournblade-actor-sheet.js";
import { MournbladeCreatureSheet } from "./mournblade-creature-sheet.js";
// import { MournbladeActorSheet } from "./mournblade-actor-sheet.js";
// import { MournbladeCreatureSheet } from "./mournblade-creature-sheet.js";
import { MournbladeUtility } from "./mournblade-utility.js";
import { MournbladeCombat } from "./mournblade-combat.js";
import { MournbladeItem } from "./mournblade-item.js";
import { MournbladeConfig } from "./mournblade-config.js";
// Import DataModels
import * as models from "./models/index.mjs";
// Import AppV2 Item Sheets
import * as sheets from "./applications/sheets/_module.mjs";
import { MournbladeRollDialog } from "./mournblade-roll-dialog.js";
/* -------------------------------------------- */
/* Foundry VTT Initialization */
/* -------------------------------------------- */
@@ -45,35 +52,80 @@ Hooks.once("init", async function () {
// Define custom Entity classes
CONFIG.Combat.documentClass = MournbladeCombat
CONFIG.Actor.documentClass = MournbladeActor
CONFIG.Actor.dataModels = {
personnage: models.PersonnageDataModel,
creature: models.CreatureDataModel,
}
CONFIG.Item.documentClass = MournbladeItem
CONFIG.Item.dataModels = {
arme: models.ArmeDataModel,
bouclier: models.BouclierDataModel,
capacite: models.CapaciteDataModel,
competence: models.CompetenceDataModel,
don: models.DonDataModel,
equipement: models.EquipementDataModel,
heritage: models.HeritageDataModel,
metier: models.MetierDataModel,
modifier: models.ModifierDataModel,
monnaie: models.MonnaieDataModel,
origine: models.OrigineDataModel,
pacte: models.PacteDataModel,
protection: models.ProtectionDataModel,
rune: models.RuneDataModel,
runeeffect: models.RuneEffectDataModel,
tendance: models.TendanceDataModel,
traitchaotique: models.TraitChaotiqueDataModel,
traitespece: models.TraitEspeceDataModel
}
game.system.mournblade = {
config : MournbladeConfig.getConfig(),
models,
sheets,
MournbladeRollDialog
}
/* -------------------------------------------- */
// Register sheet application classes
foundry.documents.collections.Actors.unregisterSheet("core", foundry.appv1.sheets.ActorSheet);
foundry.documents.collections.Actors.registerSheet("fvtt-mournblade", MournbladeActorSheet, { types: ["personnage"], makeDefault: true })
foundry.documents.collections.Actors.registerSheet("fvtt-mournblade", MournbladeCreatureSheet, { types: ["creature"], makeDefault: true })
foundry.documents.collections.Actors.registerSheet("fvtt-mournblade", sheets.MournbladePersonnageSheet, { types: ["personnage"], makeDefault: true });
foundry.documents.collections.Actors.registerSheet("fvtt-mournblade", sheets.MournbladeCreatureSheet, { types: ["creature"], makeDefault: true });
foundry.documents.collections.Items.unregisterSheet("core", foundry.appv1.sheets.ItemSheet);
foundry.documents.collections.Items.registerSheet("fvtt-mournblade", MournbladeItemSheet, { makeDefault: true })
foundry.documents.collections.Items.registerSheet("fvtt-mournblade", sheets.MournbladeArmeSheet, { types: ["arme"], makeDefault: true });
foundry.documents.collections.Items.registerSheet("fvtt-mournblade", sheets.MournbladeBouclierSheet, { types: ["bouclier"], makeDefault: true });
foundry.documents.collections.Items.registerSheet("fvtt-mournblade", sheets.MournbladeCapaciteSheet, { types: ["capacite"], makeDefault: true });
foundry.documents.collections.Items.registerSheet("fvtt-mournblade", sheets.MournbladeCompetenceSheet, { types: ["competence"], makeDefault: true });
foundry.documents.collections.Items.registerSheet("fvtt-mournblade", sheets.MournbladeDonSheet, { types: ["don"], makeDefault: true });
foundry.documents.collections.Items.registerSheet("fvtt-mournblade", sheets.MournbladeEquipementSheet, { types: ["equipement"], makeDefault: true });
foundry.documents.collections.Items.registerSheet("fvtt-mournblade", sheets.MournbladeHeritageSheet, { types: ["heritage"], makeDefault: true });
foundry.documents.collections.Items.registerSheet("fvtt-mournblade", sheets.MournbladeMetierSheet, { types: ["metier"], makeDefault: true });
foundry.documents.collections.Items.registerSheet("fvtt-mournblade", sheets.MournbladeModifierSheet, { types: ["modifier"], makeDefault: true });
foundry.documents.collections.Items.registerSheet("fvtt-mournblade", sheets.MournbladeMonnaieSheet, { types: ["monnaie"], makeDefault: true });
foundry.documents.collections.Items.registerSheet("fvtt-mournblade", sheets.MournbladeOrigineSheet, { types: ["origine"], makeDefault: true });
foundry.documents.collections.Items.registerSheet("fvtt-mournblade", sheets.MournbladePacteSheet, { types: ["pacte"], makeDefault: true });
foundry.documents.collections.Items.registerSheet("fvtt-mournblade", sheets.MournbladeProtectionSheet, { types: ["protection"], makeDefault: true });
foundry.documents.collections.Items.registerSheet("fvtt-mournblade", sheets.MournbladeRuneSheet, { types: ["rune"], makeDefault: true });
foundry.documents.collections.Items.registerSheet("fvtt-mournblade", sheets.MournbladeRuneEffectSheet, { types: ["runeeffect"], makeDefault: true });
foundry.documents.collections.Items.registerSheet("fvtt-mournblade", sheets.MournbladeTendanceSheet, { types: ["tendance"], makeDefault: true });
foundry.documents.collections.Items.registerSheet("fvtt-mournblade", sheets.MournbladeTraitChaotiqueSheet, { types: ["traitchaotique"], makeDefault: true });
foundry.documents.collections.Items.registerSheet("fvtt-mournblade", sheets.MournbladeTraitEspeceSheet, { types: ["traitespece"], makeDefault: true });
MournbladeUtility.init();
});
/* -------------------------------------------- */
function welcomeMessage() {
async function welcomeMessage() {
const templateData = {};
const html = await renderTemplate("systems/fvtt-mournblade/templates/chat-welcome-message.hbs", templateData);
ChatMessage.create({
user: game.user.id,
whisper: [game.user.id],
content: `<div id="welcome-message-Mournblade"><span class="rdd-roll-part">
<strong>Bienvenue dans les Jeunes Royaumes de Mournblade !</strong>
<p>Les livres de Mournblade sont nécessaires pour jouer : https://www.titam-france.fr</p>
<p>Mournblade 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: html
});
}
/* -------------------------------------------- */

View File

@@ -1,56 +1,56 @@
import { MournbladeUtility } from "./mournblade-utility.js";
export class MournbladeRollDialog extends Dialog {
export class MournbladeRollDialog extends Application {
/* -------------------------------------------- */
static async create(actor, rollData ) {
let options = { classes: ["MournbladeDialog"], width: 340, height: 'fit-content', 'z-index': 99999 };
let html = await foundry.applications.handlebars.renderTemplate('systems/fvtt-mournblade/templates/roll-dialog-generic.html', rollData);
return new MournbladeRollDialog(actor, rollData, html, options );
return new MournbladeRollDialog(actor, rollData);
}
/* -------------------------------------------- */
constructor(actor, rollData, html, options, close = undefined) {
let conf = {
title: "Test de Capacité",
content: html,
buttons: {
rolld10: {
icon: '<i class="fas fa-check"></i>',
label: "Lancer 1d10",
callback: () => { this.roll("1d10") }
},
rolld20: {
icon: '<i class="fas fa-check"></i>',
label: "Lancer 1d20",
callback: () => { this.roll("1d20") }
},
cancel: {
icon: '<i class="fas fa-times"></i>',
label: "Annuler",
callback: () => { this.close() }
} },
close: close
constructor(actor, rollData, options = {}) {
super(options);
this.actor = actor;
this.rollData = rollData;
}
static get defaultOptions() {
return foundry.utils.mergeObject(super.defaultOptions, {
classes: ["fvtt-mournblade", "sheet", "item"],
template: "systems/fvtt-mournblade/templates/roll-dialog-generic.hbs",
width: 400,
height: "auto",
title: "Test de Capacité"
});
}
getData() {
const data = foundry.utils.duplicate(this.rollData);
if (!data.config) {
data.config = game.system.mournblade.config;
}
return data;
}
super(conf, options);
this.actor = actor
this.rollData = rollData
_onCancel() {
this.close();
}
/* -------------------------------------------- */
roll ( dice) {
this.rollData.mainDice = dice
MournbladeUtility.rollMournblade( this.rollData )
_onRoll(dice) {
this.rollData.mainDice = dice;
MournbladeUtility.rollMournblade(this.rollData);
this.close();
}
/* -------------------------------------------- */
activateListeners(html) {
super.activateListeners(html);
// Roll buttons
html.find(".rolld10").click(this._onRoll.bind(this, "1d10"));
html.find(".rolld20").click(this._onRoll.bind(this, "1d20"));
html.find(".cancel").click(this._onCancel.bind(this));
function onLoad() {
}

View File

@@ -163,8 +163,10 @@ export class MournbladeUtility {
static async preloadHandlebarsTemplates() {
const templatePaths = [
'systems/fvtt-mournblade/templates/editor-notes-gm.html',
'systems/fvtt-mournblade/templates/partial-item-description.html'
'systems/fvtt-mournblade/templates/editor-notes-gm.hbs',
'systems/fvtt-mournblade/templates/partial-item-description.hbs',
'systems/fvtt-mournblade/templates/partial-item-header.hbs',
'systems/fvtt-mournblade/templates/partial-item-nav.hbs'
]
return foundry.applications.handlebars.loadTemplates(templatePaths);
}
@@ -209,7 +211,7 @@ export class MournbladeUtility {
static createArrayOptionList(min, max) {
let options = [];
for (let i = min; i <= max; i++) {
options.push({key:`${i}`, label:`${i}`});
options.push({ key: `${i}`, label: `${i}` });
}
return options;
}
@@ -298,7 +300,11 @@ export class MournbladeUtility {
}
}
}
this.computeQualityResult(rollData)
}
/* -------------------------------------------- */
static computeQualityResult(rollData) {
//console.log("Result : ", rollData)
if (rollData.difficulte > 0 && !rollData.isDramatique) {
rollData.isSuccess = (rollData.finalResult >= rollData.difficulte)
@@ -367,7 +373,7 @@ export class MournbladeUtility {
if (rollData.visee) {
rollData.diceFormula += "+5"
}
if (rollData.cibleconsciente) {
if (rollData.cibleconsciente && rollData.defender) {
rollData.diceFormula += `-${rollData.defender.system.attributs.adr.value}`
}
if (rollData.ciblecourt) {
@@ -377,7 +383,7 @@ export class MournbladeUtility {
rollData.diceFormula += `-10`
}
}
if (rollData.typeCouvert != "aucun") {
if (rollData.typeCouvert && rollData.typeCouvert != "aucun" && rollData.config.couverts[rollData.typeCouvert]) {
rollData.diceFormula += `+${rollData.config.couverts[rollData.typeCouvert].value}`
}
}
@@ -423,7 +429,7 @@ export class MournbladeUtility {
actor.setModifier("Charge de Cavalerie : -5 défense pour le tour", "defense", -5)
}
this.createChatWithRollMode(rollData.alias, {
content: await foundry.applications.handlebars.renderTemplate(`systems/fvtt-mournblade/templates/chat-generic-result.html`, rollData)
content: await foundry.applications.handlebars.renderTemplate(`systems/fvtt-mournblade/templates/chat-generic-result-v2.hbs`, rollData)
}, rollData)
}
@@ -517,7 +523,7 @@ export class MournbladeUtility {
}
this.createChatWithRollMode(rollData.alias, {
content: await renderTemplate(`systems/fvtt-mournblade/templates/chat-degats-result.html`, rollData)
content: await foundry.applications.handlebars.renderTemplate(`systems/fvtt-mournblade/templates/chat-degats-result-v2.hbs`, rollData)
}, rollData)
}
@@ -568,17 +574,17 @@ export class MournbladeUtility {
rollData.finalResult += rollData.bonusRoll.total
this.computeResult(rollData)
this.computeQualityResult(rollData)
this.createChatWithRollMode(rollData.alias, {
content: await renderTemplate(`systems/fvtt-mournblade/templates/chat-generic-result.html`, rollData)
content: await foundry.applications.handlebars.renderTemplate(`systems/fvtt-mournblade/templates/chat-generic-result-v2.hbs`, rollData)
}, rollData)
}
/* -------------------------------------------- */
static getUsers(filter) {
return game.users.filter(filter).map(user => user.data._id);
return game.users.filter(filter).map(user => user._id);
}
/* -------------------------------------------- */
@@ -766,7 +772,7 @@ export class MournbladeUtility {
let rollData = message.getFlag("world", "mournblade-roll")
let actor = MournbladeUtility.getActorFromRollData(rollData)
if (rollData.competence) {
let nbPred = rollData.competence.data.predilections.filter(pred => !pred.used).length
let nbPred = rollData.competence.system.predilections.filter(pred => !pred.used).length
return (!rollData.isReroll && rollData.competence && nbPred > 0)
}
return false
@@ -776,7 +782,7 @@ export class MournbladeUtility {
let rollData = message.getFlag("world", "mournblade-roll")
let actor = MournbladeUtility.getActorFromRollData(rollData)
if (rollData.competence) {
return rollData.competence.data.doublebonus
return rollData.competence.system.doublebonus
}
return false
}
@@ -841,7 +847,7 @@ export class MournbladeUtility {
/* -------------------------------------------- */
static async confirmDelete(actorSheet, li) {
let itemId = li.data("item-id");
let itemId = li.dataset?.itemId || li.data("item-id");
let msgTxt = "<p>Voulez vous supprimer cet item ?";
let buttons = {
delete: {
@@ -849,7 +855,7 @@ export class MournbladeUtility {
label: "Oui !",
callback: () => {
actorSheet.actor.deleteEmbeddedDocuments("Item", [itemId]);
li.slideUp(200, () => actorSheet.render(false));
actorSheet.render(false);
}
},
cancel: {

4968
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

16
package.json Normal file
View File

@@ -0,0 +1,16 @@
{
"name": "fvtt-mournblade",
"version": "1.0.0",
"description": "Mournblade RPG for FoundryVTT - French",
"scripts": {
"build": "gulp build",
"watch": "gulp watch"
},
"author": "Uberwald/LeRatierBretonnien",
"license": "SEE LICENSE IN LICENCE.txt",
"devDependencies": {
"gulp": "^4.0.2",
"gulp-less": "^5.0.0",
"gulp-sourcemaps": "^3.0.0"
}
}

View File

@@ -1 +1 @@
MANIFEST-000240
MANIFEST-000304

View File

@@ -1,8 +1,8 @@
2025/06/03-13:38:34.829840 7f53e4df86c0 Recovering log #238
2025/06/03-13:38:34.883917 7f53e4df86c0 Delete type=3 #236
2025/06/03-13:38:34.884056 7f53e4df86c0 Delete type=0 #238
2025/06/03-13:46:40.549617 7f53df3ff6c0 Level-0 table #243: started
2025/06/03-13:46:40.549726 7f53df3ff6c0 Level-0 table #243: 0 bytes OK
2025/06/03-13:46:40.591881 7f53df3ff6c0 Delete type=0 #241
2025/06/03-13:46:40.701236 7f53df3ff6c0 Manual compaction at level-0 from '!items!0swiE8k5zfUIqmXu' @ 72057594037927935 : 1 .. '!items!wv5EiePmPTpqFutt' @ 0 : 0; will stop at (end)
2025/06/03-13:46:40.701447 7f53df3ff6c0 Manual compaction at level-1 from '!items!0swiE8k5zfUIqmXu' @ 72057594037927935 : 1 .. '!items!wv5EiePmPTpqFutt' @ 0 : 0; will stop at (end)
2026/01/09-16:51:34.709189 7f1c56bff6c0 Recovering log #302
2026/01/09-16:51:34.720652 7f1c56bff6c0 Delete type=3 #300
2026/01/09-16:51:34.720827 7f1c56bff6c0 Delete type=0 #302
2026/01/09-17:10:52.171232 7f1c54bfb6c0 Level-0 table #307: started
2026/01/09-17:10:52.171270 7f1c54bfb6c0 Level-0 table #307: 0 bytes OK
2026/01/09-17:10:52.181182 7f1c54bfb6c0 Delete type=0 #305
2026/01/09-17:10:52.181380 7f1c54bfb6c0 Manual compaction at level-0 from '!items!0swiE8k5zfUIqmXu' @ 72057594037927935 : 1 .. '!items!wv5EiePmPTpqFutt' @ 0 : 0; will stop at (end)
2026/01/09-17:10:52.181415 7f1c54bfb6c0 Manual compaction at level-1 from '!items!0swiE8k5zfUIqmXu' @ 72057594037927935 : 1 .. '!items!wv5EiePmPTpqFutt' @ 0 : 0; will stop at (end)

View File

@@ -1,9 +1,8 @@
2025/05/29-15:55:26.176609 7f53e5dfa6c0 Recovering log #233
2025/05/29-15:55:26.190009 7f53e5dfa6c0 Delete type=3 #229
2025/05/29-15:55:26.190103 7f53e5dfa6c0 Delete type=3 #221
2025/05/29-15:55:26.190162 7f53e5dfa6c0 Delete type=0 #233
2025/05/29-16:03:58.142314 7f53df3ff6c0 Level-0 table #239: started
2025/05/29-16:03:58.142371 7f53df3ff6c0 Level-0 table #239: 0 bytes OK
2025/05/29-16:03:58.149718 7f53df3ff6c0 Delete type=0 #237
2025/05/29-16:03:58.170022 7f53df3ff6c0 Manual compaction at level-0 from '!items!0swiE8k5zfUIqmXu' @ 72057594037927935 : 1 .. '!items!wv5EiePmPTpqFutt' @ 0 : 0; will stop at (end)
2025/05/29-16:03:58.170098 7f53df3ff6c0 Manual compaction at level-1 from '!items!0swiE8k5zfUIqmXu' @ 72057594037927935 : 1 .. '!items!wv5EiePmPTpqFutt' @ 0 : 0; will stop at (end)
2026/01/09-16:50:28.487537 7f1c56bff6c0 Recovering log #298
2026/01/09-16:50:28.498450 7f1c56bff6c0 Delete type=3 #296
2026/01/09-16:50:28.498515 7f1c56bff6c0 Delete type=0 #298
2026/01/09-16:51:28.840653 7f1c54bfb6c0 Level-0 table #303: started
2026/01/09-16:51:28.840708 7f1c54bfb6c0 Level-0 table #303: 0 bytes OK
2026/01/09-16:51:28.847927 7f1c54bfb6c0 Delete type=0 #301
2026/01/09-16:51:28.868475 7f1c54bfb6c0 Manual compaction at level-0 from '!items!0swiE8k5zfUIqmXu' @ 72057594037927935 : 1 .. '!items!wv5EiePmPTpqFutt' @ 0 : 0; will stop at (end)
2026/01/09-16:51:28.868551 7f1c54bfb6c0 Manual compaction at level-1 from '!items!0swiE8k5zfUIqmXu' @ 72057594037927935 : 1 .. '!items!wv5EiePmPTpqFutt' @ 0 : 0; will stop at (end)

View File

@@ -1 +1 @@
MANIFEST-000239
MANIFEST-000303

View File

@@ -1,8 +1,8 @@
2025/06/03-13:38:35.003129 7f53dffff6c0 Recovering log #237
2025/06/03-13:38:35.063448 7f53dffff6c0 Delete type=3 #235
2025/06/03-13:38:35.063543 7f53dffff6c0 Delete type=0 #237
2025/06/03-13:46:40.628405 7f53df3ff6c0 Level-0 table #242: started
2025/06/03-13:46:40.628456 7f53df3ff6c0 Level-0 table #242: 0 bytes OK
2025/06/03-13:46:40.666357 7f53df3ff6c0 Delete type=0 #240
2025/06/03-13:46:40.701286 7f53df3ff6c0 Manual compaction at level-0 from '!items!5dGXNiL3WN4cAk7X' @ 72057594037927935 : 1 .. '!items!zzz9JrtWjELdoAfK' @ 0 : 0; will stop at (end)
2025/06/03-13:46:40.701434 7f53df3ff6c0 Manual compaction at level-1 from '!items!5dGXNiL3WN4cAk7X' @ 72057594037927935 : 1 .. '!items!zzz9JrtWjELdoAfK' @ 0 : 0; will stop at (end)
2026/01/09-16:51:34.750271 7f1c55bfd6c0 Recovering log #301
2026/01/09-16:51:34.760726 7f1c55bfd6c0 Delete type=3 #299
2026/01/09-16:51:34.760813 7f1c55bfd6c0 Delete type=0 #301
2026/01/09-17:10:52.202603 7f1c54bfb6c0 Level-0 table #306: started
2026/01/09-17:10:52.202692 7f1c54bfb6c0 Level-0 table #306: 0 bytes OK
2026/01/09-17:10:52.216180 7f1c54bfb6c0 Delete type=0 #304
2026/01/09-17:10:52.229242 7f1c54bfb6c0 Manual compaction at level-0 from '!items!5dGXNiL3WN4cAk7X' @ 72057594037927935 : 1 .. '!items!zzz9JrtWjELdoAfK' @ 0 : 0; will stop at (end)
2026/01/09-17:10:52.229348 7f1c54bfb6c0 Manual compaction at level-1 from '!items!5dGXNiL3WN4cAk7X' @ 72057594037927935 : 1 .. '!items!zzz9JrtWjELdoAfK' @ 0 : 0; will stop at (end)

View File

@@ -1,9 +1,8 @@
2025/05/29-15:55:26.234910 7f53dffff6c0 Recovering log #232
2025/05/29-15:55:26.245499 7f53dffff6c0 Delete type=3 #228
2025/05/29-15:55:26.245611 7f53dffff6c0 Delete type=3 #220
2025/05/29-15:55:26.245670 7f53dffff6c0 Delete type=0 #232
2025/05/29-16:03:58.183794 7f53df3ff6c0 Level-0 table #238: started
2025/05/29-16:03:58.183822 7f53df3ff6c0 Level-0 table #238: 0 bytes OK
2025/05/29-16:03:58.189942 7f53df3ff6c0 Delete type=0 #236
2025/05/29-16:03:58.196960 7f53df3ff6c0 Manual compaction at level-0 from '!items!5dGXNiL3WN4cAk7X' @ 72057594037927935 : 1 .. '!items!zzz9JrtWjELdoAfK' @ 0 : 0; will stop at (end)
2025/05/29-16:03:58.197030 7f53df3ff6c0 Manual compaction at level-1 from '!items!5dGXNiL3WN4cAk7X' @ 72057594037927935 : 1 .. '!items!zzz9JrtWjELdoAfK' @ 0 : 0; will stop at (end)
2026/01/09-16:50:28.529034 7f1c56bff6c0 Recovering log #297
2026/01/09-16:50:28.539837 7f1c56bff6c0 Delete type=3 #295
2026/01/09-16:50:28.539910 7f1c56bff6c0 Delete type=0 #297
2026/01/09-16:51:28.861880 7f1c54bfb6c0 Level-0 table #302: started
2026/01/09-16:51:28.861911 7f1c54bfb6c0 Level-0 table #302: 0 bytes OK
2026/01/09-16:51:28.868272 7f1c54bfb6c0 Delete type=0 #300
2026/01/09-16:51:28.868530 7f1c54bfb6c0 Manual compaction at level-0 from '!items!5dGXNiL3WN4cAk7X' @ 72057594037927935 : 1 .. '!items!zzz9JrtWjELdoAfK' @ 0 : 0; will stop at (end)
2026/01/09-16:51:28.868572 7f1c54bfb6c0 Manual compaction at level-1 from '!items!5dGXNiL3WN4cAk7X' @ 72057594037927935 : 1 .. '!items!zzz9JrtWjELdoAfK' @ 0 : 0; will stop at (end)

View File

@@ -1 +1 @@
MANIFEST-000239
MANIFEST-000303

View File

@@ -1,8 +1,8 @@
2025/06/03-13:38:34.942102 7f53e4df86c0 Recovering log #237
2025/06/03-13:38:35.000785 7f53e4df86c0 Delete type=3 #235
2025/06/03-13:38:35.000863 7f53e4df86c0 Delete type=0 #237
2025/06/03-13:46:40.592034 7f53df3ff6c0 Level-0 table #242: started
2025/06/03-13:46:40.592075 7f53df3ff6c0 Level-0 table #242: 0 bytes OK
2025/06/03-13:46:40.628226 7f53df3ff6c0 Delete type=0 #240
2025/06/03-13:46:40.701268 7f53df3ff6c0 Manual compaction at level-0 from '!items!1cZd2hlTV9tykDED' @ 72057594037927935 : 1 .. '!items!y47dBO3Mf5Pn7tOd' @ 0 : 0; will stop at (end)
2025/06/03-13:46:40.701319 7f53df3ff6c0 Manual compaction at level-1 from '!items!1cZd2hlTV9tykDED' @ 72057594037927935 : 1 .. '!items!y47dBO3Mf5Pn7tOd' @ 0 : 0; will stop at (end)
2026/01/09-16:51:34.736494 7f1c563fe6c0 Recovering log #301
2026/01/09-16:51:34.746896 7f1c563fe6c0 Delete type=3 #299
2026/01/09-16:51:34.747053 7f1c563fe6c0 Delete type=0 #301
2026/01/09-17:10:52.181524 7f1c54bfb6c0 Level-0 table #306: started
2026/01/09-17:10:52.181569 7f1c54bfb6c0 Level-0 table #306: 0 bytes OK
2026/01/09-17:10:52.192560 7f1c54bfb6c0 Delete type=0 #304
2026/01/09-17:10:52.229188 7f1c54bfb6c0 Manual compaction at level-0 from '!items!1cZd2hlTV9tykDED' @ 72057594037927935 : 1 .. '!items!y47dBO3Mf5Pn7tOd' @ 0 : 0; will stop at (end)
2026/01/09-17:10:52.229310 7f1c54bfb6c0 Manual compaction at level-1 from '!items!1cZd2hlTV9tykDED' @ 72057594037927935 : 1 .. '!items!y47dBO3Mf5Pn7tOd' @ 0 : 0; will stop at (end)

View File

@@ -1,9 +1,8 @@
2025/05/29-15:55:26.213516 7f53e4df86c0 Recovering log #232
2025/05/29-15:55:26.225680 7f53e4df86c0 Delete type=3 #228
2025/05/29-15:55:26.225779 7f53e4df86c0 Delete type=3 #220
2025/05/29-15:55:26.225833 7f53e4df86c0 Delete type=0 #232
2025/05/29-16:03:58.177296 7f53df3ff6c0 Level-0 table #238: started
2025/05/29-16:03:58.177336 7f53df3ff6c0 Level-0 table #238: 0 bytes OK
2025/05/29-16:03:58.183675 7f53df3ff6c0 Delete type=0 #236
2025/05/29-16:03:58.196949 7f53df3ff6c0 Manual compaction at level-0 from '!items!1cZd2hlTV9tykDED' @ 72057594037927935 : 1 .. '!items!y47dBO3Mf5Pn7tOd' @ 0 : 0; will stop at (end)
2025/05/29-16:03:58.197004 7f53df3ff6c0 Manual compaction at level-1 from '!items!1cZd2hlTV9tykDED' @ 72057594037927935 : 1 .. '!items!y47dBO3Mf5Pn7tOd' @ 0 : 0; will stop at (end)
2026/01/09-16:50:28.515550 7f1c563fe6c0 Recovering log #297
2026/01/09-16:50:28.525696 7f1c563fe6c0 Delete type=3 #295
2026/01/09-16:50:28.525817 7f1c563fe6c0 Delete type=0 #297
2026/01/09-16:51:28.848057 7f1c54bfb6c0 Level-0 table #302: started
2026/01/09-16:51:28.848089 7f1c54bfb6c0 Level-0 table #302: 0 bytes OK
2026/01/09-16:51:28.854366 7f1c54bfb6c0 Delete type=0 #300
2026/01/09-16:51:28.868495 7f1c54bfb6c0 Manual compaction at level-0 from '!items!1cZd2hlTV9tykDED' @ 72057594037927935 : 1 .. '!items!y47dBO3Mf5Pn7tOd' @ 0 : 0; will stop at (end)
2026/01/09-16:51:28.868541 7f1c54bfb6c0 Manual compaction at level-1 from '!items!1cZd2hlTV9tykDED' @ 72057594037927935 : 1 .. '!items!y47dBO3Mf5Pn7tOd' @ 0 : 0; will stop at (end)

View File

@@ -1 +1 @@
MANIFEST-000239
MANIFEST-000303

View File

@@ -1,8 +1,8 @@
2025/06/03-13:38:35.120991 7f53e4df86c0 Recovering log #237
2025/06/03-13:38:35.175559 7f53e4df86c0 Delete type=3 #235
2025/06/03-13:38:35.175657 7f53e4df86c0 Delete type=0 #237
2025/06/03-13:46:40.666519 7f53df3ff6c0 Level-0 table #242: started
2025/06/03-13:46:40.666557 7f53df3ff6c0 Level-0 table #242: 0 bytes OK
2025/06/03-13:46:40.701027 7f53df3ff6c0 Delete type=0 #240
2025/06/03-13:46:40.701306 7f53df3ff6c0 Manual compaction at level-0 from '!items!2GaJZsqr2c2mcDRv' @ 72057594037927935 : 1 .. '!items!ui4JGsGwHNlSXVK3' @ 0 : 0; will stop at (end)
2025/06/03-13:46:40.815749 7f53df3ff6c0 Manual compaction at level-1 from '!items!2GaJZsqr2c2mcDRv' @ 72057594037927935 : 1 .. '!items!ui4JGsGwHNlSXVK3' @ 0 : 0; will stop at (end)
2026/01/09-16:51:34.777168 7f1c563fe6c0 Recovering log #301
2026/01/09-16:51:34.788037 7f1c563fe6c0 Delete type=3 #299
2026/01/09-16:51:34.788106 7f1c563fe6c0 Delete type=0 #301
2026/01/09-17:10:52.240948 7f1c54bfb6c0 Level-0 table #306: started
2026/01/09-17:10:52.241037 7f1c54bfb6c0 Level-0 table #306: 0 bytes OK
2026/01/09-17:10:52.254088 7f1c54bfb6c0 Delete type=0 #304
2026/01/09-17:10:52.274702 7f1c54bfb6c0 Manual compaction at level-0 from '!items!2GaJZsqr2c2mcDRv' @ 72057594037927935 : 1 .. '!items!ui4JGsGwHNlSXVK3' @ 0 : 0; will stop at (end)
2026/01/09-17:10:52.274758 7f1c54bfb6c0 Manual compaction at level-1 from '!items!2GaJZsqr2c2mcDRv' @ 72057594037927935 : 1 .. '!items!ui4JGsGwHNlSXVK3' @ 0 : 0; will stop at (end)

View File

@@ -1,9 +1,8 @@
2025/05/29-15:55:26.270465 7f53e55f96c0 Recovering log #232
2025/05/29-15:55:26.282262 7f53e55f96c0 Delete type=3 #228
2025/05/29-15:55:26.282411 7f53e55f96c0 Delete type=3 #220
2025/05/29-15:55:26.282478 7f53e55f96c0 Delete type=0 #232
2025/05/29-16:03:58.203630 7f53df3ff6c0 Level-0 table #238: started
2025/05/29-16:03:58.203677 7f53df3ff6c0 Level-0 table #238: 0 bytes OK
2025/05/29-16:03:58.209907 7f53df3ff6c0 Delete type=0 #236
2025/05/29-16:03:58.224352 7f53df3ff6c0 Manual compaction at level-0 from '!items!2GaJZsqr2c2mcDRv' @ 72057594037927935 : 1 .. '!items!ui4JGsGwHNlSXVK3' @ 0 : 0; will stop at (end)
2025/05/29-16:03:58.224420 7f53df3ff6c0 Manual compaction at level-1 from '!items!2GaJZsqr2c2mcDRv' @ 72057594037927935 : 1 .. '!items!ui4JGsGwHNlSXVK3' @ 0 : 0; will stop at (end)
2026/01/09-16:50:28.558115 7f1c553fc6c0 Recovering log #297
2026/01/09-16:50:28.568519 7f1c553fc6c0 Delete type=3 #295
2026/01/09-16:50:28.568591 7f1c553fc6c0 Delete type=0 #297
2026/01/09-16:51:28.868695 7f1c54bfb6c0 Level-0 table #302: started
2026/01/09-16:51:28.868789 7f1c54bfb6c0 Level-0 table #302: 0 bytes OK
2026/01/09-16:51:28.875865 7f1c54bfb6c0 Delete type=0 #300
2026/01/09-16:51:28.896773 7f1c54bfb6c0 Manual compaction at level-0 from '!items!2GaJZsqr2c2mcDRv' @ 72057594037927935 : 1 .. '!items!ui4JGsGwHNlSXVK3' @ 0 : 0; will stop at (end)
2026/01/09-16:51:28.896837 7f1c54bfb6c0 Manual compaction at level-1 from '!items!2GaJZsqr2c2mcDRv' @ 72057594037927935 : 1 .. '!items!ui4JGsGwHNlSXVK3' @ 0 : 0; will stop at (end)

View File

@@ -1 +1 @@
MANIFEST-000239
MANIFEST-000303

View File

@@ -1,8 +1,8 @@
2025/06/03-13:38:35.178238 7f53e5dfa6c0 Recovering log #237
2025/06/03-13:38:35.231112 7f53e5dfa6c0 Delete type=3 #235
2025/06/03-13:38:35.231235 7f53e5dfa6c0 Delete type=0 #237
2025/06/03-13:46:40.815886 7f53df3ff6c0 Level-0 table #242: started
2025/06/03-13:46:40.815947 7f53df3ff6c0 Level-0 table #242: 0 bytes OK
2025/06/03-13:46:40.852810 7f53df3ff6c0 Delete type=0 #240
2025/06/03-13:46:40.963250 7f53df3ff6c0 Manual compaction at level-0 from '!items!09s33sFuju8zjPqI' @ 72057594037927935 : 1 .. '!items!xlyFCQClBZ1N3O1B' @ 0 : 0; will stop at (end)
2025/06/03-13:46:40.963359 7f53df3ff6c0 Manual compaction at level-1 from '!items!09s33sFuju8zjPqI' @ 72057594037927935 : 1 .. '!items!xlyFCQClBZ1N3O1B' @ 0 : 0; will stop at (end)
2026/01/09-16:51:34.790636 7f1c55bfd6c0 Recovering log #301
2026/01/09-16:51:34.801330 7f1c55bfd6c0 Delete type=3 #299
2026/01/09-16:51:34.801460 7f1c55bfd6c0 Delete type=0 #301
2026/01/09-17:10:52.229549 7f1c54bfb6c0 Level-0 table #306: started
2026/01/09-17:10:52.229666 7f1c54bfb6c0 Level-0 table #306: 0 bytes OK
2026/01/09-17:10:52.240692 7f1c54bfb6c0 Delete type=0 #304
2026/01/09-17:10:52.274685 7f1c54bfb6c0 Manual compaction at level-0 from '!items!09s33sFuju8zjPqI' @ 72057594037927935 : 1 .. '!items!xlyFCQClBZ1N3O1B' @ 0 : 0; will stop at (end)
2026/01/09-17:10:52.274739 7f1c54bfb6c0 Manual compaction at level-1 from '!items!09s33sFuju8zjPqI' @ 72057594037927935 : 1 .. '!items!xlyFCQClBZ1N3O1B' @ 0 : 0; will stop at (end)

View File

@@ -1,9 +1,8 @@
2025/05/29-15:55:26.287199 7f53dffff6c0 Recovering log #232
2025/05/29-15:55:26.297484 7f53dffff6c0 Delete type=3 #228
2025/05/29-15:55:26.298188 7f53dffff6c0 Delete type=3 #220
2025/05/29-15:55:26.298300 7f53dffff6c0 Delete type=0 #232
2025/05/29-16:03:58.210092 7f53df3ff6c0 Level-0 table #238: started
2025/05/29-16:03:58.210134 7f53df3ff6c0 Level-0 table #238: 0 bytes OK
2025/05/29-16:03:58.216327 7f53df3ff6c0 Delete type=0 #236
2025/05/29-16:03:58.224370 7f53df3ff6c0 Manual compaction at level-0 from '!items!09s33sFuju8zjPqI' @ 72057594037927935 : 1 .. '!items!xlyFCQClBZ1N3O1B' @ 0 : 0; will stop at (end)
2025/05/29-16:03:58.224436 7f53df3ff6c0 Manual compaction at level-1 from '!items!09s33sFuju8zjPqI' @ 72057594037927935 : 1 .. '!items!xlyFCQClBZ1N3O1B' @ 0 : 0; will stop at (end)
2026/01/09-16:50:28.570757 7f1c56bff6c0 Recovering log #297
2026/01/09-16:50:28.582016 7f1c56bff6c0 Delete type=3 #295
2026/01/09-16:50:28.582087 7f1c56bff6c0 Delete type=0 #297
2026/01/09-16:51:28.876191 7f1c54bfb6c0 Level-0 table #302: started
2026/01/09-16:51:28.876280 7f1c54bfb6c0 Level-0 table #302: 0 bytes OK
2026/01/09-16:51:28.882908 7f1c54bfb6c0 Delete type=0 #300
2026/01/09-16:51:28.896793 7f1c54bfb6c0 Manual compaction at level-0 from '!items!09s33sFuju8zjPqI' @ 72057594037927935 : 1 .. '!items!xlyFCQClBZ1N3O1B' @ 0 : 0; will stop at (end)
2026/01/09-16:51:28.896847 7f1c54bfb6c0 Manual compaction at level-1 from '!items!09s33sFuju8zjPqI' @ 72057594037927935 : 1 .. '!items!xlyFCQClBZ1N3O1B' @ 0 : 0; will stop at (end)

View File

@@ -1 +1 @@
MANIFEST-000239
MANIFEST-000303

View File

@@ -1,8 +1,8 @@
2025/06/03-13:38:35.066449 7f53e55f96c0 Recovering log #237
2025/06/03-13:38:35.118619 7f53e55f96c0 Delete type=3 #235
2025/06/03-13:38:35.118742 7f53e55f96c0 Delete type=0 #237
2025/06/03-13:46:41.647962 7f53df3ff6c0 Level-0 table #242: started
2025/06/03-13:46:41.648023 7f53df3ff6c0 Level-0 table #242: 0 bytes OK
2025/06/03-13:46:41.687775 7f53df3ff6c0 Delete type=0 #240
2025/06/03-13:46:41.746023 7f53df3ff6c0 Manual compaction at level-0 from '!items!2t1KmBeQNuKK5qlN' @ 72057594037927935 : 1 .. '!items!yBvkQb9S64s908sR' @ 0 : 0; will stop at (end)
2025/06/03-13:46:41.785457 7f53df3ff6c0 Manual compaction at level-1 from '!items!2t1KmBeQNuKK5qlN' @ 72057594037927935 : 1 .. '!items!yBvkQb9S64s908sR' @ 0 : 0; will stop at (end)
2026/01/09-16:51:34.764312 7f1c553fc6c0 Recovering log #301
2026/01/09-16:51:34.774286 7f1c553fc6c0 Delete type=3 #299
2026/01/09-16:51:34.774446 7f1c553fc6c0 Delete type=0 #301
2026/01/09-17:10:52.216414 7f1c54bfb6c0 Level-0 table #306: started
2026/01/09-17:10:52.216464 7f1c54bfb6c0 Level-0 table #306: 0 bytes OK
2026/01/09-17:10:52.228895 7f1c54bfb6c0 Delete type=0 #304
2026/01/09-17:10:52.229275 7f1c54bfb6c0 Manual compaction at level-0 from '!items!2t1KmBeQNuKK5qlN' @ 72057594037927935 : 1 .. '!items!yBvkQb9S64s908sR' @ 0 : 0; will stop at (end)
2026/01/09-17:10:52.229374 7f1c54bfb6c0 Manual compaction at level-1 from '!items!2t1KmBeQNuKK5qlN' @ 72057594037927935 : 1 .. '!items!yBvkQb9S64s908sR' @ 0 : 0; will stop at (end)

View File

@@ -1,9 +1,8 @@
2025/05/29-15:55:26.251480 7f53e5dfa6c0 Recovering log #232
2025/05/29-15:55:26.263256 7f53e5dfa6c0 Delete type=3 #228
2025/05/29-15:55:26.263429 7f53e5dfa6c0 Delete type=3 #220
2025/05/29-15:55:26.263489 7f53e5dfa6c0 Delete type=0 #232
2025/05/29-16:03:58.190030 7f53df3ff6c0 Level-0 table #238: started
2025/05/29-16:03:58.190053 7f53df3ff6c0 Level-0 table #238: 0 bytes OK
2025/05/29-16:03:58.196709 7f53df3ff6c0 Delete type=0 #236
2025/05/29-16:03:58.196970 7f53df3ff6c0 Manual compaction at level-0 from '!items!2t1KmBeQNuKK5qlN' @ 72057594037927935 : 1 .. '!items!yBvkQb9S64s908sR' @ 0 : 0; will stop at (end)
2025/05/29-16:03:58.197022 7f53df3ff6c0 Manual compaction at level-1 from '!items!2t1KmBeQNuKK5qlN' @ 72057594037927935 : 1 .. '!items!yBvkQb9S64s908sR' @ 0 : 0; will stop at (end)
2026/01/09-16:50:28.544082 7f1c55bfd6c0 Recovering log #297
2026/01/09-16:50:28.554845 7f1c55bfd6c0 Delete type=3 #295
2026/01/09-16:50:28.554920 7f1c55bfd6c0 Delete type=0 #297
2026/01/09-16:51:28.854478 7f1c54bfb6c0 Level-0 table #302: started
2026/01/09-16:51:28.854507 7f1c54bfb6c0 Level-0 table #302: 0 bytes OK
2026/01/09-16:51:28.861732 7f1c54bfb6c0 Delete type=0 #300
2026/01/09-16:51:28.868514 7f1c54bfb6c0 Manual compaction at level-0 from '!items!2t1KmBeQNuKK5qlN' @ 72057594037927935 : 1 .. '!items!yBvkQb9S64s908sR' @ 0 : 0; will stop at (end)
2026/01/09-16:51:28.868561 7f1c54bfb6c0 Manual compaction at level-1 from '!items!2t1KmBeQNuKK5qlN' @ 72057594037927935 : 1 .. '!items!yBvkQb9S64s908sR' @ 0 : 0; will stop at (end)

View File

@@ -1 +1 @@
MANIFEST-000135
MANIFEST-000199

View File

@@ -1,8 +1,8 @@
2025/06/03-13:38:34.627636 7f53dffff6c0 Recovering log #133
2025/06/03-13:38:34.686392 7f53dffff6c0 Delete type=3 #131
2025/06/03-13:38:34.686467 7f53dffff6c0 Delete type=0 #133
2025/06/03-13:46:40.512658 7f53df3ff6c0 Level-0 table #138: started
2025/06/03-13:46:40.512710 7f53df3ff6c0 Level-0 table #138: 0 bytes OK
2025/06/03-13:46:40.549233 7f53df3ff6c0 Delete type=0 #136
2025/06/03-13:46:40.549463 7f53df3ff6c0 Manual compaction at level-0 from '!actors!00CKDCqVh5fLZbYo' @ 72057594037927935 : 1 .. '!folders!dwT9WnH0ZnpuZh92' @ 0 : 0; will stop at (end)
2025/06/03-13:46:40.549512 7f53df3ff6c0 Manual compaction at level-1 from '!actors!00CKDCqVh5fLZbYo' @ 72057594037927935 : 1 .. '!folders!dwT9WnH0ZnpuZh92' @ 0 : 0; will stop at (end)
2026/01/09-16:51:34.660696 7f1c55bfd6c0 Recovering log #197
2026/01/09-16:51:34.671894 7f1c55bfd6c0 Delete type=3 #195
2026/01/09-16:51:34.672048 7f1c55bfd6c0 Delete type=0 #197
2026/01/09-17:10:52.192700 7f1c54bfb6c0 Level-0 table #202: started
2026/01/09-17:10:52.192739 7f1c54bfb6c0 Level-0 table #202: 0 bytes OK
2026/01/09-17:10:52.202328 7f1c54bfb6c0 Delete type=0 #200
2026/01/09-17:10:52.229219 7f1c54bfb6c0 Manual compaction at level-0 from '!actors!00CKDCqVh5fLZbYo' @ 72057594037927935 : 1 .. '!folders!dwT9WnH0ZnpuZh92' @ 0 : 0; will stop at (end)
2026/01/09-17:10:52.229329 7f1c54bfb6c0 Manual compaction at level-1 from '!actors!00CKDCqVh5fLZbYo' @ 72057594037927935 : 1 .. '!folders!dwT9WnH0ZnpuZh92' @ 0 : 0; will stop at (end)

View File

@@ -1,9 +1,8 @@
2025/05/29-15:55:26.112642 7f53e4df86c0 Recovering log #128
2025/05/29-15:55:26.125187 7f53e4df86c0 Delete type=3 #124
2025/05/29-15:55:26.126018 7f53e4df86c0 Delete type=3 #116
2025/05/29-15:55:26.126088 7f53e4df86c0 Delete type=0 #128
2025/05/29-16:03:58.156641 7f53df3ff6c0 Level-0 table #134: started
2025/05/29-16:03:58.156669 7f53df3ff6c0 Level-0 table #134: 0 bytes OK
2025/05/29-16:03:58.162999 7f53df3ff6c0 Delete type=0 #132
2025/05/29-16:03:58.170062 7f53df3ff6c0 Manual compaction at level-0 from '!actors!00CKDCqVh5fLZbYo' @ 72057594037927935 : 1 .. '!folders!dwT9WnH0ZnpuZh92' @ 0 : 0; will stop at (end)
2025/05/29-16:03:58.170152 7f53df3ff6c0 Manual compaction at level-1 from '!actors!00CKDCqVh5fLZbYo' @ 72057594037927935 : 1 .. '!folders!dwT9WnH0ZnpuZh92' @ 0 : 0; will stop at (end)
2026/01/09-16:50:28.436690 7f1c563fe6c0 Recovering log #193
2026/01/09-16:50:28.446521 7f1c563fe6c0 Delete type=3 #191
2026/01/09-16:50:28.446584 7f1c563fe6c0 Delete type=0 #193
2026/01/09-16:51:28.813532 7f1c54bfb6c0 Level-0 table #198: started
2026/01/09-16:51:28.813707 7f1c54bfb6c0 Level-0 table #198: 0 bytes OK
2026/01/09-16:51:28.819883 7f1c54bfb6c0 Delete type=0 #196
2026/01/09-16:51:28.840406 7f1c54bfb6c0 Manual compaction at level-0 from '!actors!00CKDCqVh5fLZbYo' @ 72057594037927935 : 1 .. '!folders!dwT9WnH0ZnpuZh92' @ 0 : 0; will stop at (end)
2026/01/09-16:51:28.840496 7f1c54bfb6c0 Manual compaction at level-1 from '!actors!00CKDCqVh5fLZbYo' @ 72057594037927935 : 1 .. '!folders!dwT9WnH0ZnpuZh92' @ 0 : 0; will stop at (end)

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