38 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
203 changed files with 7531 additions and 3270 deletions

View File

@@ -1,6 +1,6 @@
name: Release Creation name: Release Creation
on: on:
release: release:
types: [published] types: [published]
@@ -8,45 +8,56 @@ jobs:
build: build:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- run: echo "💡 The ${{ gitea.repository }} repository will cloned to the runner." - run: echo "💡 The ${{ gitea.repository }} repository will cloned to the runner."
#- uses: actions/checkout@v3
- uses: RouxAntoine/checkout@v3.5.4
# get part of the tag after the `v` #- uses: actions/checkout@v3
- name: Extract tag version number - uses: https://github.com/RouxAntoine/checkout@v3.5.4
id: get_version
uses: battila7/get-version-action@v2
# Substitute the Manifest and Download URLs in the module.json # get part of the tag after the `v`
- name: Substitute Manifest and Download Links For Versioned Ones - name: Extract tag version number
id: sub_manifest_link_version id: get_version
uses: microsoft/variable-substitution@v1 uses: https://github.com/battila7/get-version-action@v2
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
- 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 # Substitute the Manifest and Download URLs in the module.json
- name: Substitute Manifest and Download Links For Versioned Ones
- name: setup go id: sub_manifest_link_version
uses: https://github.com/actions/setup-go@v4 uses: https://github.com/microsoft/variable-substitution@v1
with: with:
go-version: '>=1.20.1' files: "system.json"
env:
- name: Use Go Action version: ${{steps.get_version.outputs.version-without-v}}
id: use-go-action url: https://www.uberwald.me/gitea/${{gitea.repository}}
uses: https://gitea.com/actions/release-action@main manifest: https://www.uberwald.me/gitea/public/fvtt-te-deum/releases/download/latest/system.json
with: download: https://www.uberwald.me/gitea/public/fvtt-te-deum/releases/download/${{github.event.release.tag_name}}/fvtt-te-deum.zip
files: |-
./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
system.json - run: |
api_key: '${{secrets.ALLOW_PUSH_RELEASE}}' 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,11 +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 # 12.0.21
- Creation de PNJ OK - Creation de PNJ OK
# 12.0.20 # 12.0.20
- Corrections sur la création de perso - Corrections sur la création de perso
# 12.0.19 # 12.0.19
- Initial release ! - Initial release !

View File

@@ -1,25 +1,17 @@
var gulp = require('gulp'); var gulp = require('gulp');
var less = require('gulp-less');
var postcss = require('gulp-postcss'); var postcss = require('gulp-postcss');
var autoprefixer = require('autoprefixer'); var autoprefixer = require('autoprefixer');
var cssnext = require('postcss-preset-env');
var precss = require('precss');
gulp.task('css', function () { gulp.task('css', function () {
return gulp.src('./less/*.less')
var processors = [ .pipe(less())
autoprefixer, .pipe(postcss([autoprefixer]))
cssnext,
precss
];
return gulp.src('./postcss/*.css')
.pipe(postcss(processors))
.pipe(gulp.dest('./styles')); .pipe(gulp.dest('./styles'));
}); });
gulp.task('watch', function () {
gulp.watch('./less/*.less', gulp.series('css'));
});
function watchUpdates() { gulp.task('default', gulp.series('css'));
gulp.watch('./postcss/*.css', 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 * Feuille de personnage Te Deum - AppV2
* @extends {ActorSheet}
*/ */
import { TeDeumUtility } from "../common/tedeum-utility.js"; 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 */ /** @override */
static get defaultOptions() { static DEFAULT_OPTIONS = {
classes: ["fvtt-te-deum", "sheet", "actor"],
return foundry.utils.mergeObject(super.defaultOptions, { position: {
classes: ["fvtt-te-deum", "sheet", "actor"],
template: "systems/fvtt-te-deum/templates/actors/actor-sheet.hbs",
width: 860, width: 860,
height:680, height: 680,
tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "skills" }], },
dragDrop: [{ dragSelector: ".item-list .item", dropSelector: null }], form: {
editScore: true 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() { /** @override */
async _prepareContext() {
let formData = { const actor = this.document
return {
title: this.title, title: this.title,
id: this.actor.id, id: actor.id,
type: this.actor.type, type: actor.type,
img: this.actor.img, img: actor.img,
name: this.actor.name, name: actor.name,
editable: this.isEditable, editable: this.isEditable,
cssClass: this.isEditable ? "editable" : "locked", cssClass: this.isEditable ? "editable" : "locked",
system: foundry.utils.duplicate(this.object.system), system: foundry.utils.duplicate(actor.system),
limited: this.object.limited, systemFields: actor.system.schema.fields,
competences: this.actor.getCompetences(), limited: actor.limited,
competences: actor.getCompetences(),
config: foundry.utils.duplicate(game.system.tedeum.config), config: foundry.utils.duplicate(game.system.tedeum.config),
armes: this.actor.getArmes(), armes: actor.getArmes(),
caracList: this.actor.prepareCaracteristiques(), caracList: actor.prepareCaracteristiques(),
providence: this.actor.prepareProvidence(), providence: actor.prepareProvidence(),
arbreCompetences: this.actor.prepareArbreCompetences(), arbreCompetences: actor.prepareArbreCompetences(),
equipements: this.actor.getEquipements(), equipements: actor.getEquipements(),
armures: this.actor.getArmures(), simples: actor.getSimples(),
graces: this.actor.getGraces(), armures: actor.getArmures(),
blessures: this.actor.getBlessures(), graces: actor.getGraces(),
maladies: this.actor.getMaladies(), blessures: actor.getBlessures(),
poisons: this.actor.getPoisons(), maladies: actor.getMaladies(),
combat: this.actor.prepareCombat(), poisons: actor.getPoisons(),
bonusDegats: this.actor.getBonusDegats(), combat: actor.prepareCombat(),
nbActions: this.actor.getNbActions(), bonusDegats: actor.getBonusDegats(),
initiative: this.actor.getInitiative(), nbActions: actor.getNbActions(),
pointsArmuresLourdes: this.actor.getNbArmures(), initiative: actor.getInitiative(),
nbArmuresLourdes: this.actor.getNbArmuresLourdesActuel(), pointsArmuresLourdes: actor.getNbArmures(),
santeModifier: this.actor.getSanteModifier(), nbArmuresLourdes: actor.getNbArmuresLourdesActuel(),
educations: this.actor.getEducations(), santeModifier: actor.getSanteModifier(),
description: await TextEditor.enrichHTML(this.object.system.description, { async: true }), educations: actor.getEducations(),
notes: await TextEditor.enrichHTML(this.object.system.notes, { async: true }), enrichedDescription: await foundry.applications.ux.TextEditor.implementation.enrichHTML(actor.system.description, { async: true }),
histoire: await TextEditor.enrichHTML(this.object.system.histoire, { async: true }), enrichedEquipmentFree: await foundry.applications.ux.TextEditor.implementation.enrichHTML(actor.system.equipmentfree, { async: true }),
options: this.options, enrichedNotes: await foundry.applications.ux.TextEditor.implementation.enrichHTML(actor.system.notes, { async: true }),
owner: this.document.isOwner, enrichedHistoire: await foundry.applications.ux.TextEditor.implementation.enrichHTML(actor.system.histoire, { async: true }),
editScore: this.options.editScore, owner: actor.isOwner,
isGM: game.user.isGM isEditMode: this.isEditMode,
isPlayMode: this.isPlayMode,
isGM: game.user.isGM,
} }
this.formData = formData;
console.log("PC : ", formData, this.object);
return formData;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
/** @override */ /** @override */
activateListeners(html) { _onRender(context, options) {
super.activateListeners(html); super._onRender(context, options)
// Everything below here is only needed if the sheet is editable // Tab navigation
if (!this.options.editable) return; const nav = this.element.querySelector('nav.tabs[data-group]')
if (nav) {
html.bind("keydown", function(e) { // Ignore Enter in actores sheet const group = nav.dataset.group
if (e.keyCode === 13) return false; 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 // Ignore Enter key in sheet inputs
html.find('.item-edit').click(ev => { this.element.addEventListener('keydown', e => {
const li = $(ev.currentTarget).parents(".item-id") if (e.keyCode === 13 && e.target.tagName !== 'TEXTAREA') e.preventDefault()
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")
}) })
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 }),
}) })
fp.browse()
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;
} }
/* -------------------------------------------- */ static async #onToggleSheet(event) {
/** @override */ this._sheetMode = this.isEditMode
_updateObject(event, formData) { ? this.constructor.SHEET_MODES.PLAY
// Update the Actor : this.constructor.SHEET_MODES.EDIT
return this.object.update(formData); 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. * Override the create() function to provide additional SoS functionality.
* *
* This overrided create() function adds initial items * This overrided create() function adds initial items
* Namely: Basic skills, money, * Namely: Basic skills, money,
* *
* @param {Object} data Barebones actor data which this function adds onto. * @param {Object} data Barebones actor data which this function adds onto.
* @param {Object} options (Unused) Additional options which customize the creation workflow. * @param {Object} options (Unused) Additional options which customize the creation workflow.
@@ -34,7 +34,7 @@ export class TeDeumActor extends Actor {
return actor; return actor;
} }
if (data.type == 'pj' || data.type == 'pnj') { if (data.type == 'pj' || data.type == 'pnj') {
const skills = await TeDeumUtility.loadCompendium("fvtt-te-deum.competences") const skills = await TeDeumUtility.loadCompendium("fvtt-te-deum.competences")
data.items = data.items || [] data.items = data.items || []
for (let skill of skills) { for (let skill of skills) {
@@ -64,15 +64,44 @@ export class TeDeumActor extends Actor {
super._preUpdate(changed, options, user); super._preUpdate(changed, options, user);
} }
/* -------------------------------------------- */
getCompetenceScore(compName) { getCompetenceScore(compName) {
let competence = this.items.find(item => item.type == "competence" && item.name.toLowerCase() == compName.toLowerCase()) let competence = this.items.find(item => item.type == "competence" && item.name.toLowerCase() == compName.toLowerCase())
if (competence) { if (competence) {
if (competence.system.isBase) {
return this.system.caracteristiques[competence.system.caracteristique].value
}
return competence.system.score return competence.system.score
} }
return 0 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) { _onUpdate(changed, options, userId) {
let updates = [] let updates = []
@@ -112,12 +141,6 @@ export class TeDeumActor extends Actor {
updates.push({ _id: initiative.id, "system.score": Number(newScore) }) 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") let effort = this.items.find(item => item.type == "competence" && item.name.toLowerCase() == "effort")
newScore = this.getCommonBaseValue(this.system.caracteristiques.puissance.value) newScore = this.getCommonBaseValue(this.system.caracteristiques.puissance.value)
if (effort && effort?.system.score != newScore) { if (effort && effort?.system.score != newScore) {
@@ -127,8 +150,10 @@ export class TeDeumActor extends Actor {
if (updates.length > 0) { if (updates.length > 0) {
this.updateEmbeddedDocuments('Item', updates) this.updateEmbeddedDocuments('Item', updates)
} }
super._onUpdate(changed, options, userId);
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
async _preCreate(data, options, user) { async _preCreate(data, options, user) {
await super._preCreate(data, options, user); await super._preCreate(data, options, user);
@@ -145,7 +170,7 @@ export class TeDeumActor extends Actor {
getCommonBaseValue(value) { getCommonBaseValue(value) {
return game.system.tedeum.config.COMMON_VALUE[value]?.value || 0 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 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] 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() { getNbArmures() {
return game.system.tedeum.config.MAX_ARMURES_LOURDES[this.system.caracteristiques.puissance.value] 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) TeDeumUtility.sortArrayObjectsByName(comp)
return comp; return comp;
} }
getSimples() {
let comp = foundry.utils.duplicate(this.items.filter(item => item.type == 'simple') || [])
TeDeumUtility.sortArrayObjectsByName(comp)
return comp;
}
getArmures() { getArmures() {
let comp = foundry.utils.duplicate(this.items.filter(item => item.type == 'armure') || []) let comp = foundry.utils.duplicate(this.items.filter(item => item.type == 'armure') || [])
TeDeumUtility.sortArrayObjectsByName(comp) TeDeumUtility.sortArrayObjectsByName(comp)
@@ -259,41 +307,105 @@ export class TeDeumActor extends Actor {
modTotal += blessDef.modifier modTotal += blessDef.modifier
} }
// Si le nombre de blessures est supérieur au score d'endurance, alors malus supplémentaire // 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") let enduranceScore = this.getCompetenceScore("endurance")
if (blessures.length > endurance.system.score) { if (blessures.length > enduranceScore) {
modTotal += -1 modTotal += -1
} }
return modTotal 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) { async appliquerDegats(rollData) {
let combat = this.prepareCombat() let combat = this.prepareCombat()
rollData.defenderName = this.name rollData.defenderName = this.name
let touche = combat[rollData.loc.id].touche 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) { if (rollData.degats > 0 && rollData.degats > touche) {
let diff = rollData.degats - touche let diff = rollData.degats - touche
for (let bId in game.system.tedeum.config.blessures) { for (let bId in game.system.tedeum.config.blessures) {
let blessure = game.system.tedeum.config.blessures[bId] let blessure = game.system.tedeum.config.blessures[bId]
if (diff >= blessure.degatsMin && diff <= blessure.degatsMax) { if (diff >= blessure.degatsMin && diff <= blessure.degatsMax) {
// Create a new blessure object if (rollData.isReussiteCritique) {
let blessureObj = { bId = game.system.tedeum.config.blessuresOrder[blessure.value + 1]
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,
}
} }
rollData.blessure = blessureObj blessureId = bId
this.createEmbeddedDocuments('Item', [blessureObj]); 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 // Display the relevant chat message
let msg = await TeDeumUtility.createChatWithRollMode(rollData.alias, { 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) await msg.setFlag("world", "te-deum-rolldata", rollData)
} }
@@ -303,7 +415,11 @@ export class TeDeumActor extends Actor {
c.key = key c.key = key
c.name = game.system.tedeum.config.caracteristiques[key].label c.name = game.system.tedeum.config.caracteristiques[key].label
c.generalqualite = game.system.tedeum.config.descriptionValeur[c.value].qualite 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.dice = game.system.tedeum.config.descriptionValeur[c.value].dice
c.negativeDice = game.system.tedeum.config.descriptionValeur[c.value].negativeDice c.negativeDice = game.system.tedeum.config.descriptionValeur[c.value].negativeDice
} }
@@ -322,7 +438,11 @@ export class TeDeumActor extends Actor {
prepareProvidence() { prepareProvidence() {
let providence = foundry.utils.deepClone(this.system.providence) let providence = foundry.utils.deepClone(this.system.providence)
providence.name = "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.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)." 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 return providence
@@ -360,11 +480,14 @@ export class TeDeumActor extends Actor {
providence.value = Math.min(Math.max(providence.value + value, 0), 6) providence.value = Math.min(Math.max(providence.value + value, 0), 6)
this.update({ "system.providence": providence }) this.update({ "system.providence": providence })
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
modifyXP(key, value) { async modifyXP(key, value) {
let xp = this.system.caracteristiques[key].experience let xp = this.system.caracteristiques[key].experience
xp = Math.max(xp + value, 0) 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 flag = armure.system.superposableCuir
} }
if (item.system.typeArmure == "maille") { if (item.system.typeArmure == "maille") {
flag = armure.system.superposableMaille flag = armure.system.superposableMaille
} }
if (item.system.typeArmure == "plate") { if (item.system.typeArmure == "plate") {
flag = armure.system.superposablePlate flag = armure.system.superposablePlate
@@ -512,12 +635,16 @@ export class TeDeumActor extends Actor {
/* -------------------------------------------- */ /* -------------------------------------------- */
getInitiativeScore() { getInitiativeScore() {
let initiative = this.items.find(it => it.type == "competence" && it.name.toLowerCase() == "initiative") let initiative = this.getInitiativeValue()
if (initiative) { // Vérifie les armes avec bonus d'initiative
return initiative.system.score 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 initiative
return -1;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
@@ -578,6 +705,7 @@ export class TeDeumActor extends Actor {
let rollData = this.getCommonCompetence(compId) let rollData = this.getCommonCompetence(compId)
rollData.mode = "competence" rollData.mode = "competence"
rollData.title = rollData.competence.name 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") this.startRoll(rollData).catch("Error on startRoll")
} }
@@ -585,13 +713,13 @@ export class TeDeumActor extends Actor {
async rollDegatsArme(armeId) { async rollDegatsArme(armeId) {
let weapon = this.items.get(armeId) let weapon = this.items.get(armeId)
if (weapon) { if (weapon) {
let bDegats = 0 let bDegats = { value: 0 }
if ( weapon.system.typeArme == "melee" ) { if (weapon.system.typeArme == "melee") {
bDegats = this.getBonusDegats() bDegats = this.getBonusDegats()
} }
let formula = weapon.system.degats + "+" + bDegats.value let formula = weapon.system.degats + "+" + bDegats.value
let degatsRoll = await new Roll(formula).roll() 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() let rollData = this.getCommonRollData()
rollData.mode = "degats" rollData.mode = "degats"
rollData.formula = formula rollData.formula = formula
@@ -600,7 +728,7 @@ export class TeDeumActor extends Actor {
rollData.degats = degatsRoll.total rollData.degats = degatsRoll.total
let msg = await TeDeumUtility.createChatWithRollMode(rollData.alias, { 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) await msg.setFlag("world", "te-deum-rolldata", rollData)
console.log("Rolldata result", rollData) console.log("Rolldata result", rollData)
@@ -630,14 +758,20 @@ export class TeDeumActor extends Actor {
// Setup competence + carac // Setup competence + carac
if (!compName) { 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()) let competence = this.items.find(item => item.type == "competence" && item.name.toLowerCase() == compName.toLowerCase())
if (competence) { if (competence) {
rollData.competence = 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]) let c = foundry.utils.duplicate(this.system.caracteristiques[competence.system.caracteristique])
this.updateCarac(c, competence.system.caracteristique) this.updateCarac(c, competence.system.caracteristique)
rollData.carac = c 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 { } else {
ui.notifications.warn("Impossible de trouver la compétence " + compName) ui.notifications.warn("Impossible de trouver la compétence " + compName)
return return
@@ -651,8 +785,7 @@ export class TeDeumActor extends Actor {
/* -------------------------------------------- */ /* -------------------------------------------- */
async startRoll(rollData) { async startRoll(rollData) {
console.log("startRoll", rollData) console.log("startRoll", rollData)
let rollDialog = await TeDeumRollDialog.create(this, rollData) await TeDeumRollDialog.create(this, rollData)
rollDialog.render(true)
} }
} }

View File

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

View File

@@ -2,20 +2,44 @@ import { TeDeumUtility } from "../common/tedeum-utility.js";
/* -------------------------------------------- */ /* -------------------------------------------- */
export class TeDeumCombat extends Combat { export class TeDeumCombat extends Combat {
/* -------------------------------------------- */ /* -------------------------------------------- */
async rollInitiative(ids, formula = undefined, messageOptions = {} ) { async rollInitiative(ids, formula = undefined, messageOptions = {}) {
//console.log("Roll INIT !") //console.log("Roll INIT !")
ids = typeof ids === "string" ? [ids] : ids; ids = typeof ids === "string" ? [ids] : ids;
for (let cId of ids) { for (let cId of ids) {
const c = this.combatants.get(cId); const c = this.combatants.get(cId);
let initBonus = c.actor ? c.actor.getInitiativeScore( this.id, cId ) : -1; let initBonus = c.actor ? c.actor.getInitiativeScore(this.id, cId) : -1;
await this.updateEmbeddedDocuments("Combatant", [ { _id: cId, initiative: initBonus } ]); console.log("Init Bonus : ", c.name, initBonus)
await this.updateEmbeddedDocuments("Combatant", [{ _id: cId, initiative: initBonus }]);
} }
return this; 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() { static async checkTurnPosition() {
while (game.combat.turn > 0) { while (game.combat.turn > 0) {

View File

@@ -4,30 +4,46 @@ export const SYSTEM_ID = "fvtt-te-deum";
export const TEDEUM_CONFIG = { export const TEDEUM_CONFIG = {
BONUS_DEGATS: [{}, { label: "1d4", value: -2 }, { label: "1d6", value: -1 }, { label: "1d8", value: 0 }, 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 }, 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 }, 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 }, 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 }, COUT_XP: [{}, { value: 10 }, { value: 10 }, { value: 10 },
{ value: 10 }, { value: 30 }, { value: 50 }], { value: 10 }, { value: 30 }, { value: 50 }],
LOCALISATION: { LOCALISATION: {
"pieddroit": { label: "Pied Droit", value: 1, locMod: 0, id: "pieddroit", nbArmure: 1, score: { min: 1, max: 1 }, coord: { top: 500, left: 0 } }, "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", nbArmure: 1, score: { min: 3, max: 4 }, coord: { top: 400, left: 100 } }, "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", nbArmure: 1, score: { min: 5, max: 6 }, coord: { top: 400, left: 300 } }, "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", nbArmure: 1, score: { min: 2, max: 2 }, coord: { top: 500, left: 400 } }, "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", nbArmure: 1, score: { min: 7, max: 7 }, coord: { top: 0, left: 0 } }, "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", nbArmure: 1, score: { min: 8, max: 8 }, coord: { top: 0, left: 400 } }, "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", nbArmure: 2, score: { min: 9, max: 10 }, coord: { top: 200, left: 0 } }, "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", nbArmure: 2, score: { min: 11, max: 12 }, coord: { top: 200, left: 400 } }, "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", locMod: -2, nbArmure: 2, score: { min: 13, max: 17 }, coord: { top: 200, left: 200 } }, "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", locMod: -2, nbArmure: 2, score: { min: 18, max: 20 }, coord: { top: 0, 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: { 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 }, "encombrante": { label: "Encombrante", id: "encombrante", melee: true, tir: true },
"maintiendistance": { label: "Maintien à distance", id: "maintiendistance", melee: true, tir: false }, "maintiendistance": { label: "Maintien à distance", id: "maintiendistance", melee: true, tir: false },
"coupassomant": { label: "Coup assomant", id: "coupassomant", melee: true, tir: false }, "coupassomant": { label: "Coup assomant", id: "coupassomant", melee: true, tir: false },
@@ -43,11 +59,11 @@ export const TEDEUM_CONFIG = {
}, },
ARME_PORTEES: { ARME_PORTEES: {
"brulepourpoint": { label: "Brûle-pourpoint", difficulty: "facile", id: "brulepourpoint" }, "brulepourpoint": { label: "Brûle-pourpoint (5)", difficulty: "facile", id: "brulepourpoint" },
"courte": { label: "Courte", difficulty: "pardefaut", id: "courte" }, "courte": { label: "Courte (7)", difficulty: "pardefaut", id: "courte" },
"moyenne": { label: "Moyenne", difficulty: "difficile", id: "moyenne" }, "moyenne": { label: "Moyenne (11)", difficulty: "difficile", id: "moyenne" },
"longue": { label: "Longue", difficulty: "perilleux", id: "longue" }, "longue": { label: "Longue (13)", difficulty: "perilleux", id: "longue" },
"extreme": { label: "Extrême", difficulty: "desespere", id: "extreme" }, "extreme": { label: "Extrême (15)", difficulty: "desespere", id: "extreme" },
}, },
genre: { genre: {
@@ -57,7 +73,7 @@ export const TEDEUM_CONFIG = {
descriptionValeurOdd: { descriptionValeurOdd: {
1: { valeur: 1, qualite: "Mauvais", dice: "d4", negativeDice: "d20", savoir: "Sot", sensibilite: "Obtus", entregent: "Rustaud", puissance: "Menu", complexion: "Anémique", adresse: "Empesé" }, 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" }, 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" }, 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" }, 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: { descriptionValeur: {
1: { valeur: 1, qualite: "Mauvais", dice: "d4", negativeDice: "d20", savoir: "Sot", sensibilite: "Obtus", entregent: "Rustaud", puissance: "Menu", complexion: "Anémique", adresse: "Empesé" }, 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" }, 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" }, 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" }, 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" }, 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"], diceValeur: ["d4", "d6", "d8", "d10", "d12", "d20"],
degatsArmure: { degatsArmure: {
sansarmure: { label: "Sans armure" }, sansarmure: { label: "Sans armure" },
@@ -86,7 +110,7 @@ export const TEDEUM_CONFIG = {
}, },
caracteristiques: { 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." }, 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." }, 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." }, 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." }, 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: { allonges: {
courte: { courte: { malus: 0 }, moyenne: { malus: -1 }, longue: { malus: -2 }, treslongue: { malus: 0, esquive: 2 } }, 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: { malus: 0 }, moyenne: { malus: 0 }, longue: { malus: -1 }, treslongue: { 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: { malus: -2 }, moyenne: { malus: -1 }, longue: { malus: 0 }, treslongue: { malus: -1, esquive: 1 } }, 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: { malus: 0, esquive: 2 }, moyenne: { malus: 0, esquive: 2 }, longue: { malus: 0, esquive: 1 }, treslongue: { malus: 0 } }, 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: [ providence: [
{ labelM: "Brebis égarée", labelF: "Brebis égarée", value: 0, diceValue: "0" }, { 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" }, melee: { label: "Mêlée", value: "melee" },
tir: { label: "Tir", value: "tir" } tir: { label: "Tir", value: "tir" }
}, },
genreEducation: {
"homme": { label: "Homme", value: "Homme" },
"femme": { label: "Femme", value: "Femme" },
"mixte": { label: "Mixte", value: "Mixte" }
},
armeAllonges: { armeAllonges: {
courte: { label: "Courte", value: "courte" }, courte: { label: "Courte", value: "courte" },
moyenne: { label: "Moyenne", value: "moyenne" }, moyenne: { label: "Moyenne", value: "moyenne" },
@@ -139,24 +168,29 @@ export const TEDEUM_CONFIG = {
}, },
difficulte: { difficulte: {
aucune: { label: "Aucune", key: "aucune", value: 0 }, aucune: { label: "Aucune", key: "aucune", value: 0 },
routine: { label: "Routine", key: "routine", value: 3 }, routine: { label: "Routine (3)", key: "routine", value: 3 },
facile: { label: "Facile", key: "facile", value: 5 }, facile: { label: "Facile (5)", key: "facile", value: 5 },
pardefaut: { label: "Par Défaut", key: "pardefaut", value: 7 }, pardefaut: { label: "Par Défaut (7)", key: "pardefaut", value: 7 },
malaise: { label: "Malaisé", key: "malaise", value: 9 }, malaise: { label: "Malaisé (9)", key: "malaise", value: 9 },
difficile: { label: "Difficile", key: "difficile", value: 11 }, difficile: { label: "Difficile (11)", key: "difficile", value: 11 },
perilleux: { label: "Perilleux", key: "perilleux", value: 13 }, perilleux: { label: "Perilleux (13)", key: "perilleux", value: 13 },
desespere: { label: "Désespéré", key: "desespere", value: 15 } desespere: { label: "Désespéré (15)", key: "desespere", value: 15 }
}, },
monnaie: { monnaie: {
denier: { label: "Deniers", id: "denier", value: 1 }, denier: { label: "Deniers", id: "denier", value: 1 },
sol: { label: "Sols", id: "sol", value: 10 }, sol: { label: "Sols", id: "sol", value: 10 },
livre: { label: "Livres", id: "livre", value: 100 } 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: { etapesEducation: {
pouponniere: { label: "La Pouponnière", value: "pouponniere", agemin: 0, agemax: 6, nbCompetences: 2, nbCaracteristiques: 3, hasQuestionnaire: true, hasDebouches: false, hasMultiplier: false, canCompetencesOpt: false }, 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, nbCaracteristiques: 3, hasDebouches: false, hasQuestionnaire: true, 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, hasQuestionnaire: true, hasDebouches: 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, hasQuestionnaire: false, hasDebouches: false, hasMultiplier: true, canCompetencesOpt: true }, 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: { origineSociale: {
noblesseepee: { label: "Noblesse d'épée", id: "noblesseepee", caracteristiques: { entregent: 1, puissance: 1 }, cagnotte: 10, cagnotteUnit: "livres", value: 1 }, 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: "1", label: "+1 niveau" },
{ value: "2", label: "+2 niveaux" } { value: "2", label: "+2 niveaux" }
], ],
blessuresOrder: ["indemne", "estafilade", "plaie", "plaiebeante", "plaieatroce", "tuenet", "tuenet", "tuenet", "tuenet", "tuenet"],
blessures: { blessures: {
indemne: { value: 0, label: "Indemne", key: "indemne", degatsMax: -1, count: 0, modifier: 0 }, 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 }, 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 }, 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 }, 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 }, 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: { virulence: {
aucune: { label: "Aucune", value: "aucune", modifier: 0 }, 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 { export class TeDeumUtility {
/* -------------------------------------------- */ /* -------------------------------------------- */
@@ -12,22 +14,68 @@ export class TeDeumUtility {
CONFIG.JournalEntry.compendiumBanner = "systems/fvtt-te-deum/images/ui/compendium_banner.webp" 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.Macro.compendiumBanner = "systems/fvtt-te-deum/images/ui/compendium_banner.webp"
CONFIG.Adventure.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) => { Hooks.on("renderActorDirectory", (app, html, data) => {
if (game.user.can('ACTOR_CREATE')) { if (game.user.can('ACTOR_CREATE')) {
const button = document.createElement('button'); 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.innerHTML = 'Créer un Personnage'
button.addEventListener('click', () => { button.addEventListener('click', () => {
let cr = new game.system.tedeum.TeDeumCharacterCreator(); let cr = new game.system.tedeum.TeDeumCharacterCreator();
cr.init() 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 () { Handlebars.registerHelper('isGM', function () {
return game.user.isGM 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 // Load compendium data
const competences = await TeDeumUtility.loadCompendium("fvtt-te-deum.competences") const competences = await TeDeumUtility.loadCompendium("fvtt-te-deum.competences")
@@ -119,14 +182,24 @@ export class TeDeumUtility {
/* -------------------------------------------- */ /* -------------------------------------------- */
static welcomeMessage() { static welcomeMessage() {
if (game.user.isGM) { if (game.user.isGM) {
ChatMessage.create({ // Try to fetch the welcome message from the github repo "welcome-message-ecryme.html"
user: game.user.id, fetch(ECRYME_WELCOME_MESSAGE_URL)
whisper: [game.user.id], .then(response => response.text())
content: `<div id="chat-welcome welcome-message-tedeum"><span class="rdd-roll-part"> .then(html => {
<strong>Bienvenu dans Te Deum Pour Un Massacre !</strong> ChatMessage.create({
<div class="chat-welcome">Ce système vous est proposé par Open Sesame Games.<br> user: game.user.id,
Vous trouverez de l'aide dans @UUID[Compendium.fvtt-te-deum.aides.JournalEntry.uNwJgi4kXBCiZmAH]{Aide pour Te Deum}<br> whisper: [game.user.id],
ainsi que sur le Discord de Foundry FR : https://discord.gg/pPSDNJk</div>` }); 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.hasMultiplier = etape.hasMultiplier;
formData.hasDebouches = etape.hasDebouches; formData.hasDebouches = etape.hasDebouches;
formData.canCompetencesOpt = etape.canCompetencesOpt; formData.canCompetencesOpt = etape.canCompetencesOpt;
formData.hasGenre = etape.hasGenre;
} }
/*-------------------------------------------- */ /*-------------------------------------------- */
@@ -192,7 +266,7 @@ export class TeDeumUtility {
return actor return actor
} }
/* -------------------------------------------- */ /* -------------------------------------------- */ /* -------------------------------------------- */
static async manageOpposition(rollData) { static async manageOpposition(rollData) {
if (!this.currentOpposition) { if (!this.currentOpposition) {
// Store rollData as current GM opposition // Store rollData as current GM opposition
@@ -200,29 +274,86 @@ export class TeDeumUtility {
ui.notifications.info("Opposition démarrée avec " + rollData.alias); ui.notifications.info("Opposition démarrée avec " + rollData.alias);
} else { } else {
// Perform the opposition // Perform the opposition
let rWinner = this.currentOpposition let isAttackWinner = true
let rLooser = rollData let rWinner, rLooser
if (rWinner.total < rLooser.total) { if (this.currentOpposition.total <= rollData.total) {
rWinner = rollData rWinner = foundry.utils.duplicate(rollData)
rLooser = this.currentOpposition 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 this.currentOpposition = undefined // Reset opposition
let oppositionData = { let oppositionData = {
winner: rWinner, winner: rWinner,
looser: rLooser 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, { 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) 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) { 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 messageId = TeDeumUtility.findChatMessageId(event.currentTarget)
let message = game.messages.get(messageId) let message = game.messages.get(messageId)
let rollData = message.getFlag("world", "te-deum-rolldata") let rollData = message.getFlag("world", "te-deum-rolldata")
@@ -230,6 +361,33 @@ export class TeDeumUtility {
TeDeumUtility.manageOpposition(rollData, messageId) 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/actors/editor-notes-gm.hbs',
'systems/fvtt-te-deum/templates/items/partial-item-nav.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/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 let rollData = msg.data.rollData
if (game.user.isGM) { if (game.user.isGM) {
let chatMsg = await this.createChatMessage(rollData.alias, "blindroll", { 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 whisper: game.user.id
}) })
chatMsg.setFlag("world", "tedeum-rolldata", rollData) 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) { 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")) await this.showDiceSoNice(critiqueRoll, game.settings.get("core", "rollMode"))
rollData.critiqueRoll = foundry.utils.duplicate(critiqueRoll) 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 rollData.isEchecCritique = true
} }
} }
@@ -439,9 +632,18 @@ export class TeDeumUtility {
if (rollData.isMouvement) { if (rollData.isMouvement) {
localModifier -= 1 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) let diceBase = this.modifyDice(rollData.carac.dice, localModifier + Number(rollData.bonusMalus) + rollData.santeModifier)
if (!diceBase) return; if (!diceBase) return;
diceFormula = diceBase + "x + " + rollData.competence.system.score diceFormula = diceBase + "x + " + rollData.compScore
} }
if (rollData.enableProvidence) { if (rollData.enableProvidence) {
diceFormula += " + " + rollData.providence.dice diceFormula += " + " + rollData.providence.dice
@@ -451,32 +653,33 @@ export class TeDeumUtility {
/* -------------------------------------------- */ /* -------------------------------------------- */
static async getLocalisation(rollData) { static async getLocalisation(rollData) {
let locRoll = await new Roll("1d20").roll() let locRoll
await this.showDiceSoNice(locRoll, game.settings.get("core", "rollMode")) if (rollData.loc) {
rollData.locRoll = foundry.utils.duplicate(locRoll) locRoll = await new Roll(String(rollData.loc.score.min)).roll()
for (let key in game.system.tedeum.config.LOCALISATION) { } else {
let loc = game.system.tedeum.config.LOCALISATION[key] locRoll = await new Roll("1d20").roll()
if (locRoll.total >= loc.score.min && locRoll.total <= loc.score.max) { await this.showDiceSoNice(locRoll, game.settings.get("core", "rollMode"))
rollData.loc = foundry.utils.duplicate(loc) for (let key in game.system.tedeum.config.LOCALISATION) {
break 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) { static async processAttaqueMelee(rollData) {
if (rollData.arme?.system.typeArme != "melee") { await this.getLocalisation(rollData)
return let actor = game.actors.get(rollData.actorId)
} let bDegats = actor.getAttaqueBonusDegats(rollData)
if (rollData.isSuccess) { rollData.degatsFormula = rollData.arme.system.degats + "+" + bDegats
await this.getLocalisation(rollData) let degatsRoll = await new Roll(rollData.degatsFormula).roll()
let actor = game.actors.get(rollData.actorId) await this.showDiceSoNice(degatsRoll, game.settings.get("core", "rollMode"))
let bDegats = actor.getBonusDegats() rollData.degatsRoll = foundry.utils.duplicate(degatsRoll)
let degatsRoll = await new Roll(rollData.arme.system.degats + "+" + bDegats.value).roll() rollData.degats = degatsRoll.total
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) await this.getLocalisation(rollData)
// Now the degats // Now the degats
let degatsRoll = await new Roll(rollData.arme.system.degats).roll() 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.degatsRoll = foundry.utils.duplicate(degatsRoll)
rollData.degats = degatsRoll.total 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) { static async rollTeDeum(rollData) {
@@ -504,6 +746,18 @@ export class TeDeumUtility {
rollData.difficulty = "pardefaut" rollData.difficulty = "pardefaut"
} }
rollData.difficulty = game.system.tedeum.config.difficulte[rollData.difficulty].value 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) let diceFormula = this.computeRollFormula(rollData, actor)
if (!diceFormula) return; if (!diceFormula) return;
console.log("RollData", rollData, diceFormula) console.log("RollData", rollData, diceFormula)
@@ -519,10 +773,11 @@ export class TeDeumUtility {
await this.computeResults(rollData) await this.computeResults(rollData)
await this.processAttaqueDistance(rollData) await this.processAttaqueDistance(rollData)
await this.processAttaqueMelee(rollData)
await this.manageCombatActions(actor, rollData)
let msg = await this.createChatWithRollMode(rollData.alias, { 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) await msg.setFlag("world", "te-deum-rolldata", rollData)
console.log("Rolldata result", rollData) console.log("Rolldata result", rollData)
@@ -531,19 +786,6 @@ export class TeDeumUtility {
if (rollData.enableProvidence) { if (rollData.enableProvidence) {
actor.modifyProvidence(-1) 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) { 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 msgTxt = "<p>Etes vous certain de supprimer cet item ?";
let buttons = { let buttons = {
delete: { delete: {
@@ -669,7 +911,12 @@ export class TeDeumUtility {
label: "Oui, aucun souci", label: "Oui, aucun souci",
callback: () => { callback: () => {
actorSheet.actor.deleteEmbeddedDocuments("Item", [itemId]); 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: { cancel: {

View File

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

View File

@@ -4,8 +4,9 @@ export class TeDeumBlessureSchema extends foundry.abstract.TypeDataModel {
const requiredInteger = { required: true, nullable: false, integer: true }; const requiredInteger = { required: true, nullable: false, integer: true };
const schema = {}; const schema = {};
schema.typeBlessure = new fields.StringField({required: true, choices: ["indemne", "estafilade", "plaie", "plaiebeante", "plaieatroce", "tuenet"], initial: "estafilade"}); 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.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 }); schema.description = new fields.HTMLField({ required: true, blank: true });

View File

@@ -14,7 +14,9 @@ export class TeDeumEducationSchema extends foundry.abstract.TypeDataModel {
return obj; 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.nbChoixCarac = new fields.NumberField({ ...requiredInteger, initial: 1, min: 1 });
schema.caracteristiques = new fields.SchemaField(Array.fromRange(3, 1).reduce((caracs, i) => { schema.caracteristiques = new fields.SchemaField(Array.fromRange(3, 1).reduce((caracs, i) => {
caracs[`carac${i}`] = new fields.SchemaField({ caracs[`carac${i}`] = new fields.SchemaField({
@@ -30,7 +32,7 @@ export class TeDeumEducationSchema extends foundry.abstract.TypeDataModel {
}); });
return comps; return comps;
}, {})); }, {}));
schema.hasCompetencesOpt = new fields.BooleanField({initial: false}) schema.hasCompetencesOpt = new fields.BooleanField({initial: false})
schema.competencesOptNumber = new fields.NumberField({ ...requiredInteger, initial: 1, min:0 }) schema.competencesOptNumber = new fields.NumberField({ ...requiredInteger, initial: 1, min:0 })
schema.competencesOpt = new fields.SchemaField(Array.fromRange(14, 1).reduce((comps, i) => { 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: "" }), reponse: new fields.StringField({ required: true, blank: true, initial: "" }),
compName: new fields.StringField({ required: true, blank: true, initial: "" }), compName: new fields.StringField({ required: true, blank: true, initial: "" }),
toSelect: new fields.BooleanField({ initial: false }), 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({ comps[`comp${i}`] = new fields.SchemaField({
compName: new fields.StringField({ required: true, blank: true, initial: "" }), compName: new fields.StringField({ required: true, blank: true, initial: "" }),
}); });
@@ -61,7 +63,7 @@ export class TeDeumEducationSchema extends foundry.abstract.TypeDataModel {
}); });
return questions; return questions;
}, {})); }, {}));
schema.debouches = new fields.SchemaField(Array.fromRange(24, 1).reduce((debouches, i) => { schema.debouches = new fields.SchemaField(Array.fromRange(24, 1).reduce((debouches, i) => {
debouches[`debouche${i}`] = new fields.SchemaField({ debouches[`debouche${i}`] = new fields.SchemaField({
debouche: new fields.StringField({ required: true, blank: true, initial: "" }) 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.cagnotteMultiplier = new fields.NumberField({ ...requiredDouble, initial: 1.0, min: 0 });
schema.cagnotteDivider = 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.description = new fields.HTMLField({ required: true, blank: true });
schema.trousseau = new fields.StringField({ required: true, blank: true, initial: "" }); 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; 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.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.fievre = new fields.StringField({required: true, choices: ["aucune", "legere", "forte", "grave"], initial: "aucune"});
schema.symptomes = new fields.HTMLField({ required: true, blank: true }); 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 }); 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({ obj[loc.id] = new fields.SchemaField({
armure: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0, max: 20 }), armure: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0, max: 20 }),
touche: 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; return obj;
}, {}) }, {})
); );
schema.fortune = new fields.SchemaField({ 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 }) , "livres": new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 }) ,
"sous": 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.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.connaissances = new fields.HTMLField({required: true, blank: true});
schema.histoire = 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.vetements = new fields.HTMLField({required: true, blank: true});
schema.equipmentfree = 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.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.age = new fields.StringField({ required: false, blank: true, initial: "" });
schema.statutocial = new fields.StringField({ required: false, blank: true, initial: undefined }); schema.datenaissance = new fields.StringField({ required: false, blank: true, initial: "" });
schema.chargestitre = new fields.StringField({ required: false, blank: true, initial: undefined }); schema.statutocial = new fields.StringField({ required: false, blank: true, initial: "" });
schema.charges = new fields.StringField({ required: false, blank: true, initial: undefined }); schema.chargestitre = new fields.StringField({ required: false, blank: true, initial: "" });
schema.religion = new fields.StringField({ required: false, blank: true, initial: undefined }); schema.charges = new fields.StringField({ required: false, blank: true, initial: "" });
schema.lieunaissance = new fields.StringField({ required: false, blank: true, initial: undefined }); schema.religion = new fields.StringField({ required: false, blank: true, initial: "" });
schema.lieunaissance = new fields.StringField({ required: false, blank: true, initial: "" });
return schema; return schema;
} }
} }

View File

@@ -1,87 +1,103 @@
import { TeDeumUtility } from "../common/tedeum-utility.js"; 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) { static async create(actor, rollData) {
const dialog = new TeDeumRollDialog(actor, rollData)
let options = { classes: ["tedeum-roll-dialog"], width: 540, height: 'fit-content', 'z-index': 99999 } dialog.render(true)
let html = await renderTemplate('systems/fvtt-te-deum/templates/dialogs/roll-dialog-generic.hbs', rollData); return dialog
return new TeDeumRollDialog(actor, rollData, html, options);
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
constructor(actor, rollData, html, options, close = undefined) { async _prepareContext() {
let conf = { return { ...this.rollData }
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 refreshDialog() { async refreshDialog() {
const content = await renderTemplate("systems/fvtt-te-deum/templates/dialogs/roll-dialog-generic.hbs", this.rollData) this.render()
this.data.content = content
this.render(true)
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
activateListeners(html) { static #onRoll(event, target) {
super.activateListeners(html); TeDeumUtility.rollTeDeum(this.rollData)
this.close()
}
let dialog = this; /* -------------------------------------------- */
function onLoad() { static #onCancel(event, target) {
} this.close()
$(function () { onLoad(); }); }
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) 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" 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" 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 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.porteeTir = event.currentTarget.value
this.rollData.difficulty = game.system.tedeum.config.ARME_PORTEES[this.rollData.porteeTir].difficulty 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.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 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 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"; import { TeDeumUtility } from "../common/tedeum-utility.js";
const { HandlebarsApplicationMixin } = foundry.applications.api
/** /**
* Extend the basic ItemSheet with some very simple modifications * Feuille d'item Te Deum - AppV2
* @extends {ItemSheet}
*/ */
export class TeDeumItemSheet extends ItemSheet { export class TeDeumItemSheet extends HandlebarsApplicationMixin(foundry.applications.sheets.ItemSheetV2) {
/** @override */ /** @override */
static get defaultOptions() { static DEFAULT_OPTIONS = {
return foundry.utils.mergeObject(super.defaultOptions, { classes: ["fvtt-te-deum", "sheet", "item"],
classes: ["fvtt-te-deum", "sheet", "item"], position: {
template: "systems/fvtt-te-deum/templates/item-sheet.hbs",
dragDrop: [{ dragSelector: null, dropSelector: null }],
width: 620, width: 620,
height: 580, 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,
},
} }
/* -------------------------------------------- */ // Static PARTS pointing to the dynamic wrapper template
_getHeaderButtons() { static PARTS = {
let buttons = super._getHeaderButtons(); sheet: { template: "systems/fvtt-te-deum/templates/items/item-sheet.hbs" },
// 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
} }
/* -------------------------------------------- */ tabGroups = { primary: "description" }
async getData() {
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, title: this.title,
id: this.id, id: item.id,
type: this.object.type, type: item.type,
img: this.object.img, img: item.img,
name: this.object.name, name: item.name,
editable: this.isEditable, editable: this.isEditable,
cssClass: this.isEditable ? "editable" : "locked", 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), config: foundry.utils.duplicate(game.system.tedeum.config),
competences: TeDeumUtility.getCompetencesForDropDown(), competences: TeDeumUtility.getCompetencesForDropDown(),
limited: this.object.limited, limited: item.limited,
options: this.options, owner: item.isOwner,
owner: this.document.isOwner, enrichedDescription: await enrich(item.system.description),
description: await TextEditor.enrichHTML(this.object.system.description, { async: true }), enrichedTransmission: await enrich(item.system.transmission),
notes: await TextEditor.enrichHTML(this.object.system.notes, { async: true }), enrichedSymptomes: await enrich(item.system.symptomes),
isGM: game.user.isGM 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 (item.type === "education") {
if (this.object.type == "education") { TeDeumUtility.prepareEducationContent(context)
TeDeumUtility.prepareEducationContent(formData);
} }
return 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
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
postItem() { /** @override */
let chatData = duplicate(this.item) _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) { 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")) {
if (chatData.img.includes("/blank.png")) { chatData.img = null
chatData.img = null;
} }
// JSON object for easy creation chatData.jsondata = JSON.stringify({ compendium: "postedItem", payload: chatData })
chatData.jsondata = JSON.stringify( const html = await foundry.applications.handlebars.renderTemplate(
{ 'systems/fvtt-te-deum/templates/post-item.html', chatData
compendium: "postedItem", )
payload: chatData, ChatMessage.create(TeDeumUtility.chatDataSetup(html))
});
renderTemplate('systems/fvtt-te-deum/templates/post-item.html', chatData).then(html => {
let chatOptions = TeDeumUtility.chatDataSetup(html);
ChatMessage.create(chatOptions)
});
} }
/* -------------------------------------------- */ static async #onDeleteSubitem(event, target) {
async viewSubitem(ev) { const field = target.dataset.type
let levelIndex = Number($(ev.currentTarget).parents(".item").data("level-index")) const idx = parseInt(target.dataset.index)
let choiceIndex = Number($(ev.currentTarget).parents(".item").data("choice-index")) const oldArray = this.document.system[field]
let featureId = $(ev.currentTarget).parents(".item").data("feature-id") if (Array.isArray(oldArray) && oldArray[idx]?.name !== 'None') {
const newArray = oldArray.filter((_, i) => i !== idx)
let itemData = this.object.system.levels[levelIndex].choices[choiceIndex].features[featureId] this.document.update({ [`system.${field}`]: newArray })
if (itemData.name != 'None') {
let item = await Item.create(itemData, { temporary: true });
item.system.origin = "embeddedItem";
new TeDeumItemSheet(item).render(true);
} }
} }
/* -------------------------------------------- */ static async #onViewSubitem(event, target) {
async deleteSubitem(ev) { const li = target.closest(".item")
let field = $(ev.currentTarget).data('type'); const levelIndex = parseInt(li?.dataset.levelIndex)
let idx = Number($(ev.currentTarget).data('index')); const choiceIndex = parseInt(li?.dataset.choiceIndex)
let oldArray = this.object.system[field]; const featureId = li?.dataset.featureId
let itemData = this.object.system[field][idx]; const itemData = this.document.system.levels?.[levelIndex]?.choices?.[choiceIndex]?.features?.[featureId]
if (itemData.name != 'None') { if (itemData?.name !== 'None') {
let newArray = []; const item = await Item.create(itemData, { temporary: true })
for (let i = 0; i < oldArray.length; i++) { item.system.origin = "embeddedItem"
if (i != idx) { new TeDeumItemSheet(item).render(true)
newArray.push(oldArray[i]);
}
}
this.object.update({ [`system.${field}`]: newArray });
} }
} }
/* -------------------------------------------- */ // #endregion
/** @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)
}
} }

View File

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

View File

@@ -1,8 +1,7 @@
2025/03/01-19:40:45.555874 7fe59dffb6c0 Recovering log #37 2026/02/28-09:14:40.938346 7f56f93fe6c0 Recovering log #243
2025/03/01-19:40:45.565732 7fe59dffb6c0 Delete type=3 #35 2026/02/28-09:14:40.993306 7f56f93fe6c0 Delete type=3 #241
2025/03/01-19:40:45.565785 7fe59dffb6c0 Delete type=0 #37 2026/02/28-09:14:40.993438 7f56f93fe6c0 Delete type=0 #243
2025/03/01-19:41:57.321763 7fe59d7fa6c0 Level-0 table #42: started 2026/02/28-11:53:47.481993 7f54e37ef6c0 Level-0 table #248: started
2025/03/01-19:41:57.321801 7fe59d7fa6c0 Level-0 table #42: 0 bytes OK 2026/02/28-11:53:47.482026 7f54e37ef6c0 Level-0 table #248: 0 bytes OK
2025/03/01-19:41:57.328249 7fe59d7fa6c0 Delete type=0 #40 2026/02/28-11:53:47.487859 7f54e37ef6c0 Delete type=0 #246
2025/03/01-19:41:57.328418 7fe59d7fa6c0 Manual compaction at level-0 from '!journal!uNwJgi4kXBCiZmAH' @ 72057594037927935 : 1 .. '!journal.pages!uNwJgi4kXBCiZmAH.onhNU0mXhOpdNZJF' @ 0 : 0; will stop at (end) 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)
2025/03/01-19:41:57.328438 7fe59d7fa6c0 Manual compaction at level-1 from '!journal!uNwJgi4kXBCiZmAH' @ 72057594037927935 : 1 .. '!journal.pages!uNwJgi4kXBCiZmAH.onhNU0mXhOpdNZJF' @ 0 : 0; will stop at (end)

View File

@@ -1,8 +1,7 @@
2025/03/01-19:35:57.154413 7fe59e7fc6c0 Recovering log #33 2026/02/27-17:11:33.828064 7f56f8bfd6c0 Recovering log #239
2025/03/01-19:35:57.165621 7fe59e7fc6c0 Delete type=3 #31 2026/02/27-17:11:33.838170 7f56f8bfd6c0 Delete type=3 #237
2025/03/01-19:35:57.165677 7fe59e7fc6c0 Delete type=0 #33 2026/02/27-17:11:33.838231 7f56f8bfd6c0 Delete type=0 #239
2025/03/01-19:38:46.090031 7fe59d7fa6c0 Level-0 table #38: started 2026/02/27-17:22:38.249017 7f54e37ef6c0 Level-0 table #244: started
2025/03/01-19:38:46.090085 7fe59d7fa6c0 Level-0 table #38: 0 bytes OK 2026/02/27-17:22:38.249057 7f54e37ef6c0 Level-0 table #244: 0 bytes OK
2025/03/01-19:38:46.096397 7fe59d7fa6c0 Delete type=0 #36 2026/02/27-17:22:38.255519 7f54e37ef6c0 Delete type=0 #242
2025/03/01-19:38:46.113755 7fe59d7fa6c0 Manual compaction at level-0 from '!journal!uNwJgi4kXBCiZmAH' @ 72057594037927935 : 1 .. '!journal.pages!uNwJgi4kXBCiZmAH.onhNU0mXhOpdNZJF' @ 0 : 0; will stop at (end) 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)
2025/03/01-19:38:46.113810 7fe59d7fa6c0 Manual compaction at level-1 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-000141 MANIFEST-000347

View File

@@ -1,7 +1,7 @@
2025/03/01-19:40:45.461315 7fe59effd6c0 Recovering log #139 2026/02/28-09:14:40.507166 7f56f8bfd6c0 Recovering log #345
2025/03/01-19:40:45.471298 7fe59effd6c0 Delete type=3 #137 2026/02/28-09:14:40.569877 7f56f8bfd6c0 Delete type=3 #343
2025/03/01-19:40:45.471427 7fe59effd6c0 Delete type=0 #139 2026/02/28-09:14:40.570013 7f56f8bfd6c0 Delete type=0 #345
2025/03/01-19:41:57.262543 7fe59d7fa6c0 Level-0 table #144: started 2026/02/28-11:53:47.420510 7f54e37ef6c0 Level-0 table #350: started
2025/03/01-19:41:57.262603 7fe59d7fa6c0 Level-0 table #144: 0 bytes OK 2026/02/28-11:53:47.420538 7f54e37ef6c0 Level-0 table #350: 0 bytes OK
2025/03/01-19:41:57.269401 7fe59d7fa6c0 Delete type=0 #142 2026/02/28-11:53:47.427480 7f54e37ef6c0 Delete type=0 #348
2025/03/01-19:41:57.269633 7fe59d7fa6c0 Manual compaction at level-0 from '!folders!InCQeTRdT5jXMX82' @ 72057594037927935 : 1 .. '!items!wxIHkrq98eQ3cOvp' @ 0 : 0; will stop at (end) 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/03/01-19:35:57.054371 7fe59f7fe6c0 Recovering log #135 2026/02/27-17:11:33.742557 7f56f8bfd6c0 Recovering log #341
2025/03/01-19:35:57.064331 7fe59f7fe6c0 Delete type=3 #133 2026/02/27-17:11:33.751671 7f56f8bfd6c0 Delete type=3 #339
2025/03/01-19:35:57.064442 7fe59f7fe6c0 Delete type=0 #135 2026/02/27-17:11:33.751725 7f56f8bfd6c0 Delete type=0 #341
2025/03/01-19:38:46.045299 7fe59d7fa6c0 Level-0 table #140: started 2026/02/27-17:22:38.183980 7f54e37ef6c0 Level-0 table #346: started
2025/03/01-19:38:46.045318 7fe59d7fa6c0 Level-0 table #140: 0 bytes OK 2026/02/27-17:22:38.184010 7f54e37ef6c0 Level-0 table #346: 0 bytes OK
2025/03/01-19:38:46.052039 7fe59d7fa6c0 Delete type=0 #138 2026/02/27-17:22:38.189997 7f54e37ef6c0 Delete type=0 #344
2025/03/01-19:38:46.058190 7fe59d7fa6c0 Manual compaction at level-0 from '!folders!InCQeTRdT5jXMX82' @ 72057594037927935 : 1 .. '!items!wxIHkrq98eQ3cOvp' @ 0 : 0; will stop at (end) 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-000141 MANIFEST-000348

View File

@@ -1,7 +1,7 @@
2025/03/01-19:40:45.474414 7fe59dffb6c0 Recovering log #139 2026/02/28-09:14:40.573416 7f56f93fe6c0 Recovering log #346
2025/03/01-19:40:45.484515 7fe59dffb6c0 Delete type=3 #137 2026/02/28-09:14:40.630571 7f56f93fe6c0 Delete type=3 #344
2025/03/01-19:40:45.484615 7fe59dffb6c0 Delete type=0 #139 2026/02/28-09:14:40.630725 7f56f93fe6c0 Delete type=0 #346
2025/03/01-19:41:57.244110 7fe59d7fa6c0 Level-0 table #144: started 2026/02/28-11:53:47.408468 7f54e37ef6c0 Level-0 table #351: started
2025/03/01-19:41:57.244149 7fe59d7fa6c0 Level-0 table #144: 0 bytes OK 2026/02/28-11:53:47.408492 7f54e37ef6c0 Level-0 table #351: 0 bytes OK
2025/03/01-19:41:57.250209 7fe59d7fa6c0 Delete type=0 #142 2026/02/28-11:53:47.414369 7f54e37ef6c0 Delete type=0 #349
2025/03/01-19:41:57.269578 7fe59d7fa6c0 Manual compaction at level-0 from '!folders!2wTJBj3dicRKzNOE' @ 72057594037927935 : 1 .. '!items!ufvhWG5V8pX0qrtR' @ 0 : 0; will stop at (end) 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/03/01-19:35:57.068105 7fe59e7fc6c0 Recovering log #135 2026/02/27-17:11:33.753908 7f56f9bff6c0 Recovering log #342
2025/03/01-19:35:57.078819 7fe59e7fc6c0 Delete type=3 #133 2026/02/27-17:11:33.763888 7f56f9bff6c0 Delete type=3 #340
2025/03/01-19:35:57.078913 7fe59e7fc6c0 Delete type=0 #135 2026/02/27-17:11:33.763941 7f56f9bff6c0 Delete type=0 #342
2025/03/01-19:38:46.052161 7fe59d7fa6c0 Level-0 table #140: started 2026/02/27-17:22:38.176835 7f54e37ef6c0 Level-0 table #347: started
2025/03/01-19:38:46.052188 7fe59d7fa6c0 Level-0 table #140: 0 bytes OK 2026/02/27-17:22:38.176924 7f54e37ef6c0 Level-0 table #347: 0 bytes OK
2025/03/01-19:38:46.058075 7fe59d7fa6c0 Delete type=0 #138 2026/02/27-17:22:38.183841 7f54e37ef6c0 Delete type=0 #345
2025/03/01-19:38:46.058217 7fe59d7fa6c0 Manual compaction at level-0 from '!folders!2wTJBj3dicRKzNOE' @ 72057594037927935 : 1 .. '!items!ufvhWG5V8pX0qrtR' @ 0 : 0; will stop at (end) 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-000138 MANIFEST-000346

View File

@@ -1,7 +1,7 @@
2025/03/01-19:40:45.446777 7fe59f7fe6c0 Recovering log #136 2026/02/28-09:14:40.445424 7f56e3fff6c0 Recovering log #344
2025/03/01-19:40:45.457998 7fe59f7fe6c0 Delete type=3 #134 2026/02/28-09:14:40.502194 7f56e3fff6c0 Delete type=3 #342
2025/03/01-19:40:45.458083 7fe59f7fe6c0 Delete type=0 #136 2026/02/28-09:14:40.502321 7f56e3fff6c0 Delete type=0 #344
2025/03/01-19:41:57.250328 7fe59d7fa6c0 Level-0 table #141: started 2026/02/28-11:53:47.402111 7f54e37ef6c0 Level-0 table #349: started
2025/03/01-19:41:57.250355 7fe59d7fa6c0 Level-0 table #141: 0 bytes OK 2026/02/28-11:53:47.402185 7f54e37ef6c0 Level-0 table #349: 0 bytes OK
2025/03/01-19:41:57.256324 7fe59d7fa6c0 Delete type=0 #139 2026/02/28-11:53:47.408357 7f54e37ef6c0 Delete type=0 #347
2025/03/01-19:41:57.269599 7fe59d7fa6c0 Manual compaction at level-0 from '!folders!4OPhigzcPv46qbWW' @ 72057594037927935 : 1 .. '!items!yx4k7lQHGcom99mk' @ 0 : 0; will stop at (end) 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/03/01-19:35:57.039829 7fe59dffb6c0 Recovering log #132 2026/02/27-17:11:33.729701 7f56f93fe6c0 Recovering log #340
2025/03/01-19:35:57.049894 7fe59dffb6c0 Delete type=3 #130 2026/02/27-17:11:33.739927 7f56f93fe6c0 Delete type=3 #338
2025/03/01-19:35:57.049949 7fe59dffb6c0 Delete type=0 #132 2026/02/27-17:11:33.739998 7f56f93fe6c0 Delete type=0 #340
2025/03/01-19:38:46.032600 7fe59d7fa6c0 Level-0 table #137: started 2026/02/27-17:22:38.190111 7f54e37ef6c0 Level-0 table #345: started
2025/03/01-19:38:46.032653 7fe59d7fa6c0 Level-0 table #137: 0 bytes OK 2026/02/27-17:22:38.190141 7f54e37ef6c0 Level-0 table #345: 0 bytes OK
2025/03/01-19:38:46.038775 7fe59d7fa6c0 Delete type=0 #135 2026/02/27-17:22:38.196111 7f54e37ef6c0 Delete type=0 #343
2025/03/01-19:38:46.058171 7fe59d7fa6c0 Manual compaction at level-0 from '!folders!4OPhigzcPv46qbWW' @ 72057594037927935 : 1 .. '!items!yx4k7lQHGcom99mk' @ 0 : 0; will stop at (end) 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-000148 MANIFEST-000358

View File

@@ -1,7 +1,7 @@
2025/03/01-19:40:45.487407 7fe59e7fc6c0 Recovering log #146 2026/02/28-09:14:40.634961 7f56e3fff6c0 Recovering log #356
2025/03/01-19:40:45.498701 7fe59e7fc6c0 Delete type=3 #144 2026/02/28-09:14:40.683602 7f56e3fff6c0 Delete type=3 #354
2025/03/01-19:40:45.498803 7fe59e7fc6c0 Delete type=0 #146 2026/02/28-09:14:40.683765 7f56e3fff6c0 Delete type=0 #356
2025/03/01-19:41:57.256411 7fe59d7fa6c0 Level-0 table #151: started 2026/02/28-11:53:47.414491 7f54e37ef6c0 Level-0 table #361: started
2025/03/01-19:41:57.256434 7fe59d7fa6c0 Level-0 table #151: 0 bytes OK 2026/02/28-11:53:47.414521 7f54e37ef6c0 Level-0 table #361: 0 bytes OK
2025/03/01-19:41:57.262412 7fe59d7fa6c0 Delete type=0 #149 2026/02/28-11:53:47.420403 7f54e37ef6c0 Delete type=0 #359
2025/03/01-19:41:57.269615 7fe59d7fa6c0 Manual compaction at level-0 from '!folders!9PQi3Lv54rpcxavo' @ 72057594037927935 : 1 .. '!items!zGlRtP7zSnkjuuue' @ 0 : 0; will stop at (end) 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,7 +1,7 @@
2025/03/01-19:35:57.082694 7fe59effd6c0 Recovering log #141 2026/02/27-17:11:33.765979 7f56f93fe6c0 Recovering log #352
2025/03/01-19:35:57.093326 7fe59effd6c0 Delete type=3 #139 2026/02/27-17:11:33.775426 7f56f93fe6c0 Delete type=3 #350
2025/03/01-19:35:57.093376 7fe59effd6c0 Delete type=0 #141 2026/02/27-17:11:33.775496 7f56f93fe6c0 Delete type=0 #352
2025/03/01-19:38:46.038876 7fe59d7fa6c0 Level-0 table #147: started 2026/02/27-17:22:38.196266 7f54e37ef6c0 Level-0 table #357: started
2025/03/01-19:38:46.038898 7fe59d7fa6c0 Level-0 table #147: 0 bytes OK 2026/02/27-17:22:38.196298 7f54e37ef6c0 Level-0 table #357: 0 bytes OK
2025/03/01-19:38:46.045195 7fe59d7fa6c0 Delete type=0 #145 2026/02/27-17:22:38.202584 7f54e37ef6c0 Delete type=0 #355
2025/03/01-19:38:46.058182 7fe59d7fa6c0 Manual compaction at level-0 from '!folders!9PQi3Lv54rpcxavo' @ 72057594037927935 : 1 .. '!items!zGlRtP7zSnkjuuue' @ 0 : 0; will stop at (end) 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