40 Commits

Author SHA1 Message Date
b407f6e8c0 Migration complétée vers appv2
All checks were successful
Release Creation / build (release) Successful in 1m14s
2026-02-28 12:14:21 +01:00
aecc15d8b9 Migration complétée vers appv2 2026-02-28 12:14:01 +01:00
a2b712b78d Diverses corrections + ajouts armes en compendiums
All checks were successful
Release Creation / build (release) Successful in 1m53s
2026-02-26 13:30:53 +01:00
fc6bb7a4b1 CSS rework et autres améliorations
All checks were successful
Release Creation / build (release) Successful in 46s
2026-02-12 23:08:51 +01:00
f26130d208 CSS rework et autres améliorations 2026-02-12 23:05:22 +01:00
39da08d4cb CSS rework et autres améliorations 2026-02-12 23:04:37 +01:00
e639b6ae3e Fix rollData = 1
All checks were successful
Release Creation / build (release) Successful in 3m36s
2025-12-01 17:57:19 +01:00
8c247a8981 Echec automatique sur 1
All checks were successful
Release Creation / build (release) Successful in 49s
2025-11-21 21:36:27 +01:00
a09e1a1d95 Les compétences de base ne peuvent être supprimées
All checks were successful
Release Creation / build (release) Successful in 47s
2025-11-02 18:30:20 +01:00
787f88873a Les compétences de base ne peuvent être supprimées 2025-11-02 18:29:46 +01:00
ac481e0dd9 Various minot fixes
All checks were successful
Release Creation / build (release) Successful in 1m18s
2025-10-30 20:24:24 +00:00
375622d900 Add welcome message 2025-10-17 15:31:32 +02:00
3bc055cc1f Add welcome message 2025-10-17 15:28:15 +02:00
c97b7a4889 Correction sur blessures et actions restantes
All checks were successful
Release Creation / build (release) Successful in 53s
2025-10-16 22:59:32 +02:00
5d13500838 Fix sur combat + mains gauche
All checks were successful
Release Creation / build (release) Successful in 43s
2025-09-24 16:43:52 +02:00
d21515e1e3 Fix sur combat + mains gauche 2025-09-24 16:43:40 +02:00
78ef009465 Fix sur combat + mains gauche 2025-09-24 16:42:08 +02:00
e794611bf3 Gestion assistée pour les actions
All checks were successful
Release Creation / build (release) Successful in 46s
2025-09-24 15:11:58 +02:00
529a62045e Gestion assistée pour les actions 2025-09-24 15:09:00 +02:00
d462d22a0a Manye enhancements for combat
All checks were successful
Release Creation / build (release) Successful in 42s
2025-09-18 17:26:02 +02:00
710ee54531 Manye enhancements for combat 2025-09-18 17:24:42 +02:00
7994aa7db4 Fix savoir lors de la creation de perso
All checks were successful
Release Creation / build (release) Successful in 1m30s
2025-09-08 23:47:19 +02:00
5176b4ce87 Amelioration histoire creation de perso, CSS bouton et genre de la providence
All checks were successful
Release Creation / build (release) Successful in 56s
2025-07-20 11:21:08 +02:00
3d6f195fc2 Educcation fix + CSS v13
All checks were successful
Release Creation / build (release) Successful in 43s
2025-07-02 23:08:34 +02:00
3693d68c24 Correction sur les compétences de base
All checks were successful
Release Creation / build (release) Successful in 1m0s
2025-06-04 15:29:32 +02:00
16ccd2f3e1 Foundry v13 migration 2025-05-09 10:28:22 +02:00
631eb280ca Foundry v13 migration
All checks were successful
Release Creation / build (release) Successful in 55s
2025-05-09 10:26:29 +02:00
88ca98945f Fix #3 2025-04-20 09:25:48 +02:00
edfb2105d3 Various enhancements + fixes
All checks were successful
Release Creation / build (release) Successful in 56s
2025-04-12 00:18:45 +02:00
84cc59c57d Fix and enhancements
All checks were successful
Release Creation / build (release) Successful in 2m23s
2025-04-05 23:15:46 +02:00
e9c0fbd818 Fix URL scheme
All checks were successful
Release Creation / build (release) Successful in 1m30s
2025-03-19 13:55:30 +01:00
aaabb7ed75 Correction sur XP, echec critique et tir réussi
All checks were successful
Release Creation / build (release) Successful in 53s
2025-03-18 20:38:30 +01:00
fee7a3a9fb Gestion opposition en combat melee 2025-03-11 20:16:26 +01:00
31517030f6 Gestion opposition en combat melee
All checks were successful
Release Creation / build (release) Successful in 39s
2025-03-11 20:10:06 +01:00
c5cbf2a6d1 Gestion du genre dans la creation de perso 2025-03-11 13:45:04 +01:00
a30f813d94 Fix genre 2025-03-10 16:56:25 +01:00
090f6be601 Fix genre 2025-03-10 16:56:10 +01:00
60db1f65e4 Prit fix sur equipement et armes d'hast 2025-03-10 15:52:37 +01:00
d532765d2b Correction sur creation PNJ
All checks were successful
Release Creation / build (release) Successful in 2m0s
2025-03-01 22:01:01 +01:00
b6016742ae Enable PNJ 2025-03-01 19:42:15 +01:00
203 changed files with 7534 additions and 3283 deletions

View File

@@ -1,6 +1,6 @@
name: Release Creation
on:
on:
release:
types: [published]
@@ -8,45 +8,56 @@ 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
- run: echo "💡 The ${{ gitea.repository }} repository will cloned to the runner."
# get part of the tag after the `v`
- name: Extract tag version number
id: get_version
uses: battila7/get-version-action@v2
#- uses: actions/checkout@v3
- uses: https://github.com/RouxAntoine/checkout@v3.5.4
# Substitute the Manifest and Download URLs in the module.json
- name: Substitute Manifest and Download Links For Versioned Ones
id: sub_manifest_link_version
uses: microsoft/variable-substitution@v1
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/${{gitea.repository}}/releases/download/latest/system.json
download: https://www.uberwald.me/gitea/${{gitea.repository}}/releases/download/${{github.event.release.tag_name}}/fvtt-te-deum-${{github.event.release.tag_name}}.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
# get part of the tag after the `v`
- name: Extract tag version number
id: get_version
uses: https://github.com/battila7/get-version-action@v2
- run: zip -r ./fvtt-te-deum-${{github.event.release.tag_name}}.zip system.json template.json README.md LICENSE.txt assets/ fonts/ images/ lang/ modules/ styles/ packs/ templates/ te-deum.mjs
- 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-te-deum-${{github.event.release.tag_name}}.zip
system.json
api_key: '${{secrets.ALLOW_PUSH_RELEASE}}'
# Substitute the Manifest and Download URLs in the module.json
- name: Substitute Manifest and Download Links For Versioned Ones
id: sub_manifest_link_version
uses: https://github.com/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-te-deum/releases/download/latest/system.json
download: https://www.uberwald.me/gitea/public/fvtt-te-deum/releases/download/${{github.event.release.tag_name}}/fvtt-te-deum.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-te-deum.zip system.json README.md LICENSE.txt assets/ fonts/ images/ lang/ modules/ styles/ packs/ templates/
- name: setup go
uses: https://github.com/actions/setup-go@v4
with:
go-version: ">=1.20.1"
- name: Use Go Action
id: use-go-action
uses: https://gitea.com/actions/release-action@main
with:
files: |-
./fvtt-te-deum.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-te-deum'
version: ${{github.event.release.tag_name}}
manifest: 'https://www.uberwald.me/gitea/public/fvtt-te-deum/releases/download/latest/system.json'
notes: 'https://www.uberwald.me/gitea/${{gitea.repository}}/releases/download/${{github.event.release.tag_name}}/fvtt-te-deum.zip'
compatibility-minimum: '13'
compatibility-verified: '13'

54
.gitignore vendored Normal file
View File

@@ -0,0 +1,54 @@
# Dependencies
node_modules/
package-lock.json
# Build outputs
styles/tedeum.css
styles/*.css.map
# IDE & Editor files
.vscode/
.idea/
*.swp
*.swo
*~
.DS_Store
# System files
Thumbs.db
desktop.ini
# Logs
npm-debug.log*
yarn-debug.log*
yarn-error.log*
*.log
# Temporary files
*.tmp
*.temp
.cache/
# Environment variables
.env
.env.local
# Optional: Uncomment if you want to ignore pack database files
# These are usually committed for systems, but can be regenerated
# packs/**/*.ldb
# packs/**/LOG
# packs/**/LOG.old
# packs/**/MANIFEST-*
# packs/**/CURRENT
# Compiled source
dist/
build/
# OS generated files
.DS_Store
.DS_Store?
._*
.Spotlight-V100
.Trashes
ehthumbs.db

View File

@@ -1,7 +1,29 @@
# 13.0.0
- Support de Foundry v13
# 12.0.23
- Correction sur les jets réussie en tir
- Correction sur le dés négatif pour les échecs critiques
- Correction sur l'XP et édition de l'XP en mode MJ
# 12.0.22
- Correction pour les armes d'hast
- Correction sur la zone libre d'équipement
- Bouton + pour créer un équipement à nouveau opérationnel
- Modification de la gestion des jets en combat, avec gestion opposition ou degats immédiats
- Gestion du genre dans la création de personnage
# 12.0.21
- Creation de PNJ OK
# 12.0.20
- Corrections sur la création de perso
- Corrections sur la création de perso
# 12.0.19
- Initial release !

View File

@@ -1,25 +1,17 @@
var gulp = require('gulp');
var less = require('gulp-less');
var postcss = require('gulp-postcss');
var autoprefixer = require('autoprefixer');
var cssnext = require('postcss-preset-env');
var precss = require('precss');
gulp.task('css', function () {
var processors = [
autoprefixer,
cssnext,
precss
];
return gulp.src('./postcss/*.css')
.pipe(postcss(processors))
return gulp.src('./less/*.less')
.pipe(less())
.pipe(postcss([autoprefixer]))
.pipe(gulp.dest('./styles'));
});
gulp.task('watch', function () {
gulp.watch('./less/*.less', gulp.series('css'));
});
function watchUpdates() {
gulp.watch('./postcss/*.css', css);
}
gulp.task('default', gulp.series('css'));

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

BIN
images/icons/xpplus1.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

469
less/actor-sheet.less Normal file
View File

@@ -0,0 +1,469 @@
.editor {
border: 2;
height: 100%;
padding: 0 3px;
}
.medium-editor {
border: 2;
height: 240px;
max-height: 240px;
overflow-y: auto;
overflow-x: hidden;
padding: 0 3px;
prose-mirror, .editor, .editor-content, .ProseMirror {
overflow: hidden;
height: auto;
}
}
.small-editor {
border: 2;
height: 120px;
max-height: 120px;
overflow-y: auto;
overflow-x: hidden;
padding: 0 3px;
prose-mirror, .editor, .editor-content, .ProseMirror {
overflow: hidden;
height: auto;
}
}
.questionnaire-reponse {
max-width: 42rem;
margin-left: 1rem;
}
.questionnaire-element {
margin-top: 0.5rem;
}
// Style unifié pour tous les inputs et selects (fiches acteur, item, roll dialogs)
.fvtt-te-deum {
input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="submit"]):not([type="image"]):not([type="file"]),
select {
background: rgba(248, 245, 238, 0.95);
color: rgba(19, 18, 18, 0.95);
border: 1px solid rgba(139, 115, 85, 0.35);
border-radius: 3px;
padding: 0.15rem 0.3rem;
transition: border-color 0.2s ease, box-shadow 0.2s ease;
&:hover {
border-color: rgba(139, 115, 85, 0.65);
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12);
}
&:focus {
outline: none;
border-color: rgba(139, 115, 85, 0.85);
box-shadow: 0 0 0 2px rgba(139, 115, 85, 0.2);
}
&:disabled {
color: rgba(19, 18, 18, 0.4);
background: rgba(220, 216, 205, 0.6);
border-color: rgba(139, 115, 85, 0.15);
}
}
textarea {
background: rgba(248, 245, 238, 0.95);
color: rgba(19, 18, 18, 0.95);
border: 1px solid rgba(139, 115, 85, 0.35);
border-radius: 3px;
padding: 0.2rem 0.4rem;
transition: border-color 0.2s ease, box-shadow 0.2s ease;
&:hover {
border-color: rgba(139, 115, 85, 0.65);
}
&:focus {
outline: none;
border-color: rgba(139, 115, 85, 0.85);
box-shadow: 0 0 0 2px rgba(139, 115, 85, 0.2);
}
}
}
.fvtt-te-deum.window-app .window-content,
.fvtt-te-deum.application .window-content,
.fvtt-te-deum.window-app.sheet .window-content .sheet-body,
.fvtt-te-deum.application.sheet .window-content .sheet-body {
font-size: 0.8rem;
background: rgba(226, 226, 222, 0.95);
color: rgba(19, 18, 18, 0.95);
}
// Améliorations pour les fiches d'items
.item-form {
.sheet-header {
background: linear-gradient(
135deg,
rgba(226, 226, 222, 0.95) 0%,
rgba(240, 235, 225, 0.9) 100%
);
padding: 0.8rem;
border-radius: 8px;
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15);
border: 1px solid rgba(139, 115, 85, 0.3);
margin-bottom: 0.5rem;
h1.charname input {
// Voir règles haute-spécificité charname ci-dessous
}
}
.sheet-body {
ul {
list-style: none;
padding: 0;
margin: 0;
li.flexrow {
background: rgba(255, 255, 255, 0.3);
padding: 0.4rem 0.6rem;
margin: 0.3rem 0;
border-radius: 4px;
border-left: 3px solid rgba(139, 115, 85, 0.3);
transition: all 0.2s ease;
&:hover {
background: rgba(255, 255, 255, 0.5);
border-left-color: rgba(139, 115, 85, 0.6);
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}
}
}
h3 {
background: linear-gradient(
135deg,
rgba(196, 186, 166, 0.6) 0%,
rgba(226, 226, 222, 0.5) 100%
);
padding: 0.4rem 0.6rem;
margin: 0.8rem 0 0.4rem 0;
border-radius: 4px;
border-left: 4px solid rgba(139, 115, 85, 0.6);
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
font-family: MailartRubberstamp;
font-size: 1.1rem;
color: #3d3a2e;
}
input[type="checkbox"] {
width: 18px;
height: 18px;
cursor: pointer;
}
}
}
// Champ "name" — règles haute-spécificité (spec 0,6,2 / 0,7,2) pour surcharger les règles génériques d'input
// Fiche acteur : font-size 3rem
.fvtt-te-deum.application .window-content .sheet-header h1.charname input[name="name"],
.fvtt-te-deum.window-app .window-content .sheet-header h1.charname input[name="name"] {
font-family: "GreatPrimer";
font-size: 3rem;
background: transparent;
border: none;
border-bottom: 2px solid rgba(139, 115, 85, 0.4);
color: rgba(50, 35, 15, 0.95);
width: 100%;
height: 100%;
margin: 0;
letter-spacing: 0.05em;
transition: border-color 0.2s ease;
&:hover {
border-width: 2px;
border-color: rgba(139, 115, 85, 0.7);
}
&:focus {
border-bottom-color: rgba(139, 115, 85, 0.9);
outline: none;
}
}
// Fiche item : même style mais font-size plus petit
.fvtt-te-deum.application .window-content .item-form .sheet-header h1.charname input[name="name"],
.fvtt-te-deum.window-app .window-content .item-form .sheet-header h1.charname input[name="name"] {
font-size: 1.6rem;
height: auto;
}
.fvtt-te-deum .sheet-body {
padding: 0.25rem 0.5rem;
&:after {
content: "";
display: block;
clear: both;
}
}
.fvtt-te-deum nav {
&.tabs {
.item {
z-index: 2;
position: relative;
opacity: 1;
color: rgba(29, 28, 31);
padding: 0 0.25rem;
&:after {
content: "";
position: absolute;
top: 0;
right: 0;
height: 2rem;
width: 1px;
}
}
}
}
.select-diff {
display: inline-block;
text-align: left;
width: 50px;
}
.fvtt-te-deum.window-app.sheet .window-content .carac-value,
.fvtt-te-deum.application.sheet .window-content .carac-value,
.fvtt-te-deum.window-app.sheet .window-content .competence-xp,
.fvtt-te-deum.application.sheet .window-content .competence-xp {
margin: 0.05rem;
flex-basis: 3rem;
text-align: center;
}
.fvtt-te-deum h1,
.fvtt-te-deum h2,
.fvtt-te-deum h3,
.fvtt-te-deum h4 {
font-weight: bold;
color: rgba(19, 18, 18, 0.95);
}
.fvtt-te-deum .malus-sante {
font-size: 0.88rem;
font-weight: normal;
}
.fvtt-te-deum .malus-sante-active {
color: rgba(200, 80, 10, 0.95);
font-weight: bold;
}
.fvtt-te-deum ul,
.fvtt-te-deum ol {
margin: 0;
padding: 0;
}
.fvtt-te-deum ul,
.fvtt-te-deum li {
list-style-type: none;
}
.header-fields {
li {
margin: 0;
padding: 0;
}
}
.alterne-list {
& > .list-item {
&:hover {
background: rgba(226, 226, 222, 0.4);
transform: translateX(2px);
}
&:nth-child(even) {
background: rgba(240, 235, 225, 0.3);
}
&:nth-child(odd) {
background: rgba(250, 245, 235, 0.2);
}
}
}
.specialisation-label {
font-size: 0.8rem;
}
.carac-label,
.attr-label {
font-weight: bold;
}
.list-item {
margin: 0.125rem;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
border-radius: 0.3rem;
padding: 0.3rem 0.4rem;
flex: 1 1 5rem;
border: 1px solid rgba(139, 115, 85, 0.15);
transition: all 0.2s ease;
&:hover {
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.15);
border-color: rgba(139, 115, 85, 0.3);
background: rgba(255, 255, 255, 0.3);
}
}
.list-item-shadow {
background: linear-gradient(
135deg,
rgba(170, 168, 167, 0.25) 0%,
rgba(200, 195, 185, 0.2) 100%
);
flex-grow: 0;
flex-wrap: nowrap;
justify-content: flex-start;
border-left: 3px solid rgba(139, 115, 85, 0.3);
}
.list-item-shadow2 {
background: linear-gradient(
135deg,
rgba(87, 60, 32, 0.2) 0%,
rgba(120, 90, 60, 0.15) 100%
);
flex-grow: 0;
flex-wrap: nowrap;
justify-content: flex-start;
border-left: 3px solid rgba(87, 60, 32, 0.4);
}
.item-display-show {
display: block;
}
.item-display-hide {
display: none;
}
.item-quantite {
margin-left: 0.5rem;
}
.list-item-margin1 {
margin-left: 1rem;
}
.list-item-margin2 {
margin-left: 2rem;
}
.list-item-margin3 {
margin-left: 3rem;
}
.list-item-margin4 {
margin-left: 4rem;
}
.sheet-competence-img {
width: 24px;
max-width: 24px;
height: 24px;
max-height: 24px;
flex-grow: 0;
margin-right: 0.25rem;
border-radius: 3px;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.15);
border: 1px solid rgba(139, 115, 85, 0.3);
}
.competence-column {
flex-direction: column;
align-content: flex-start;
justify-content: flex-start;
flex-grow: 0;
flex-basis: 1;
}
.competence-header {
align-content: flex-start;
justify-content: flex-start;
font-weight: bold;
flex-grow: 0;
}
.comp-li {
max-width: 8rem;
width: 8rem;
}
.description-label {
flex-grow: 2;
margin-left: 4px;
}
.status-header-label {
margin-left: 2px;
}
.roll-dialog-label {
margin: 4px 0;
min-width: 96px;
}
.short-label {
flex-grow: 1;
}
.keyword-label {
font-size: 0.85rem;
}
.item-sheet-label {
flex-grow: 1;
}
.item-text-long-line {
flex-grow: 3;
}
.score-label {
flex-grow: 2;
align-content: center;
}
.attribut-value,
.carac-value {
flex-grow: 0;
flex-basis: 64px;
margin-right: 4px;
margin-left: 4px;
}
.sante-value,
.competence-value {
flex-grow: 0;
flex-basis: 2rem;
margin-right: 0.25rem;
margin-left: 0.25rem;
}
.description-value {
flex-grow: 0;
flex-basis: 4rem;
margin-right: 0.25rem;
margin-left: 0.25rem;
}
.small-label {
margin-top: 5px;
}

235
less/base.less Normal file
View File

@@ -0,0 +1,235 @@
.fvtt-te-deum.window-app,
.fvtt-te-deum.application {
text-align: justify;
font-size: 16px;
letter-spacing: 1px;
&.sheet {
.window-content {
margin: 0;
padding: 0;
font-family: "GreatPrimer";
.sheet-header {
color: rgba(19, 18, 18, 0.95);
background: rgba(226, 226, 222, 0.95);
}
.tooltip {
&:hover {
.tooltiptext {
top: 2rem;
left: 2rem;
margin: 0;
padding: 0.25rem;
}
}
}
}
}
}
.fvtt-te-deum.sheet header.sheet-header h1 input,
.window-app .window-header,
.application .window-header,
#actors .directory-list,
#navigation #scene-list .scene.nav-item {
font-size: 1rem;
}
.fvtt-te-deum.sheet {
nav {
&.sheet-tabs,
&.tabs {
font-size: 0.8rem;
font-size: 1.2rem;
font-weight: bold;
height: 3rem;
flex: 0 0 3rem;
margin: 0;
padding: 0 0 0 0.25rem;
text-align: center;
line-height: 1.5rem;
border-top: 0 none;
border-bottom: 0 none;
background:
linear-gradient(rgba(226, 226, 222, 0.5), rgba(226, 226, 222, 0.5)),
url("../images/ui/frise_bottom_01.webp");
background-repeat: no-repeat;
background-size: 100% 100%;
z-index: 1;
}
}
header {
&.sheet-header {
.profile-img {
-o-object-fit: cover;
object-fit: cover;
-o-object-position: 50% 0;
object-position: 50% 0;
margin: 0.5rem 0 0.5rem 0.5rem;
padding: 0;
}
.flex-compteurs {
text-align: right;
}
.resource-content {
width: 2rem;
}
}
}
.tab[data-tab] {
padding: 0;
}
li {
margin: 0.2rem;
padding: 0.15rem;
}
}
.fvtt-te-deum.window-app input,
.fvtt-te-deum.application input,
.fvtt-te-deum .item-form,
.fvtt-te-deum.sheet header.sheet-header .flex-group-center.flex-compteurs,
.fvtt-te-deum.sheet header.sheet-header .flex-group-center.flex-fatigue,
.fvtt-te-deum select,
.fvtt-te-deum button,
.item-checkbox,
#sidebar,
#players,
#navigation #nav-toggle {
font-size: 0.8rem;
}
.window-header {
background: rgba(0, 0, 0, 0.75);
}
.strong-text {
font-weight: bold;
}
.fvtt-te-deum .tabs .item.active,
.fvtt-te-deum .blessures-list li ul li:first-child:hover,
.fvtt-te-deum a:hover {
text-shadow: 1px 0px 0px #ff6600;
}
.rollable:hover,
.rollable:focus {
color: #000;
text-shadow: 0 0 10px red;
cursor: pointer;
}
li.folder > .folder-header h3 {
color: #aaa;
}
.fvtt-te-deum table {
border: 1px solid #7a7971;
}
.grid,
.grid-2col {
display: grid;
grid-column: span 2 / span 2;
grid-template-columns: repeat(2, minmax(0, 1fr));
grid-gap: 10px;
grid-gap: 10px;
gap: 10px;
margin: 10px 0;
padding: 0;
}
.grid-3col {
grid-column: span 3 / span 3;
grid-template-columns: repeat(3, minmax(0, 1fr));
}
.grid-4col {
grid-column: span 4 / span 4;
grid-template-columns: repeat(4, minmax(0, 1fr));
}
.grid-5col {
grid-column: span 5 / span 5;
grid-template-columns: repeat(5, minmax(0, 1fr));
}
.grid-6col {
grid-column: span 5 / span 5;
grid-template-columns: repeat(5, minmax(0, 1fr));
}
.grid-7col {
grid-column: span 7 / span 7;
grid-template-columns: repeat(7, minmax(0, 1fr));
}
.grid-8col {
grid-column: span 8 / span 8;
grid-template-columns: repeat(8, minmax(0, 1fr));
}
.grid-9col {
grid-column: span 9 / span 9;
grid-template-columns: repeat(9, minmax(0, 1fr));
}
.grid-10col {
grid-column: span 10 / span 10;
grid-template-columns: repeat(10, minmax(0, 1fr));
}
.grid-11col {
grid-column: span 11 / span 11;
grid-template-columns: repeat(11, minmax(0, 1fr));
}
.grid-12col {
grid-column: span 12 / span 12;
grid-template-columns: repeat(12, minmax(0, 1fr));
}
.flex-group-center,
.flex-group-left,
.flex-group-right {
justify-content: center;
align-items: center;
text-align: center;
padding: 5px;
}
.flex-group-left {
justify-content: flex-start;
text-align: left;
}
.flex-group-right {
justify-content: flex-end;
text-align: right;
}
.flex-center {
align-items: center;
justify-content: center;
text-align: center;
}
.table-create-actor {
font-size: 0.8rem;
}
.flex-between {
justify-content: space-between;
}
.flex-shrink {
flex: "flex-shrink";
}

581
less/chat.less Normal file
View File

@@ -0,0 +1,581 @@
.chat-message-header {
background: linear-gradient(
135deg,
rgba(226, 226, 222, 0.95) 0%,
rgba(196, 186, 166, 0.9) 100%
);
font-size: 0.9rem;
min-height: 26px;
text-align: center;
vertical-align: middle;
display: flex;
align-items: center;
justify-content: center;
border-bottom: 2px solid rgba(139, 115, 85, 0.6);
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.15);
padding: 0.1rem 0.3rem;
border-radius: 6px 6px 0 0;
}
.chat-message .message-header .flavor-text,
.chat-message .message-header .whisper-to {
font-size: 0.9rem;
}
.chat-result-text {
font-weight: bold;
font-family: GreatPrimer;
font-size: 1.1rem;
color: rgba(80, 50, 15, 0.95);
padding: 0 0 0.1rem 0;
line-height: 1.3;
border-bottom: 1px solid rgba(139, 115, 85, 0.4);
display: block;
margin-bottom: 0.2rem;
letter-spacing: 0.03em;
}
.chat-actor-name {
font-weight: bold;
font-family: GreatPrimer;
font-size: 1.1rem;
color: rgba(80, 50, 15, 0.95);
line-height: 1;
letter-spacing: 0.03em;
margin: 0;
padding: 0;
}
.chat-actor-name-opposition {
font-weight: bold;
font-family: GreatPrimer;
font-size: 1.1rem;
color: rgba(80, 50, 15, 0.95);
padding: 0.1rem 0.3rem;
letter-spacing: 0.03em;
}
.chat-result-success {
color: #2d5016;
background: linear-gradient(
135deg,
rgba(144, 238, 144, 0.3),
rgba(107, 186, 107, 0.25)
);
padding: 0.25rem 0.6rem;
border-radius: 4px;
border-left: 3px solid #4a7c2c;
display: inline-block;
margin: 0.15rem 0;
box-shadow: 0 1px 3px rgba(45, 80, 22, 0.2);
font-weight: bold;
}
.chat-result-failure {
color: #7a1a1a;
background: linear-gradient(
135deg,
rgba(255, 160, 160, 0.3),
rgba(205, 120, 120, 0.25)
);
padding: 0.25rem 0.6rem;
border-radius: 4px;
border-left: 3px solid #a82020;
display: inline-block;
margin: 0.15rem 0;
box-shadow: 0 1px 3px rgba(122, 26, 26, 0.2);
font-weight: bold;
}
.chat-img {
width: 64px;
height: 64px;
}
.chat-command-img {
border: 0px;
width: 32px;
height: 32px;
transition:
transform 0.2s ease,
box-shadow 0.2s ease;
border-radius: 4px;
&:hover {
transform: scale(1.1);
box-shadow: 0 3px 8px rgba(255, 102, 0, 0.4);
}
}
.chat-result-column {
min-width: 70%;
width: 70%;
}
.roll-dialog-header {
background: linear-gradient(
135deg,
rgba(226, 226, 222, 0.95) 0%,
rgba(196, 186, 166, 0.9) 100%
);
min-height: 48px;
padding: 0.4rem 0.6rem;
border-radius: 6px 6px 0 0;
border-bottom: 2px solid rgba(139, 115, 85, 0.6);
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.15);
display: flex;
align-items: center;
justify-content: center;
gap: 0.5rem;
.actor-icon {
width: 40px;
height: 40px;
border-radius: 50%;
border: 2px solid rgba(139, 115, 85, 0.5);
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
}
.dialog-roll-title {
font-family: GreatPrimer;
font-size: 1.1rem;
margin: 0;
color: #3d3a2e;
text-shadow: 1px 1px 1px rgba(255, 255, 255, 0.5);
}
}
.actor-icon {
width: 28px;
height: 28px;
padding: 1px;
border-radius: 50%;
border: 2px solid rgba(139, 115, 85, 0.5);
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
flex-shrink: 0;
margin-right: 0.4rem;
}
.padding-dice {
padding-top: 0.2rem;
padding-bottom: 0.2rem;
}
.dice-image {
box-sizing: border-box;
border: none;
border-radius: 0;
max-width: 100%;
}
.dice-image-reroll {
background-color: rgba(115, 224, 115, 0.25);
border-color: #011d33;
box-sizing: border-box;
border: 1px;
border-radius: 0%;
max-width: 100%;
}
.chat-dice {
width: 15%;
height: 15%;
font-size: 15px;
padding: 10px;
padding-bottom: 20px;
padding-top: 0.2rem;
padding-bottom: 0.2rem;
}
.div-center {
align-self: center;
}
.chat-message {
background: rgba(240, 235, 225, 0.95);
font-size: 0.9rem;
border-radius: 8px;
box-shadow: 0 3px 8px rgba(0, 0, 0, 0.15);
border: 1px solid rgba(139, 115, 85, 0.3);
&.whisper {
background: rgba(220, 220, 210, 0.85);
border: 2px solid #545469;
box-shadow: 0 3px 10px rgba(84, 84, 105, 0.3);
}
.chat-icon {
border: 0;
padding: 2px 6px 2px 2px;
float: left;
width: 64px;
height: 64px;
}
}
.ability-icon {
border: 0;
padding: 2px 2px 2px 2px;
max-width: 32px;
max-height: 32px;
width: auto;
height: auto;
}
.small-ability-icon {
border: 0;
padding: 2px 2px 2px 2px;
max-width: 16px;
max-height: 16px;
width: auto;
height: auto;
}
.combat-icon {
border: 0;
padding: 2px 2px 2px 2px;
max-width: 24px;
max-height: 24px;
width: auto;
height: auto;
}
#sidebar-tabs {
flex: 0 0 32px;
box-sizing: border-box;
margin: 0 0 5px;
border-bottom: 1px solid rgba(0, 0, 0, 0);
box-shadow: inset 0 0 2rem rgba(0, 0, 0, 0.5);
& > .item {
&.active {
border: 1px solid rgba(114, 98, 72, 1);
background: rgba(30, 25, 20, 0.75);
box-shadow: 0 0 6px inset rgba(114, 98, 72, 1);
}
}
}
#controls .scene-control,
#controls .control-tool {
box-shadow: 0 0 3px #000;
margin: 0 0 8px;
border-radius: 0;
background: rgba(30, 25, 20, 1);
background-origin: padding-box;
border-image-width: 4px;
border-image-outset: 0px;
}
#controls .scene-control.active,
#controls .control-tool.active,
#controls .scene-control:hover,
#controls .control-tool:hover {
background: rgba(72, 46, 28, 1);
background-origin: padding-box;
border-image-width: 4px;
border-image-outset: 0px;
box-shadow: 0 0 3px #ff6400;
}
#hotbar {
#action-bar {
#macro-list {
border: 1px solid rgba(72, 46, 28, 1);
box-shadow: 2px 2px 5px #000000;
}
.macro {
border-image: url(img/ui/bg_control.jpg) 21 repeat;
border-image-slice: 6 6 6 6 fill;
border-image-width: 6px 6px 6px 6px;
border-image-outset: 0px 0px 0px 0px;
border-radius: 0px;
}
}
.bar-controls {
background: rgba(30, 25, 20, 1);
border: 1px solid rgba(72, 46, 28, 1);
}
}
#players {
border-image-width: 4px;
border-image-outset: 0px;
background: rgba(30, 25, 20, 1);
}
#navigation {
#scene-list {
.scene {
&.nav-item {
background: rgba(30, 25, 20, 1);
background-origin: padding-box;
border-image-width: 4px;
border-image-outset: 0px;
&.active {
background: rgba(72, 46, 28, 1);
}
}
}
}
#nav-toggle {
background: rgba(30, 25, 20, 1);
background-origin: padding-box;
border-image-width: 4px;
border-image-outset: 0px;
}
}
#navigation #scene-list .scene.view,
#navigation #scene-list .scene.context {
background: rgba(72, 46, 28, 1);
background-origin: padding-box;
border-image-width: 4px;
border-image-outset: 0px;
box-shadow: 0 0 3px #ff6400;
}
.chat-card-button {
box-shadow: inset 0px 1px 0px 0px #a6827e;
background: linear-gradient(
to bottom,
rgba(33, 55, 74, 0.98824) 5%,
rgba(21, 40, 51, 0.67059) 100%
);
background-color: rgba(125, 93, 59, 0);
border-radius: 3px;
border: 2px ridge #846109;
display: inline-block;
cursor: pointer;
color: #ffffff;
font-size: 0.8rem;
padding: 4px 12px 0px 12px;
text-decoration: none;
text-shadow: 0px 1px 0px #4d3534;
position: relative;
margin: 2px;
&:hover {
background: linear-gradient(to bottom, #800000 5%, #3e0101 100%);
background-color: red;
}
&:active {
position: relative;
top: 1px;
}
}
.plus-minus-button {
box-shadow: inset 0px 1px 0px 0px #a6827e;
background: linear-gradient(
to bottom,
rgba(33, 55, 74, 0.98824) 5%,
rgba(21, 40, 51, 0.67059) 100%
);
background-color: rgba(125, 93, 59, 0);
border-radius: 2px;
border: 1px ridge #846109;
display: inline-block;
cursor: pointer;
color: #ffffff;
margin: 2px 2px 2px 2px;
padding: 2px 2px 2px 2px;
text-decoration: none;
text-shadow: 0px 1px 0px #4d3534;
position: relative;
margin: 0px;
}
.plus-minus-button:hover,
.chat-card-button:hover {
background: linear-gradient(to bottom, #800000 5%, #3e0101 100%);
background-color: red;
}
.plus-minus-button:active,
.chat-card-button:active {
position: relative;
top: 1px;
}
.plus-minus {
font-size: 0.9rem;
font-weight: bold;
}
.ul-level1 {
padding-left: 2rem;
}
#pause {
font-size: 2rem;
& > h3 {
color: #ccc;
}
& > img {
content: url(../images/ui/logo_tedeum_pause.webp);
height: 200px;
width: 200px;
top: -200px;
left: calc(50% - 132px);
}
}
#logo {
content: url(../images/ui/logo_tedeum_pause.webp);
width: 100px;
height: 60px;
}
.dice-cell {
padding-left: 12px;
padding-right: 12px;
width: 60px;
text-align: center;
}
.dice-formula,
.dice-total {
height: 54px;
position: relative;
}
// Améliorations esthétiques pour les messages de chat
.chat-roll-details {
background: rgba(255, 255, 255, 0.4);
border-radius: 4px;
padding: 0.4rem 0.5rem;
margin: 0.25rem 0;
border: 1px solid rgba(139, 115, 85, 0.25);
ul {
margin: 0;
padding-left: 0.8rem;
li {
padding: 0.05rem 0;
line-height: 1.25;
strong {
color: rgba(70, 67, 49, 0.9);
}
}
}
}
.chat-roll-result-section {
background: linear-gradient(
135deg,
rgba(255, 250, 240, 0.6),
rgba(245, 240, 230, 0.5)
);
border-radius: 4px;
padding: 0.35rem;
margin: 0.2rem 0;
border: 2px solid rgba(139, 115, 85, 0.3);
box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.1);
.chat-total-result {
font-size: 1rem;
font-weight: bold;
color: #3d3a2e;
text-align: center;
padding: 0.25rem;
background: rgba(226, 226, 222, 0.5);
border-radius: 4px;
margin-bottom: 0.25rem;
text-shadow: 1px 1px 2px rgba(255, 255, 255, 0.5);
}
}
.chat-dice-formula {
display: inline-block;
background: rgba(139, 115, 85, 0.15);
padding: 0.15rem 0.4rem;
border-radius: 3px;
font-family: monospace;
font-size: 0.9em;
border: 1px solid rgba(139, 115, 85, 0.3);
color: #5a4a3a;
font-weight: 600;
}
.chat-difficulty-badge {
display: inline-block;
background: linear-gradient(
135deg,
rgba(180, 160, 130, 0.4),
rgba(160, 140, 110, 0.35)
);
padding: 0.15rem 0.5rem;
border-radius: 10px;
font-weight: bold;
border: 1px solid rgba(139, 115, 85, 0.4);
color: #4a3a2a;
font-size: 0.85em;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.15);
}
.chat-info-badge {
display: inline-block;
background: rgba(100, 149, 237, 0.15);
padding: 0.15rem 0.4rem;
border-radius: 3px;
border-left: 2px solid rgba(70, 130, 180, 0.6);
margin: 0.08rem 0;
font-size: 0.8em;
color: #2c4a6a;
}
.chat-warning-badge {
display: inline-block;
background: rgba(255, 200, 100, 0.2);
padding: 0.15rem 0.4rem;
border-radius: 3px;
border-left: 2px solid rgba(218, 165, 32, 0.7);
margin: 0.08rem 0;
font-size: 0.8em;
color: #7a5a1a;
}
.chat-actions-bar {
display: flex;
justify-content: center;
gap: 0.3rem;
padding: 0.4rem;
background: rgba(226, 226, 222, 0.4);
border-top: 1px solid rgba(139, 115, 85, 0.25);
border-radius: 0 0 6px 6px;
margin-top: 0.25rem;
a {
transition: all 0.2s ease;
&:hover {
transform: translateY(-2px);
}
}
}
.chat-negative-dice {
display: inline-block;
background: linear-gradient(
135deg,
rgba(255, 100, 100, 0.2),
rgba(220, 80, 80, 0.15)
);
padding: 0.2rem 0.5rem;
border-radius: 4px;
border: 2px solid rgba(178, 34, 34, 0.4);
font-weight: bold;
color: #8b0000;
margin: 0.15rem 0;
box-shadow: 0 1px 3px rgba(178, 34, 34, 0.2);
}

235
less/dialogs.less Normal file
View File

@@ -0,0 +1,235 @@
.te-deum-roll-dialog {
.window-header {
border-radius: 10px 10px 0% 0%;
}
.window-content {
border-radius: 0% 0% 10px 10px;
}
}
.skill-roll-dialog {
background: linear-gradient(
135deg,
rgba(240, 235, 225, 0.98) 0%,
rgba(250, 245, 235, 0.95) 100%
);
border-radius: 8px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
border: 1px solid rgba(139, 115, 85, 0.3);
overflow: hidden;
.flexcol {
padding: 0.6rem 0.8rem;
gap: 0.4rem;
}
.flexrow {
margin: 0.3rem 0;
padding: 0.4rem 0.5rem;
background: rgba(255, 255, 255, 0.4);
border-radius: 4px;
border-left: 3px solid rgba(139, 115, 85, 0.3);
align-items: center;
gap: 0.5rem;
transition: all 0.2s ease;
&:hover {
background: rgba(255, 255, 255, 0.6);
border-left-color: rgba(139, 115, 85, 0.6);
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}
}
.roll-dialog-label {
font-family: GreatPrimer;
font-size: 0.85rem;
font-weight: 600;
color: #3d3a2e;
min-width: 140px;
&:first-child {
color: rgba(70, 67, 49, 0.9);
font-weight: 700;
}
}
input[type="checkbox"] {
width: 18px;
height: 18px;
cursor: pointer;
}
div {
margin-top: 4px;
margin-bottom: 4px;
}
.sheet-footer {
padding: 0.5rem 0.8rem;
gap: 0.5rem;
border-top: 1px solid rgba(139, 115, 85, 0.3);
margin-top: 0.5rem;
button {
flex: 1;
padding: 0.4rem 0.8rem;
border-radius: 4px;
font-family: "GreatPrimer";
font-size: 0.9rem;
cursor: pointer;
border: 1px solid rgba(139, 115, 85, 0.5);
background: linear-gradient(135deg, rgba(196, 186, 166, 0.8) 0%, rgba(226, 226, 222, 0.9) 100%);
color: rgba(50, 35, 15, 0.95);
transition: all 0.2s ease;
&:hover {
background: linear-gradient(135deg, rgba(196, 186, 166, 1) 0%, rgba(210, 205, 195, 1) 100%);
border-color: rgba(139, 115, 85, 0.8);
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.15);
}
}
}
}
.confront-dice {
border-width: 0px;
}
.bonus-spec {
max-width: 48px;
}
.confront-bonus-container {
position: relative;
flex-grow: 1;
text-align: center;
color: black;
}
.pool-list {
align-items: center;
justify-content: center;
}
.corps-combat-block {
position: relative;
width: 600px;
height: 600px;
}
.silhouette-combat-picture {
width: 250px;
max-width: 250px;
border: 0;
}
.silhouette-combat-block {
position: absolute;
background: white;
border-color: darkgray;
border-style: ridge;
border: 1;
width: 180px;
min-height: 84px;
height: auto;
margin: 0 auto;
font-size: 0.8rem;
align-self: center;
overflow: visible;
}
.silhouette-combat-space {
width: 60px;
min-width: 60px;
}
.center-content {
display: flex;
justify-content: center;
align-items: center;
}
.chat-message .message {
font-family: "GreatPrimer";
font-size: 0.9rem;
}
.fvtt-te-deum-character-creator {
/*background: rgba(226, 226, 222, 0.95);*/
font-family: "GreatPrimer";
font-size: 0.9rem;
.field-title {
font-weight: bold;
}
.form-group label {
color: rgba(30, 25, 15, 0.9);
}
.status-section {
display: block;
max-width: 34rem;
}
.creator-finished-section {
display: block;
max-width: 34rem;
text-align: center;
margin-bottom: 1rem;
}
.stage-main-details {
text-align: center;
margin-top: 1rem;
}
}
.grace-texte {
margin-top: 1rem;
}
.chat-welcome {
text-align: center;
}
.item-name-label {
min-width: 12rem;
}
.compendium-sidebar .directory-item.compendium.locked .compendium-name {
background: rgba(0, 0, 0, 0.1);
}
.compendium-sidebar .directory-item.compendium .compendium-name {
background: rgba(0, 0, 0, 0.1);
}
.compendium-sidebar .directory-item.compendium:hover .compendium-name {
text-shadow: 0 0 8px var(--color-shadow-primary);
background: rgba(0, 0, 0, 0.9);
}
.compendium-sidebar .directory-item.compendium .compendium-footer .source {
display: inline-block;
font-size: var(--font-size-12);
padding: 1px 0.5rem 0 0.25rem;
border-radius: 0 3px 0 0;
background: rgba(0, 0, 0, 0.1);
}
.tedeum-create-character {
align-self: anchor-center;
}
.message-chat-center {
text-align: center;
}
.welcome-message-h3 {
font-size: 1.2rem;
text-align: center;
margin-bottom: 0.5rem;
color: darkred;
}

414
less/items.less Normal file
View File

@@ -0,0 +1,414 @@
.padd-right {
margin-right: 8px;
}
.padd-left {
margin-left: 8px;
}
.fortune-row {
flex-wrap: nowrap;
align-items: center;
gap: 0.4rem;
padding: 0.3rem 0.5rem;
margin-bottom: 0.5rem;
label {
flex: 0 0 auto;
min-width: unset;
font-weight: 600;
color: rgba(70, 67, 49, 0.9);
}
input {
flex: 0 0 auto;
}
}
.stack-left {
align-items: center;
flex-shrink: 1;
flex-grow: 0;
}
.packed-left {
white-space: nowrap;
flex-grow: 0;
}
.input-numeric-short {
width: 52px;
max-width: 52px;
flex-grow: 0;
flex-shrink: 0;
flex-basis: 52px;
margin-right: 0.15rem;
margin-left: 0.15rem;
}
.abilities-table {
align-content: flex-start;
}
.tokenhudext {
display: flex;
flex: 0 !important;
font-weight: 600;
&.left {
justify-content: flex-start;
flex-direction: column;
position: absolute;
top: 2.75rem;
right: 4rem;
}
&.right {
justify-content: flex-start;
flex-direction: column;
position: absolute;
top: 2.75rem;
left: 4rem;
}
}
.control-icon {
&.tokenhudicon {
width: -moz-fit-content;
width: fit-content;
height: -moz-fit-content;
height: fit-content;
min-width: 6rem;
flex-basis: auto;
padding: 0;
line-height: 1rem;
margin: 0.25rem;
&.right {
margin-left: 8px;
}
}
}
#token-hud {
.status-effects {
&.active {
z-index: 2;
}
}
}
.token-sheet {
.window-content {
.flexcol {
.sheet-tabs {
font-size: 0.8rem;
}
}
}
}
.item-checkbox {
height: 25px;
border: 1px solid rgba(115, 105, 83, 0.65098);
border-left: none;
font-weight: 500;
font-size: 1rem;
color: black;
padding-top: 5px;
margin-right: 0px;
width: 45px;
position: relative;
left: 0px;
text-align: center;
}
.skill-label {
font-size: 0.7rem;
}
.skill-good-checkbox {
max-height: 10px;
max-width: 10px;
}
.flex-actions-bar {
flex-grow: 2;
}
#sidebar {
font-size: 1rem;
background-color: #f5f5f5;
background-position: 0px 35px;
background-repeat: no-repeat;
background: rgba(226, 226, 222, 0.95);
color: rgba(19, 18, 18, 0.95);
&.collapsed {
height: 470px !important;
}
#sidebar-tabs {
i {
display: inline-block;
background-position: center;
background-size: cover;
text-shadow: 1px 1px 0 rgba(0, 0, 0, 0.75);
}
}
}
#sidebar-tabs > .collapsed,
#chat-controls .chat-control-icon {
color: rgba(19, 18, 18, 0.95);
text-shadow: 1px 1px 0 rgba(0, 0, 0, 0.75);
}
.sidebar-tab {
.directory-list {
.entity {
border-top: 1px rgba(0, 0, 0, 0.25);
border-bottom: 0 none;
padding: 0.25rem 0;
&:hover {
background: rgba(0, 0, 0, 0.05);
cursor: pointer;
}
}
}
}
.status-small-label {
font-size: 0.65rem;
}
.no-grow {
flex-grow: 1;
max-width: 32px;
}
.status-col-name {
max-width: 72px;
}
.img-no-border {
max-width: 48px;
max-height: 48px;
border: 0px;
}
.items-title-bg {
margin-top: 6px;
color: rgba(19, 18, 18, 0.95);
background: linear-gradient(
135deg,
rgba(196, 186, 166, 0.6) 0%,
rgba(226, 226, 222, 0.5) 100%
);
border-radius: 4px;
padding: 0.3rem 0.5rem;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
border-left: 4px solid rgba(139, 115, 85, 0.6);
h3 {
margin: 0;
padding: 0;
font-size: 1.15rem;
font-weight: 600;
color: rgba(19, 18, 18, 0.95);
}
}
.item-name-label-header-long2 {
flex-grow: 1;
max-width: 14rem;
min-width: 14rem;
}
.impact-box {
border-width: 2px;
border-color: #000000;
border-radius: 6px;
border: 2px ridge #443307;
margin: 4px;
padding: 4px;
}
.impact-title {
font-size: bold;
display: flex;
align-items: center;
justify-content: center;
margin-left: auto;
margin-right: auto;
text-align: center;
}
.items-title-text {
text-align: center;
font-family: MailartRubberstamp;
margin-left: 4px;
}
.lock-icon {
width: 16px;
height: 16px;
}
.item-sheet-img {
width: 64px;
height: 64px;
border: 2px solid rgba(139, 115, 85, 0.4);
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
object-fit: cover;
}
.item-name-img {
flex-grow: 1;
max-width: 2rem;
min-width: 2rem;
}
.item-field {
margin-top: 4px;
}
.item-field-xp {
margin-top: 4px;
min-width: 8rem;
max-width: 8rem;
}
.item-field-label-short {
flex-grow: 1;
max-width: 4rem;
min-width: 4rem;
}
.item-field-label-medium {
flex-grow: 1;
max-width: 6rem;
min-width: 6rem;
}
.item-field-label-long,
.item-name-label-long {
font-weight: 600;
color: rgba(70, 67, 49, 0.9);
min-width: 160px;
}
.item-field-skill {
flex-grow: 1;
max-width: 6.8rem;
min-width: 6.8rem;
}
.item-field-label-long {
flex-grow: 1;
max-width: 10rem;
min-width: 10rem;
}
.item-field-title-long {
flex-grow: 1;
max-width: 12rem;
min-width: 12rem;
}
.item-field-label-long14 {
flex-grow: 1;
max-width: 14rem;
min-width: 14rem;
color: rgba(70, 67, 49, 0.9);
font-size: 1.0rem;
font-weight: 600;
}
.carac-box {
background: linear-gradient(
135deg,
rgba(226, 226, 222, 0.4) 0%,
rgba(240, 235, 225, 0.3) 100%
);
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
border-radius: 0.45rem;
padding: 0.3rem 0.5rem;
border: 1px solid rgba(139, 115, 85, 0.2);
transition: all 0.2s ease;
&:hover {
border-color: rgba(139, 115, 85, 0.4);
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.15);
}
}
.comp-box {
max-width: 16rem;
min-width: 16rem;
width: 16rem;
min-height: 1.6rem;
background: linear-gradient(
135deg,
rgba(250, 245, 235, 0.5) 0%,
rgba(255, 255, 255, 0.3) 100%
);
padding: 0.25rem 0.4rem;
margin: 0.15rem;
border-radius: 3px;
border-left: 2px solid rgba(139, 115, 85, 0.3);
transition: all 0.2s ease;
&:hover {
background: rgba(226, 226, 222, 0.4);
border-left-color: rgba(139, 115, 85, 0.6);
transform: translateX(2px);
}
}
.item-control-end {
align-self: flex-end;
}
.alternate-list {
margin-top: 4px;
flex-wrap: nowrap;
}
.item-filler {
flex-grow: 6;
flex-shrink: 7;
}
.item-controls-fixed {
min-width: 2rem;
max-width: 2rem;
}
.item-controls-fixed-full {
min-width: 3rem;
max-width: 3rem;
}
.item-left-pad {
margin-left: 4px;
}
.attribute-label {
font-weight: bold;
}
.flexrow-no-expand {
flex-grow: 0;
}
.item-input-small {
max-width: 16px;
max-height: 12px;
}
.character-summary-rollable {
text-decoration: underline;
}

240
less/layout.less Normal file
View File

@@ -0,0 +1,240 @@
.fvtt-te-deum.window-app.sheet .window-content,
.fvtt-te-deum.application.sheet .window-content {
overflow: hidden;
display: flex;
flex-direction: column;
}
// AppV2: le part wrapper et la section root du template doivent propager la hauteur
// Uniquement pour les fiches (.sheet) — les autres fenêtres (dialogs) gardent un layout block normal
.application.fvtt-te-deum.sheet .window-content > [data-application-part],
.application.fvtt-te-deum.sheet .window-content > [data-application-part] > section {
flex: 1 1 0;
min-height: 0;
display: flex;
flex-direction: column;
overflow: hidden;
}
.fvtt-te-deum {
display: flex;
flex-direction: column;
overflow: hidden;
.sheet-header {
flex: 0 0 auto;
overflow: hidden;
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: flex-start;
margin-bottom: 10px;
background: linear-gradient(
135deg,
rgba(226, 226, 222, 0.95) 0%,
rgba(240, 235, 225, 0.9) 100%
);
padding: 0.3rem 0.8rem;
border-radius: 8px;
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15);
border: 1px solid rgba(139, 115, 85, 0.3);
.profile-img {
flex: 0 0 128px;
width: 128px;
height: auto;
max-height: 128px;
margin-top: 0px;
margin-right: 10px;
-o-object-fit: cover;
object-fit: cover;
-o-object-position: 50% 0;
object-position: 50% 0;
border-width: 0px;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
border: 2px solid rgba(139, 115, 85, 0.4);
}
.header-fields {
flex: 1;
}
h1 {
&.charname {
height: 50px;
padding: 0px;
margin: 5px 0;
border-bottom: 0;
}
}
.header-identity-fields {
flex-wrap: nowrap;
align-items: center;
gap: 0.3rem;
margin-top: 0.2rem;
input, select {
flex: 1 1 auto;
font-size: 0.75rem;
height: 1.6rem;
}
}
.header-identity-label {
flex: 0 0 auto;
font-size: 0.7rem;
font-weight: 600;
color: rgba(70, 67, 49, 0.9);
white-space: nowrap;
}
}
.sheet-tabs {
flex: 0;
font-family: "MailartRubberstamp";
font-size: 2.2rem;
}
.tox {
.tox-editor-container {
background: #fff;
}
.tox-edit-area {
padding: 0 8px;
}
}
.resource-label {
font-weight: bold;
text-transform: uppercase;
}
.tabs {
height: 40px;
border-top: 1px solid rgba(139, 115, 85, 0.4);
border-bottom: 1px solid rgba(139, 115, 85, 0.4);
background: linear-gradient(
180deg,
rgba(226, 226, 222, 0.5) 0%,
rgba(240, 235, 225, 0.3) 100%
);
color: #000000;
font-family: "GreatPrimer";
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
.item {
line-height: 40px;
font-weight: bold;
padding: 0 1rem;
transition: all 0.2s ease;
&:hover {
background: rgba(226, 226, 222, 0.6);
color: rgba(70, 67, 49, 0.9);
}
&.active {
text-decoration: underline;
text-shadow: none;
background: rgba(196, 186, 166, 0.4);
border-bottom: 3px solid rgba(139, 115, 85, 0.8);
}
}
}
.items-list {
list-style: none;
margin: 1px 0;
padding: 0;
overflow-y: auto;
.item-header {
font-weight: bold;
}
.item {
height: 30px;
line-height: 24px;
padding: 1px 0;
border-bottom: 1px solid #bbb;
.item-image {
flex: 0 0 24px;
margin-right: 5px;
}
img {
display: block;
}
}
.item-name {
margin: 0;
}
.item-controls {
flex: 0 0 86px;
text-align: right;
}
}
}
.profile-img-container {
margin-right: 0.2rem;
max-width: 140px;
width: 140px;
}
.button-img {
vertical-align: baseline;
width: 8%;
height: 8%;
max-height: 48px;
border-width: 0px;
border: 1px solid rgba(0, 0, 0, 0);
&:hover {
color: rgba(255, 255, 128, 0.7);
border: 1px solid rgba(255, 128, 0, 0.8);
cursor: pointer;
}
}
.button-effect-img {
vertical-align: baseline;
width: 16px;
max-height: 16px;
height: 16;
border-width: 0;
}
.small-button-container {
height: 16px;
width: 16px;
border: 0;
vertical-align: bottom;
}
.fvtt-te-deum .sheet-body {
flex: 1 1 0;
min-height: 0;
overflow: hidden;
font-size: 0.8rem;
font-family: "GreatPrimer";
}
.fvtt-te-deum .sheet-body .tab {
height: 100%;
overflow-y: auto;
font-size: 0.8rem;
font-family: "GreatPrimer";
}
.fvtt-te-deum .sheet-body .tab .editor {
height: 100%;
font-size: 0.8rem;
font-family: "GreatPrimer";
}

7
less/tedeum.less Normal file
View File

@@ -0,0 +1,7 @@
@import "variables";
@import "base";
@import "layout";
@import "actor-sheet";
@import "items";
@import "chat";
@import "dialogs";

30
less/variables.less Normal file
View File

@@ -0,0 +1,30 @@
@font-face {
font-family: "MailartRubberstamp";
src: url("../fonts/MailartRubberstamp-Regular.woff") format("woff");
font-family: "GreatPrimer";
src: url("../fonts/IM_FELL_Great_Primer_Roman.woff") format("woff");
}
// Variables LESS
@window-header-title-font-size: 1.3rem;
@window-header-title-font-weight: normal;
@window-header-title-color: #f5f5f5;
@major-button-font-size: 1.05rem;
@major-button-font-weight: normal;
@major-button-color: #dadada;
@tab-header-font-size: 1rem;
@tab-header-font-weight: 700;
@tab-header-color: #403f3e;
@tab-header-color-active: #4a0404;
@actor-input-font-size: 0.8rem;
@actor-input-font-weight: 500;
@actor-input-color: black;
@actor-label-font-size: 0.8rem;
@actor-label-font-weight: 700;
@actor-label-color: rgba(70, 67, 49, 0.76863);
@debug-background-color-red: rgba(255, 0, 0, 0.32941);
@debug-background-color-blue: rgba(29, 0, 255, 0.32941);
@debug-background-color-green: rgba(84, 255, 0, 0.32941);
@debug-box-shadow-red: inset 0 0 2px red;
@debug-box-shadow-blue: inset 0 0 2px blue;
@debug-box-shadow-green: inset 0 0 2px green;

View File

@@ -1,169 +1,227 @@
/**
* Extend the basic ActorSheet with some very simple modifications
* @extends {ActorSheet}
* Feuille de personnage Te Deum - AppV2
*/
import { TeDeumUtility } from "../common/tedeum-utility.js";
const { HandlebarsApplicationMixin } = foundry.applications.api
/* -------------------------------------------- */
export class TeDeumActorPJSheet extends ActorSheet {
export class TeDeumActorPJSheet extends HandlebarsApplicationMixin(foundry.applications.sheets.ActorSheetV2) {
constructor(options = {}) {
super(options)
this._sheetMode = this.constructor.SHEET_MODES.PLAY
}
static SHEET_MODES = { EDIT: 0, PLAY: 1 }
/** @override */
static get defaultOptions() {
return foundry.utils.mergeObject(super.defaultOptions, {
classes: ["fvtt-te-deum", "sheet", "actor"],
template: "systems/fvtt-te-deum/templates/actors/actor-sheet.hbs",
static DEFAULT_OPTIONS = {
classes: ["fvtt-te-deum", "sheet", "actor"],
position: {
width: 860,
height:680,
tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "skills" }],
dragDrop: [{ dragSelector: ".item-list .item", dropSelector: null }],
editScore: true
});
height: 680,
},
form: {
submitOnChange: true,
closeOnSubmit: false,
},
window: {
resizable: true,
},
dragDrop: [{ dragSelector: ".item-list .item", dropSelector: null }],
actions: {
editImage: TeDeumActorPJSheet.#onEditImage,
toggleSheet: TeDeumActorPJSheet.#onToggleSheet,
editItem: TeDeumActorPJSheet.#onEditItem,
deleteItem: TeDeumActorPJSheet.#onDeleteItem,
createItem: TeDeumActorPJSheet.#onCreateItem,
createBlessure: TeDeumActorPJSheet.#onCreateBlessure,
createCompetence: TeDeumActorPJSheet.#onCreateCompetence,
equipItem: TeDeumActorPJSheet.#onEquipItem,
modifyQuantity: TeDeumActorPJSheet.#onModifyQuantity,
rollCompetence: TeDeumActorPJSheet.#onRollCompetence,
rollArme: TeDeumActorPJSheet.#onRollArme,
rollDegats: TeDeumActorPJSheet.#onRollDegats,
},
}
/** @override */
static PARTS = {
sheet: {
template: "systems/fvtt-te-deum/templates/actors/actor-sheet.hbs",
},
}
tabGroups = { primary: "principal" }
get isEditMode() {
return this._sheetMode === this.constructor.SHEET_MODES.EDIT
}
get isPlayMode() {
return this._sheetMode === this.constructor.SHEET_MODES.PLAY
}
/* -------------------------------------------- */
async getData() {
let formData = {
/** @override */
async _prepareContext() {
const actor = this.document
return {
title: this.title,
id: this.actor.id,
type: this.actor.type,
img: this.actor.img,
name: this.actor.name,
id: actor.id,
type: actor.type,
img: actor.img,
name: actor.name,
editable: this.isEditable,
cssClass: this.isEditable ? "editable" : "locked",
system: foundry.utils.duplicate(this.object.system),
limited: this.object.limited,
competences: this.actor.getCompetences(),
system: foundry.utils.duplicate(actor.system),
systemFields: actor.system.schema.fields,
limited: actor.limited,
competences: actor.getCompetences(),
config: foundry.utils.duplicate(game.system.tedeum.config),
armes: this.actor.getArmes(),
caracList: this.actor.prepareCaracteristiques(),
providence: this.actor.prepareProvidence(),
arbreCompetences: this.actor.prepareArbreCompetences(),
equipements: this.actor.getEquipements(),
armures: this.actor.getArmures(),
graces: this.actor.getGraces(),
blessures: this.actor.getBlessures(),
maladies: this.actor.getMaladies(),
poisons: this.actor.getPoisons(),
combat: this.actor.prepareCombat(),
bonusDegats: this.actor.getBonusDegats(),
nbActions: this.actor.getNbActions(),
initiative: this.actor.getInitiative(),
pointsArmuresLourdes: this.actor.getNbArmures(),
nbArmuresLourdes: this.actor.getNbArmuresLourdesActuel(),
santeModifier: this.actor.getSanteModifier(),
educations: this.actor.getEducations(),
description: await TextEditor.enrichHTML(this.object.system.description, { async: true }),
notes: await TextEditor.enrichHTML(this.object.system.notes, { async: true }),
histoire: await TextEditor.enrichHTML(this.object.system.histoire, { async: true }),
options: this.options,
owner: this.document.isOwner,
editScore: this.options.editScore,
isGM: game.user.isGM
armes: actor.getArmes(),
caracList: actor.prepareCaracteristiques(),
providence: actor.prepareProvidence(),
arbreCompetences: actor.prepareArbreCompetences(),
equipements: actor.getEquipements(),
simples: actor.getSimples(),
armures: actor.getArmures(),
graces: actor.getGraces(),
blessures: actor.getBlessures(),
maladies: actor.getMaladies(),
poisons: actor.getPoisons(),
combat: actor.prepareCombat(),
bonusDegats: actor.getBonusDegats(),
nbActions: actor.getNbActions(),
initiative: actor.getInitiative(),
pointsArmuresLourdes: actor.getNbArmures(),
nbArmuresLourdes: actor.getNbArmuresLourdesActuel(),
santeModifier: actor.getSanteModifier(),
educations: actor.getEducations(),
enrichedDescription: await foundry.applications.ux.TextEditor.implementation.enrichHTML(actor.system.description, { async: true }),
enrichedEquipmentFree: await foundry.applications.ux.TextEditor.implementation.enrichHTML(actor.system.equipmentfree, { async: true }),
enrichedNotes: await foundry.applications.ux.TextEditor.implementation.enrichHTML(actor.system.notes, { async: true }),
enrichedHistoire: await foundry.applications.ux.TextEditor.implementation.enrichHTML(actor.system.histoire, { async: true }),
owner: actor.isOwner,
isEditMode: this.isEditMode,
isPlayMode: this.isPlayMode,
isGM: game.user.isGM,
}
this.formData = formData;
console.log("PC : ", formData, this.object);
return formData;
}
/* -------------------------------------------- */
/** @override */
activateListeners(html) {
super.activateListeners(html);
_onRender(context, options) {
super._onRender(context, options)
// Everything below here is only needed if the sheet is editable
if (!this.options.editable) return;
html.bind("keydown", function(e) { // Ignore Enter in actores sheet
if (e.keyCode === 13) return false;
});
// Tab navigation
const nav = this.element.querySelector('nav.tabs[data-group]')
if (nav) {
const group = nav.dataset.group
const activeTab = this.tabGroups[group] || "principal"
nav.querySelectorAll('[data-tab]').forEach(link => {
const tab = link.dataset.tab
link.classList.toggle('active', tab === activeTab)
link.addEventListener('click', event => {
event.preventDefault()
this.tabGroups[group] = tab
this.render()
})
})
this.element.querySelectorAll(`[data-group="${group}"][data-tab]`).forEach(content => {
content.classList.toggle('active', content.dataset.tab === activeTab)
})
}
// Update Inventory Item
html.find('.item-edit').click(ev => {
const li = $(ev.currentTarget).parents(".item-id")
let itemId = li.data("item-id")
const item = this.actor.items.get( itemId );
item.sheet.render(true);
});
// Delete Inventory Item
html.find('.item-delete').click(ev => {
const li = $(ev.currentTarget).parents(".item-id")
TeDeumUtility.confirmDelete(this, li).catch("Error : No deletion confirmed")
// Ignore Enter key in sheet inputs
this.element.addEventListener('keydown', e => {
if (e.keyCode === 13 && e.target.tagName !== 'TEXTAREA') e.preventDefault()
})
html.find('.item-add').click(ev => {
let dataType = $(ev.currentTarget).data("type")
this.actor.createEmbeddedDocuments('Item', [{ name: "NewItem", type: dataType }], { renderSheet: true })
}
/* -------------------------------------------- */
// #region Static action handlers
static async #onEditImage(event) {
const fp = new FilePicker({
type: "image",
current: this.document.img,
callback: path => this.document.update({ img: path }),
})
html.find('.subactor-edit').click(ev => {
const li = $(ev.currentTarget).parents(".item");
let actorId = li.data("actor-id");
let actor = game.actors.get( actorId );
actor.sheet.render(true);
});
html.find('.subactor-delete').click(ev => {
const li = $(ev.currentTarget).parents(".item");
let actorId = li.data("actor-id");
this.actor.delSubActor(actorId);
});
html.find('.quantity-minus').click(event => {
const li = $(event.currentTarget).parents(".item");
this.actor.incDecQuantity( li.data("item-id"), -1 );
} );
html.find('.quantity-plus').click(event => {
const li = $(event.currentTarget).parents(".item");
this.actor.incDecQuantity( li.data("item-id"), +1 );
} );
html.find('.roll-competence').click((event) => {
let compId = $(event.currentTarget).data("comp-id")
this.actor.rollCompetence(compId)
});
html.find('.roll-arme').click((event) => {
const armeId = $(event.currentTarget).data("arme-id")
this.actor.rollArme(armeId)
});
html.find('.roll-degats').click((event) => {
const armeId = $(event.currentTarget).data("arme-id")
this.actor.rollDegatsArme(armeId)
});
html.find('.lock-unlock-sheet').click((event) => {
this.options.editScore = !this.options.editScore;
this.render(true);
});
html.find('.item-equip').click(ev => {
const li = $(ev.currentTarget).parents(".item");
this.actor.equipItem( li.data("item-id") );
this.render(true);
});
html.find('.update-field').change(ev => {
const fieldName = $(ev.currentTarget).data("field-name");
let value = Number(ev.currentTarget.value);
this.actor.update( { [`${fieldName}`]: value } );
});
}
/* -------------------------------------------- */
/** @override */
setPosition(options = {}) {
const position = super.setPosition(options);
const sheetBody = this.element.find(".sheet-body");
const bodyHeight = position.height - 192;
sheetBody.css("height", bodyHeight);
return position;
fp.browse()
}
/* -------------------------------------------- */
/** @override */
_updateObject(event, formData) {
// Update the Actor
return this.object.update(formData);
static async #onToggleSheet(event) {
this._sheetMode = this.isEditMode
? this.constructor.SHEET_MODES.PLAY
: this.constructor.SHEET_MODES.EDIT
this.render()
}
static async #onEditItem(event, target) {
const li = target.closest("[data-item-id]")
const item = this.actor.items.get(li?.dataset.itemId)
if (item) item.sheet.render(true)
}
static async #onDeleteItem(event, target) {
const li = target.closest("[data-item-id]")
await TeDeumUtility.confirmDelete(this, li)
}
static async #onCreateItem(event, target) {
const type = target.dataset.type
await this.actor.createEmbeddedDocuments('Item', [{ name: "Nouveau " + type, type }], { renderSheet: true })
}
static async #onCreateBlessure(event, target) {
const type = target.dataset.type
await this.actor.createEmbeddedDocuments('Item', [{
name: "Nouvelle " + type, type,
system: { typeBlessure: "estafilade", localisation: "corps", value: 0, appliquee: true, description: "" }
}], { renderSheet: true })
}
static async #onCreateCompetence(event, target) {
const type = target.dataset.type
const caracKey = target.dataset.caracKey
await this.actor.createEmbeddedDocuments('Item', [{ name: "Nouvelle " + type, type, system: { caracteristique: caracKey } }], { renderSheet: true })
}
static async #onEquipItem(event, target) {
const li = target.closest("[data-item-id]")
if (!li?.dataset.itemId) return
await this.actor.equipItem(li.dataset.itemId)
}
static async #onModifyQuantity(event, target) {
const li = target.closest("[data-item-id]")
if (!li?.dataset.itemId) return
const item = this.actor.items.get(li.dataset.itemId)
if (!item) return
const delta = parseInt(target.dataset.qty) || 0
await this.actor.incDecQuantity(li.dataset.itemId, delta)
}
static async #onRollCompetence(event, target) {
const li = target.closest("[data-item-id]")
if (!li?.dataset.itemId) return
await this.actor.rollCompetence(li.dataset.itemId)
}
static async #onRollArme(event, target) {
const li = target.closest("[data-item-id]")
if (!li?.dataset.itemId) return
await this.actor.rollArme(li.dataset.itemId)
}
static async #onRollDegats(event, target) {
const li = target.closest("[data-item-id]")
if (!li?.dataset.itemId) return
await this.actor.rollDegatsArme(li.dataset.itemId)
}
// #endregion
}

View File

@@ -14,8 +14,8 @@ export class TeDeumActor extends Actor {
/**
* Override the create() function to provide additional SoS functionality.
*
* This overrided create() function adds initial items
* Namely: Basic skills, money,
* This overrided create() function adds initial items
* Namely: Basic skills, money,
*
* @param {Object} data Barebones actor data which this function adds onto.
* @param {Object} options (Unused) Additional options which customize the creation workflow.
@@ -34,7 +34,7 @@ export class TeDeumActor extends Actor {
return actor;
}
if (data.type == 'pj') {
if (data.type == 'pj' || data.type == 'pnj') {
const skills = await TeDeumUtility.loadCompendium("fvtt-te-deum.competences")
data.items = data.items || []
for (let skill of skills) {
@@ -64,15 +64,44 @@ export class TeDeumActor extends Actor {
super._preUpdate(changed, options, user);
}
/* -------------------------------------------- */
getCompetenceScore(compName) {
let competence = this.items.find(item => item.type == "competence" && item.name.toLowerCase() == compName.toLowerCase())
if (competence) {
if (competence.system.isBase) {
return this.system.caracteristiques[competence.system.caracteristique].value
}
return competence.system.score
}
return 0
}
/* -------------------------------------------- */
getMeilleureCompetenceMainGauche(comp) {
let compScore = this.getCompetenceScore(comp.name)
let mainGaucheScore = this.getCompetenceScore("main gauche")
if (mainGaucheScore < compScore) {
ui.notifications.info(`${this.name} : Utilisation de la compétence Main Gauche au lieu de ${comp.name}`)
let mainGaucheComp = this.items.find(item => item.type == "competence" && item.name.toLowerCase() == "main gauche")
if (!mainGaucheComp) {
// Create a fake competence object
mainGaucheComp = foundry.utils.duplicate(comp)
mainGaucheComp.name = "Main Gauche"
mainGaucheComp.system.isBase = false
mainGaucheComp.system.score = 0
mainGaucheComp.system.caracteristique = "adresse"
mainGaucheComp.system.description = "Compétence Main Gauche (automatique)"
mainGaucheComp.system.isMainGauche = true
return mainGaucheComp
} else {
return mainGaucheComp
}
} else {
return comp
}
}
/* -------------------------------------------- */
_onUpdate(changed, options, userId) {
let updates = []
@@ -112,12 +141,6 @@ export class TeDeumActor extends Actor {
updates.push({ _id: initiative.id, "system.score": Number(newScore) })
}
let actionsTour = this.items.find(item => item.type == "competence" && item.name.toLowerCase() == "actions/tour")
newScore = this.getCommonBaseValue(this.system.caracteristiques.adresse.value)
if (actionsTour && actionsTour?.system.score != newScore) {
updates.push({ _id: actionsTour.id, "system.score": Number(newScore) })
}
let effort = this.items.find(item => item.type == "competence" && item.name.toLowerCase() == "effort")
newScore = this.getCommonBaseValue(this.system.caracteristiques.puissance.value)
if (effort && effort?.system.score != newScore) {
@@ -127,8 +150,10 @@ export class TeDeumActor extends Actor {
if (updates.length > 0) {
this.updateEmbeddedDocuments('Item', updates)
}
super._onUpdate(changed, options, userId);
}
/* -------------------------------------------- */
async _preCreate(data, options, user) {
await super._preCreate(data, options, user);
@@ -145,7 +170,7 @@ export class TeDeumActor extends Actor {
getCommonBaseValue(value) {
return game.system.tedeum.config.COMMON_VALUE[value]?.value || 0
}
getInitiative() {
getInitiativeValue() {
return game.system.tedeum.config.COMMON_VALUE[this.system.caracteristiques.adresse.value]?.value || 0
}
/* -------------------------------------------- */
@@ -153,6 +178,24 @@ export class TeDeumActor extends Actor {
return game.system.tedeum.config.BONUS_DEGATS[this.system.caracteristiques.puissance.value]
}
/* -------------------------------------------- */
getAttaqueBonusDegats(rollData = undefined) {
let base = game.system.tedeum.config.BONUS_DEGATS[this.system.caracteristiques.puissance.value].value
let additionalBonus = 0
if (rollData) {
// Spécificité armes naturelle avec gantelet
if (rollData?.arme?.system.specificites?.poing?.hasSpec && this.items.find(item => item.type == "armure" && item.name.toLowerCase() == "gantelet" && item.system.equipe)) {
additionalBonus += 1
rollData.gantelet = true
}
if (rollData.isChargeAPied) {
additionalBonus += this.getCompetenceScore("course")
} else if (rollData.isChargeACheval) {
additionalBonus += this.getCompetenceScore("equitation")
}
}
return base + additionalBonus
}
/* -------------------------------------------- */
getNbArmures() {
return game.system.tedeum.config.MAX_ARMURES_LOURDES[this.system.caracteristiques.puissance.value]
}
@@ -198,6 +241,11 @@ export class TeDeumActor extends Actor {
TeDeumUtility.sortArrayObjectsByName(comp)
return comp;
}
getSimples() {
let comp = foundry.utils.duplicate(this.items.filter(item => item.type == 'simple') || [])
TeDeumUtility.sortArrayObjectsByName(comp)
return comp;
}
getArmures() {
let comp = foundry.utils.duplicate(this.items.filter(item => item.type == 'armure') || [])
TeDeumUtility.sortArrayObjectsByName(comp)
@@ -259,41 +307,105 @@ export class TeDeumActor extends Actor {
modTotal += blessDef.modifier
}
// Si le nombre de blessures est supérieur au score d'endurance, alors malus supplémentaire
let endurance = this.items.find(item => item.type == "competence" && item.name.toLowerCase() == "endurance")
if (blessures.length > endurance.system.score) {
let enduranceScore = this.getCompetenceScore("endurance")
if (blessures.length > enduranceScore) {
modTotal += -1
}
return modTotal
}
/* -------------------------------------------- */
async appliquerBlessure(blessureId, locId, comment = "") {
let blessure = game.system.tedeum.config.blessures[blessureId]
if (!blessure) {
ui.notifications.warn("Type de blessure inconnu : " + blessureId)
console.error("Type de blessure inconnu : " + blessureId)
return
}
// Create a new blessure object
let blessureObj = {
name: blessure.label,
type: "blessure",
system: {
typeBlessure: blessureId,
localisation: locId || "maindroite",
value: blessure.value,
appliquee: true,
description: comment,
}
}
this.createEmbeddedDocuments('Item', [blessureObj]);
}
/* -------------------------------------------- */
getArmorDegatsModifier(rollData, combat) {
let loc = combat[rollData.loc.id]
// Sans armure
if (loc.armures.length == 0) {
return rollData.arme.system.degatsArmure.sansarmure
}
// Avec armure de cuir
if (loc.armures.find(a => a.system.typeArmure == "cuir")) {
return rollData.arme.system.degatsArmure.cuir
}
// Avec armure de maille
if (loc.armures.find(a => a.system.typeArmure == "maille")) {
return rollData.arme.system.degatsArmure.mailles
}
// Avec armure de plate
if (loc.armures.find(a => a.system.typeArmure == "plate")) {
return rollData.arme.system.degatsArmure.plates
}
return 0
}
/* -------------------------------------------- */
async appliquerDegats(rollData) {
let combat = this.prepareCombat()
rollData.defenderName = this.name
let touche = combat[rollData.loc.id].touche
let armorDegatModifier = this.getArmorDegatsModifier(rollData, combat)
rollData.degats += armorDegatModifier
rollData.armorDegatModifier = armorDegatModifier
let blessureId = "indemne"
if (rollData.degats > 0 && rollData.degats > touche) {
let diff = rollData.degats - touche
for (let bId in game.system.tedeum.config.blessures) {
let blessure = game.system.tedeum.config.blessures[bId]
if (diff >= blessure.degatsMin && diff <= blessure.degatsMax) {
// Create a new blessure object
let blessureObj = {
name: blessure.label,
type: "blessure",
system: {
typeBlessure: bId,
localisation: rollData.loc.id,
appliquee: true,
description: "Blessure infligée par un coup de " + rollData.arme.name + " de " + rollData.alias,
}
if (rollData.isReussiteCritique) {
bId = game.system.tedeum.config.blessuresOrder[blessure.value + 1]
}
rollData.blessure = blessureObj
this.createEmbeddedDocuments('Item', [blessureObj]);
blessureId = bId
break
}
}
}
if (rollData.isReussiteCritique && blessureId == "indemne") { // Critical success without degats => lightest blessure
blessureId = "estafilade"
}
console.log("Appliquer dégats", rollData, combat, blessureId)
if (blessureId != "indemne") {
let blessure = game.system.tedeum.config.blessures[blessureId]
// Create a new blessure object
let blessureObj = {
name: blessure.label,
type: "blessure",
system: {
typeBlessure: blessureId,
localisation: rollData.loc.id,
value: blessure.value,
appliquee: true,
description: "Blessure infligée par un coup de " + rollData.arme.name + " de " + rollData.alias,
}
}
rollData.blessure = blessureObj
rollData.touche = touche
this.createEmbeddedDocuments('Item', [blessureObj]);
}
// Display the relevant chat message
let msg = await TeDeumUtility.createChatWithRollMode(rollData.alias, {
content: await renderTemplate(`systems/fvtt-te-deum/templates/chat/chat-blessure-result.hbs`, rollData)
content: await foundry.applications.handlebars.renderTemplate(`systems/fvtt-te-deum/templates/chat/chat-blessure-result.hbs`, rollData)
})
await msg.setFlag("world", "te-deum-rolldata", rollData)
}
@@ -303,7 +415,11 @@ export class TeDeumActor extends Actor {
c.key = key
c.name = game.system.tedeum.config.caracteristiques[key].label
c.generalqualite = game.system.tedeum.config.descriptionValeur[c.value].qualite
c.qualite = game.system.tedeum.config.descriptionValeur[c.value][key]
if (this.system.genre.toLowerCase() == "homme") {
c.qualite = game.system.tedeum.config.descriptionValeur[c.value][key]
} else {
c.qualite = game.system.tedeum.config.descriptionValeurFemme[c.value][key]
}
c.dice = game.system.tedeum.config.descriptionValeur[c.value].dice
c.negativeDice = game.system.tedeum.config.descriptionValeur[c.value].negativeDice
}
@@ -322,7 +438,11 @@ export class TeDeumActor extends Actor {
prepareProvidence() {
let providence = foundry.utils.deepClone(this.system.providence)
providence.name = "Providence"
providence.qualite = game.system.tedeum.config.providence[providence.value].labelM
if (this.system.genre.toLowerCase() == "homme") {
providence.qualite = game.system.tedeum.config.providence[providence.value].labelM
} else {
providence.qualite = game.system.tedeum.config.providence[providence.value].labelF
}
providence.dice = game.system.tedeum.config.providence[providence.value].diceValue
providence.description = "La Providence représente la Volonté Divine à l'œuvre pour guider ou sauver un être humain. Les PJ montent dans léchelle de la Providence en menant à bien leurs missions et en se montrant vertueux. Les points de Providence peuvent servir à augmenter temporairement une caractéris- tique, à modifier la gravité d'une blessure, et à résister au vieillissement. Chaque person- nage commence avec un score initial de 1 en Providence (au niveau Pauvre pécheur)."
return providence
@@ -360,11 +480,14 @@ export class TeDeumActor extends Actor {
providence.value = Math.min(Math.max(providence.value + value, 0), 6)
this.update({ "system.providence": providence })
}
/* -------------------------------------------- */
modifyXP(key, value) {
async modifyXP(key, value) {
let xp = this.system.caracteristiques[key].experience
xp = Math.max(xp + value, 0)
this.update({ [`system.caracteristiques.${key}.experience`]: xp })
await this.update({ [`system.caracteristiques.${key}.experience`]: xp })
this.sheet?.render(true)
ui.notifications.info(`+${value} XP en ${game.system.tedeum.config.caracteristiques[key].label}`)
}
/* -------------------------------------------- */
@@ -437,7 +560,7 @@ export class TeDeumActor extends Actor {
flag = armure.system.superposableCuir
}
if (item.system.typeArmure == "maille") {
flag = armure.system.superposableMaille
flag = armure.system.superposableMaille
}
if (item.system.typeArmure == "plate") {
flag = armure.system.superposablePlate
@@ -512,12 +635,16 @@ export class TeDeumActor extends Actor {
/* -------------------------------------------- */
getInitiativeScore() {
let initiative = this.items.find(it => it.type == "competence" && it.name.toLowerCase() == "initiative")
if (initiative) {
return initiative.system.score
let initiative = this.getInitiativeValue()
// Vérifie les armes avec bonus d'initiative
let armes = this.getArmes()
for (let arme of armes) {
if (arme.system.equipe && Number(arme.system.initiativeBonus) && Number(arme.system.initiativeBonus) != 0) {
ui.notifications.info("L'arme " + arme.name + " vous confère un bonus d'initiative de " + arme.system.initiativeBonus)
initiative += arme.system.initiativeBonus
}
}
ui.notifications.warn("Impossible de trouver la compétence Initiative pour l'acteur " + this.name)
return -1;
return initiative
}
/* -------------------------------------------- */
@@ -578,6 +705,7 @@ export class TeDeumActor extends Actor {
let rollData = this.getCommonCompetence(compId)
rollData.mode = "competence"
rollData.title = rollData.competence.name
rollData.compScore = rollData.competence.system.isBase ? this.system.caracteristiques[rollData.competence.system.caracteristique].value : rollData.competence.system.score
this.startRoll(rollData).catch("Error on startRoll")
}
@@ -585,13 +713,13 @@ export class TeDeumActor extends Actor {
async rollDegatsArme(armeId) {
let weapon = this.items.get(armeId)
if (weapon) {
let bDegats = 0
if ( weapon.system.typeArme == "melee" ) {
let bDegats = { value: 0 }
if (weapon.system.typeArme == "melee") {
bDegats = this.getBonusDegats()
}
let formula = weapon.system.degats + "+" + bDegats.value
let degatsRoll = await new Roll(formula).roll()
await TeDeumUtility.showDiceSoNice(degatsRoll, game.settings.get("core", "rollMode") )
await TeDeumUtility.showDiceSoNice(degatsRoll, game.settings.get("core", "rollMode"))
let rollData = this.getCommonRollData()
rollData.mode = "degats"
rollData.formula = formula
@@ -600,7 +728,7 @@ export class TeDeumActor extends Actor {
rollData.degats = degatsRoll.total
let msg = await TeDeumUtility.createChatWithRollMode(rollData.alias, {
content: await renderTemplate(`systems/fvtt-te-deum/templates/chat/chat-degats-result.hbs`, rollData)
content: await foundry.applications.handlebars.renderTemplate(`systems/fvtt-te-deum/templates/chat/chat-degats-result.hbs`, rollData)
})
await msg.setFlag("world", "te-deum-rolldata", rollData)
console.log("Rolldata result", rollData)
@@ -630,14 +758,20 @@ export class TeDeumActor extends Actor {
// Setup competence + carac
if (!compName) {
compName = weapon.system.competence
let compIdx = weapon.system.competence
compName = game.system.tedeum.config.armeCompetences[compIdx]?.label
}
let competence = this.items.find(item => item.type == "competence" && item.name.toLowerCase() == compName.toLowerCase())
if (competence) {
rollData.competence = competence
rollData.compScore = rollData.competence.system.isBase ? this.system.caracteristiques[rollData.competence.system.caracteristique].value : rollData.competence.system.score
let c = foundry.utils.duplicate(this.system.caracteristiques[competence.system.caracteristique])
this.updateCarac(c, competence.system.caracteristique)
rollData.carac = c
rollData.allongeLabel = game.system.tedeum.config.armeAllonges[weapon.system.allonge].label
rollData.allongeId = "courte"
rollData.allonges = foundry.utils.duplicate(game.system.tedeum.config.allonges[weapon.system.allonge])
} else {
ui.notifications.warn("Impossible de trouver la compétence " + compName)
return
@@ -651,8 +785,7 @@ export class TeDeumActor extends Actor {
/* -------------------------------------------- */
async startRoll(rollData) {
console.log("startRoll", rollData)
let rollDialog = await TeDeumRollDialog.create(this, rollData)
rollDialog.render(true)
await TeDeumRollDialog.create(this, rollData)
}
}

View File

@@ -6,13 +6,14 @@ export class TeDeumCharacterCreator {
async init() {
this.stages = {}
this.currentStage = "origineSociale"
this.sex = undefined
this.sexe = undefined
this.origineSociale = undefined
this.religion = undefined
this.caracBonus = {}
this.competenceBonus = {}
this.suiviReponses = []
this.competences = TeDeumUtility.getCompetencesForDropDown()
this.choiceSummary = {}
for (let k in game.system.tedeum.config.caracteristiques) {
this.caracBonus[k] = { value: 0 }
@@ -39,6 +40,7 @@ export class TeDeumCharacterCreator {
} else {
this.competenceBonus[compName].value += 1
}
this.choiceSummary[this.currentStage].competences[compName] = 1
}
/*--------------------------------------------*/
@@ -69,7 +71,7 @@ export class TeDeumCharacterCreator {
/*--------------------------------------------*/
async askStageName(context) {
const content = await renderTemplate("systems/fvtt-te-deum/templates/dialogs/character-creator-select-stage-name.hbs", context)
const content = await foundry.applications.handlebars.renderTemplate("systems/fvtt-te-deum/templates/dialogs/character-creator-select-stage-name.hbs", context)
const choiceResult = await foundry.applications.api.DialogV2.wait({
window: { title: context.title },
classes: ["fvtt-te-deum"],
@@ -116,6 +118,7 @@ export class TeDeumCharacterCreator {
/*--------------------------------------------*/
async askQuestionnaire(stage, context) {
context.subtitle = "Questionnaire"
this.choiceSummary[this.currentStage].questionnaire = {}
for (let key in stage.system.questionnaire) {
let question = stage.system.questionnaire[key]
@@ -127,7 +130,7 @@ export class TeDeumCharacterCreator {
context.competences = {}
context.responseKey = "reponse1" // By default
const content = await renderTemplate("systems/fvtt-te-deum/templates/dialogs/character-creator-select-questions.hbs", context)
const content = await foundry.applications.handlebars.renderTemplate("systems/fvtt-te-deum/templates/dialogs/character-creator-select-questions.hbs", context)
const choiceResult = await foundry.applications.api.DialogV2.wait({
window: { title: context.title },
classes: ["fvtt-te-deum"],
@@ -156,7 +159,7 @@ export class TeDeumCharacterCreator {
// Get the responseKey data
let responseKey = $(event.target).data("response-key")
let compName = event.target.value
console.log("Questionnaire Change", responseKey, compName)
console.log("Questionnaire Change", responseKey, compName)
context.competences[responseKey] = compName.toLowerCase()
})
}
@@ -170,13 +173,14 @@ export class TeDeumCharacterCreator {
let compName = context.competences[context.responseKey] || selectedResponse.compName
this.increaseCompetence(compName)
this.suiviReponses.push({ etape: stage.name, question: question.question, reponse: selectedResponse.reponse, compName: compName })
this.suiviReponses.push({ key: this.currentStage, etape: stage.name, question: question.question, reponse: selectedResponse.reponse, compName: compName })
}
}
/*------------- -------------------------------*/
async askCompetences(stage, context) {
context.subtitle = "Choix des Compétences"
this.choiceSummary[this.currentStage].competences = {}
context.fixedCompetences = {}
context.selectCompetences = {}
@@ -192,7 +196,7 @@ export class TeDeumCharacterCreator {
}
}
const content = await renderTemplate("systems/fvtt-te-deum/templates/dialogs/character-creator-select-competences.hbs", context)
const content = await foundry.applications.handlebars.renderTemplate("systems/fvtt-te-deum/templates/dialogs/character-creator-select-competences.hbs", context)
const choiceResult = await foundry.applications.api.DialogV2.wait({
window: { title: context.title },
classes: ["fvtt-te-deum"],
@@ -236,7 +240,7 @@ export class TeDeumCharacterCreator {
}
}
const content = await renderTemplate("systems/fvtt-te-deum/templates/dialogs/character-creator-select-competences.hbs", context)
const content = await foundry.applications.handlebars.renderTemplate("systems/fvtt-te-deum/templates/dialogs/character-creator-select-competences.hbs", context)
const choiceResult = await foundry.applications.api.DialogV2.wait({
window: { title: context.title },
classes: ["fvtt-te-deum"],
@@ -273,6 +277,10 @@ export class TeDeumCharacterCreator {
/*------------- -------------------------------*/
async askCarac(stage, context) {
context.subtitle = "Choix des Caractéristiques"
this.choiceSummary[this.currentStage] = {
caracBonus : {},
competences : {}
}
let selected = []
for (let i = 0; i < stage.system.nbChoixCarac; i++) {
@@ -283,7 +291,7 @@ export class TeDeumCharacterCreator {
context.caracList.push(game.system.tedeum.config.caracteristiques[carac.caracId])
}
const content = await renderTemplate("systems/fvtt-te-deum/templates/dialogs/character-creator-select-carac.hbs", context)
const content = await foundry.applications.handlebars.renderTemplate("systems/fvtt-te-deum/templates/dialogs/character-creator-select-carac.hbs", context)
const choiceResult = await foundry.applications.api.DialogV2.wait({
window: { title: context.title },
classes: ["fvtt-te-deum"],
@@ -312,6 +320,7 @@ export class TeDeumCharacterCreator {
}
this.caracBonus[choiceResult.carac].value += 1
selected.push(choiceResult.carac)
this.choiceSummary[this.currentStage].caracBonus[choiceResult.carac] = 1
}
}
@@ -325,7 +334,7 @@ export class TeDeumCharacterCreator {
origineChoice: game.system.tedeum.config.origineSociale
}
const content = await renderTemplate("systems/fvtt-te-deum/templates/dialogs/character-creator-origine.hbs", context)
const content = await foundry.applications.handlebars.renderTemplate("systems/fvtt-te-deum/templates/dialogs/character-creator-origine.hbs", context)
const label = "Valider le choix de l'Origine Sociale"
const choiceResult = await foundry.applications.api.DialogV2.wait({
window: { title: context.title },
@@ -360,6 +369,12 @@ export class TeDeumCharacterCreator {
for (let key in this.origineSociale.caracteristiques) {
this.caracBonus[key].value += this.origineSociale.caracteristiques[key]
}
this.choiceSummary['origineSociale'] = {
sexe: this.sexe,
religion: this.religion,
origineSociale: this.origineSociale.label,
caracBonus: this.caracBonus,
}
this.currentStage = "pouponniere"
}
@@ -374,6 +389,7 @@ export class TeDeumCharacterCreator {
title: "Création de personnage - La Pouponnière",
subtitle: "Choix de la Pouponnière",
label: "Valider le choix de la Pouponnière",
hasGenre: false,
choices: pouponniereItems,
caracBonus: this.caracBonus,
competenceBonus: this.competenceBonus
@@ -387,6 +403,7 @@ export class TeDeumCharacterCreator {
this.pouponniere = foundry.utils.duplicate(stage.items.find(item => item.id === choiceResult.selectedItem))
context.title = `La Pouponnière - ${this.pouponniere.name}`
TeDeumUtility.prepareEducationContent(this.pouponniere);
this.choiceSummary['pouponniere'] = {}
context.label = "Valider l'augmentation de caracteristique"
await this.askCarac(this.pouponniere, context)
@@ -403,11 +420,12 @@ export class TeDeumCharacterCreator {
/*--------------------------------------------*/
async renderPetitsGrimauds(stage) {
// Filter available pouponniere from origineSociale
let grimaudsItems = stage.items.filter(item => item.system.accessible[this.origineSociale.id].isaccessible)
let grimaudsItems = stage.items.filter(item => item.system.accessible[this.origineSociale.id].isaccessible && (item.system.genre === this.sexe || item.system.genre === "Mixte"))
let context = {
title: "Les Petits Grimauds",
label: "Valider le choix des Petits Grimauds",
hasGenre: true,
choices: grimaudsItems,
caracBonus: this.caracBonus,
competenceBonus: this.competenceBonus
@@ -437,12 +455,13 @@ export class TeDeumCharacterCreator {
/*--------------------------------------------*/
async renderRosesDeLaVie(stage) {
// Filter available pouponniere from origineSociale
let rosesItems = stage.items.filter(item => item.system.accessible[this.origineSociale.id].isaccessible)
let rosesItems = stage.items.filter(item => item.system.accessible[this.origineSociale.id].isaccessible && (item.system.genre === this.sexe || item.system.genre === "Mixte"))
let context = {
title: "Création de personnage - Les Roses de la Vie",
label: "Valider le choix des Roses de la Vie",
choices: rosesItems,
hasGenre: true,
caracBonus: this.caracBonus,
competenceBonus: this.competenceBonus
@@ -488,6 +507,7 @@ export class TeDeumCharacterCreator {
title: "Création de personnage - L'Age Viril",
label: "Valider le choix de l'Age Viril",
choices: ageVirilItems,
hasGenre: false,
caracBonus: this.caracBonus,
competenceBonus: this.competenceBonus
}
@@ -541,7 +561,7 @@ export class TeDeumCharacterCreator {
let actor = await TeDeumActor.create({name: "Nouveau personnage", type: "pj"})
let updates = {}
for (let key in this.caracBonus) {
updates[`system.caracteristiques.${key}.value`] = Number(this.caracBonus[key].value)+1
updates[`system.caracteristiques.${key}.value`] = Number(this.caracBonus[key].value)+1
}
updates['system.genre'] = this.sexe
updates['system.religion'] = TeDeumUtility.upperFirst(this.religion)
@@ -549,22 +569,22 @@ export class TeDeumCharacterCreator {
updates['system.equipmentfree'] = this.ageViril.system.trousseau
actor.update( updates);
// Process competences : increase know skills
// Process competences : increase know skills
let updateComp = []
let toAdd = []
for (let compName in this.competenceBonus) {
let comp = actor.items.find( i => i.type == "competence" && i.name.toLowerCase() === compName.toLowerCase())
if (comp) {
updateComp.push({ _id: comp._id, "system.score": this.competenceBonus[compName].value })
updateComp.push({ _id: comp._id, "system.score": comp.system.score + this.competenceBonus[compName].value })
} else {
toAdd.push( compName)
}
}
}
actor.updateEmbeddedDocuments("Item", updateComp)
// Process adding skills
// Process adding skills
let compendiumSkill = TeDeumUtility.getCompetences()
let compToAdd = [ this.pouponniere, this.grimauds, this.roses, this.ageViril ]
let compToAdd = [ this.pouponniere, this.grimauds, this.roses, this.ageViril ]
for (let compName of toAdd) {
let comp = compendiumSkill.find( i => i.name.toLowerCase() === compName.toLowerCase())
comp.system.score = this.competenceBonus[compName].value
@@ -577,14 +597,42 @@ export class TeDeumCharacterCreator {
await actor.update({ [`system.fortune.${this.origineSociale.cagnotteUnit}`]: newArgent})
let histoire = ""
for (let reponse of this.suiviReponses) {
histoire += `<p>${reponse.question}<br>${reponse.reponse} (${reponse.compName})</p>`
for ( let key in this.choiceSummary) {
let stageSummary = this.choiceSummary[key]
if (stageSummary.sexe) {
histoire += `<h3>Origine Sociale</h3>`
histoire += `<p>${stageSummary.sexe} - ${stageSummary.religion} - ${stageSummary.origineSociale}</p>`
} else {
histoire += `<h3>${game.system.tedeum.config.etapesEducation[key].label}</h3>`
}
if (stageSummary.caracBonus) {
histoire += `<p><strong>Caractéristiques : </strong><ul>`
for (let caracKey in stageSummary.caracBonus) {
histoire += `<li>${TeDeumUtility.upperFirst(caracKey)} +1</li>`
}
histoire += `</ul></p>`
}
if (stageSummary.competences) {
histoire += `<p><strong>Compétences : </strong><ul>`
for (let compName in stageSummary.competences) {
histoire += `<li>${TeDeumUtility.upperFirst(compName)} +1</li>`
}
histoire += `</ul></p>`
}
let questions = this.suiviReponses.filter( r => r.key === key)
if (questions.length > 0) {
histoire += `<p><strong>Réponses au questionnaire : </strong><ul>`
for (let question of questions) {
histoire += `<li>${question.question} : <i>${question.reponse}</i> (${TeDeumUtility.upperFirst(question.compName)}+1)</li>`
}
histoire += `</ul></p>`
}
}
await actor.update({ "system.histoire": histoire})
actor.render(true)
context.pointsCompetence = {
"savoir": { score: actor.getCompetenceScore("Mémoriser"), label: "Savoir" },
"savoir": { score: actor.getCompetenceScore("Mémoriser"), label: "Savoir" },
"sensibilite": { score: actor.getCompetenceScore("Perception"), label: "Sensibilité" },
"entregent": { score: actor.getCompetenceScore("Charme"), label: "Entregent" },
"puissance": { score: actor.getCompetenceScore("Effort"), label: "Puissance" },
@@ -592,7 +640,7 @@ export class TeDeumCharacterCreator {
"adresse": { score: actor.getCompetenceScore("Initiative"), label: "Adresse" },
}
const content = await renderTemplate("systems/fvtt-te-deum/templates/dialogs/character-creator-finished.hbs", context)
const content = await foundry.applications.handlebars.renderTemplate("systems/fvtt-te-deum/templates/dialogs/character-creator-finished.hbs", context)
const label = "Terminer"
const choiceResult = await foundry.applications.api.DialogV2.wait({
window: { title: context.title },

View File

@@ -2,20 +2,44 @@ import { TeDeumUtility } from "../common/tedeum-utility.js";
/* -------------------------------------------- */
export class TeDeumCombat extends Combat {
/* -------------------------------------------- */
async rollInitiative(ids, formula = undefined, messageOptions = {} ) {
async rollInitiative(ids, formula = undefined, messageOptions = {}) {
//console.log("Roll INIT !")
ids = typeof ids === "string" ? [ids] : ids;
for (let cId of ids) {
const c = this.combatants.get(cId);
let initBonus = c.actor ? c.actor.getInitiativeScore( this.id, cId ) : -1;
await this.updateEmbeddedDocuments("Combatant", [ { _id: cId, initiative: initBonus } ]);
let initBonus = c.actor ? c.actor.getInitiativeScore(this.id, cId) : -1;
console.log("Init Bonus : ", c.name, initBonus)
await this.updateEmbeddedDocuments("Combatant", [{ _id: cId, initiative: initBonus }]);
}
return this;
}
/* -------------------------------------------- */
async modifyAction(combatantId, delta, isMainGauche = false) {
let combatant = this.combatants.get(combatantId)
if (!combatant) return;
let ca = combatant.getFlag("world", "available-actions")
if (!ca) {
ca = { nbActions: 1, nbActionsMainGauche: 0 }
}
if (isMainGauche) {
ca.nbActionsMainGauche += delta
} else {
ca.nbActions += delta
}
if (ca.nbActionsMainGauche < 0) ca.nbActionsMainGauche = 0
if (ca.nbActions < 0) ca.nbActions = 0
console.log("Modify Action : ", combatant.name, ca)
if (game.user.isGM) {
await TeDeumUtility.updateCombatantActions(combatant, ca)
} else {
game.socket.emit("system.fvtt-te-deum", { msg: "msg_modify_combat_action", data: { combatantId: combatantId, ca: ca } })
}
}
/* -------------------------------------------- */
static async checkTurnPosition() {
while (game.combat.turn > 0) {

View File

@@ -4,30 +4,46 @@ export const SYSTEM_ID = "fvtt-te-deum";
export const TEDEUM_CONFIG = {
BONUS_DEGATS: [{}, { label: "1d4", value: -2 }, { label: "1d6", value: -1 }, { label: "1d8", value: 0 },
{ label: "1d10", value: 1 }, { label: "1d12", value: 2 }, { label: "1d20", value: 3 }],
{ label: "1d10", value: 1 }, { label: "1d12", value: 2 }, { label: "1d20", value: 3 }],
MAX_ARMURES_LOURDES: [{}, { value: 1 }, { value: 3 }, { value: 5 },
{ value: 7 }, { value: 9 }, { value: 11 }],
{ value: 7 }, { value: 9 }, { value: 11 }],
ACTIONS_PAR_TOUR: [{}, { value: 1 }, { value: 2 }, { value: 2 },
{ value: 3 }, { value: 3 }, { value: 4 }],
{ value: 3 }, { value: 3 }, { value: 4 }],
COMMON_VALUE: [{}, { value: 1 }, { value: 2 }, { value: 3 },
{ value: 4 }, { value: 5 }, { value: 6 }],
{ value: 4 }, { value: 5 }, { value: 6 }],
COUT_XP: [{}, { value: 10 }, { value: 10 }, { value: 10 },
{ value: 10 }, { value: 30 }, { value: 50 }],
{ value: 10 }, { value: 30 }, { value: 50 }],
LOCALISATION: {
"pieddroit": { label: "Pied Droit", value: 1, locMod: 0, id: "pieddroit", nbArmure: 1, score: { min: 1, max: 1 }, coord: { top: 500, left: 0 } },
"jambedroite": { label: "Jambe Droite", value: 1, locMod: -1, id: "jambedroite", nbArmure: 1, score: { min: 3, max: 4 }, coord: { top: 400, left: 100 } },
"jambegauche": { label: "Jambe Gauche", value: 1, locMod: -1, id: "jambegauche", nbArmure: 1, score: { min: 5, max: 6 }, coord: { top: 400, left: 300 } },
"piedgauche": { label: "Pied Gauche", value: 1, locMod: 0, id: "piedgauche", nbArmure: 1, score: { min: 2, max: 2 }, coord: { top: 500, left: 400 } },
"maindroite": { label: "Main Droite", value: 1, locMod: 0, id: "maindroite", nbArmure: 1, score: { min: 7, max: 7 }, coord: { top: 0, left: 0 } },
"maingauche": { label: "Main Gauche", value: 1, locMod: 0, id: "maingauche", nbArmure: 1, score: { min: 8, max: 8 }, coord: { top: 0, left: 400 } },
"brasdroit": { label: "Bras Droit", value: 1, locMod: -1, id: "brasdroit", nbArmure: 2, score: { min: 9, max: 10 }, coord: { top: 200, left: 0 } },
"brasgauche": { label: "Bras Gauche", value: 1, locMod: -1, id: "brasgauche", nbArmure: 2, score: { min: 11, max: 12 }, coord: { top: 200, left: 400 } },
"corps": { label: "Corps", value: 1, id: "corps", locMod: -2, nbArmure: 2, score: { min: 13, max: 17 }, coord: { top: 200, left: 200 } },
"tete": { label: "Tête", value: 1, id: "tete", locMod: -2, nbArmure: 2, score: { min: 18, max: 20 }, coord: { top: 0, left: 200 } },
"pieddroit": { label: "Pied Droit", value: 1, locMod: 0, id: "pieddroit", categorie: "pied", nbArmure: 1, score: { min: 1, max: 1 }, coord: { top: 500, left: 0 } },
"jambedroite": { label: "Jambe Droite", value: 1, locMod: -1, id: "jambedroite", categorie: "jambe", nbArmure: 1, score: { min: 3, max: 4 }, coord: { top: 400, left: 100 } },
"jambegauche": { label: "Jambe Gauche", value: 1, locMod: -1, id: "jambegauche", categorie: "jambe", nbArmure: 1, score: { min: 5, max: 6 }, coord: { top: 400, left: 300 } },
"piedgauche": { label: "Pied Gauche", value: 1, locMod: 0, id: "piedgauche", categorie: "pied", nbArmure: 1, score: { min: 2, max: 2 }, coord: { top: 500, left: 400 } },
"maindroite": { label: "Main Droite", value: 1, locMod: 0, id: "maindroite", categorie: "main", nbArmure: 1, score: { min: 7, max: 7 }, coord: { top: 0, left: 0 } },
"maingauche": { label: "Main Gauche", value: 1, locMod: 0, id: "maingauche", categorie: "main", nbArmure: 1, score: { min: 8, max: 8 }, coord: { top: 0, left: 400 } },
"brasdroit": { label: "Bras Droit", value: 1, locMod: -1, id: "brasdroit", categorie: "bras", nbArmure: 2, score: { min: 9, max: 10 }, coord: { top: 200, left: 0 } },
"brasgauche": { label: "Bras Gauche", value: 1, locMod: -1, id: "brasgauche", categorie: "bras", nbArmure: 2, score: { min: 11, max: 12 }, coord: { top: 200, left: 400 } },
"corps": { label: "Corps", value: 1, id: "corps", categorie: "corps", locMod: -2, nbArmure: 2, score: { min: 13, max: 17 }, coord: { top: 200, left: 200 } },
"tete": { label: "Tête", value: 1, id: "tete", categorie: "tete", locMod: -2, nbArmure: 2, score: { min: 18, max: 20 }, coord: { top: 0, left: 200 } },
},
ATTAQUE_CIBLEES: {
"aucune": { label: "Aucune", id: "aucune", locMod: 0, description: "Attaque non ciblée" },
"pieddroit": { label: "Pied Droit", id: "pieddroit", locMod: 0, description: "Attaque ciblée sur le pied droit" },
"jambedroite": { label: "Jambe Droite", id: "jambedroite", locMod: -1, description: "Attaque ciblée sur la jambe droite" },
"jambegauche": { label: "Jambe Gauche", id: "jambegauche", locMod: -1, description: "Attaque ciblée sur la jambe gauche" },
"piedgauche": { label: "Pied Gauche", id: "piedgauche", locMod: 0, description: "Attaque ciblée sur le pied gauche" },
"maindroite": { label: "Main Droite", id: "maindroite", locMod: 0, description: "Attaque ciblée sur la main droite" },
"maingauche": { label: "Main Gauche", id: "maingauche", locMod: 0, description: "Attaque ciblée sur la main gauche" },
"brasdroit": { label: "Bras Droit", id: "brasdroit", locMod: -1, description: "Attaque ciblée sur le bras droit" },
"brasgauche": { label: "Bras Gauche", id: "brasgauche", locMod: -1, description: "Attaque ciblée sur le bras gauche" },
"corps": { label: "Corps", id: "corps", locMod: -2, description: "Attaque ciblée sur le corps" },
"tete": { label: "Tête", id: "tete", locMod: -2, description: "Attaque ciblée sur la tête" },
},
ARME_SPECIFICITE: {
"poing": { label: "Poings", id: "poing", melee: true, tir: false },
"pied": { label: "Pieds", id: "pied", melee: true, tir: false },
"encombrante": { label: "Encombrante", id: "encombrante", melee: true, tir: true },
"maintiendistance": { label: "Maintien à distance", id: "maintiendistance", melee: true, tir: false },
"coupassomant": { label: "Coup assomant", id: "coupassomant", melee: true, tir: false },
@@ -43,11 +59,11 @@ export const TEDEUM_CONFIG = {
},
ARME_PORTEES: {
"brulepourpoint": { label: "Brûle-pourpoint", difficulty: "facile", id: "brulepourpoint" },
"courte": { label: "Courte", difficulty: "pardefaut", id: "courte" },
"moyenne": { label: "Moyenne", difficulty: "difficile", id: "moyenne" },
"longue": { label: "Longue", difficulty: "perilleux", id: "longue" },
"extreme": { label: "Extrême", difficulty: "desespere", id: "extreme" },
"brulepourpoint": { label: "Brûle-pourpoint (5)", difficulty: "facile", id: "brulepourpoint" },
"courte": { label: "Courte (7)", difficulty: "pardefaut", id: "courte" },
"moyenne": { label: "Moyenne (11)", difficulty: "difficile", id: "moyenne" },
"longue": { label: "Longue (13)", difficulty: "perilleux", id: "longue" },
"extreme": { label: "Extrême (15)", difficulty: "desespere", id: "extreme" },
},
genre: {
@@ -57,7 +73,7 @@ export const TEDEUM_CONFIG = {
descriptionValeurOdd: {
1: { valeur: 1, qualite: "Mauvais", dice: "d4", negativeDice: "d20", savoir: "Sot", sensibilite: "Obtus", entregent: "Rustaud", puissance: "Menu", complexion: "Anémique", adresse: "Empesé" },
2: { valeur: 2, qualite: "Médiocre", dice: "d6", negativeDice: "d12", savoir: "Limité", sensibilite: "Etriqué", entregent: "Frustre", puissance: "Délicat", complexion: "Languide", adresse: "Gauche" },
2: { valeur: 2, qualite: "Médiocre", dice: "d6", negativeDice: "d12", savoir: "Limité", sensibilite: "Etriqué", entregent: "Fruste", puissance: "Délicat", complexion: "Languide", adresse: "Gauche" },
3: { valeur: 3, qualite: "Correct", dice: "d8", negativeDice: "d10", savoir: "Mêlé", sensibilite: "Ouvert", entregent: "Badin", puissance: "Membru", complexion: "Dispos", adresse: "Ingambe" },
4: { valeur: 4, qualite: "Bon", dice: "d10", negativeDice: "d8", savoir: "Lettré", sensibilite: "Fin", entregent: "Disert", puissance: "Vigoureux", complexion: "Gaillard", adresse: "Leste" },
5: { valeur: 5, qualite: "Bon", dice: "d10", negativeDice: "d8", savoir: "Lettré", sensibilite: "Fin", entregent: "Disert", puissance: "Vigoureux", complexion: "Gaillard", adresse: "Leste" },
@@ -71,12 +87,20 @@ export const TEDEUM_CONFIG = {
},
descriptionValeur: {
1: { valeur: 1, qualite: "Mauvais", dice: "d4", negativeDice: "d20", savoir: "Sot", sensibilite: "Obtus", entregent: "Rustaud", puissance: "Menu", complexion: "Anémique", adresse: "Empesé" },
2: { valeur: 2, qualite: "Médiocre", dice: "d6", negativeDice: "d12", savoir: "Limité", sensibilite: "Etriqué", entregent: "Frustre", puissance: "Délicat", complexion: "Languide", adresse: "Gauche" },
2: { valeur: 2, qualite: "Médiocre", dice: "d6", negativeDice: "d12", savoir: "Limité", sensibilite: "Etriqué", entregent: "Fruste", puissance: "Délicat", complexion: "Languide", adresse: "Gauche" },
3: { valeur: 3, qualite: "Correct", dice: "d8", negativeDice: "d10", savoir: "Mêlé", sensibilite: "Ouvert", entregent: "Badin", puissance: "Membru", complexion: "Dispos", adresse: "Ingambe" },
4: { valeur: 4, qualite: "Bon", dice: "d10", negativeDice: "d8", savoir: "Lettré", sensibilite: "Fin", entregent: "Disert", puissance: "Vigoureux", complexion: "Gaillard", adresse: "Leste" },
5: { valeur: 5, qualite: "Excellent", dice: "d12", negativeDice: "d6", savoir: "Docte", sensibilite: "Subtil", entregent: "Galant", puissance: "Musculeux", complexion: "Sanguin", adresse: "Preste" },
6: { valeur: 6, qualite: "Admirable", dice: "d20", negativeDice: "d4", savoir: "Humaniste", sensibilite: "Spirituel", entregent: "Sémillant", puissance: "Hercule", complexion: "Aguerri", adresse: "Alerte" },
},
descriptionValeurFemme: {
1: { valeur: 1, qualite: "Mauvais", dice: "d4", negativeDice: "d20", savoir: "Sotte", sensibilite: "Obtuse", entregent: "Rustaude", puissance: "Menue", complexion: "Anémique", adresse: "Empesée" },
2: { valeur: 2, qualite: "Médiocre", dice: "d6", negativeDice: "d12", savoir: "Limitée", sensibilite: "Etriquée", entregent: "Fruste", puissance: "Délicate", complexion: "Languide", adresse: "Gauche" },
3: { valeur: 3, qualite: "Correct", dice: "d8", negativeDice: "d10", savoir: "Mêlée", sensibilite: "Ouverte", entregent: "Badine", puissance: "Membrue", complexion: "Dispose", adresse: "Ingambe" },
4: { valeur: 4, qualite: "Bon", dice: "d10", negativeDice: "d8", savoir: "Lettrée", sensibilite: "Fine", entregent: "Diserte", puissance: "Vigoureuse", complexion: "Gaillarde", adresse: "Leste" },
5: { valeur: 5, qualite: "Excellent", dice: "d12", negativeDice: "d6", savoir: "Docte", sensibilite: "Subtile", entregent: "Galante", puissance: "Musculeuse", complexion: "Sanguine", adresse: "Preste" },
6: { valeur: 6, qualite: "Admirable", dice: "d20", negativeDice: "d4", savoir: "Humaniste", sensibilite: "Spirituelle", entregent: "Sémillante", puissance: "Hercule", complexion: "Aguerrie", adresse: "Alerte" },
},
diceValeur: ["d4", "d6", "d8", "d10", "d12", "d20"],
degatsArmure: {
sansarmure: { label: "Sans armure" },
@@ -86,7 +110,7 @@ export const TEDEUM_CONFIG = {
},
caracteristiques: {
savoir: { id: "savoir", value: "savoir", label: "Savoir", description:"Cette caractéristique correspond à la capacité d'abstraction intellectuelle ainsi qu'à la culture générale du personnage. Elle permet d'évaluer la compétence de base Mémoriser." },
savoir: { id: "savoir", value: "savoir", label: "Savoir", description: "Cette caractéristique correspond à la capacité d'abstraction intellectuelle ainsi qu'à la culture générale du personnage. Elle permet d'évaluer la compétence de base Mémoriser." },
sensibilite: { id: "sensibilite", value: "sensibilite", label: "Sensibilité", description: "Cette caractéristique correspond à l'ouverture du personnage sur le monde. Elle englobe l'altruisme, la spiritualité et la créativité du personnage. Elle permet d'évaluer la compétence de base Perception." },
entregent: { id: "entregent", value: "entregent", label: "Entregent", description: "Cette caractéristique correspond à l'ensemble des prédispositions sociales du personnage. Elle englobe le charisme et le respect des usages. Elle permet d'évaluer la compétence de base Charme." },
complexion: { id: "complexion", value: "complexion", label: "Complexion", description: "Cette caractéristique permet d'évaluer la santé et la résistance physique du per- sonnage. Elle permet de calculer la com- pétence de base Endurance, capitale dans la résolution des blessures, la résistance à la douleur, au poison et aux maladies." },
@@ -94,10 +118,10 @@ export const TEDEUM_CONFIG = {
adresse: { id: "adresse", value: "adresse", label: "Adresse", description: "Cette caractéristique correspond à la rapidité et la dextérité du personnage. Elle livre le nombre d'actions qu'un personnage peut accomplir en un tour de combat et permet d'évaluer les compétences de base Initiative & Course." },
},
allonges: {
courte: { courte: { malus: 0 }, moyenne: { malus: -1 }, longue: { malus: -2 }, treslongue: { malus: 0, esquive: 2 } },
moyenne: { courte: { malus: 0 }, moyenne: { malus: 0 }, longue: { malus: -1 }, treslongue: { malus: 0, esquive: 2 } },
longue: { courte: { malus: -2 }, moyenne: { malus: -1 }, longue: { malus: 0 }, treslongue: { malus: -1, esquive: 1 } },
treslongue: { courte: { malus: 0, esquive: 2 }, moyenne: { malus: 0, esquive: 2 }, longue: { malus: 0, esquive: 1 }, treslongue: { malus: 0 } },
courte: { courte: { label: "Courte (0)", malus: 0 }, moyenne: { label: "Moyenne (-1)", malus: -1 }, longue: { label: "Longue (-2)", malus: -2 }, treslongue: { label: "Très longue (0, 2 Esquives)", malus: 0, esquive: 2 } },
moyenne: { courte: { label: "Courte (0)", malus: 0 }, moyenne: { label: "Moyenne (0)", malus: 0 }, longue: { label: "Longue (-1)", malus: -1 }, treslongue: { label: "Très longue (0, 2 Esquives)", malus: 0, esquive: 2 } },
longue: { courte: { label: "Courte (-2)", malus: -2 }, moyenne: { label: "Moyenne (-1)", malus: -1 }, longue: { label: "Longue (0)", malus: 0 }, treslongue: { label: "Très longue (-1, 2 Esquives)", malus: -1, esquive: 1 } },
treslongue: { courte: { label: "Courte (0, 2 Esquives)", malus: 0, esquive: 2 }, moyenne: { label: "Moyenne (0, 2 Esquives)", malus: 0, esquive: 2 }, longue: { label: "Longue (0, 1 Esquive)", malus: 0, esquive: 1 }, treslongue: { label: "Très longue (0)", malus: 0 } },
},
providence: [
{ labelM: "Brebis égarée", labelF: "Brebis égarée", value: 0, diceValue: "0" },
@@ -117,6 +141,11 @@ export const TEDEUM_CONFIG = {
melee: { label: "Mêlée", value: "melee" },
tir: { label: "Tir", value: "tir" }
},
genreEducation: {
"homme": { label: "Homme", value: "Homme" },
"femme": { label: "Femme", value: "Femme" },
"mixte": { label: "Mixte", value: "Mixte" }
},
armeAllonges: {
courte: { label: "Courte", value: "courte" },
moyenne: { label: "Moyenne", value: "moyenne" },
@@ -139,24 +168,29 @@ export const TEDEUM_CONFIG = {
},
difficulte: {
aucune: { label: "Aucune", key: "aucune", value: 0 },
routine: { label: "Routine", key: "routine", value: 3 },
facile: { label: "Facile", key: "facile", value: 5 },
pardefaut: { label: "Par Défaut", key: "pardefaut", value: 7 },
malaise: { label: "Malaisé", key: "malaise", value: 9 },
difficile: { label: "Difficile", key: "difficile", value: 11 },
perilleux: { label: "Perilleux", key: "perilleux", value: 13 },
desespere: { label: "Désespéré", key: "desespere", value: 15 }
routine: { label: "Routine (3)", key: "routine", value: 3 },
facile: { label: "Facile (5)", key: "facile", value: 5 },
pardefaut: { label: "Par Défaut (7)", key: "pardefaut", value: 7 },
malaise: { label: "Malaisé (9)", key: "malaise", value: 9 },
difficile: { label: "Difficile (11)", key: "difficile", value: 11 },
perilleux: { label: "Perilleux (13)", key: "perilleux", value: 13 },
desespere: { label: "Désespéré (15)", key: "desespere", value: 15 }
},
monnaie: {
denier: { label: "Deniers", id: "denier", value: 1 },
sol: { label: "Sols", id: "sol", value: 10 },
livre: { label: "Livres", id: "livre", value: 100 }
},
monnaieUnit: {
"1": { label: "Deniers", id: "denier", value: 1 },
"10": { label: "Sols", id: "sol", value: 10 },
"100": { label: "Livres", id: "livre", value: 100 }
},
etapesEducation: {
pouponniere: { label: "La Pouponnière", value: "pouponniere", agemin: 0, agemax: 6, nbCompetences: 2, nbCaracteristiques: 3, hasQuestionnaire: true, hasDebouches: false, hasMultiplier: false, canCompetencesOpt: false },
petitsgrimauds: { label: "La classe des Petits Grimauds", value: "petitsgrimauds", agemin: 7, agemax: 12, nbCompetences: 10, nbCaracteristiques: 3, hasDebouches: false, hasQuestionnaire: true, hasMultiplier: false, canCompetencesOpt: false },
rosevie: { label: "Les Roses de la Vie", value: "rosevie", agemin: 13, agemax: 16, nbCompetences: 2, nbCaracteristiques: 3, hasQuestionnaire: true, hasDebouches: true, hasMultiplier: false, canCompetencesOpt: false },
ageviril: { label: "L'Age Viril", value: "ageviril", agemin: 17, agemax: 17, nbCompetences: 9, nbCaracteristiques: 2, hasQuestionnaire: false, hasDebouches: false, hasMultiplier: true, canCompetencesOpt: true },
pouponniere: { label: "La Pouponnière", value: "pouponniere", agemin: 0, agemax: 6, nbCompetences: 2, nbCaracteristiques: 3, hasGenre: false, hasQuestionnaire: true, hasDebouches: false, hasMultiplier: false, canCompetencesOpt: false },
petitsgrimauds: { label: "La classe des Petits Grimauds", value: "petitsgrimauds", agemin: 7, agemax: 12, nbCompetences: 10, hasGenre: true, nbCaracteristiques: 3, hasDebouches: false, hasQuestionnaire: true, hasMultiplier: false, canCompetencesOpt: false },
rosevie: { label: "Les Roses de la Vie", value: "rosevie", agemin: 13, agemax: 16, nbCompetences: 2, nbCaracteristiques: 3, hasGenre: true, hasQuestionnaire: true, hasDebouches: true, hasMultiplier: false, canCompetencesOpt: false },
ageviril: { label: "L'Age Viril", value: "ageviril", agemin: 17, agemax: 17, nbCompetences: 9, nbCaracteristiques: 2, hasGenre: false, hasQuestionnaire: false, hasDebouches: false, hasMultiplier: true, canCompetencesOpt: true },
},
origineSociale: {
noblesseepee: { label: "Noblesse d'épée", id: "noblesseepee", caracteristiques: { entregent: 1, puissance: 1 }, cagnotte: 10, cagnotteUnit: "livres", value: 1 },
@@ -177,13 +211,14 @@ export const TEDEUM_CONFIG = {
{ value: "1", label: "+1 niveau" },
{ value: "2", label: "+2 niveaux" }
],
blessuresOrder: ["indemne", "estafilade", "plaie", "plaiebeante", "plaieatroce", "tuenet", "tuenet", "tuenet", "tuenet", "tuenet"],
blessures: {
indemne: { value: 0, label: "Indemne", key: "indemne", degatsMax: -1, count: 0, modifier: 0 },
estafilade: { value: 1, label: "Estafilade", key: "estafilade", degatsMin: 0, degatsMax: 2, count: 1, modifier: 0 },
plaie: { value: 2, label: "Plaie", key: "plaie", degatsMin: 3, degatsMax: 4, count: 1, modifier: -1 },
plaiebeante: { value: 3, label: "Plaie béante", key: "plaiebeante", degatsMin: 5, degatsMax: 6, count: 1, modifier: -2 },
plaieatroce: { value: 4, label: "Plaie atroce", key: "plaieatroce", degatsMin: 7, degatsMax: 8, count: 1, horsCombat: true, modifier: -12 },
tunenet: { value: 5, label: "Tué net", key: "tuenet", degatsMin: 9, degatsMax: 100, count: 1, horsCombat: true, mort: true, modifier: -12 }
tuenet: { value: 5, label: "Tué net", key: "tuenet", degatsMin: 9, degatsMax: 100, count: 1, horsCombat: true, mort: true, modifier: -100 }
},
virulence: {
aucune: { label: "Aucune", value: "aucune", modifier: 0 },

View File

@@ -1,6 +1,8 @@
/* -------------------------------------------- */
/* -------------------------------------------- */
const ECRYME_WELCOME_MESSAGE_URL = "https://www.uberwald.me/gitea/public/fvtt-te-deum/raw/branch/main/welcome-message-tedeum.html"
export class TeDeumUtility {
/* -------------------------------------------- */
@@ -12,22 +14,68 @@ export class TeDeumUtility {
CONFIG.JournalEntry.compendiumBanner = "systems/fvtt-te-deum/images/ui/compendium_banner.webp"
CONFIG.Macro.compendiumBanner = "systems/fvtt-te-deum/images/ui/compendium_banner.webp"
CONFIG.Adventure.compendiumBanner = "systems/fvtt-te-deum/images/ui/compendium_banner.webp"
}
Hooks.on('renderChatLog', (log, html, data) => TeDeumUtility.chatListeners(html));
static installHooks() {
Hooks.on('renderChatMessageHTML', (message, html) => {
TeDeumUtility.chatListeners(html);
TeDeumUtility.onRenderChatMessage(message, html);
});
Hooks.on("renderActorDirectory", (app, html, data) => {
if (game.user.can('ACTOR_CREATE')) {
const button = document.createElement('button');
button.style.width = '90%';
button.style.width = '60%';
button.classList.add('tedeum-create-character');
button.innerHTML = 'Créer un Personnage'
button.addEventListener('click', () => {
let cr = new game.system.tedeum.TeDeumCharacterCreator();
cr.init()
})
html.find('.header-actions').after(button)
$(html).find('.header-actions').after(button)
}
})
//Hooks.on("getChatLogEntryContext", (html, options) => TeDeumUtility.chatMenuManager(html, options));
Hooks.on("combatStart", async (combat, updateData, options) => {
this.resetCombatActions(combat)
});
Hooks.on("combatRound", (combat, updateData, updateOptions) => {
// List all actors related to combatant
if (game.user.isGM) {
this.resetCombatActions(combat)
}
})
Hooks.on("getCombatTrackerContextOptions", (html, options) => {
console.log("Get Combat Tracker Context", html, options)
this.pushCombatOptions(html, options);
});
}
/* -------------------------------------------- */
static pushCombatOptions(html, options) {
options.push({ name: "Actions +1", condition: true, icon: '<i class="fas fa-plus"></i>', callback: target => { game.combat.modifyAction($(target).data('combatant-id'), 1); } })
options.push({ name: "Actions -1", condition: true, icon: '<i class="fas fa-minus"></i>', callback: target => { game.combat.modifyAction($(target).data('combatant-id'), -1); } })
options.push({ name: "Actions MG +1", condition: true, icon: '<i class="fas fa-plus"></i>', callback: target => { game.combat.modifyAction($(target).data('combatant-id'), 1, true); } })
options.push({ name: "Actions MG -1", condition: true, icon: '<i class="fas fa-minus"></i>', callback: target => { game.combat.modifyAction($(target).data('combatant-id'), -1, true); } })
}
/* -------------------------------------------- */
static async resetCombatActions(combat) {
if (game.user.isGM) {
for (let c of combat.combatants) {
let actor = game.actors.get(c.actorId)
if (actor) {
let nbActions = actor.getNbActions()?.value || 0
let isMainGauche = (actor.getCompetenceScore("Main gauche") > 0)
let nbActionsMainGauche = isMainGauche ? nbActions : 0
await c.setFlag("world", "available-actions", { nbActions, nbActionsMainGauche })
await c.update({ name: `${c.token.name} (${nbActions} / ${nbActionsMainGauche})` })
}
}
}
}
/* -------------------------------------------- */
@@ -92,6 +140,21 @@ export class TeDeumUtility {
Handlebars.registerHelper('isGM', function () {
return game.user.isGM
})
Handlebars.registerHelper('monnaie', function (value) {
let monnaie = game.system.tedeum.config.monnaieUnit[String(value)]
if (monnaie) {
return monnaie.label
}
return value
})
// Handle v12 removal of this helper
Handlebars.registerHelper('select', function (selected, options) {
const escapedValue = RegExp.escape(Handlebars.escapeExpression(selected));
const rgx = new RegExp(' value=[\"\']' + escapedValue + '[\"\']');
const html = options.fn(this);
return html.replace(rgx, "$& selected");
});
// Load compendium data
const competences = await TeDeumUtility.loadCompendium("fvtt-te-deum.competences")
@@ -119,14 +182,24 @@ export class TeDeumUtility {
/* -------------------------------------------- */
static welcomeMessage() {
if (game.user.isGM) {
ChatMessage.create({
user: game.user.id,
whisper: [game.user.id],
content: `<div id="chat-welcome welcome-message-tedeum"><span class="rdd-roll-part">
<strong>Bienvenu dans Te Deum Pour Un Massacre !</strong>
<div class="chat-welcome">Ce système vous est proposé par Open Sesame Games.<br>
Vous trouverez de l'aide dans @UUID[Compendium.fvtt-te-deum.aides.JournalEntry.uNwJgi4kXBCiZmAH]{Aide pour Te Deum}<br>
ainsi que sur le Discord de Foundry FR : https://discord.gg/pPSDNJk</div>` });
// Try to fetch the welcome message from the github repo "welcome-message-ecryme.html"
fetch(ECRYME_WELCOME_MESSAGE_URL)
.then(response => response.text())
.then(html => {
ChatMessage.create({
user: game.user.id,
whisper: [game.user.id],
content: html
});
})
.catch(error => {
console.error("Error fetching welcome message:", error);
ChatMessage.create({
user: game.user.id,
whisper: [game.user.id],
content: "<b>Bienvenue dans Ecryme RPG !</b><br>Visitez le site officiel pour plus d'informations."
});
});
}
}
@@ -160,6 +233,7 @@ export class TeDeumUtility {
formData.hasMultiplier = etape.hasMultiplier;
formData.hasDebouches = etape.hasDebouches;
formData.canCompetencesOpt = etape.canCompetencesOpt;
formData.hasGenre = etape.hasGenre;
}
/*-------------------------------------------- */
@@ -192,7 +266,7 @@ export class TeDeumUtility {
return actor
}
/* -------------------------------------------- */ /* -------------------------------------------- */
/* -------------------------------------------- */
static async manageOpposition(rollData) {
if (!this.currentOpposition) {
// Store rollData as current GM opposition
@@ -200,29 +274,86 @@ export class TeDeumUtility {
ui.notifications.info("Opposition démarrée avec " + rollData.alias);
} else {
// Perform the opposition
let rWinner = this.currentOpposition
let rLooser = rollData
if (rWinner.total < rLooser.total) {
rWinner = rollData
rLooser = this.currentOpposition
let isAttackWinner = true
let rWinner, rLooser
if (this.currentOpposition.total <= rollData.total) {
rWinner = foundry.utils.duplicate(rollData)
rLooser = foundry.utils.duplicate(this.currentOpposition)
isAttackWinner = false
} else {
rWinner = foundry.utils.duplicate(this.currentOpposition)
rLooser = foundry.utils.duplicate(rollData)
isAttackWinner = true
}
this.currentOpposition = undefined // Reset opposition
let oppositionData = {
winner: rWinner,
looser: rLooser
}
// Update difficulty
rWinner.difficulty = rLooser.total
rLooser.difficulty = rWinner.total
await this.computeResults(rWinner)
await this.computeResults(rLooser)
// Auto XP management when opposed
if (rWinner.isReussiteCritique) {
let actor = this.getActorFromRollData(rWinner)
actor.modifyXP(rWinner.carac.key, 1)
}
if (rLooser.isEchecCritique) {
let actor = this.getActorFromRollData(rLooser)
actor.modifyXP(rLooser.carac.key, 1)
}
let msg = await this.createChatWithRollMode(rollData.alias, {
content: await renderTemplate(`systems/fvtt-te-deum/templates/chat/chat-opposition-result.hbs`, oppositionData)
content: await foundry.applications.handlebars.renderTemplate(`systems/fvtt-te-deum/templates/chat/chat-opposition-result.hbs`, oppositionData)
})
await msg.setFlag("world", "te-deum-rolldata", rollData)
console.log("Rolldata result", rollData)
// Si le gagnant est l'attaquant, appliquer les dégats sur la victime
if (isAttackWinner && rWinner.isSuccess && rWinner.mode == "arme" && rWinner.arme?.system.typeArme == "melee" && rWinner.defenderTokenId) {
await this.appliquerDegats(rWinner)
}
console.log("Opposition result", rollData, isAttackWinner, oppositionData)
}
}
/* -------------------------------------------- */
static getTokenActorFromId(tokenId) {
for (let scene of game.scenes) {
const tokenDoc = scene.tokens.get(tokenId)
if (tokenDoc) return tokenDoc.actor
}
return null
}
/* -------------------------------------------- */
static async appliquerDegats(rollData) {
await this.processAttaqueMelee(rollData)
let defenderActor = this.getTokenActorFromId(rollData.defenderTokenId)
if (defenderActor) {
if (game.user.isGM || defenderActor.isOwner) {
await defenderActor.appliquerDegats(rollData)
} else {
// Send a socket message — seul le premier MJ actif le traitera
game.socket.emit("system.fvtt-te-deum", { name: "msg_apply_damage", data: { rollData } });
}
// Attaque naturelle avec dégats inférieur à -2
if ((rollData?.arme?.system.specificites?.poing?.hasSpec || rollData?.arme?.system.specificites?.pied?.hasSpec) && rollData.degats < -2) {
let attacker = this.getActorFromRollData(rollData)
attacker.appliquerBlessure("estafilade", "maindroite", "Contusion suite à une attaque naturelle")
ui.notifications.info(`${attacker.name} subit 1 contusion en infligeant ${rollData.degats} dégâts à mains nues`)
}
} else {
ui.notifications.error("Impossible de trouver la cible de l'attaque, aucun degats appliqué")
}
}
/* -------------------------------------------- */ /* -------------------------------------------- */
static async chatListeners(html) {
html.on("click", '.chat-command-button', event => {
$(html).on("click", '.chat-command-opposition', event => {
let messageId = TeDeumUtility.findChatMessageId(event.currentTarget)
let message = game.messages.get(messageId)
let rollData = message.getFlag("world", "te-deum-rolldata")
@@ -230,6 +361,33 @@ export class TeDeumUtility {
TeDeumUtility.manageOpposition(rollData, messageId)
}
})
$(html).on("click", '.chat-command-appliquer-degats', event => {
let messageId = TeDeumUtility.findChatMessageId(event.currentTarget)
let message = game.messages.get(messageId)
let rollData = message.getFlag("world", "te-deum-rolldata")
if (rollData) {
TeDeumUtility.appliquerDegats(rollData, messageId)
}
})
$(html).on("click", '.chat-command-gain-xp', async event => {
let messageId = TeDeumUtility.findChatMessageId(event.currentTarget)
let message = game.messages.get(messageId)
let rollData = message.getFlag("world", "te-deum-rolldata")
if (rollData) {
let actor = TeDeumUtility.getActorFromRollData(rollData)
actor.modifyXP(rollData.carac.key, 1)
event.currentTarget.style.display = 'none'; // feedback immédiat local
await message.setFlag("world", "te-deum-xp-used", true) // sync tous les clients
}
})
}
/* -------------------------------------------- */
static onRenderChatMessage(message, html) {
if (message.getFlag("world", "te-deum-xp-used")) {
const btn = html.querySelector('.chat-command-gain-xp');
if (btn) btn.style.display = 'none';
}
}
/* -------------------------------------------- */
@@ -239,9 +397,19 @@ export class TeDeumUtility {
'systems/fvtt-te-deum/templates/actors/editor-notes-gm.hbs',
'systems/fvtt-te-deum/templates/items/partial-item-nav.hbs',
'systems/fvtt-te-deum/templates/items/partial-item-description.hbs',
'systems/fvtt-te-deum/templates/dialogs/partial-creator-status.hbs'
'systems/fvtt-te-deum/templates/dialogs/partial-creator-status.hbs',
'systems/fvtt-te-deum/templates/items/item-arme-sheet.hbs',
'systems/fvtt-te-deum/templates/items/item-armure-sheet.hbs',
'systems/fvtt-te-deum/templates/items/item-blessure-sheet.hbs',
'systems/fvtt-te-deum/templates/items/item-competence-sheet.hbs',
'systems/fvtt-te-deum/templates/items/item-education-sheet.hbs',
'systems/fvtt-te-deum/templates/items/item-equipement-sheet.hbs',
'systems/fvtt-te-deum/templates/items/item-grace-sheet.hbs',
'systems/fvtt-te-deum/templates/items/item-maladie-sheet.hbs',
'systems/fvtt-te-deum/templates/items/item-origine-sheet.hbs',
'systems/fvtt-te-deum/templates/items/item-simple-sheet.hbs',
]
return loadTemplates(templatePaths);
return foundry.applications.handlebars.loadTemplates(templatePaths);
}
/* -------------------------------------------- */
@@ -318,12 +486,34 @@ export class TeDeumUtility {
let rollData = msg.data.rollData
if (game.user.isGM) {
let chatMsg = await this.createChatMessage(rollData.alias, "blindroll", {
content: await renderTemplate(msg.data.template, rollData),
content: await foundry.applications.handlebars.renderTemplate(msg.data.template, rollData),
whisper: game.user.id
})
chatMsg.setFlag("world", "tedeum-rolldata", rollData)
}
}
if (msg.name == "msg_modify_combat_action") {
if (game.user.isGM) {
let { combatantId, ca } = msg.data
let combatant = game.combat.combatants.get(combatantId)
if (combatant) {
console.log("sock - Modify Combat Action : ", combatant.name, ca)
await TeDeumUtility.updateCombatantActions(combatant, ca)
}
}
}
if (msg.name == "msg_apply_damage") {
const firstGM = game.users.find(u => u.isGM && u.active)
if (game.user === firstGM) {
let rollData = msg.data.rollData
let defenderActor = TeDeumUtility.getTokenActorFromId(rollData.defenderTokenId)
if (defenderActor) {
await defenderActor.appliquerDegats(rollData)
} else {
ui.notifications.error("Impossible de trouver la cible de l'attaque, aucun degats appliqué")
}
}
}
}
/* -------------------------------------------- */
@@ -408,10 +598,13 @@ export class TeDeumUtility {
}
}
if (rollData.diceSum == 1) {
let critiqueRoll = await new Roll(rollData.carac.negativeDice).roll()
let critiqueRoll = await new Roll(rollData.carac.negativeDice)
rollData.isSuccess = false
await critiqueRoll.evaluate()
await this.showDiceSoNice(critiqueRoll, game.settings.get("core", "rollMode"))
rollData.critiqueRoll = foundry.utils.duplicate(critiqueRoll)
if (critiqueRoll.total > rollData.competence.score) {
rollData.critiqueTotal = critiqueRoll.total
if (critiqueRoll.total > rollData.competence.system.score) {
rollData.isEchecCritique = true
}
}
@@ -439,9 +632,18 @@ export class TeDeumUtility {
if (rollData.isMouvement) {
localModifier -= 1
}
if (rollData.arme && rollData.allongeId) {
localModifier += rollData.allonges[rollData.allongeId].malus
rollData.allongeMalus = rollData.allonges[rollData.allongeId].malus
rollData.nbEsquives = rollData.allonges[rollData.allongeId]?.esquive || 0
}
if (rollData.attaqueCiblee && rollData.attaqueCiblee != "aucune") {
localModifier -= 1
rollData.loc = foundry.utils.duplicate(game.system.tedeum.config.LOCALISATION[rollData.attaqueCiblee])
}
let diceBase = this.modifyDice(rollData.carac.dice, localModifier + Number(rollData.bonusMalus) + rollData.santeModifier)
if (!diceBase) return;
diceFormula = diceBase + "x + " + rollData.competence.system.score
diceFormula = diceBase + "x + " + rollData.compScore
}
if (rollData.enableProvidence) {
diceFormula += " + " + rollData.providence.dice
@@ -451,32 +653,33 @@ export class TeDeumUtility {
/* -------------------------------------------- */
static async getLocalisation(rollData) {
let locRoll = await new Roll("1d20").roll()
await this.showDiceSoNice(locRoll, game.settings.get("core", "rollMode"))
rollData.locRoll = foundry.utils.duplicate(locRoll)
for (let key in game.system.tedeum.config.LOCALISATION) {
let loc = game.system.tedeum.config.LOCALISATION[key]
if (locRoll.total >= loc.score.min && locRoll.total <= loc.score.max) {
rollData.loc = foundry.utils.duplicate(loc)
break
let locRoll
if (rollData.loc) {
locRoll = await new Roll(String(rollData.loc.score.min)).roll()
} else {
locRoll = await new Roll("1d20").roll()
await this.showDiceSoNice(locRoll, game.settings.get("core", "rollMode"))
for (let key in game.system.tedeum.config.LOCALISATION) {
let loc = game.system.tedeum.config.LOCALISATION[key]
if (locRoll.total >= loc.score.min && locRoll.total <= loc.score.max) {
rollData.loc = foundry.utils.duplicate(loc)
break
}
}
}
rollData.locRoll = foundry.utils.duplicate(locRoll)
}
/* -------------------------------------------- */
static async processAttaqueMelee(rollData) {
if (rollData.arme?.system.typeArme != "melee") {
return
}
if (rollData.isSuccess) {
await this.getLocalisation(rollData)
let actor = game.actors.get(rollData.actorId)
let bDegats = actor.getBonusDegats()
let degatsRoll = await new Roll(rollData.arme.system.degats + "+" + bDegats.value).roll()
await this.showDiceSoNice(degatsRoll, game.settings.get("core", "rollMode"))
rollData.degatsRoll = foundry.utils.duplicate(degatsRoll)
rollData.degats = degatsRoll.total
}
await this.getLocalisation(rollData)
let actor = game.actors.get(rollData.actorId)
let bDegats = actor.getAttaqueBonusDegats(rollData)
rollData.degatsFormula = rollData.arme.system.degats + "+" + bDegats
let degatsRoll = await new Roll(rollData.degatsFormula).roll()
await this.showDiceSoNice(degatsRoll, game.settings.get("core", "rollMode"))
rollData.degatsRoll = foundry.utils.duplicate(degatsRoll)
rollData.degats = degatsRoll.total
}
/* -------------------------------------------- */
@@ -489,12 +692,51 @@ export class TeDeumUtility {
await this.getLocalisation(rollData)
// Now the degats
let degatsRoll = await new Roll(rollData.arme.system.degats).roll()
await this.showDiceSoNice(locRoll, game.settings.get("core", "rollMode"))
await this.showDiceSoNice(degatsRoll, game.settings.get("core", "rollMode"))
rollData.degatsRoll = foundry.utils.duplicate(degatsRoll)
rollData.degats = degatsRoll.total
}
}
/* -------------------------------------------- */
static async updateCombatantActions(combatant, ca) {
await combatant.setFlag("world", "available-actions", ca)
await combatant.update({ name: `${combatant.token.name} (${ca.nbActions} / ${ca.nbActionsMainGauche})` })
}
/* -------------------------------------------- */
static async manageCombatActions(actor, rollData) {
let combat = game.combats.active
if (!combat) return;
let combatant = combat.getCombatantByActor(actor)
if (!combatant) return;
let ca = combatant.getFlag("world", "available-actions")
if (!ca) return;
if (rollData.mode == "arme" && rollData.isMainGauche) {
if (ca.nbActionsMainGauche > 0) {
ca.nbActionsMainGauche -= 1
ca.nbActions = Math.max(ca.nbActions - 1, 0)
} else {
ui.notifications.error(`${actor.name} n'a plus d'actions disponibles à la main gauche pour ce round`)
}
}
if (ca.nbActions > 0) {
ca.nbActions -= 1
} else {
ui.notifications.error(`${actor.name} n'a plus d'actions disponibles pour ce round`)
}
console.log("Manage combat actions 1", actor.name, combatant)
if (game.user.isGM) {
await this.updateCombatantActions(combatant, ca)
} else {
// Send a socket message
game.socket.emit("system.fvtt-te-deum", { name: "msg_modify_combat_action", data: { combatantId: combatant.id, ca } });
}
rollData.hasActions = true
rollData.remainingActions = ca.nbActions
rollData.remainingActionsMainGauche = ca.nbActionsMainGauche
}
/* -------------------------------------------- */
static async rollTeDeum(rollData) {
@@ -504,6 +746,18 @@ export class TeDeumUtility {
rollData.difficulty = "pardefaut"
}
rollData.difficulty = game.system.tedeum.config.difficulte[rollData.difficulty].value
// Compute the real competence score
if (rollData.competence) {
if (rollData.isMainGauche) {
rollData.competence = actor.getMeilleureCompetenceMainGauche(rollData.competence)
}
if (rollData.competence.system.isBase) {
rollData.compScore = actor.system.caracteristiques[rollData.competence.system.caracteristique].value
} else {
rollData.compScore = rollData.competence.system.score
}
}
let diceFormula = this.computeRollFormula(rollData, actor)
if (!diceFormula) return;
console.log("RollData", rollData, diceFormula)
@@ -519,10 +773,11 @@ export class TeDeumUtility {
await this.computeResults(rollData)
await this.processAttaqueDistance(rollData)
await this.processAttaqueMelee(rollData)
await this.manageCombatActions(actor, rollData)
let msg = await this.createChatWithRollMode(rollData.alias, {
content: await renderTemplate(`systems/fvtt-te-deum/templates/chat/chat-generic-result.hbs`, rollData)
content: await foundry.applications.handlebars.renderTemplate(`systems/fvtt-te-deum/templates/chat/chat-generic-result.hbs`, rollData)
})
await msg.setFlag("world", "te-deum-rolldata", rollData)
console.log("Rolldata result", rollData)
@@ -531,19 +786,6 @@ export class TeDeumUtility {
if (rollData.enableProvidence) {
actor.modifyProvidence(-1)
}
// Manage XP
if (rollData.isReussiteCritique || rollData.isEchecCritique) {
actor.modifyXP(rollData.carac.key, 1)
}
// gestion degats automatique
if (rollData.arme && rollData.defenderTokenId) {
let defenderToken = canvas.tokens.placeables.find(t => t.id == rollData.defenderTokenId)
if (defenderToken) {
let actor = defenderToken.actor
await actor.appliquerDegats(rollData)
}
}
}
/* -------------------------------------------- */
@@ -661,7 +903,7 @@ export class TeDeumUtility {
/* -------------------------------------------- */
static async confirmDelete(actorSheet, li) {
let itemId = li.data("item-id");
let itemId = li.dataset ? li.dataset.itemId : li.data("item-id");
let msgTxt = "<p>Etes vous certain de supprimer cet item ?";
let buttons = {
delete: {
@@ -669,7 +911,12 @@ export class TeDeumUtility {
label: "Oui, aucun souci",
callback: () => {
actorSheet.actor.deleteEmbeddedDocuments("Item", [itemId]);
li.slideUp(200, () => actorSheet.render(false));
if (li.slideUp) {
li.slideUp(200, () => actorSheet.render(false));
} else {
li.style.display = "none";
actorSheet.render(false);
}
}
},
cancel: {

View File

@@ -1,17 +1,17 @@
export class TeDeumArmeSchema extends foundry.abstract.TypeDataModel {
export class TeDeumArmeSchema extends foundry.abstract.TypeDataModel {
static defineSchema() {
const fields = foundry.data.fields;
const requiredInteger = { required: true, nullable: false, integer: true };
const requiredDouble = { required: true, nullable: false, integer: false };
const schema = {};
schema.typeArme = new fields.StringField({required: true, choices: ["melee", "tir"], initial: "melee"});
schema.allonge = new fields.StringField({required: true, choices: ["courte", "moyenne", "longue", "treslongue"], initial: "courte"});
schema.typeArme = new fields.StringField({ required: true, choices: ["melee", "tir"], initial: "melee" });
schema.allonge = new fields.StringField({ required: true, choices: ["courte", "moyenne", "longue", "treslongue"], initial: "courte" });
schema.specificites = new fields.SchemaField(
Object.values((game.system.tedeum.config.ARME_SPECIFICITE)).reduce((obj, spec) => {
obj[spec.id] = new fields.SchemaField({
hasSpec: new fields.BooleanField({initial: false}),
hasSpec: new fields.BooleanField({ initial: false }),
});
return obj;
}, {})
@@ -26,35 +26,35 @@ export class TeDeumArmeSchema extends foundry.abstract.TypeDataModel {
}, {})
);
schema.degatsArmure = new fields.SchemaField( {
sansarmure : new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 }),
cuir : new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 }),
plates : new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 }),
mailles : new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 }),
schema.degatsArmure = new fields.SchemaField({
sansarmure: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 }),
cuir: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 }),
plates: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 }),
mailles: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 }),
});
schema.tempsRecharge = new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 });
schema.competenceRecharge = new fields.StringField({ required: false, choices:["aucune", "archerie", "arquebusade"], initial: "aucune", blank: true });
schema.competenceRecharge = new fields.StringField({ required: false, choices: ["aucune", "archerie", "arquebusade"], initial: "aucune", blank: true });
schema.valeurEchecCritique = new fields.NumberField({ ...requiredInteger, initial: 1, min: 1 });
schema.initiativeBonus = new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 });
schema.initiativeBonus = new fields.NumberField({ ...requiredInteger, initial: 0 });
schema.degats = new fields.StringField({ required: false, blank: true, initial: "0" });
schema.degatscrosse = new fields.StringField({ required: false, blank: true, initial: "0" });
let comp = []
for (let key of Object.keys(game.system.tedeum.config.armeCompetences)) {
comp.push(key);
}
schema.competence = new fields.StringField({ required: true, choices:comp, initial: "bagarre" });
schema.competence2 = new fields.StringField({ required: false, choices:comp, initial: "", blank: true });
schema.competence = new fields.StringField({ required: true, choices: comp, initial: "bagarre" });
schema.competence2 = new fields.StringField({ required: false, choices: comp, initial: "", blank: true });
schema.prix = new fields.NumberField({ ...requiredDouble, initial: 0, min: 0 });
schema.monnaie = new fields.StringField({ required: true, blank: false, initial: "denier" });
schema.equipe = new fields.BooleanField({initial: false}),
schema.description = new fields.HTMLField({ required: true, blank: true });
schema.equipe = new fields.BooleanField({ initial: false }),
schema.description = new fields.HTMLField({ required: true, blank: true });
return schema;
}

View File

@@ -4,8 +4,9 @@ export class TeDeumBlessureSchema extends foundry.abstract.TypeDataModel {
const requiredInteger = { required: true, nullable: false, integer: true };
const schema = {};
schema.typeBlessure = new fields.StringField({required: true, choices: ["indemne", "estafilade", "plaie", "plaiebeante", "plaieatroce", "tuenet"], initial: "estafilade"});
schema.localisation = new fields.StringField({required: true, choices: ["piedgauche", "pieddroit", "jambegauche", "jambedroite", "maingauche", "maindroite", "brasgauche", "brasdroit", "tete", "corps"], initial: "corps"});
schema.typeBlessure = new fields.StringField({ required: true, choices: ["indemne", "estafilade", "plaie", "plaiebeante", "plaieatroce", "tuenet"], initial: "estafilade" });
schema.value = new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 })
schema.localisation = new fields.StringField({ required: true, choices: ["piedgauche", "pieddroit", "jambegauche", "jambedroite", "maingauche", "maindroite", "brasgauche", "brasdroit", "tete", "corps"], initial: "corps" });
schema.description = new fields.HTMLField({ required: true, blank: true });

View File

@@ -14,7 +14,9 @@ export class TeDeumEducationSchema extends foundry.abstract.TypeDataModel {
return obj;
}, {})
);
schema.genre = new fields.StringField({required: true, initial: "Homme", choices: ["masculin", "mixte", "Homme", "Femme", "Mixte"]});
schema.nbChoixCarac = new fields.NumberField({ ...requiredInteger, initial: 1, min: 1 });
schema.caracteristiques = new fields.SchemaField(Array.fromRange(3, 1).reduce((caracs, i) => {
caracs[`carac${i}`] = new fields.SchemaField({
@@ -30,7 +32,7 @@ export class TeDeumEducationSchema extends foundry.abstract.TypeDataModel {
});
return comps;
}, {}));
schema.hasCompetencesOpt = new fields.BooleanField({initial: false})
schema.competencesOptNumber = new fields.NumberField({ ...requiredInteger, initial: 1, min:0 })
schema.competencesOpt = new fields.SchemaField(Array.fromRange(14, 1).reduce((comps, i) => {
@@ -49,7 +51,7 @@ export class TeDeumEducationSchema extends foundry.abstract.TypeDataModel {
reponse: new fields.StringField({ required: true, blank: true, initial: "" }),
compName: new fields.StringField({ required: true, blank: true, initial: "" }),
toSelect: new fields.BooleanField({ initial: false }),
compList: new fields.SchemaField(Array.fromRange(10, 1).reduce((comps, i) => {
compList: new fields.SchemaField(Array.fromRange(16, 1).reduce((comps, i) => {
comps[`comp${i}`] = new fields.SchemaField({
compName: new fields.StringField({ required: true, blank: true, initial: "" }),
});
@@ -61,7 +63,7 @@ export class TeDeumEducationSchema extends foundry.abstract.TypeDataModel {
});
return questions;
}, {}));
schema.debouches = new fields.SchemaField(Array.fromRange(24, 1).reduce((debouches, i) => {
debouches[`debouche${i}`] = new fields.SchemaField({
debouche: new fields.StringField({ required: true, blank: true, initial: "" })
@@ -71,7 +73,7 @@ export class TeDeumEducationSchema extends foundry.abstract.TypeDataModel {
schema.cagnotteMultiplier = new fields.NumberField({ ...requiredDouble, initial: 1.0, min: 0 });
schema.cagnotteDivider = new fields.NumberField({ ...requiredDouble, initial: 1.0, min: 0 });
schema.description = new fields.HTMLField({ required: true, blank: true });
schema.trousseau = new fields.StringField({ required: true, blank: true, initial: "" });

View File

@@ -13,4 +13,10 @@ export class TeDeumEquipementSchema extends foundry.abstract.TypeDataModel {
return schema;
}
get monnaieLabel() {
console.log("monnaieLabel", this.monnaie,game.system.tedeum.config.monnaieUnit)
return game.system.tedeum.config.monnaieUnit[String(this.monnaie)]?.label;
}
}

View File

@@ -9,7 +9,8 @@ export class TeDeumMaladieSchema extends foundry.abstract.TypeDataModel {
schema.virulence = new fields.StringField({required: true, choices: ["fatigue", "epuisement", "souffrance", "agonie"], initial: "fatigue"});
schema.fievre = new fields.StringField({required: true, choices: ["aucune", "legere", "forte", "grave"], initial: "aucune"});
schema.symptomes = new fields.HTMLField({ required: true, blank: true });
schema.appliquee = new fields.BooleanField({initial: false}),
schema.complications = new fields.HTMLField({ required: true, blank: true });
schema.appliquee = new fields.BooleanField({initial: false});
schema.description = new fields.HTMLField({ required: true, blank: true });

View File

@@ -26,33 +26,35 @@ export class TeDeumPJSchema extends foundry.abstract.TypeDataModel {
obj[loc.id] = new fields.SchemaField({
armure: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0, max: 20 }),
touche: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0, max: 20 }),
blessures: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0, max: 20 })
blessures: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0, max: 20 })
});
return obj;
}, {})
);
schema.fortune = new fields.SchemaField({
"ecus": new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 }),
"ecus": new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 }),
"livres": new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 }) ,
"sous": new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 }) ,
"deniers": new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 })
"deniers": new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 })
});
schema.description = new fields.HTMLField({required: true, blank: true});
schema.notes = new fields.HTMLField({required: true, blank: true});
schema.connaissances = new fields.HTMLField({required: true, blank: true});
schema.histoire = new fields.HTMLField({required: true, blank: true});
schema.vetements = new fields.HTMLField({required: true, blank: true});
schema.equipmentfree = new fields.HTMLField({required: true, blank: true});
schema.genre = new fields.StringField({required: true, choices: game.system.tedeum.config.genre, initial: "Femme"});
schema.age = new fields.StringField({ required: false, blank: true, initial: undefined });
schema.statutocial = new fields.StringField({ required: false, blank: true, initial: undefined });
schema.chargestitre = new fields.StringField({ required: false, blank: true, initial: undefined });
schema.charges = new fields.StringField({ required: false, blank: true, initial: undefined });
schema.religion = new fields.StringField({ required: false, blank: true, initial: undefined });
schema.lieunaissance = new fields.StringField({ required: false, blank: true, initial: undefined });
schema.age = new fields.StringField({ required: false, blank: true, initial: "" });
schema.datenaissance = new fields.StringField({ required: false, blank: true, initial: "" });
schema.statutocial = new fields.StringField({ required: false, blank: true, initial: "" });
schema.chargestitre = new fields.StringField({ required: false, blank: true, initial: "" });
schema.charges = new fields.StringField({ required: false, blank: true, initial: "" });
schema.religion = new fields.StringField({ required: false, blank: true, initial: "" });
schema.lieunaissance = new fields.StringField({ required: false, blank: true, initial: "" });
return schema;
}
}

View File

@@ -1,87 +1,103 @@
import { TeDeumUtility } from "../common/tedeum-utility.js";
export class TeDeumRollDialog extends Dialog {
const { HandlebarsApplicationMixin } = foundry.applications.api
/* -------------------------------------------- */
export class TeDeumRollDialog extends HandlebarsApplicationMixin(foundry.applications.api.ApplicationV2) {
static DEFAULT_OPTIONS = {
classes: ["fvtt-te-deum", "te-deum-roll-dialog"],
window: { title: "Lancer !", resizable: false },
position: { width: 540 },
actions: {
roll: TeDeumRollDialog.#onRoll,
cancel: TeDeumRollDialog.#onCancel,
}
}
static PARTS = {
content: { template: "systems/fvtt-te-deum/templates/dialogs/roll-dialog-generic.hbs" }
}
/* -------------------------------------------- */
constructor(actor, rollData, options = {}) {
super(options)
this.actor = actor
this.rollData = rollData
}
/* -------------------------------------------- */
static async create(actor, rollData) {
let options = { classes: ["tedeum-roll-dialog"], width: 540, height: 'fit-content', 'z-index': 99999 }
let html = await renderTemplate('systems/fvtt-te-deum/templates/dialogs/roll-dialog-generic.hbs', rollData);
return new TeDeumRollDialog(actor, rollData, html, options);
const dialog = new TeDeumRollDialog(actor, rollData)
dialog.render(true)
return dialog
}
/* -------------------------------------------- */
constructor(actor, rollData, html, options, close = undefined) {
let conf = {
title: "Lancer !",
content: html,
buttons: {
roll: {
icon: '<i class="fas fa-check"></i>',
label: "Lancer",
callback: () => { this.roll() }
},
cancel: {
icon: '<i class="fas fa-times"></i>',
label: "Annuler",
callback: () => { this.close() }
}
},
close: close
}
super(conf, options);
this.actor = actor;
this.rollData = rollData;
}
/* -------------------------------------------- */
roll() {
TeDeumUtility.rollTeDeum(this.rollData)
async _prepareContext() {
return { ...this.rollData }
}
/* -------------------------------------------- */
async refreshDialog() {
const content = await renderTemplate("systems/fvtt-te-deum/templates/dialogs/roll-dialog-generic.hbs", this.rollData)
this.data.content = content
this.render(true)
this.render()
}
/* -------------------------------------------- */
activateListeners(html) {
super.activateListeners(html);
static #onRoll(event, target) {
TeDeumUtility.rollTeDeum(this.rollData)
this.close()
}
let dialog = this;
function onLoad() {
}
$(function () { onLoad(); });
/* -------------------------------------------- */
static #onCancel(event, target) {
this.close()
}
html.find('#bonusMalusPerso').change((event) => {
/* -------------------------------------------- */
_onRender(context, options) {
super._onRender(context, options)
const html = this.element
html.querySelector('#bonusMalusPerso')?.addEventListener('change', (event) => {
this.rollData.bonusMalusPerso = Number(event.currentTarget.value)
})
html.find('#roll-difficulty').change((event) => {
html.querySelector('#roll-allonge')?.addEventListener('change', (event) => {
this.rollData.allongeId = event.currentTarget.value
})
html.querySelector('#roll-main-gauche')?.addEventListener('change', (event) => {
this.rollData.isMainGauche = event.currentTarget.checked
})
html.querySelector('#roll-difficulty')?.addEventListener('change', (event) => {
this.rollData.difficulty = String(event.currentTarget.value) || "pardefaut"
})
html.find('#roll-bonus-malus').change((event) => {
html.querySelector('#roll-attaque-ciblee')?.addEventListener('change', (event) => {
this.rollData.attaqueCiblee = event.currentTarget.value || "0"
})
html.querySelector('#roll-bonus-malus')?.addEventListener('change', (event) => {
this.rollData.bonusMalus = event.currentTarget.value || "0"
})
html.find('#roll-enable-providence').change((event) => {
html.querySelector('#roll-enable-providence')?.addEventListener('change', (event) => {
this.rollData.enableProvidence = event.currentTarget.checked
})
html.find('#roll-portee-tir').change((event) => {
html.querySelector('#roll-portee-tir')?.addEventListener('change', (event) => {
this.rollData.porteeTir = event.currentTarget.value
this.rollData.difficulty = game.system.tedeum.config.ARME_PORTEES[this.rollData.porteeTir].difficulty
this.rollData.porteeLabel = game.system.tedeum.config.ARME_PORTEES[this.rollData.porteeTir].label
this.refreshDialog()
})
html.find('#roll-tir-viser').change((event) => {
html.querySelector('#roll-tir-viser')?.addEventListener('change', (event) => {
this.rollData.isViser = event.currentTarget.checked
})
html.find('#roll-tir-mouvement').change((event) => {
html.querySelector('#roll-tir-mouvement')?.addEventListener('change', (event) => {
this.rollData.isMouvement = event.currentTarget.checked
})
html.querySelector('#roll-charge-a-pied')?.addEventListener('change', (event) => {
this.rollData.isChargeAPied = event.currentTarget.checked
})
html.querySelector('#roll-charge-a-cheval')?.addEventListener('change', (event) => {
this.rollData.isChargeACheval = event.currentTarget.checked
})
}
}
}

View File

@@ -1,173 +1,154 @@
import { TeDeumUtility } from "../common/tedeum-utility.js";
const { HandlebarsApplicationMixin } = foundry.applications.api
/**
* Extend the basic ItemSheet with some very simple modifications
* @extends {ItemSheet}
* Feuille d'item Te Deum - AppV2
*/
export class TeDeumItemSheet extends ItemSheet {
export class TeDeumItemSheet extends HandlebarsApplicationMixin(foundry.applications.sheets.ItemSheetV2) {
/** @override */
static get defaultOptions() {
return foundry.utils.mergeObject(super.defaultOptions, {
classes: ["fvtt-te-deum", "sheet", "item"],
template: "systems/fvtt-te-deum/templates/item-sheet.hbs",
dragDrop: [{ dragSelector: null, dropSelector: null }],
static DEFAULT_OPTIONS = {
classes: ["fvtt-te-deum", "sheet", "item"],
position: {
width: 620,
height: 580,
tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "description" }]
});
},
form: {
submitOnChange: true,
closeOnSubmit: false,
},
window: {
resizable: true,
},
actions: {
editImage: TeDeumItemSheet.#onEditImage,
postItem: TeDeumItemSheet.#onPostItem,
deleteSubitem: TeDeumItemSheet.#onDeleteSubitem,
viewSubitem: TeDeumItemSheet.#onViewSubitem,
},
}
/* -------------------------------------------- */
_getHeaderButtons() {
let buttons = super._getHeaderButtons();
// Add "Post to chat" button
// We previously restricted this to GM and editable items only. If you ever find this comment because it broke something: eh, sorry!
buttons.unshift(
{
class: "post",
icon: "fas fa-comment",
onclick: ev => { }
})
return buttons
// Static PARTS pointing to the dynamic wrapper template
static PARTS = {
sheet: { template: "systems/fvtt-te-deum/templates/items/item-sheet.hbs" },
}
/* -------------------------------------------- */
async getData() {
tabGroups = { primary: "description" }
let formData = {
/* -------------------------------------------- */
/** @override */
async _prepareContext() {
const item = this.document
const TextEditor = foundry.applications.ux.TextEditor.implementation
const enrich = async (val) => val !== undefined ? await TextEditor.enrichHTML(val ?? "", { async: true }) : ""
const context = {
title: this.title,
id: this.id,
type: this.object.type,
img: this.object.img,
name: this.object.name,
id: item.id,
type: item.type,
img: item.img,
name: item.name,
editable: this.isEditable,
cssClass: this.isEditable ? "editable" : "locked",
system: foundry.utils.duplicate(this.object.system),
system: foundry.utils.duplicate(item.system),
systemFields: item.system.schema.fields,
config: foundry.utils.duplicate(game.system.tedeum.config),
competences: TeDeumUtility.getCompetencesForDropDown(),
limited: this.object.limited,
options: this.options,
owner: this.document.isOwner,
description: await TextEditor.enrichHTML(this.object.system.description, { async: true }),
notes: await TextEditor.enrichHTML(this.object.system.notes, { async: true }),
isGM: game.user.isGM
limited: item.limited,
owner: item.isOwner,
enrichedDescription: await enrich(item.system.description),
enrichedTransmission: await enrich(item.system.transmission),
enrichedSymptomes: await enrich(item.system.symptomes),
enrichedComplications: await enrich(item.system.complications),
enrichedVertus: await enrich(item.system.vertus),
enrichedToxicite: await enrich(item.system.toxicite),
isGM: game.user.isGM,
itemPartialName: `systems/fvtt-te-deum/templates/items/item-${item.type}-sheet.hbs`,
}
if (this.object.type == "education") {
TeDeumUtility.prepareEducationContent(formData);
if (item.type === "education") {
TeDeumUtility.prepareEducationContent(context)
}
this.options.editable = !(this.object.origin == "embeddedItem");
console.log("ITEM DATA", formData, this);
return formData;
}
/* -------------------------------------------- */
_getHeaderButtons() {
let buttons = super._getHeaderButtons();
buttons.unshift({
class: "post",
icon: "fas fa-comment",
onclick: ev => this.postItem()
});
return buttons
return context
}
/* -------------------------------------------- */
postItem() {
let chatData = duplicate(this.item)
/** @override */
_onRender(context, options) {
super._onRender(context, options)
// Tab navigation
const nav = this.element.querySelector('nav.tabs[data-group]')
if (nav) {
const group = nav.dataset.group
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()
})
})
this.element.querySelectorAll(`[data-group="${group}"][data-tab]`).forEach(content => {
content.classList.toggle('active', content.dataset.tab === activeTab)
})
}
// Ignore Enter key in inputs
this.element.addEventListener('keydown', e => {
if (e.keyCode === 13 && e.target.tagName !== 'TEXTAREA') e.preventDefault()
})
}
// #region Static action handlers
static async #onEditImage(event, target) {
const fp = new FilePicker({
type: "image",
current: this.document.img,
callback: path => this.document.update({ img: path }),
})
fp.browse()
}
static async #onPostItem(event, target) {
const chatData = foundry.utils.duplicate(this.item)
if (this.actor) {
chatData.actor = { id: this.actor.id };
chatData.actor = { id: this.actor.id }
}
// Don't post any image for the item (which would leave a large gap) if the default image is used
if (chatData.img.includes("/blank.png")) {
chatData.img = null;
if (chatData.img?.includes("/blank.png")) {
chatData.img = null
}
// JSON object for easy creation
chatData.jsondata = JSON.stringify(
{
compendium: "postedItem",
payload: chatData,
});
renderTemplate('systems/fvtt-te-deum/templates/post-item.html', chatData).then(html => {
let chatOptions = TeDeumUtility.chatDataSetup(html);
ChatMessage.create(chatOptions)
});
chatData.jsondata = JSON.stringify({ compendium: "postedItem", payload: chatData })
const html = await foundry.applications.handlebars.renderTemplate(
'systems/fvtt-te-deum/templates/post-item.html', chatData
)
ChatMessage.create(TeDeumUtility.chatDataSetup(html))
}
/* -------------------------------------------- */
async viewSubitem(ev) {
let levelIndex = Number($(ev.currentTarget).parents(".item").data("level-index"))
let choiceIndex = Number($(ev.currentTarget).parents(".item").data("choice-index"))
let featureId = $(ev.currentTarget).parents(".item").data("feature-id")
let itemData = this.object.system.levels[levelIndex].choices[choiceIndex].features[featureId]
if (itemData.name != 'None') {
let item = await Item.create(itemData, { temporary: true });
item.system.origin = "embeddedItem";
new TeDeumItemSheet(item).render(true);
static async #onDeleteSubitem(event, target) {
const field = target.dataset.type
const idx = parseInt(target.dataset.index)
const oldArray = this.document.system[field]
if (Array.isArray(oldArray) && oldArray[idx]?.name !== 'None') {
const newArray = oldArray.filter((_, i) => i !== idx)
this.document.update({ [`system.${field}`]: newArray })
}
}
/* -------------------------------------------- */
async deleteSubitem(ev) {
let field = $(ev.currentTarget).data('type');
let idx = Number($(ev.currentTarget).data('index'));
let oldArray = this.object.system[field];
let itemData = this.object.system[field][idx];
if (itemData.name != 'None') {
let newArray = [];
for (let i = 0; i < oldArray.length; i++) {
if (i != idx) {
newArray.push(oldArray[i]);
}
}
this.object.update({ [`system.${field}`]: newArray });
static async #onViewSubitem(event, target) {
const li = target.closest(".item")
const levelIndex = parseInt(li?.dataset.levelIndex)
const choiceIndex = parseInt(li?.dataset.choiceIndex)
const featureId = li?.dataset.featureId
const itemData = this.document.system.levels?.[levelIndex]?.choices?.[choiceIndex]?.features?.[featureId]
if (itemData?.name !== 'None') {
const item = await Item.create(itemData, { temporary: true })
item.system.origin = "embeddedItem"
new TeDeumItemSheet(item).render(true)
}
}
/* -------------------------------------------- */
/** @override */
activateListeners(html) {
super.activateListeners(html);
// Everything below here is only needed if the sheet is editable
if (!this.options.editable) return;
// Update Inventory Item
html.find('.item-edit').click(ev => {
const li = $(ev.currentTarget).parents(".item");
const item = this.object.options.actor.getOwnedItem(li.data("item-id"));
item.sheet.render(true);
});
html.find('.delete-subitem').click(ev => {
this.deleteSubitem(ev);
});
// Update Inventory Item
html.find('.item-delete').click(ev => {
const li = $(ev.currentTarget).parents(".item");
let itemId = li.data("item-id");
let itemType = li.data("item-type");
});
}
/* -------------------------------------------- */
get template() {
let type = this.item.type;
return `systems/fvtt-te-deum/templates/items/item-${type}-sheet.hbs`
}
/* -------------------------------------------- */
/** @override */
_updateObject(event, formData) {
return this.object.update(formData)
}
// #endregion
}

View File

@@ -51,7 +51,7 @@ Hooks.once("init", async function () {
// preload handlebars templates
TeDeumUtility.preloadHandlebarsTemplates();
// Set an initiative formula for the system
// Set an initiative formula for the system
CONFIG.Combat.initiative = {
formula: "1d6",
decimals: 1
@@ -79,17 +79,19 @@ Hooks.once("init", async function () {
blessure: TeDeumBlessureSchema,
maladie: TeDeumMaladieSchema,
};
console.log("TeDeum RPG | Ready");
Actors.unregisterSheet("core", ActorSheet);
Actors.registerSheet("fvtt-te-deum", TeDeumActorPJSheet, { types: ["pj"], makeDefault: true });
Actors.registerSheet("fvtt-te-deum", TeDeumActorPJSheet, { types: ["pnj"], makeDefault: true });
Items.unregisterSheet("core", ItemSheet);
Items.registerSheet("fvtt-te-deum", TeDeumItemSheet, { makeDefault: true });
foundry.documents.collections.Actors.unregisterSheet("core", foundry.appv1.sheets.ActorSheet);
foundry.documents.collections.Actors.registerSheet("fvtt-te-deum", TeDeumActorPJSheet, { types: ["pj"], makeDefault: true });
foundry.documents.collections.Actors.registerSheet("fvtt-te-deum", TeDeumActorPJSheet, { types: ["pnj"], makeDefault: true });
TeDeumUtility.init()
foundry.documents.collections.Items.unregisterSheet("core", foundry.appv1.sheets.ItemSheet);
foundry.documents.collections.Items.registerSheet("fvtt-te-deum", TeDeumItemSheet, { makeDefault: true });
TeDeumUtility.init()
TeDeumUtility.installHooks()
});
@@ -98,6 +100,7 @@ Hooks.once("init", async function () {
/* -------------------------------------------- */
Hooks.once("ready", function () {
// User warning
if (!game.user.isGM && game.user.character == undefined) {
ui.notifications.info("Attention ! Aucun personnage relié au joueur !");
@@ -106,11 +109,11 @@ Hooks.once("ready", function () {
user: game.user._id
});
}
import("https://www.uberwald.me/fvtt_appcount/count-class-ready.js").then(moduleCounter=>{
import("https://www.uberwald.me/fvtt_appcount/count-class-ready.js").then(moduleCounter => {
console.log("ClassCounter loaded", moduleCounter)
moduleCounter.ClassCounter.registerUsageCount()
}).catch(err=>
}).catch(err =>
console.log("No stats available, giving up.")
)
TeDeumUtility.ready();
@@ -134,4 +137,3 @@ Hooks.on("chatMessage", (html, content, msg) => {
}
return true;
});

21
package.json Normal file
View File

@@ -0,0 +1,21 @@
{
"name": "fvtt-te-deum",
"version": "1.0.0",
"description": "Système Te Deum pour FoundryVTT",
"private": true,
"scripts": {
"build:css": "gulp css",
"watch:css": "gulp watch"
},
"devDependencies": {
"gulp": "^4.0.2",
"gulp-less": "^5.0.0",
"less": "^4.2.0",
"autoprefixer": "^10.4.20",
"gulp-postcss": "^9.0.1",
"postcss": "^8.4.49"
},
"keywords": ["foundry-vtt", "te-deum"],
"author": "",
"license": "ISC"
}

Binary file not shown.

BIN
packs/aides/000236.ldb Normal file

Binary file not shown.

View File

@@ -1 +1 @@
MANIFEST-000031
MANIFEST-000245

View File

@@ -1,8 +1,7 @@
2025/02/25-21:31:20.523300 7fcd227fc6c0 Recovering log #29
2025/02/25-21:31:20.533410 7fcd227fc6c0 Delete type=3 #27
2025/02/25-21:31:20.533498 7fcd227fc6c0 Delete type=0 #29
2025/02/25-21:35:34.575677 7fcd20bff6c0 Level-0 table #34: started
2025/02/25-21:35:34.575713 7fcd20bff6c0 Level-0 table #34: 0 bytes OK
2025/02/25-21:35:34.581867 7fcd20bff6c0 Delete type=0 #32
2025/02/25-21:35:34.595379 7fcd20bff6c0 Manual compaction at level-0 from '!journal!uNwJgi4kXBCiZmAH' @ 72057594037927935 : 1 .. '!journal.pages!uNwJgi4kXBCiZmAH.onhNU0mXhOpdNZJF' @ 0 : 0; will stop at (end)
2025/02/25-21:35:34.595417 7fcd20bff6c0 Manual compaction at level-1 from '!journal!uNwJgi4kXBCiZmAH' @ 72057594037927935 : 1 .. '!journal.pages!uNwJgi4kXBCiZmAH.onhNU0mXhOpdNZJF' @ 0 : 0; will stop at (end)
2026/02/28-09:14:40.938346 7f56f93fe6c0 Recovering log #243
2026/02/28-09:14:40.993306 7f56f93fe6c0 Delete type=3 #241
2026/02/28-09:14:40.993438 7f56f93fe6c0 Delete type=0 #243
2026/02/28-11:53:47.481993 7f54e37ef6c0 Level-0 table #248: started
2026/02/28-11:53:47.482026 7f54e37ef6c0 Level-0 table #248: 0 bytes OK
2026/02/28-11:53:47.487859 7f54e37ef6c0 Delete type=0 #246
2026/02/28-11:53:47.488058 7f54e37ef6c0 Manual compaction at level-0 from '!journal!uNwJgi4kXBCiZmAH' @ 72057594037927935 : 1 .. '!journal.pages!uNwJgi4kXBCiZmAH.onhNU0mXhOpdNZJF' @ 0 : 0; will stop at (end)

View File

@@ -1,8 +1,7 @@
2025/02/25-20:49:36.885720 7fcd22ffd6c0 Recovering log #25
2025/02/25-20:49:36.980833 7fcd22ffd6c0 Delete type=3 #23
2025/02/25-20:49:36.980955 7fcd22ffd6c0 Delete type=0 #25
2025/02/25-21:29:18.220253 7fcd20bff6c0 Level-0 table #30: started
2025/02/25-21:29:18.220310 7fcd20bff6c0 Level-0 table #30: 0 bytes OK
2025/02/25-21:29:18.251218 7fcd20bff6c0 Delete type=0 #28
2025/02/25-21:29:18.384283 7fcd20bff6c0 Manual compaction at level-0 from '!journal!uNwJgi4kXBCiZmAH' @ 72057594037927935 : 1 .. '!journal.pages!uNwJgi4kXBCiZmAH.onhNU0mXhOpdNZJF' @ 0 : 0; will stop at (end)
2025/02/25-21:29:18.384413 7fcd20bff6c0 Manual compaction at level-1 from '!journal!uNwJgi4kXBCiZmAH' @ 72057594037927935 : 1 .. '!journal.pages!uNwJgi4kXBCiZmAH.onhNU0mXhOpdNZJF' @ 0 : 0; will stop at (end)
2026/02/27-17:11:33.828064 7f56f8bfd6c0 Recovering log #239
2026/02/27-17:11:33.838170 7f56f8bfd6c0 Delete type=3 #237
2026/02/27-17:11:33.838231 7f56f8bfd6c0 Delete type=0 #239
2026/02/27-17:22:38.249017 7f54e37ef6c0 Level-0 table #244: started
2026/02/27-17:22:38.249057 7f54e37ef6c0 Level-0 table #244: 0 bytes OK
2026/02/27-17:22:38.255519 7f54e37ef6c0 Delete type=0 #242
2026/02/27-17:22:38.255693 7f54e37ef6c0 Manual compaction at level-0 from '!journal!uNwJgi4kXBCiZmAH' @ 72057594037927935 : 1 .. '!journal.pages!uNwJgi4kXBCiZmAH.onhNU0mXhOpdNZJF' @ 0 : 0; will stop at (end)

Binary file not shown.

BIN
packs/aides/MANIFEST-000245 Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -1 +1 @@
MANIFEST-000133
MANIFEST-000347

View File

@@ -1,7 +1,7 @@
2025/02/25-21:31:20.430273 7fcd22ffd6c0 Recovering log #131
2025/02/25-21:31:20.440203 7fcd22ffd6c0 Delete type=3 #129
2025/02/25-21:31:20.440252 7fcd22ffd6c0 Delete type=0 #131
2025/02/25-21:35:34.532301 7fcd20bff6c0 Level-0 table #136: started
2025/02/25-21:35:34.532327 7fcd20bff6c0 Level-0 table #136: 0 bytes OK
2025/02/25-21:35:34.538182 7fcd20bff6c0 Delete type=0 #134
2025/02/25-21:35:34.551679 7fcd20bff6c0 Manual compaction at level-0 from '!folders!InCQeTRdT5jXMX82' @ 72057594037927935 : 1 .. '!items!wxIHkrq98eQ3cOvp' @ 0 : 0; will stop at (end)
2026/02/28-09:14:40.507166 7f56f8bfd6c0 Recovering log #345
2026/02/28-09:14:40.569877 7f56f8bfd6c0 Delete type=3 #343
2026/02/28-09:14:40.570013 7f56f8bfd6c0 Delete type=0 #345
2026/02/28-11:53:47.420510 7f54e37ef6c0 Level-0 table #350: started
2026/02/28-11:53:47.420538 7f54e37ef6c0 Level-0 table #350: 0 bytes OK
2026/02/28-11:53:47.427480 7f54e37ef6c0 Delete type=0 #348
2026/02/28-11:53:47.427767 7f54e37ef6c0 Manual compaction at level-0 from 'undefined' @ 72057594037927935 : 1 .. 'undefined' @ 0 : 0; will stop at (end)

View File

@@ -1,7 +1,7 @@
2025/02/25-20:49:36.106601 7fcd21ffb6c0 Recovering log #127
2025/02/25-20:49:36.195396 7fcd21ffb6c0 Delete type=3 #125
2025/02/25-20:49:36.195529 7fcd21ffb6c0 Delete type=0 #127
2025/02/25-21:29:17.947467 7fcd20bff6c0 Level-0 table #132: started
2025/02/25-21:29:17.947511 7fcd20bff6c0 Level-0 table #132: 0 bytes OK
2025/02/25-21:29:17.987072 7fcd20bff6c0 Delete type=0 #130
2025/02/25-21:29:17.987251 7fcd20bff6c0 Manual compaction at level-0 from '!folders!InCQeTRdT5jXMX82' @ 72057594037927935 : 1 .. '!items!wxIHkrq98eQ3cOvp' @ 0 : 0; will stop at (end)
2026/02/27-17:11:33.742557 7f56f8bfd6c0 Recovering log #341
2026/02/27-17:11:33.751671 7f56f8bfd6c0 Delete type=3 #339
2026/02/27-17:11:33.751725 7f56f8bfd6c0 Delete type=0 #341
2026/02/27-17:22:38.183980 7f54e37ef6c0 Level-0 table #346: started
2026/02/27-17:22:38.184010 7f54e37ef6c0 Level-0 table #346: 0 bytes OK
2026/02/27-17:22:38.189997 7f54e37ef6c0 Delete type=0 #344
2026/02/27-17:22:38.202756 7f54e37ef6c0 Manual compaction at level-0 from 'undefined' @ 72057594037927935 : 1 .. 'undefined' @ 0 : 0; will stop at (end)

Binary file not shown.

BIN
packs/armes/MANIFEST-000347 Normal file

Binary file not shown.

View File

View File

View File

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
packs/armures/000339.ldb Normal file

Binary file not shown.

View File

@@ -1 +1 @@
MANIFEST-000133
MANIFEST-000348

View File

@@ -1,7 +1,7 @@
2025/02/25-21:31:20.442940 7fcd227fc6c0 Recovering log #131
2025/02/25-21:31:20.453064 7fcd227fc6c0 Delete type=3 #129
2025/02/25-21:31:20.453114 7fcd227fc6c0 Delete type=0 #131
2025/02/25-21:35:34.538283 7fcd20bff6c0 Level-0 table #136: started
2025/02/25-21:35:34.538304 7fcd20bff6c0 Level-0 table #136: 0 bytes OK
2025/02/25-21:35:34.544358 7fcd20bff6c0 Delete type=0 #134
2025/02/25-21:35:34.551687 7fcd20bff6c0 Manual compaction at level-0 from '!folders!2wTJBj3dicRKzNOE' @ 72057594037927935 : 1 .. '!items!ufvhWG5V8pX0qrtR' @ 0 : 0; will stop at (end)
2026/02/28-09:14:40.573416 7f56f93fe6c0 Recovering log #346
2026/02/28-09:14:40.630571 7f56f93fe6c0 Delete type=3 #344
2026/02/28-09:14:40.630725 7f56f93fe6c0 Delete type=0 #346
2026/02/28-11:53:47.408468 7f54e37ef6c0 Level-0 table #351: started
2026/02/28-11:53:47.408492 7f54e37ef6c0 Level-0 table #351: 0 bytes OK
2026/02/28-11:53:47.414369 7f54e37ef6c0 Delete type=0 #349
2026/02/28-11:53:47.427738 7f54e37ef6c0 Manual compaction at level-0 from '!folders!2wTJBj3dicRKzNOE' @ 72057594037927935 : 1 .. '!items!ufvhWG5V8pX0qrtR' @ 0 : 0; will stop at (end)

View File

@@ -1,7 +1,7 @@
2025/02/25-20:49:36.212555 7fcd22ffd6c0 Recovering log #127
2025/02/25-20:49:36.305645 7fcd22ffd6c0 Delete type=3 #125
2025/02/25-20:49:36.305755 7fcd22ffd6c0 Delete type=0 #127
2025/02/25-21:29:17.834303 7fcd20bff6c0 Level-0 table #132: started
2025/02/25-21:29:17.834368 7fcd20bff6c0 Level-0 table #132: 0 bytes OK
2025/02/25-21:29:17.871779 7fcd20bff6c0 Delete type=0 #130
2025/02/25-21:29:17.987222 7fcd20bff6c0 Manual compaction at level-0 from '!folders!2wTJBj3dicRKzNOE' @ 72057594037927935 : 1 .. '!items!ufvhWG5V8pX0qrtR' @ 0 : 0; will stop at (end)
2026/02/27-17:11:33.753908 7f56f9bff6c0 Recovering log #342
2026/02/27-17:11:33.763888 7f56f9bff6c0 Delete type=3 #340
2026/02/27-17:11:33.763941 7f56f9bff6c0 Delete type=0 #342
2026/02/27-17:22:38.176835 7f54e37ef6c0 Level-0 table #347: started
2026/02/27-17:22:38.176924 7f54e37ef6c0 Level-0 table #347: 0 bytes OK
2026/02/27-17:22:38.183841 7f54e37ef6c0 Delete type=0 #345
2026/02/27-17:22:38.202741 7f54e37ef6c0 Manual compaction at level-0 from '!folders!2wTJBj3dicRKzNOE' @ 72057594037927935 : 1 .. '!items!ufvhWG5V8pX0qrtR' @ 0 : 0; will stop at (end)

Binary file not shown.

Binary file not shown.

View File

View File

View File

View File

View File

View File

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -1 +1 @@
MANIFEST-000130
MANIFEST-000346

View File

@@ -1,7 +1,7 @@
2025/02/25-21:31:20.416892 7fcd21ffb6c0 Recovering log #128
2025/02/25-21:31:20.427488 7fcd21ffb6c0 Delete type=3 #126
2025/02/25-21:31:20.427535 7fcd21ffb6c0 Delete type=0 #128
2025/02/25-21:35:34.525613 7fcd20bff6c0 Level-0 table #133: started
2025/02/25-21:35:34.525647 7fcd20bff6c0 Level-0 table #133: 0 bytes OK
2025/02/25-21:35:34.532166 7fcd20bff6c0 Delete type=0 #131
2025/02/25-21:35:34.551667 7fcd20bff6c0 Manual compaction at level-0 from '!folders!4OPhigzcPv46qbWW' @ 72057594037927935 : 1 .. '!items!yx4k7lQHGcom99mk' @ 0 : 0; will stop at (end)
2026/02/28-09:14:40.445424 7f56e3fff6c0 Recovering log #344
2026/02/28-09:14:40.502194 7f56e3fff6c0 Delete type=3 #342
2026/02/28-09:14:40.502321 7f56e3fff6c0 Delete type=0 #344
2026/02/28-11:53:47.402111 7f54e37ef6c0 Level-0 table #349: started
2026/02/28-11:53:47.402185 7f54e37ef6c0 Level-0 table #349: 0 bytes OK
2026/02/28-11:53:47.408357 7f54e37ef6c0 Delete type=0 #347
2026/02/28-11:53:47.427714 7f54e37ef6c0 Manual compaction at level-0 from '!folders!4OPhigzcPv46qbWW' @ 72057594037927935 : 1 .. '!items!yx4k7lQHGcom99mk' @ 0 : 0; will stop at (end)

View File

@@ -1,7 +1,7 @@
2025/02/25-20:49:35.983838 7fcd227fc6c0 Recovering log #124
2025/02/25-20:49:36.086131 7fcd227fc6c0 Delete type=3 #122
2025/02/25-20:49:36.086317 7fcd227fc6c0 Delete type=0 #124
2025/02/25-21:29:17.912757 7fcd20bff6c0 Level-0 table #129: started
2025/02/25-21:29:17.912821 7fcd20bff6c0 Level-0 table #129: 0 bytes OK
2025/02/25-21:29:17.947301 7fcd20bff6c0 Delete type=0 #127
2025/02/25-21:29:17.987243 7fcd20bff6c0 Manual compaction at level-0 from '!folders!4OPhigzcPv46qbWW' @ 72057594037927935 : 1 .. '!items!yx4k7lQHGcom99mk' @ 0 : 0; will stop at (end)
2026/02/27-17:11:33.729701 7f56f93fe6c0 Recovering log #340
2026/02/27-17:11:33.739927 7f56f93fe6c0 Delete type=3 #338
2026/02/27-17:11:33.739998 7f56f93fe6c0 Delete type=0 #340
2026/02/27-17:22:38.190111 7f54e37ef6c0 Level-0 table #345: started
2026/02/27-17:22:38.190141 7f54e37ef6c0 Level-0 table #345: 0 bytes OK
2026/02/27-17:22:38.196111 7f54e37ef6c0 Delete type=0 #343
2026/02/27-17:22:38.202769 7f54e37ef6c0 Manual compaction at level-0 from '!folders!4OPhigzcPv46qbWW' @ 72057594037927935 : 1 .. '!items!yx4k7lQHGcom99mk' @ 0 : 0; will stop at (end)

Binary file not shown.

Binary file not shown.

View File

View File

View File

View File

View File

View File

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -1 +1 @@
MANIFEST-000139
MANIFEST-000358

View File

@@ -1,14 +1,7 @@
2025/02/25-21:31:20.455668 7fcd217fa6c0 Recovering log #136
2025/02/25-21:31:20.467004 7fcd217fa6c0 Delete type=3 #134
2025/02/25-21:31:20.467103 7fcd217fa6c0 Delete type=0 #136
2025/02/25-21:35:34.551837 7fcd20bff6c0 Level-0 table #142: started
2025/02/25-21:35:34.555923 7fcd20bff6c0 Level-0 table #142: 45263 bytes OK
2025/02/25-21:35:34.561930 7fcd20bff6c0 Delete type=0 #140
2025/02/25-21:35:34.582002 7fcd20bff6c0 Manual compaction at level-0 from '!folders!9PQi3Lv54rpcxavo' @ 72057594037927935 : 1 .. '!items!zGlRtP7zSnkjuuue' @ 0 : 0; will stop at '!items!yBfCr85GXSpzhRkF' @ 339 : 1
2025/02/25-21:35:34.582009 7fcd20bff6c0 Compacting 1@0 + 1@1 files
2025/02/25-21:35:34.588279 7fcd20bff6c0 Generated table #143@0: 71 keys, 246138 bytes
2025/02/25-21:35:34.588301 7fcd20bff6c0 Compacted 1@0 + 1@1 files => 246138 bytes
2025/02/25-21:35:34.594753 7fcd20bff6c0 compacted to: files[ 0 1 0 0 0 0 0 ]
2025/02/25-21:35:34.594924 7fcd20bff6c0 Delete type=2 #138
2025/02/25-21:35:34.595213 7fcd20bff6c0 Delete type=2 #142
2025/02/25-21:35:34.595401 7fcd20bff6c0 Manual compaction at level-0 from '!items!yBfCr85GXSpzhRkF' @ 339 : 1 .. '!items!zGlRtP7zSnkjuuue' @ 0 : 0; will stop at (end)
2026/02/28-09:14:40.634961 7f56e3fff6c0 Recovering log #356
2026/02/28-09:14:40.683602 7f56e3fff6c0 Delete type=3 #354
2026/02/28-09:14:40.683765 7f56e3fff6c0 Delete type=0 #356
2026/02/28-11:53:47.414491 7f54e37ef6c0 Level-0 table #361: started
2026/02/28-11:53:47.414521 7f54e37ef6c0 Level-0 table #361: 0 bytes OK
2026/02/28-11:53:47.420403 7f54e37ef6c0 Delete type=0 #359
2026/02/28-11:53:47.427753 7f54e37ef6c0 Manual compaction at level-0 from '!folders!9PQi3Lv54rpcxavo' @ 72057594037927935 : 1 .. '!items!zGlRtP7zSnkjuuue' @ 0 : 0; will stop at (end)

View File

@@ -1,14 +1,7 @@
2025/02/25-20:49:36.314175 7fcd217fa6c0 Recovering log #132
2025/02/25-20:49:36.403485 7fcd217fa6c0 Delete type=3 #130
2025/02/25-20:49:36.403607 7fcd217fa6c0 Delete type=0 #132
2025/02/25-21:29:17.987386 7fcd20bff6c0 Level-0 table #137: started
2025/02/25-21:29:18.006349 7fcd20bff6c0 Level-0 table #137: 5726 bytes OK
2025/02/25-21:29:18.041844 7fcd20bff6c0 Delete type=0 #135
2025/02/25-21:29:18.159515 7fcd20bff6c0 Manual compaction at level-0 from '!folders!9PQi3Lv54rpcxavo' @ 72057594037927935 : 1 .. '!items!zGlRtP7zSnkjuuue' @ 0 : 0; will stop at '!items!v4mzjKOYibOsJ9Wn' @ 334 : 1
2025/02/25-21:29:18.159529 7fcd20bff6c0 Compacting 1@0 + 1@1 files
2025/02/25-21:29:18.179100 7fcd20bff6c0 Generated table #138@0: 71 keys, 245910 bytes
2025/02/25-21:29:18.179146 7fcd20bff6c0 Compacted 1@0 + 1@1 files => 245910 bytes
2025/02/25-21:29:18.219660 7fcd20bff6c0 compacted to: files[ 0 1 0 0 0 0 0 ]
2025/02/25-21:29:18.219809 7fcd20bff6c0 Delete type=2 #55
2025/02/25-21:29:18.220047 7fcd20bff6c0 Delete type=2 #137
2025/02/25-21:29:18.220167 7fcd20bff6c0 Manual compaction at level-0 from '!items!v4mzjKOYibOsJ9Wn' @ 334 : 1 .. '!items!zGlRtP7zSnkjuuue' @ 0 : 0; will stop at (end)
2026/02/27-17:11:33.765979 7f56f93fe6c0 Recovering log #352
2026/02/27-17:11:33.775426 7f56f93fe6c0 Delete type=3 #350
2026/02/27-17:11:33.775496 7f56f93fe6c0 Delete type=0 #352
2026/02/27-17:22:38.196266 7f54e37ef6c0 Level-0 table #357: started
2026/02/27-17:22:38.196298 7f54e37ef6c0 Level-0 table #357: 0 bytes OK
2026/02/27-17:22:38.202584 7f54e37ef6c0 Delete type=0 #355
2026/02/27-17:22:38.202781 7f54e37ef6c0 Manual compaction at level-0 from '!folders!9PQi3Lv54rpcxavo' @ 72057594037927935 : 1 .. '!items!zGlRtP7zSnkjuuue' @ 0 : 0; will stop at (end)

Binary file not shown.

Binary file not shown.

View File

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