Compare commits

..

44 Commits

Author SHA1 Message Date
d532765d2b Correction sur creation PNJ
All checks were successful
Release Creation / build (release) Successful in 2m0s
2025-03-01 22:01:01 +01:00
b6016742ae Enable PNJ 2025-03-01 19:42:15 +01:00
761f95d6d9 Ajout comp libres
All checks were successful
Release Creation / build (release) Successful in 44s
2025-02-25 22:29:05 +01:00
c24f4fe502 Ajout comp libres
All checks were successful
Release Creation / build (release) Successful in 1m13s
2025-02-25 21:29:52 +01:00
caedcf5e21 Update release 2025-02-24 19:53:03 +01:00
fe0814e498 Conserve l'historique des réponses
All checks were successful
Release Creation / build (release) Successful in 1m26s
2025-02-22 22:44:00 +01:00
544f9f467a Import and fix helper pictures 2025-02-21 17:49:49 +01:00
ce5771f930 Import and fix helper pictures 2025-02-21 17:47:49 +01:00
93b8325bb9 Import and fix helper pictures
All checks were successful
Release Creation / build (release) Successful in 50s
2025-02-21 17:41:36 +01:00
48be65e7fd Add release action 2025-02-21 10:43:37 +01:00
a37ce76ab8 Add release action
All checks were successful
Release Creation / build (release) Successful in 1m3s
2025-02-21 10:40:14 +01:00
bbc046bc66 Release version 2025-02-19 21:13:14 +01:00
fd0864cea6 Release version 2025-02-19 21:10:44 +01:00
bf7a9f9ea5 Fix actions/tour 2025-02-13 22:42:56 +01:00
86dfa54314 Fix defense rolls 2025-02-06 10:23:38 +01:00
891a6647b7 Roll shields 2025-02-06 10:23:24 +01:00
5d9a218e04 Init, competences de base, fix creation de perso, etc 2025-02-04 21:25:08 +01:00
a0733dc049 Init, competences de base, fix creation de perso, etc 2025-02-04 21:24:47 +01:00
c32be6b24d Init, competences de base, fix creation de perso, etc 2025-02-04 21:20:54 +01:00
6f278ab8eb Minor fixes 2025-02-04 15:24:40 +01:00
b2ab6ffaa7 Various fixes and enhancements 2025-02-04 08:13:48 +01:00
94d26e971e Various fixes and enhancements 2025-02-04 08:13:26 +01:00
7eed052645 Various fixes and enhancements 2025-02-04 08:07:12 +01:00
00c1d02b6b Various fixes and enhancements 2025-02-03 23:02:39 +01:00
92396da997 Various fixes and enhancements 2025-02-03 23:00:59 +01:00
a72e671f75 First full step for character creation 2025-01-31 11:54:52 +01:00
6331ab9736 Update ! 2025-01-28 21:40:20 +01:00
4a346a4386 Minor fixes for education 2024-12-19 19:15:43 +01:00
b8de37f388 Update education + logo pause 2024-12-05 22:48:23 +01:00
4fd537c9ea Update education + logo pause 2024-12-05 22:46:48 +01:00
3a2dc7be63 Ajout de 8 questions 2024-12-05 16:23:49 +01:00
ff1252dcf5 Ajout de 8 questions 2024-12-05 16:15:16 +01:00
7a768c5426 Fix title 2024-10-27 11:51:08 +01:00
9b2016d069 Fix education + simples 2024-09-17 16:10:22 +02:00
5d843af069 Fix education + simples 2024-09-17 16:05:50 +02:00
b3655d011e Add new options for education 2024-09-16 18:37:41 +02:00
0d7c4323b5 Enhance armes+armures 2024-09-15 09:10:35 +02:00
029ad04e26 Enhance armes+armures 2024-09-13 22:14:21 +02:00
9c93134d1c Arme à distance 2024-07-10 22:59:38 +02:00
37d8957448 New version 2024-07-08 21:44:34 +02:00
629d369693 Ajout multiples pour le combat et ameliorations des items 2024-07-08 07:54:53 +02:00
10b7fcac09 Gestion des jets opposés 2024-06-06 17:17:04 +02:00
de195aff1e Gestion des jets opposés 2024-06-06 17:16:53 +02:00
82e7a170c2 Gestion des jets opposés 2024-06-06 17:16:40 +02:00
150 changed files with 2903 additions and 3501 deletions

View File

@ -0,0 +1,52 @@
name: Release Creation
on:
release:
types: [published]
jobs:
build:
runs-on: ubuntu-latest
steps:
- run: echo "💡 The ${{ gitea.repository }} repository will cloned to the runner."
#- uses: actions/checkout@v3
- uses: RouxAntoine/checkout@v3.5.4
# get part of the tag after the `v`
- name: Extract tag version number
id: get_version
uses: battila7/get-version-action@v2
# Substitute the Manifest and Download URLs in the module.json
- name: Substitute Manifest and Download Links For Versioned Ones
id: sub_manifest_link_version
uses: microsoft/variable-substitution@v1
with:
files: 'system.json'
env:
version: ${{steps.get_version.outputs.version-without-v}}
url: https://www.uberwald.me/gitea/${{gitea.repository}}
manifest: https://www.uberwald.me/gitea/public/${{gitea.repository}}/releases/download/latest/system.json
download: https://www.uberwald.me/gitea/${{gitea.repository}}/releases/download/${{github.event.release.tag_name}}/fvtt-te-deum-${{github.event.release.tag_name}}.zip
# Create a zip file with all files required by the module to add to the release
- run: |
apt update -y
apt install -y zip
- run: zip -r ./fvtt-te-deum-${{github.event.release.tag_name}}.zip system.json template.json README.md LICENSE.txt assets/ fonts/ images/ lang/ modules/ styles/ packs/ templates/ te-deum.mjs
- name: setup go
uses: https://github.com/actions/setup-go@v4
with:
go-version: '>=1.20.1'
- name: Use Go Action
id: use-go-action
uses: https://gitea.com/actions/release-action@main
with:
files: |-
./fvtt-te-deum-${{github.event.release.tag_name}}.zip
system.json
api_key: '${{secrets.ALLOW_PUSH_RELEASE}}'

View File

@ -1,4 +1,4 @@
Copyright 2023 Open Sesame Games Copyright 2025 Open Sesame Games
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

View File

@ -1,37 +1,26 @@
# Te Deum Pour Un Massacre for FoundryVTT (French RPG, Open Sesam Games, Official) # Système Foundry pour Te Deum pour un Massacre (French RPG, Open Sesame Games, Official)
This is a base game system with functionnal character sheets for the game Te Deum.
You can join the kickstarter and obtain the base books here : https://www.kickstarter.com/projects/osg-us/ecryme
# System overview
The game system in Foundry offers the following features :
- PC/NPC sheet
- Skill rolls
- Cephaly rolls (with Anency support)
- Confrontation management, with detailed result in the chat card
- Weapon rolls
- Trait management, with Spleen and Ideal also.
- Compendiums of items for the game
![System Snapshot](https://www.lahiette.com/leratierbretonnien/wp-content/uploads/2023/08/ecryme_snapshot_01.webp "System Snapshot")
This is a base game system with functionnal character sheets for the game Te Deum pour un massacre.
# Contributions # Contributions
- Original code realised by Uberwald (https://www.uberwald.me/) - Original code realised by Uberwald (https://www.uberwald.me/)
Snapshot of the system :
![Alt text](https://www.lahiette.com/leratierbretonnien/wp-content/uploads/2025/02/tedeum_snapshot.webp "a title")
# Copyright mentions # Copyright mentions
Copyright 2023 Open Sesame Games Copyright 2025 Open Sesame Games
All rights reserved All rights reserved
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Te Deum pour un massacre is a game written by Jean-Philippe Jaworski. The author retains his moral rights regarding this work in both print and digital formats.
# Requests or Problems # Requests or Problems
Please report any requests or problems you have at contact@open-sesame.games Please report any requests or problems you have at contact@open-sesame.games

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 171 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

View File

@ -0,0 +1,11 @@
# 12.0.21
- Creation de PNJ OK
# 12.0.20
- Corrections sur la création de perso
# 12.0.19
- Initial release !

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
images/icons/blessure.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

BIN
images/icons/maladie.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

BIN
images/icons/simple.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

BIN
images/ui/femme_gauche.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 160 KiB

BIN
images/ui/homme_droit.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 288 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 720 KiB

View File

@ -1,175 +1,20 @@
{ {
"TYPES": { "TYPES": {
"Actor":{ "Actor":{
"pc": "Personnage Joueur", "pj": "Personnage Joueur",
"npc": "Personnage Non Joueur", "pnj": "Personnage Non Joueur"
"annency": "Anence"
}, },
"Item": { "Item": {
"trait": "Trait", "competence": "Competence",
"weapon": "Arme", "arme": "Arme",
"equipment": "Equipement", "equipement": "Equipement",
"maneuver": "Manoeuvre", "armure": "Armure",
"specialization": "Spécialisation" "grace": "Grace",
} "origine": "Origine",
}, "education": "Education",
"ECRY": { "blessure": "Blessure",
"settings": { "maladie": "Maladie",
"cogs": "Engrenages", "simple": "Simple"
"cephaly": "Céphalie",
"boheme": "Bohême",
"amertume": "Amertume",
"gamelevel": "Niveau de jeu"
},
"chat": {
"formula": "Formule",
"difficulty": "Difficulté",
"dicesum": "Dés",
"result": "Resultat",
"margin": "Marge",
"success": "Succés!",
"failure": "Echec!",
"specialization": "Spécialisation",
"traitbonus": "Trait bonus",
"traitmalus": "Trait malus",
"bonusmalustraits": "Bonus/Malus des Traits",
"spectranscend": "Dépassement de soi : ",
"confrontselected": "Confrontation selectionnée",
"sentogm": "La confrontation a été envoyée au MJ"
},
"rule": {
"cephaly-success-12": "Durée : 1 scène - Impact : Superficiel - Bonus : 1 - Elegie : 1",
"cephaly-success-4": "Durée : 1 semaine - Impact : Léger - Bonus : 2 - Elegie : 2",
"cephaly-success-6": "Durée : 1 mois - Impact : Grave - Bonus : 3 - Elegie : 3",
"cephaly-success-8": "Durée : 1 année - Impact : Majeur - Bonus : 4 - Elegie : 4",
"cephaly-success-10": "Durée : Permanent - Impact : Mort - Bonus : 5 - Elegie : 5",
"cephaly-failure-2": "Durée : 1 scène - Impact : Superficiel - Malus : 1 - Symptôme non visible et sans gravité - Altération bégigne difficilement repérable",
"cephaly-failure-4": "Durée : 1 semaine - Impact : Léger - Malus : 2 - Symptôme visible non incapacitant - Altération repérable",
"cephaly-failure-6": "Durée : 1 mois - Impact : Grave - Malus : 3 - Symptôme incapacitant - Altération repérable et fâcheuse",
"cephaly-failure-8": "Durée : 1 année - Impact : Majeur - Malus : 4 - Symptôme très incapacitant - Altération dangereuse",
"cephaly-failure-10": "Durée : Permanent - Impact : Mort/Folie - Malus : 5 - Symptôme spectaculaire et repoussant - Altération dangereuse globalement"
},
"warn": {
"notenoughdice": "L'Accomplissement et la Préservation doivent avoir 2 dés chacun"
},
"ui": {
"equipmentfree": "Equipements (saisie libre)",
"traitType": "Type de trait",
"niveauTrait": "Niveau du trait",
"effect": "Incidence",
"weight": "Poids",
"cost": "Prix",
"costUnit": "Unité",
"ingot": "Lingot",
"ingotin": "Lingotin",
"goldcoin": "Pièce d'or",
"lige": "Lige",
"hurle": "Hurle",
"coin": "Sous",
"notes": "Notes",
"bio": "Bio",
"bionotes": "Bio&Notes",
"skills": "Compétences",
"traits": "Traits",
"equipment": "Equipement",
"physical": "Physiques",
"mental": "Mentales",
"social": "Sociales",
"athletics": "Athlétisme",
"driving": "Conduite",
"fencing": "Escrime",
"brawling": "Pugilat",
"shooting": "Tir",
"anthropomecanology": "Anthropo-Mécanologie",
"ecrymology": "Écrymologie",
"traumatology": "Traumatologie",
"traversology": "Traversologie",
"urbatechnology": "Urbatechnologie",
"quibbling": "Argutie",
"creativity": "Créativité",
"loquacity": "Faconde",
"guile": "Maraude",
"performance" :"Représentation",
"skill": "Compétence",
"troublesome": "Malaisé",
"occasional": "Peu frequent",
"difficult": "Difficile",
"uncommon": "Atypique",
"verydifficult": "Très difficile",
"rare": "Rare",
"extremdifficult": "Extrêmement difficile",
"veryrare": "Très rare",
"increddifficult": "Incroyable",
"exceptrare": "Exceptionnel",
"none": "Aucun",
"roll": "Lancer les dés !",
"cancel": "Annuler",
"rolltitle": "Ou l'on teste ses compétences",
"spec": "Spécialisation",
"traitbonus": "Traits bonus",
"traitmalus": "Traits malus",
"applyideal": "Utiliser l'idéal",
"applyspleen": "Utiliser le spleen",
"skilltranscendence": "Dépassement de soi",
"confrontation": "Confrontation",
"rollnormal": "Normal (4d6)",
"rollspleen": "Avec le Spleen (5d6, 4 plus bas conservés)",
"rollideal": "Avec l'Idéal (5d6, 4 plus haut conservés)",
"superficial": "Superficiel",
"light": "Léger",
"serious": "Grave",
"major": "Majeur",
"impactType": "Type d'Impact",
"impactLevel": "Niveau d'impact",
"impactphysical": "Physique",
"impactmental": "Mental",
"impactsocial": "Social",
"impactmalus": "Malus d'Impact",
"ongoingconfront": "Confrontations en cours",
"confront":"Confrontation",
"launchconfront": "Lancer la confrontation",
"execution": "Accomplissement",
"preservation": "Préservation",
"dicepool": "Dés disponibles",
"selectconfront": "Sélectionner pour la Confrontation",
"transcendapply": "Appliquer la Transcendence à ",
"healthcombat": "Santé&Combat",
"name": "Nom",
"weapons": "Armes",
"weapon": "Arme",
"melee": "Mêlée",
"ranged": "A Distance",
"weapontype": "Type d'arme",
"type": "Type",
"applyimpact": "Appliquer l'impact",
"applybonus": "Appliquer le bonus",
"bonuspool": "Bonus disponibles",
"cephaly": "Cephalie",
"elegy": "Elégie",
"entelechy": "Entéléchie",
"mekany": "Mekanë",
"psyche": "Psyché",
"scoria": "Scorie",
"cephalydifficulty": "Difficulté de la Céphalie",
"maneuvers": "Manoeuvres",
"annency": "Anence",
"iscollective": "Collective",
"ismultiple": "Multiple",
"description": "Description",
"location": "Lieu",
"characters": "Personnages",
"enhancements": "Améliorations",
"oniricform": "Forme Onorique (Bohême)",
"ideals": "Idéaux",
"politic": "Idéaux politiques",
"boheme": "Bohême",
"annencybonus": "Bonus d'Anence",
"bornplace": "Lieu de naissance",
"residence": "Résidence",
"origin": "Origine",
"childhood": "Enfance",
"bonus": "Bonus"
} }
} }
} }

View File

@ -11,7 +11,7 @@ export class TeDeumActorPJSheet extends ActorSheet {
/** @override */ /** @override */
static get defaultOptions() { static get defaultOptions() {
return mergeObject(super.defaultOptions, { return foundry.utils.mergeObject(super.defaultOptions, {
classes: ["fvtt-te-deum", "sheet", "actor"], classes: ["fvtt-te-deum", "sheet", "actor"],
template: "systems/fvtt-te-deum/templates/actors/actor-sheet.hbs", template: "systems/fvtt-te-deum/templates/actors/actor-sheet.hbs",
width: 860, width: 860,
@ -33,18 +33,31 @@ export class TeDeumActorPJSheet extends ActorSheet {
name: this.actor.name, name: this.actor.name,
editable: this.isEditable, editable: this.isEditable,
cssClass: this.isEditable ? "editable" : "locked", cssClass: this.isEditable ? "editable" : "locked",
system: duplicate(this.object.system), system: foundry.utils.duplicate(this.object.system),
limited: this.object.limited, limited: this.object.limited,
competences: this.actor.getCompetences(), competences: this.actor.getCompetences(),
config: duplicate(game.system.tedeum.config), config: foundry.utils.duplicate(game.system.tedeum.config),
armes: this.actor.getArmes(), armes: this.actor.getArmes(),
caracList: this.actor.prepareCaracteristiques(), caracList: this.actor.prepareCaracteristiques(),
providence: this.actor.prepareProvidence(), providence: this.actor.prepareProvidence(),
arbreCompetences: this.actor.prepareArbreCompetences(), arbreCompetences: this.actor.prepareArbreCompetences(),
equipements: this.actor.getEquipements(), equipements: this.actor.getEquipements(),
armures: this.actor.getArmures(),
graces: this.actor.getGraces(), graces: this.actor.getGraces(),
blessures: this.actor.getBlessures(),
maladies: this.actor.getMaladies(),
poisons: this.actor.getPoisons(),
combat: this.actor.prepareCombat(),
bonusDegats: this.actor.getBonusDegats(),
nbActions: this.actor.getNbActions(),
initiative: this.actor.getInitiative(),
pointsArmuresLourdes: this.actor.getNbArmures(),
nbArmuresLourdes: this.actor.getNbArmuresLourdesActuel(),
santeModifier: this.actor.getSanteModifier(),
educations: this.actor.getEducations(),
description: await TextEditor.enrichHTML(this.object.system.description, { async: true }), description: await TextEditor.enrichHTML(this.object.system.description, { async: true }),
notes: await TextEditor.enrichHTML(this.object.system.notes, { async: true }), notes: await TextEditor.enrichHTML(this.object.system.notes, { async: true }),
histoire: await TextEditor.enrichHTML(this.object.system.histoire, { async: true }),
options: this.options, options: this.options,
owner: this.document.isOwner, owner: this.document.isOwner,
editScore: this.options.editScore, editScore: this.options.editScore,
@ -115,6 +128,11 @@ export class TeDeumActorPJSheet extends ActorSheet {
const armeId = $(event.currentTarget).data("arme-id") const armeId = $(event.currentTarget).data("arme-id")
this.actor.rollArme(armeId) 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) => { html.find('.lock-unlock-sheet').click((event) => {
this.options.editScore = !this.options.editScore; this.options.editScore = !this.options.editScore;

View File

@ -34,12 +34,24 @@ export class TeDeumActor extends Actor {
return actor; return actor;
} }
if (data.type == 'pj' || data.type == 'pnj') {
const skills = await TeDeumUtility.loadCompendium("fvtt-te-deum.competences")
data.items = data.items || []
for (let skill of skills) {
if (skill.system.isBase || skill.system.score == 1) {
data.items.push(skill.toObject())
}
}
}
return super.create(data, options); return super.create(data, options);
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
async prepareData() { async prepareData() {
super.prepareData() super.prepareData()
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
@ -53,6 +65,70 @@ export class TeDeumActor extends Actor {
super._preUpdate(changed, options, user); super._preUpdate(changed, options, user);
} }
getCompetenceScore(compName) {
let competence = this.items.find(item => item.type == "competence" && item.name.toLowerCase() == compName.toLowerCase())
if (competence) {
return competence.system.score
}
return 0
}
/* -------------------------------------------- */
_onUpdate(changed, options, userId) {
let updates = []
let memoriser = this.items.find(item => item.type == "competence" && item.name.toLowerCase() == "mémoriser")
let newScore = this.getCommonBaseValue(this.system.caracteristiques.adresse.value)
if (memoriser && memoriser?.system.score != newScore) {
updates.push({ _id: memoriser.id, "system.score": Number(newScore) })
}
let perception = this.items.find(item => item.type == "competence" && item.name.toLowerCase() == "perception")
newScore = this.getCommonBaseValue(this.system.caracteristiques.sensibilite.value)
if (perception && perception.system.score != newScore) {
updates.push({ _id: perception.id, "system.score": Number(newScore) })
}
let charme = this.items.find(item => item.type == "competence" && item.name.toLowerCase() == "charme")
newScore = this.getCommonBaseValue(this.system.caracteristiques.entregent.value)
if (charme && charme?.system.score != newScore) {
updates.push({ _id: charme.id, "system.score": Number(newScore) })
}
let endurance = this.items.find(item => item.type == "competence" && item.name.toLowerCase() == "endurance")
newScore = this.getCommonBaseValue(this.system.caracteristiques.complexion.value)
if (endurance && endurance?.system.score != newScore) {
updates.push({ _id: endurance.id, "system.score": Number(newScore) })
}
let course = this.items.find(item => item.type == "competence" && item.name.toLowerCase() == "course")
newScore = this.getCommonBaseValue(this.system.caracteristiques.adresse.value)
if (course && course?.system.score != newScore) {
updates.push({ _id: course.id, "system.score": Number(newScore) })
}
let initiative = this.items.find(item => item.type == "competence" && item.name.toLowerCase() == "initiative")
newScore = this.getCommonBaseValue(this.system.caracteristiques.adresse.value)
if (initiative && initiative?.system.score != 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")
newScore = this.getCommonBaseValue(this.system.caracteristiques.puissance.value)
if (effort && effort?.system.score != newScore) {
updates.push({ _id: effort.id, "system.score": Number(newScore) })
}
if (updates.length > 0) {
this.updateEmbeddedDocuments('Item', updates)
}
}
/* -------------------------------------------- */ /* -------------------------------------------- */
async _preCreate(data, options, user) { async _preCreate(data, options, user) {
await super._preCreate(data, options, user); await super._preCreate(data, options, user);
@ -65,6 +141,13 @@ export class TeDeumActor extends Actor {
this.updateSource({ prototypeToken }); this.updateSource({ prototypeToken });
} }
/* -------------------------------------------- */
getCommonBaseValue(value) {
return game.system.tedeum.config.COMMON_VALUE[value]?.value || 0
}
getInitiative() {
return game.system.tedeum.config.COMMON_VALUE[this.system.caracteristiques.adresse.value]?.value || 0
}
/* -------------------------------------------- */ /* -------------------------------------------- */
getBonusDegats() { getBonusDegats() {
return game.system.tedeum.config.BONUS_DEGATS[this.system.caracteristiques.puissance.value] return game.system.tedeum.config.BONUS_DEGATS[this.system.caracteristiques.puissance.value]
@ -76,51 +159,143 @@ export class TeDeumActor extends Actor {
getNbActions() { getNbActions() {
return game.system.tedeum.config.ACTIONS_PAR_TOUR[this.system.caracteristiques.adresse.value] return game.system.tedeum.config.ACTIONS_PAR_TOUR[this.system.caracteristiques.adresse.value]
} }
getInitiative() {
return game.system.tedeum.config.ACTIONS_PAR_TOUR[this.system.caracteristiques.adresse.value]
}
getNbArmuresLourdesActuel() {
let armures = this.getArmures()
let nb = 0
for (let armure of armures) {
if (armure.system.equipe) {
nb += armure.system.coutArmureLourde
}
}
return nb
}
/* -------------------------------------------- */
getEducations() {
let educations = this.items.filter(item => item.type == 'education')
return educations
}
/* -------------------------------------------- */ /* -------------------------------------------- */
getCompetences() { getCompetences() {
let comp = duplicate(this.items.filter(item => item.type == 'competence') || []) let comp = foundry.utils.duplicate(this.items.filter(item => item.type == 'competence') || [])
return comp; return comp;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
getGraces() { getGraces() {
let comp = duplicate(this.items.filter(item => item.type == 'grace') || []) let comp = foundry.utils.duplicate(this.items.filter(item => item.type == 'grace') || [])
TeDeumUtility.sortArrayObjectsByName(comp) TeDeumUtility.sortArrayObjectsByName(comp)
return comp; return comp;
} }
getArmes() { getArmes() {
let comp = duplicate(this.items.filter(item => item.type == 'arme') || []) let comp = foundry.utils.duplicate(this.items.filter(item => item.type == 'arme') || [])
TeDeumUtility.sortArrayObjectsByName(comp) TeDeumUtility.sortArrayObjectsByName(comp)
return comp; return comp;
} }
getEquipements() { getEquipements() {
let comp = duplicate(this.items.filter(item => item.type == 'equipement') || []) let comp = foundry.utils.duplicate(this.items.filter(item => item.type == 'equipement') || [])
TeDeumUtility.sortArrayObjectsByName(comp) TeDeumUtility.sortArrayObjectsByName(comp)
return comp; return comp;
} }
getArmures() { getArmures() {
let comp = duplicate(this.items.filter(item => item.type == 'armure') || []) let comp = foundry.utils.duplicate(this.items.filter(item => item.type == 'armure') || [])
TeDeumUtility.sortArrayObjectsByName(comp)
return comp;
}
getBlessures() {
let comp = foundry.utils.duplicate(this.items.filter(item => item.type == 'blessure') || [])
for (let c of comp) {
let blessDef = game.system.tedeum.config.blessures[c.system.typeBlessure]
c.malus = blessDef.modifier
}
TeDeumUtility.sortArrayObjectsByName(comp)
return comp;
}
getMaladies() {
let comp = foundry.utils.duplicate(this.items.filter(item => item.type == 'maladie') || [])
for (let c of comp) {
c.malus = "N/A"
if (c.system.appliquee) {
let malDef = game.system.tedeum.config.virulence[c.system.virulence]
c.malus = malDef.modifier
}
}
TeDeumUtility.sortArrayObjectsByName(comp)
return comp;
}
getPoisons() {
let comp = foundry.utils.duplicate(this.items.filter(item => item.type == 'poison') || [])
for (let c of comp) {
c.malus = "N/A"
if (c.system.appliquee) {
let poisDef = game.system.tedeum.config.virulencePoison[c.system.virulence]
c.malus = poisDef.modifier
}
}
TeDeumUtility.sortArrayObjectsByName(comp) TeDeumUtility.sortArrayObjectsByName(comp)
return comp; return comp;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
calculMalusBlessures() { getSanteModifier() {
let modifierBlessures = 0 let comp = foundry.utils.duplicate(this.items.filter(item => item.type == 'maladie') || [])
let nbBlessures = 0 let modTotal = 0
// Cumul des malus de blessures for (let c of comp) {
for (let locKey in this.system.localisation) { if (c.system.appliquee) {
let loc = this.system.localisation[locKey] let maladieDef = game.system.tedeum.config.virulence[c.system.virulence]
let bDef = game.system.tedeum.config.blessures[loc.blessures] modTotal += maladieDef.modifier
modifierBlessures += bDef.modifier }
nbBlessures += bDef.count }
let simples = foundry.utils.duplicate(this.items.filter(item => item.type == 'simple') || [])
for (let c of simples) {
if (c.system.appliquee) {
let simpleDef = game.system.tedeum.config.virulencePoison[c.system.virulence]
modTotal += simpleDef.modifier
}
}
let blessures = foundry.utils.duplicate(this.items.filter(item => item.type == 'blessure') || [])
for (let c of blessures) {
let blessDef = game.system.tedeum.config.blessures[c.system.typeBlessure]
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 endurance = this.items.find(item => item.type == "competence" && item.name.toLowerCase() == "endurance")
if ( nbBlessures > endurance.system.score) { if (blessures.length > endurance.system.score) {
modifierBlessures += -1 modTotal += -1
} }
return modifierBlessures return modTotal
}
/* -------------------------------------------- */
async appliquerDegats(rollData) {
let combat = this.prepareCombat()
rollData.defenderName = this.name
let touche = combat[rollData.loc.id].touche
if (rollData.degats > 0 && rollData.degats > touche) {
let diff = rollData.degats - touche
for (let bId in game.system.tedeum.config.blessures) {
let blessure = game.system.tedeum.config.blessures[bId]
if (diff >= blessure.degatsMin && diff <= blessure.degatsMax) {
// Create a new blessure object
let blessureObj = {
name: blessure.label,
type: "blessure",
system: {
typeBlessure: bId,
localisation: rollData.loc.id,
appliquee: true,
description: "Blessure infligée par un coup de " + rollData.arme.name + " de " + rollData.alias,
}
}
rollData.blessure = blessureObj
this.createEmbeddedDocuments('Item', [blessureObj]);
}
}
}
// Display the relevant chat message
let msg = await TeDeumUtility.createChatWithRollMode(rollData.alias, {
content: await renderTemplate(`systems/fvtt-te-deum/templates/chat/chat-blessure-result.hbs`, rollData)
})
await msg.setFlag("world", "te-deum-rolldata", rollData)
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
@ -139,6 +314,7 @@ export class TeDeumActor extends Actor {
for (let key in carac) { for (let key in carac) {
let c = carac[key] let c = carac[key]
this.updateCarac(c, key) this.updateCarac(c, key)
c.description = game.system.tedeum.config.caracteristiques[key].description
} }
return carac return carac
} }
@ -148,20 +324,47 @@ export class TeDeumActor extends Actor {
providence.name = "Providence" providence.name = "Providence"
providence.qualite = game.system.tedeum.config.providence[providence.value].labelM providence.qualite = game.system.tedeum.config.providence[providence.value].labelM
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)."
return providence return providence
} }
/* -------------------------------------------- */
prepareCombat() {
let combatLoc = foundry.utils.deepClone(this.system.localisation)
for (let key in combatLoc) {
combatLoc[key] = foundry.utils.mergeObject(combatLoc[key], game.system.tedeum.config.LOCALISATION[key])
combatLoc[key].armures = []
combatLoc[key].blessures = []
combatLoc[key].protectionTotal = 0
let armures = this.getArmures()
for (let armure of armures) {
if (armure.system.equipe && armure.system.localisation[key].protege) {
combatLoc[key].armures.push(armure)
combatLoc[key].protectionTotal += armure.system.protection
}
}
let blessures = this.getBlessures()
for (let blessure of blessures) {
if (blessure.system.localisation == key) {
combatLoc[key].blessures.push(blessure)
}
}
let endurance = this.items.find(item => item.type == "competence" && item.name.toLowerCase() == "endurance")
combatLoc[key].endurance = endurance.system.score + game.system.tedeum.config.LOCALISATION[key].locMod
combatLoc[key].touche = combatLoc[key].endurance + combatLoc[key].protectionTotal
}
return combatLoc
}
/* -------------------------------------------- */ /* -------------------------------------------- */
modifyProvidence(value) { modifyProvidence(value) {
let providence = foundry.utils.duplicate(this.system.providence) let providence = foundry.utils.duplicate(this.system.providence)
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) { 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 } ) this.update({ [`system.caracteristiques.${key}.experience`]: xp })
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
@ -174,7 +377,8 @@ export class TeDeumActor extends Actor {
let caracDice = game.system.tedeum.config.descriptionValeur[this.system.caracteristiques[c.system.caracteristique].value].dice let caracDice = game.system.tedeum.config.descriptionValeur[this.system.caracteristiques[c.system.caracteristique].value].dice
c.system.formula = caracDice + "+" + c.system.score c.system.formula = caracDice + "+" + c.system.score
}) })
return foundry.utils.deepClone( comp || {} ) comp = comp.sort((a, b) => a.name.localeCompare(b.name))
return foundry.utils.deepClone(comp || {})
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
@ -192,7 +396,7 @@ export class TeDeumActor extends Actor {
getItemById(id) { getItemById(id) {
let item = this.items.find(item => item.id == id); let item = this.items.find(item => item.id == id);
if (item) { if (item) {
item = duplicate(item) item = foundry.utils.duplicate(item)
} }
return item; return item;
} }
@ -200,29 +404,58 @@ export class TeDeumActor extends Actor {
/* -------------------------------------------- */ /* -------------------------------------------- */
async equipItem(itemId) { async equipItem(itemId) {
let item = this.items.find(item => item.id == itemId) let item = this.items.find(item => item.id == itemId)
if (item?.system) { if (!this.checkArmure(item)) {
if (item.type == "armure") {
let armor = this.items.find(item => item.id != itemId && item.type == "armor" && item.system.equipped)
if (armor) {
ui.notifications.warn("You already have an armor equipped!")
return return
} }
} let update = { _id: item.id, "system.equipe": !item.system.equipe };
if (item.type == "shield") {
let shield = this.items.find(item => item.id != itemId && item.type == "shield" && item.system.equipped)
if (shield) {
ui.notifications.warn("You already have a shield equipped!")
return
}
}
let update = { _id: item.id, "system.equipped": !item.system.equipped };
await this.updateEmbeddedDocuments('Item', [update]); // Updates one EmbeddedEntity await this.updateEmbeddedDocuments('Item', [update]); // Updates one EmbeddedEntity
} }
/* ------------------------------------------- */
checkArmure(item) {
if (item.type != "armure") {
return true
}
if (item.system.equipe) {
return true
}
let nbArmuresLourdes = this.getNbArmuresLourdesActuel()
if (nbArmuresLourdes + item.system.coutArmureLourde > this.getNbArmures().value) {
ui.notifications.warn("Impossible d'équiper cette armure, nombre d'armures lourdes maximum atteint")
return false
}
// Loop thru localisation
let armures = this.getArmures()
for (let loc in item.system.localisation) {
if (item.system.localisation[loc].protege) {
for (let armure of armures) {
if (armure.system.equipe && armure.system.localisation[loc].protege) {
let flag = true
//console.log("Check armure", armure, item)=
if (item.system.typeArmure == "cuir") {
flag = armure.system.superposableCuir
}
if (item.system.typeArmure == "maille") {
flag = armure.system.superposableMaille
}
if (item.system.typeArmure == "plate") {
flag = armure.system.superposablePlate
}
if (!flag) {
ui.notifications.warn("Impossible d'équiper cette armure, non superposable")
return flag
}
}
}
}
return true
}
} }
/* ------------------------------------------- */ /* ------------------------------------------- */
async buildContainerTree() { async buildContainerTree() {
let equipments = duplicate(this.items.filter(item => item.type == "equipment") || []) let equipments = foundry.utils.duplicate(this.items.filter(item => item.type == "equipment") || [])
for (let equip1 of equipments) { for (let equip1 of equipments) {
if (equip1.system.iscontainer) { if (equip1.system.iscontainer) {
equip1.system.contents = [] equip1.system.contents = []
@ -278,10 +511,13 @@ export class TeDeumActor extends Actor {
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
getInitiativeScore(combatId, combatantId) { getInitiativeScore() {
let init = Math.floor((this.system.attributs.physique.value + this.system.attributs.habilite.value) / 2) let initiative = this.items.find(it => it.type == "competence" && it.name.toLowerCase() == "initiative")
let subValue = new Roll("1d20").roll({ async: false }) if (initiative) {
return init + (subValue.total / 100) return initiative.system.score
}
ui.notifications.warn("Impossible de trouver la compétence Initiative pour l'acteur " + this.name)
return -1;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
@ -317,7 +553,7 @@ export class TeDeumActor extends Actor {
rollData.actorId = this.id rollData.actorId = this.id
rollData.img = this.img rollData.img = this.img
rollData.providence = this.prepareProvidence() rollData.providence = this.prepareProvidence()
rollData.malusBlessures = this.calculMalusBlessures() rollData.santeModifier = this.getSanteModifier()
return rollData return rollData
} }
@ -326,11 +562,11 @@ export class TeDeumActor extends Actor {
getCommonCompetence(compId) { getCommonCompetence(compId) {
let rollData = this.getCommonRollData() let rollData = this.getCommonRollData()
let competence = duplicate(this.items.find(it => it.type =="competence" && it.id == compId)) let competence = foundry.utils.duplicate(this.items.find(it => it.type == "competence" && it.id == compId))
rollData.competence = competence rollData.competence = competence
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.img = competence.img rollData.img = competence.img
@ -345,17 +581,67 @@ export class TeDeumActor extends Actor {
this.startRoll(rollData).catch("Error on startRoll") this.startRoll(rollData).catch("Error on startRoll")
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
rollArme(armeId) { async rollDegatsArme(armeId) {
let weapon = this.items.get(armeId) let weapon = this.items.get(armeId)
if (weapon) { if (weapon) {
weapon = duplicate(weapon) let bDegats = 0
if ( weapon.system.typeArme == "melee" ) {
bDegats = this.getBonusDegats()
}
let formula = weapon.system.degats + "+" + bDegats.value
let degatsRoll = await new Roll(formula).roll()
await TeDeumUtility.showDiceSoNice(degatsRoll, game.settings.get("core", "rollMode") )
let rollData = this.getCommonRollData()
rollData.mode = "degats"
rollData.formula = formula
rollData.arme = foundry.utils.duplicate(weapon)
rollData.degatsRoll = foundry.utils.duplicate(degatsRoll)
rollData.degats = degatsRoll.total
let msg = await TeDeumUtility.createChatWithRollMode(rollData.alias, {
content: await renderTemplate(`systems/fvtt-te-deum/templates/chat/chat-degats-result.hbs`, rollData)
})
await msg.setFlag("world", "te-deum-rolldata", rollData)
console.log("Rolldata result", rollData)
}
}
/* -------------------------------------------- */
rollArme(armeId, compName = undefined) {
let weapon = this.items.get(armeId)
if (weapon) {
weapon = foundry.utils.duplicate(weapon)
let rollData = this.getCommonRollData() let rollData = this.getCommonRollData()
rollData.mode = "arme" rollData.mode = "arme"
rollData.isTir = weapon.system.typeArme == "tir"
rollData.arme = weapon rollData.arme = weapon
rollData.img = weapon.img rollData.img = weapon.img
rollData.title = weapon.name rollData.title = weapon.name
rollData.porteeTir = "courte"
rollData.porteeLabel = game.system.tedeum.config.ARME_PORTEES.courte.label
rollData.isViser = false
rollData.isMouvement = false
// Display warning if not target defined
if (!rollData.defenderTokenId) {
ui.notifications.warn("Vous attaquez avec une arme : afin de bénéficier des automatisations, il est conseillé de selectionner une cible")
}
// Setup competence + carac
if (!compName) {
compName = weapon.system.competence
}
let competence = this.items.find(item => item.type == "competence" && item.name.toLowerCase() == compName.toLowerCase())
if (competence) {
rollData.competence = competence
let c = foundry.utils.duplicate(this.system.caracteristiques[competence.system.caracteristique])
this.updateCarac(c, competence.system.caracteristique)
rollData.carac = c
} else {
ui.notifications.warn("Impossible de trouver la compétence " + compName)
return
}
this.startRoll(rollData).catch("Error on startRoll") this.startRoll(rollData).catch("Error on startRoll")
} else { } else {
ui.notifications.warn("Impossible de trouver l'arme concernée ") ui.notifications.warn("Impossible de trouver l'arme concernée ")

View File

@ -0,0 +1,621 @@
import { TeDeumUtility } from "../common/tedeum-utility.js";
import { TeDeumActor } from "../actors/tedeum-actor.js";
export class TeDeumCharacterCreator {
/*--------------------------------------------*/
async init() {
this.stages = {}
this.currentStage = "origineSociale"
this.sex = undefined
this.origineSociale = undefined
this.religion = undefined
this.caracBonus = {}
this.competenceBonus = {}
this.suiviReponses = []
this.competences = TeDeumUtility.getCompetencesForDropDown()
for (let k in game.system.tedeum.config.caracteristiques) {
this.caracBonus[k] = { value: 0 }
}
for (let stage in game.system.tedeum.config.etapesEducation) {
this.stages[stage] = { selectedItem: null, items: [] }
}
const educations = await TeDeumUtility.loadCompendium("fvtt-te-deum.education")
for (let edu of educations) {
this.stages[edu.system.etape].items.push(edu)
}
this.processStage()
}
/*--------------------------------------------*/
increaseCompetence(compName) {
if (compName === "" || compName == undefined || compName == "undefined") { return }
compName = compName.toLowerCase()
if (!this.competenceBonus[compName]) {
this.competenceBonus[compName] = { value: 1 }
} else {
this.competenceBonus[compName].value += 1
}
}
/*--------------------------------------------*/
processReponses(question) {
let fullResponses = []
for (let key in question.reponses) {
let response = question.reponses[key]
fullResponses.push({ id: key, label: `${response.reponse} (${TeDeumUtility.upperFirst( response.compName)} +1)` })
}
return fullResponses
}
/*--------------------------------------------*/
processReponsesRadio(question) {
let fullResponses = {}
let selected = true
for (let key in question.reponses) {
let response = question.reponses[key]
if (response.toSelect) {
fullResponses[key] = { label: `${response.reponse}`, competences: response.compList, selected }
} else {
fullResponses[key] = { label: `${response.reponse} (${response.compName} +1)`, selected }
}
selected = false
}
return fullResponses
}
/*--------------------------------------------*/
async askStageName(context) {
const content = await renderTemplate("systems/fvtt-te-deum/templates/dialogs/character-creator-select-stage-name.hbs", context)
const choiceResult = await foundry.applications.api.DialogV2.wait({
window: { title: context.title },
classes: ["fvtt-te-deum"],
content,
buttons: [
{
label: context.label,
callback: (event, button, dialog) => {
const output = Array.from(button.form.elements).reduce((obj, input) => {
if (input.name) obj[input.name] = input.value
return obj
}, {})
return output
},
},
],
actions: {
},
rejectClose: false, // Click on Close button will not launch an error
render: (event, dialog) => {
$(".stage-selector").change(event => {
let stageId = event.target.value
let stage = context.choices.find(item => item.id === stageId)
let link = `<a class="content-link" draggable="true" data-link=""
data-uuid="Compendium.fvtt-te-deum.education.Item.${stageId}" data-id="${stageId}" data-type="Item"
data-pack="fvtt-te-deum.education" data-tooltip="Education Objet"><i class="fas fa-suitcase"></i>${stage.name}</a>`
$(".stage-main-details").html(`Voir le détail : ${link}`)
})
document.getElementById("stage-selector").dispatchEvent(new Event('change'))
}
})
return choiceResult
}
/*--------------------------------------------*/
processCompetences(compList) {
for (let compName in compList) {
this.increaseCompetence(compName)
}
}
/*--------------------------------------------*/
async askQuestionnaire(stage, context) {
context.subtitle = "Questionnaire"
for (let key in stage.system.questionnaire) {
let question = stage.system.questionnaire[key]
if (question.question === "") { break }
context.question = question.question
context.responses = this.processReponses(question)
context.responsesRadio = this.processReponsesRadio(question)
context.competences = {}
context.responseKey = "reponse1" // By default
const content = await renderTemplate("systems/fvtt-te-deum/templates/dialogs/character-creator-select-questions.hbs", context)
const choiceResult = await foundry.applications.api.DialogV2.wait({
window: { title: context.title },
classes: ["fvtt-te-deum"],
content,
buttons: [
{
label: context.label,
callback: (event, button, dialog) => {
const output = Array.from(button.form.elements).reduce((obj, input) => {
if (input.name) obj[input.name] = input.value
return obj
}, {})
return output
},
},
],
actions: {
},
rejectClose: false, // Click on Close button will not launch an error
render: (event, dialog) => {
$(".questionnaire-radio").click(event => {
let responseKey = $(event.target).data("response-key")
context.responseKey = responseKey
})
$(".questionnaire-select-competence").change(event => {
// Get the responseKey data
let responseKey = $(event.target).data("response-key")
let compName = event.target.value
console.log("Questionnaire Change", responseKey, compName)
context.competences[responseKey] = compName.toLowerCase()
})
}
})
if (choiceResult == null) {
this.currentStage = "cancelled"
return
}
let selectedResponse = question.reponses[context.responseKey]
let compName = context.competences[context.responseKey] || selectedResponse.compName
this.increaseCompetence(compName)
this.suiviReponses.push({ etape: stage.name, question: question.question, reponse: selectedResponse.reponse, compName: compName })
}
}
/*------------- -------------------------------*/
async askCompetences(stage, context) {
context.subtitle = "Choix des Compétences"
context.fixedCompetences = {}
context.selectCompetences = {}
for (let compKey in stage.system.competences) {
let comp = stage.system.competences[compKey]
if (comp.valid && comp.compName !== "") {
if (comp.toSelect) {
context.hasSelectCompetences = true
context.selectCompetences[comp.compName] = TeDeumUtility.upperFirst(comp.compName)
} else {
context.fixedCompetences[comp.compName] = TeDeumUtility.upperFirst(comp.compName)
}
}
}
const content = await renderTemplate("systems/fvtt-te-deum/templates/dialogs/character-creator-select-competences.hbs", context)
const choiceResult = await foundry.applications.api.DialogV2.wait({
window: { title: context.title },
classes: ["fvtt-te-deum"],
content,
buttons: [
{
label: context.label,
callback: (event, button, dialog) => {
const output = Array.from(button.form.elements).reduce((obj, input) => {
if (input.name) obj[input.name] = input.value
return obj
}, {})
return output
},
},
],
actions: {
},
rejectClose: false, // Click on Close button will not launch an error
render: (event, dialog) => {
}
})
if (choiceResult == null) {
this.currentStage = "cancelled"
return
}
context.fixedCompetences[choiceResult.selectedCompetence] = choiceResult.selectedCompetence
this.processCompetences(context.fixedCompetences)
// Handle specific case when multiple skills can be selected (ie compagnon case)
if ( stage.system.hasCompetencesOpt ) {
context.fixedCompetences = []
context.hasSelectCompetences = true
for (let i = 0; i < stage.system.competencesOptNumber; i++) {
context.competences = {}
context.selectCompetences = {}
for (let compKey in stage.system.competencesOpt) {
let comp = stage.system.competencesOpt[compKey]
if (comp.compName !== "") {
context.selectCompetences[comp.compName] = TeDeumUtility.upperFirst(comp.compName)
}
}
const content = await renderTemplate("systems/fvtt-te-deum/templates/dialogs/character-creator-select-competences.hbs", context)
const choiceResult = await foundry.applications.api.DialogV2.wait({
window: { title: context.title },
classes: ["fvtt-te-deum"],
content,
buttons: [
{
label: context.label,
callback: (event, button, dialog) => {
const output = Array.from(button.form.elements).reduce((obj, input) => {
if (input.name) obj[input.name] = input.value
return obj
}, {})
return output
},
},
],
actions: {
},
rejectClose: false, // Click on Close button will not launch an error
render: (event, dialog) => {
}
})
if (choiceResult == null) {
this.currentStage = "cancelled"
return
}
context.fixedCompetences[choiceResult.selectedCompetence] = choiceResult.selectedCompetence
this.processCompetences(context.fixedCompetences)
}
}
}
/*------------- -------------------------------*/
async askCarac(stage, context) {
context.subtitle = "Choix des Caractéristiques"
let selected = []
for (let i = 0; i < stage.system.nbChoixCarac; i++) {
context.caracList = []
for (let caracKey in stage.system.caracteristiques) {
let carac = stage.system.caracteristiques[caracKey]
if (selected.includes(carac.caracId)) { continue }
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 choiceResult = await foundry.applications.api.DialogV2.wait({
window: { title: context.title },
classes: ["fvtt-te-deum"],
content,
buttons: [
{
label: context.label,
callback: (event, button, dialog) => {
const output = Array.from(button.form.elements).reduce((obj, input) => {
if (input.name) obj[input.name] = input.value
return obj
}, {})
return output
},
},
],
actions: {
},
rejectClose: false, // Click on Close button will not launch an error
render: (event, dialog) => {
}
})
if (choiceResult == null) {
this.currentStage = "cancelled"
return
}
this.caracBonus[choiceResult.carac].value += 1
selected.push(choiceResult.carac)
}
}
/*--------------------------------------------*/
async renderOrigineSociale(stage) {
let context = {
title: "Création de personnage",
subtitle: "Origine Sociale",
sexeChoice: { "Homme": "Homme", "Femme": "Femme" },
religionChoice: { "catholique": "Catholique", "protestante": "Protestante" },
origineChoice: game.system.tedeum.config.origineSociale
}
const content = await renderTemplate("systems/fvtt-te-deum/templates/dialogs/character-creator-origine.hbs", context)
const label = "Valider le choix de l'Origine Sociale"
const choiceResult = await foundry.applications.api.DialogV2.wait({
window: { title: context.title },
classes: ["fvtt-te-deum"],
content,
buttons: [
{
label: label,
callback: (event, button, dialog) => {
const output = Array.from(button.form.elements).reduce((obj, input) => {
if (input.name) obj[input.name] = input.value
return obj
}, {})
return output
},
},
],
actions: {
},
rejectClose: false, // Click on Close button will not launch an error
render: (event, dialog) => { }
})
if (choiceResult == null) {
this.currentStage = "cancelled"
return
}
this.sexe = choiceResult.sexe
this.religion = choiceResult.religion
this.origineSociale = foundry.utils.duplicate(game.system.tedeum.config.origineSociale[choiceResult.origineSociale])
for (let key in this.origineSociale.caracteristiques) {
this.caracBonus[key].value += this.origineSociale.caracteristiques[key]
}
this.currentStage = "pouponniere"
}
/*--------------------------------------------*/
async renderPouponniere(stage) {
// Filter available pouponniere from origineSociale
let pouponniereItems = stage.items.filter(item => item.system.accessible[this.origineSociale.id].isaccessible)
let context = {
title: "Création de personnage - La Pouponnière",
subtitle: "Choix de la Pouponnière",
label: "Valider le choix de la Pouponnière",
choices: pouponniereItems,
caracBonus: this.caracBonus,
competenceBonus: this.competenceBonus
}
let choiceResult = await this.askStageName(context)
if (choiceResult == null) {
this.currentStage = "cancelled"
return
}
this.pouponniere = foundry.utils.duplicate(stage.items.find(item => item.id === choiceResult.selectedItem))
context.title = `La Pouponnière - ${this.pouponniere.name}`
TeDeumUtility.prepareEducationContent(this.pouponniere);
context.label = "Valider l'augmentation de caracteristique"
await this.askCarac(this.pouponniere, context)
context.label = "Valider l'augmentation de compétences"
await this.askCompetences(this.pouponniere, context)
context.label = "Valider cette réponse"
await this.askQuestionnaire(this.pouponniere, context)
this.currentStage = "petitsgrimauds"
}
/*--------------------------------------------*/
async renderPetitsGrimauds(stage) {
// Filter available pouponniere from origineSociale
let grimaudsItems = stage.items.filter(item => item.system.accessible[this.origineSociale.id].isaccessible)
let context = {
title: "Les Petits Grimauds",
label: "Valider le choix des Petits Grimauds",
choices: grimaudsItems,
caracBonus: this.caracBonus,
competenceBonus: this.competenceBonus
}
let choiceResult = await this.askStageName(context)
if (choiceResult == null) {
this.currentStage = "cancelled"
return
}
this.grimauds = foundry.utils.duplicate(stage.items.find(item => item.id === choiceResult.selectedItem))
context.title = `LesPetits Grimauds - ${this.grimauds.name}`
TeDeumUtility.prepareEducationContent(this.grimauds);
context.label = "Valider l'augmentation de caracteristique"
await this.askCarac(this.grimauds, context)
context.label = "Valider l'augmentation de compétences"
await this.askCompetences(this.grimauds, context)
context.label = "Valider cette réponse"
await this.askQuestionnaire(this.grimauds, context)
this.currentStage = "rosevie"
}
/*--------------------------------------------*/
async renderRosesDeLaVie(stage) {
// Filter available pouponniere from origineSociale
let rosesItems = stage.items.filter(item => item.system.accessible[this.origineSociale.id].isaccessible)
let context = {
title: "Création de personnage - Les Roses de la Vie",
label: "Valider le choix des Roses de la Vie",
choices: rosesItems,
caracBonus: this.caracBonus,
competenceBonus: this.competenceBonus
}
let choiceResult = await this.askStageName(context)
if (choiceResult == null) {
this.currentStage = "cancelled"
return
}
this.roses = foundry.utils.duplicate(stage.items.find(item => item.id === choiceResult.selectedItem))
context.title = `Les Roses de la Vie - ${this.roses.name}`
TeDeumUtility.prepareEducationContent(this.roses);
context.label = "Valider l'augmentation de caracteristique"
await this.askCarac(this.roses, context)
context.label = "Valider l'augmentation de compétences"
await this.askCompetences(this.roses, context)
context.label = "Valider cette réponse"
await this.askQuestionnaire(this.roses, context)
this.currentStage = "ageviril"
}
/*--------------------------------------------*/
async renderAgeViril(stage) {
let virilDebouche = this.roses.system.debouches
let ageVirilItems = []
for (let key in virilDebouche) {
let debouche = virilDebouche[key]
if (debouche.debouche === "") { continue }
let deboucheItem = stage.items.find(item => item.name.toLowerCase().includes(debouche.debouche.toLowerCase()))
if (deboucheItem) {
ageVirilItems.push(deboucheItem)
} else {
console.log(`Debouche ${debouche.debouche} not found !`)
}
}
let context = {
title: "Création de personnage - L'Age Viril",
label: "Valider le choix de l'Age Viril",
choices: ageVirilItems,
caracBonus: this.caracBonus,
competenceBonus: this.competenceBonus
}
let choiceResult = await this.askStageName(context)
if (choiceResult == null) {
this.currentStage = "cancelled"
return
}
this.ageViril = foundry.utils.duplicate(stage.items.find(item => item.id === choiceResult.selectedItem))
context.title = `L'Age Viril - ${this.ageViril.name}`
TeDeumUtility.prepareEducationContent(this.ageViril);
context.label = "Valider l'augmentation de caracteristique"
await this.askCarac(this.ageViril, context)
context.label = "Valider l'augmentation de compétences"
await this.askCompetences(this.ageViril, context)
this.currentStage = "finished"
}
/*--------------------------------------------*/
async processStage() {
while (this.currentStage !== "finished") {
let stage = this.stages[this.currentStage]
switch (this.currentStage) {
case "origineSociale":
await this.renderOrigineSociale(stage)
break
case "pouponniere":
await this.renderPouponniere(stage)
break
case "petitsgrimauds":
await this.renderPetitsGrimauds(stage)
break
case "rosevie":
await this.renderRosesDeLaVie(stage)
break
case "ageviril":
await this.renderAgeViril(stage)
break
case "cancelled":
return
break
}
}
console.log("Carac Bonus", this.caracBonus)
console.log("Competence Bonus", this.competenceBonus)
let actor = await TeDeumActor.create({name: "Nouveau personnage", type: "pj"})
let updates = {}
for (let key in this.caracBonus) {
updates[`system.caracteristiques.${key}.value`] = Number(this.caracBonus[key].value)+1
}
updates['system.genre'] = this.sexe
updates['system.religion'] = TeDeumUtility.upperFirst(this.religion)
updates['system.statutocial'] = this.origineSociale.label
updates['system.equipmentfree'] = this.ageViril.system.trousseau
actor.update( updates);
// Process competences : increase know skills
let updateComp = []
let toAdd = []
for (let compName in this.competenceBonus) {
let comp = actor.items.find( i => i.type == "competence" && i.name.toLowerCase() === compName.toLowerCase())
if (comp) {
updateComp.push({ _id: comp._id, "system.score": this.competenceBonus[compName].value })
} else {
toAdd.push( compName)
}
}
actor.updateEmbeddedDocuments("Item", updateComp)
// Process adding skills
let compendiumSkill = TeDeumUtility.getCompetences()
let compToAdd = [ this.pouponniere, this.grimauds, this.roses, this.ageViril ]
for (let compName of toAdd) {
let comp = compendiumSkill.find( i => i.name.toLowerCase() === compName.toLowerCase())
comp.system.score = this.competenceBonus[compName].value
compToAdd.push(comp)
}
await actor.createEmbeddedDocuments('Item', compToAdd)
let newArgent = this.origineSociale.cagnotte * this.ageViril.system.cagnotteMultiplier
newArgent /= this.ageViril.system.cagnotteDivider
await actor.update({ [`system.fortune.${this.origineSociale.cagnotteUnit}`]: newArgent})
let histoire = ""
for (let reponse of this.suiviReponses) {
histoire += `<p>${reponse.question}<br>${reponse.reponse} (${reponse.compName})</p>`
}
await actor.update({ "system.histoire": histoire})
actor.render(true)
context.pointsCompetence = {
"savoir": { score: actor.getCompetenceScore("Mémoriser"), label: "Savoir" },
"sensibilite": { score: actor.getCompetenceScore("Perception"), label: "Sensibilité" },
"entregent": { score: actor.getCompetenceScore("Charme"), label: "Entregent" },
"puissance": { score: actor.getCompetenceScore("Effort"), label: "Puissance" },
"complexion": { score: actor.getCompetenceScore("Endurance"), label: "Complexion" },
"adresse": { score: actor.getCompetenceScore("Initiative"), label: "Adresse" },
}
const content = await renderTemplate("systems/fvtt-te-deum/templates/dialogs/character-creator-finished.hbs", context)
const label = "Terminer"
const choiceResult = await foundry.applications.api.DialogV2.wait({
window: { title: context.title },
classes: ["fvtt-te-deum"],
content,
buttons: [
{
label: label,
callback: (event, button, dialog) => {
const output = Array.from(button.form.elements).reduce((obj, input) => {
if (input.name) obj[input.name] = input.value
return obj
}, {})
return output
},
},
],
actions: {
},
rejectClose: false, // Click on Close button will not launch an error
render: (event, dialog) => { }
})
}
}

View File

@ -5,21 +5,17 @@ export class TeDeumCombat extends Combat {
/* -------------------------------------------- */ /* -------------------------------------------- */
async rollInitiative(ids, formula = undefined, messageOptions = {} ) { async rollInitiative(ids, formula = undefined, messageOptions = {} ) {
//console.log("Roll INIT !")
ids = typeof ids === "string" ? [ids] : ids; ids = typeof ids === "string" ? [ids] : ids;
for (let cId = 0; cId < ids.length; cId++) { for (let cId of ids) {
const c = this.combatants.get(ids[cId]); const c = this.combatants.get(cId);
let id = c._id || c.id; let initBonus = c.actor ? c.actor.getInitiativeScore( this.id, cId ) : -1;
let initBonus = c.actor ? c.actor.getInitiativeScore( this.id, id ) : -1; await this.updateEmbeddedDocuments("Combatant", [ { _id: cId, initiative: initBonus } ]);
await this.updateEmbeddedDocuments("Combatant", [ { _id: id, initiative: initBonus } ]);
} }
return this; return this;
} }
/* -------------------------------------------- */
_onUpdate(changed, options, userId) {
}
/* -------------------------------------------- */ /* -------------------------------------------- */
static async checkTurnPosition() { static async checkTurnPosition() {
while (game.combat.turn > 0) { while (game.combat.turn > 0) {

View File

@ -9,30 +9,30 @@ export const TEDEUM_CONFIG = {
{ 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 },
{ 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, id: "pieddroit", nbArmure: 1 }, "pieddroit": { label: "Pied Droit", value: 1, locMod: 0, id: "pieddroit", nbArmure: 1, score: { min: 1, max: 1 }, coord: { top: 500, left: 0 } },
"jambedroite": { label: "Jambe Droite", value: 1, id: "jambedroite", nbArmure: 1 }, "jambedroite": { label: "Jambe Droite", value: 1, locMod: -1, id: "jambedroite", nbArmure: 1, score: { min: 3, max: 4 }, coord: { top: 400, left: 100 } },
"jambegauche": { label: "Jambe Gauche", value: 1, id: "jambegauche", nbArmure: 1 }, "jambegauche": { label: "Jambe Gauche", value: 1, locMod: -1, id: "jambegauche", nbArmure: 1, score: { min: 5, max: 6 }, coord: { top: 400, left: 300 } },
"piedgauche": { label: "Pied Gauche", value: 1, id: "piedgauche", nbArmure: 1 }, "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, id: "piedgauche", nbArmure: 1 }, "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, id: "maindroite", nbArmure: 1 }, "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, id: "maingauche", nbArmure: 1 }, "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, id: "brasdroit", nbArmure: 2 }, "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, id: "brasgauche", nbArmure: 2 }, "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", nbArmure: 2 }, "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", nbArmure: 2 },
}, },
ARME_SPECIFICITE: { ARME_SPECIFICITE: {
"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 },
"peutlancer": { label: "Peut être lancée", id: "peutlancer", melee: true, tir: false}, "peutlancer": { label: "Peut être lancée", id: "peutlancer", melee: true, tir: false },
"pasboutportant": { label: "Inutilisable à bout portant", id: "pasboutportant", melee: false, tir: true}, "pasboutportant": { label: "Inutilisable à bout portant", id: "pasboutportant", melee: false, tir: true },
"rechargearquebusade": { label: "Retrancher l'Arquebusade au temps de recharge", id: "rechargearquebusade", melee: false, tir: true },
"mitraille": { label: "Mitraille", id: "mitraille", melee: false, tir: true }, "mitraille": { label: "Mitraille", id: "mitraille", melee: false, tir: true },
"degatscharge": { label: "Dégâts accrus à la charge", id: "degatscharge", melee: true, tir: false }, "degatscharge": { label: "Dégâts accrus à la charge", id: "degatscharge", melee: true, tir: false },
"crochecavalier": { label: "Croche-cavalier", id: "crochecavalier", melee: true, tir: false }, "crochecavalier": { label: "Croche-cavalier", id: "crochecavalier", melee: true, tir: false },
@ -43,11 +43,16 @@ export const TEDEUM_CONFIG = {
}, },
ARME_PORTEES: { ARME_PORTEES: {
"brulepourpoint": { label: "Brûle-pourpoint", difficulty: "facile", id: "brulepourpoint"}, "brulepourpoint": { label: "Brûle-pourpoint", difficulty: "facile", id: "brulepourpoint" },
"courte": { label: "Courte", difficulty: "pardefaut", id: "courte"}, "courte": { label: "Courte", difficulty: "pardefaut", id: "courte" },
"moyenne": { label: "Moyenne", difficulty: "difficile", id: "moyenne"}, "moyenne": { label: "Moyenne", difficulty: "difficile", id: "moyenne" },
"longue": { label: "Longue", difficulty: "perilleux", id: "longue"}, "longue": { label: "Longue", difficulty: "perilleux", id: "longue" },
"extreme": { label: "Extrême", difficulty: "desespere", id: "extreme"}, "extreme": { label: "Extrême", difficulty: "desespere", id: "extreme" },
},
genre: {
Homme: { label: "Homme", value: "Homme" },
Femme: { label: "Femme", value: "Femme" }
}, },
descriptionValeurOdd: { descriptionValeurOdd: {
@ -72,23 +77,28 @@ export const TEDEUM_CONFIG = {
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" },
}, },
diceValeur: [ "d4", "d6", "d8", "d10", "d12", "d20" ], diceValeur: ["d4", "d6", "d8", "d10", "d12", "d20"],
degatsArmure : { degatsArmure: {
sansarmure : { label: "Sans armure"}, sansarmure: { label: "Sans armure" },
cuir : { label: "Cuir"}, cuir: { label: "Cuir" },
plates : { label: "Plates"}, plates: { label: "Plates" },
mailles : { label: "Mailles"}, mailles: { label: "Mailles" },
}, },
caracteristiques: { caracteristiques: {
savoir: { id: "savoir", value: "savoir", label: "Savoir" }, 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é" }, 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" }, 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" }, 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." },
puissance: { id: "puissance", value: "puissance", label: "Puissance" }, puissance: { id: "puissance", value: "puissance", label: "Puissance", description: "Cette caractéristique correspond à la force physique du personnage. Elle permet d'évaluer la compétence de base Effort, le bonus de dégâts au corps à corps, ainsi que le nombre de pièces d'armure lourde qu'un per- sonnage peut endosser sans être trop ralenti." },
adresse: { id: "adresse", value: "adresse", label: "Adresse" }, adresse: { id: "adresse", value: "adresse", label: "Adresse", description: "Cette caractéristique correspond à la rapidité et la dextérité du personnage. Elle livre le nombre d'actions qu'un personnage peut accomplir en un tour de combat et permet d'évaluer les compétences de base Initiative & Course." },
},
allonges: {
courte: { courte: { malus: 0 }, moyenne: { malus: -1 }, longue: { malus: -2 }, treslongue: { malus: 0, esquive: 2 } },
moyenne: { courte: { malus: 0 }, moyenne: { malus: 0 }, longue: { malus: -1 }, treslongue: { malus: 0, esquive: 2 } },
longue: { courte: { malus: -2 }, moyenne: { malus: -1 }, longue: { malus: 0 }, treslongue: { malus: -1, esquive: 1 } },
treslongue: { courte: { malus: 0, esquive: 2 }, moyenne: { malus: 0, esquive: 2 }, longue: { malus: 0, esquive: 1 }, treslongue: { malus: 0 } },
}, },
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" },
{ labelM: "Pauvre pêcheur", labelF: "Pauvre pêcheresse", value: 1, diceValue: "d4" }, { labelM: "Pauvre pêcheur", labelF: "Pauvre pêcheresse", value: 1, diceValue: "d4" },
@ -98,7 +108,11 @@ export const TEDEUM_CONFIG = {
{ labelM: "Oint du Seigneur", labelF: "Ointe du Seigneur", value: 5, diceValue: "d12" }, { labelM: "Oint du Seigneur", labelF: "Ointe du Seigneur", value: 5, diceValue: "d12" },
{ labelM: "Dans la main de Dieu", labelF: "Dans la main de Dieu", value: 6, diceValue: "d20" }, { labelM: "Dans la main de Dieu", labelF: "Dans la main de Dieu", value: 6, diceValue: "d20" },
], ],
armureTypes: {
cuir: { label: "Cuir", value: "cuir" },
maille: { label: "Maille", value: "maille" },
plate: { label: "Plate", value: "plate" },
},
armeTypes: { armeTypes: {
melee: { label: "Mêlée", value: "melee" }, melee: { label: "Mêlée", value: "melee" },
tir: { label: "Tir", value: "tir" } tir: { label: "Tir", value: "tir" }
@ -107,7 +121,7 @@ export const TEDEUM_CONFIG = {
courte: { label: "Courte", value: "courte" }, courte: { label: "Courte", value: "courte" },
moyenne: { label: "Moyenne", value: "moyenne" }, moyenne: { label: "Moyenne", value: "moyenne" },
longue: { label: "Longue", value: "longue" }, longue: { label: "Longue", value: "longue" },
treslongue: { label: "Très longue", value: "treslongue"} treslongue: { label: "Très longue", value: "treslongue" }
}, },
armeCompetences: { armeCompetences: {
bagarre: { label: "Bagarre", value: "bagarre" }, bagarre: { label: "Bagarre", value: "bagarre" },
@ -118,14 +132,20 @@ export const TEDEUM_CONFIG = {
archerie: { label: "Archerie", value: "archerie" }, archerie: { label: "Archerie", value: "archerie" },
arquebusade: { label: "Arquebusade", value: "arquebusade" } arquebusade: { label: "Arquebusade", value: "arquebusade" }
}, },
competencesRecharge: {
aucune: { label: "Aucune", value: "aucune" },
archerie: { label: "Archerie", value: "archerie" },
arquebusade: { label: "Arquebusade", value: "arquebusade" }
},
difficulte: { difficulte: {
routine: { label: "Routine", value: 3 }, aucune: { label: "Aucune", key: "aucune", value: 0 },
facile: { label: "Facile", value: 5 }, routine: { label: "Routine", key: "routine", value: 3 },
pardefaut: { label: "Par Défaut", value: 7 }, facile: { label: "Facile", key: "facile", value: 5 },
malaise: { label: "Malaisé", value: 9 }, pardefaut: { label: "Par Défaut", key: "pardefaut", value: 7 },
difficile: { label: "difficile", value: 11 }, malaise: { label: "Malaisé", key: "malaise", value: 9 },
perilleux: { label: "Perilleux", value: 13 }, difficile: { label: "Difficile", key: "difficile", value: 11 },
desespere: { label: "Désespéré", value: 15 } perilleux: { label: "Perilleux", key: "perilleux", value: 13 },
desespere: { label: "Désespéré", key: "desespere", value: 15 }
}, },
monnaie: { monnaie: {
denier: { label: "Deniers", id: "denier", value: 1 }, denier: { label: "Deniers", id: "denier", value: 1 },
@ -133,22 +153,22 @@ export const TEDEUM_CONFIG = {
livre: { label: "Livres", id: "livre", value: 100 } livre: { 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, hasMultiplier: false }, pouponniere: { label: "La Pouponnière", value: "pouponniere", agemin: 0, agemax: 6, nbCompetences: 2, nbCaracteristiques: 3, hasQuestionnaire: true, hasDebouches: false, hasMultiplier: false, canCompetencesOpt: false },
petitsgrimauds: { label: "La classe des Petits Grimauds", value: "petitsgrimauds", agemin: 7, agemax: 12,nbCompetences: 2, nbCaracteristiques: 3, hasQuestionnaire: true, hasMultiplier: false }, petitsgrimauds: { label: "La classe des Petits Grimauds", value: "petitsgrimauds", agemin: 7, agemax: 12, nbCompetences: 10, nbCaracteristiques: 3, hasDebouches: false, hasQuestionnaire: true, hasMultiplier: false, canCompetencesOpt: false },
rosevie: { label: "Les Roses de la Vie", value: "rosevie", agemin: 13, agemax: 16, nbCompetences: 2, nbCaracteristiques: 3, hasQuestionnaire: true, hasMultiplier: false }, rosevie: { label: "Les Roses de la Vie", value: "rosevie", agemin: 13, agemax: 16, nbCompetences: 2, nbCaracteristiques: 3, hasQuestionnaire: true, hasDebouches: true, hasMultiplier: false, canCompetencesOpt: false },
ageviril: { label: "L'Age Viril", value: "ageviril", agemin: 17, agemax: 17, nbCompetences: 9, nbCaracteristiques: 2, hasQuestionnaire: false, hasMultiplier: true }, ageviril: { label: "L'Age Viril", value: "ageviril", agemin: 17, agemax: 17, nbCompetences: 9, nbCaracteristiques: 2, hasQuestionnaire: false, hasDebouches: false, hasMultiplier: true, canCompetencesOpt: true },
}, },
origineSociale: { origineSociale: {
noblesseepee: { label: "Noblesse d'épée", id: "noblesseepee", value: 1 }, noblesseepee: { label: "Noblesse d'épée", id: "noblesseepee", caracteristiques: { entregent: 1, puissance: 1 }, cagnotte: 10, cagnotteUnit: "livres", value: 1 },
noblessecloche: { label: "Noblesse de cloche", id: "noblessecloche", value: 2 }, noblessecloche: { label: "Noblesse de cloche", id: "noblessecloche", caracteristiques: { entregent: 1, savoir: 1 }, cagnotte: 50, cagnotteUnit: "livres", value: 2 },
hautenoblesse: { label: "Haute noblesse (Illégitime)", id: "hautenoblesse", value: 3 }, hautenoblesse: { label: "Haute noblesse (Illégitime)", id: "hautenoblesse", caracteristiques: { complexion: 1, puissance: 1 }, cagnotte: 20, cagnotteUnit: "livres", value: 3 },
hautebourgeoisie: { label: "Haute bourgeoisie", id: "hautebourgeoisie", value: 4 }, hautebourgeoisie: { label: "Haute bourgeoisie", id: "hautebourgeoisie", caracteristiques: { savoir: 1, sensibilite: 1 }, cagnotte: 60, cagnotteUnit: "livres", value: 4 },
petitebourgeoisie: { label: "Petite bourgeoisie (Marchands)", id: "petitebourgeoisie", value: 5 }, petitebourgeoisie: { label: "Petite bourgeoisie (Marchands)", caracteristiques: { entregent: 1, sensibilite: 1 }, cagnotte: 20, cagnotteUnit: "livres", id: "petitebourgeoisie", value: 5 },
artisan: { label: "Artisans", id: "artisan", value: 6 }, artisan: { label: "Artisans", id: "artisan", caracteristiques: { adresse: 1, sensibilite: 1 }, cagnotte: 10, cagnotteUnit: "livres", value: 6 },
laboureur: { label: "Laboureurs", id: "laboureur", value: 7 }, laboureur: { label: "Laboureurs", id: "laboureur", caracteristiques: { entregent: 1, complexion: 1 }, cagnotte: 10, cagnotteUnit: "livres", value: 7 },
domesticite: { label: "Domesticité", id: "domesticite", value: 8 }, domesticite: { label: "Domesticité", id: "domesticite", caracteristiques: { entregent: 1, adresse: 1 }, cagnotte: 2, cagnotteUnit: "sous", value: 8 },
paysannerie: { label: "Paysannerie", id: "paysannerie", value: 9 }, paysannerie: { label: "Paysannerie", id: "paysannerie", caracteristiques: { puissance: 1, complexion: 1 }, cagnotte: 1, cagnotteUnit: "sous", value: 9 },
gueux: { label: "Gueux", id: "gueux", value: 10 }, gueux: { label: "Gueux", id: "gueux", caracteristiques: { adresse: 1, complexion: 1 }, cagnotte: 4, cagnotteUnit: "deniers", value: 10 },
}, },
bonusMalus: [ bonusMalus: [
{ value: "-2", label: "-2 niveaux" }, { value: "-2", label: "-2 niveaux" },
@ -157,13 +177,33 @@ export const TEDEUM_CONFIG = {
{ value: "1", label: "+1 niveau" }, { value: "1", label: "+1 niveau" },
{ value: "2", label: "+2 niveaux" } { value: "2", label: "+2 niveaux" }
], ],
blessures: [ blessures: {
{ value: 0, label: "Indemne", degatsMax: -1, count: 0, modifier: 0 }, indemne: { value: 0, label: "Indemne", key: "indemne", degatsMax: -1, count: 0, modifier: 0 },
{ value: 1, label: "Estafilade/Contusion", degatsMax: 2, count: 1, modifier: 0 }, estafilade: { value: 1, label: "Estafilade", key: "estafilade", degatsMin: 0, degatsMax: 2, count: 1, modifier: 0 },
{ value: 2, label: "Plaie", degatsMax: 4, count: 1, modifier: -1 }, plaie: { value: 2, label: "Plaie", key: "plaie", degatsMin: 3, degatsMax: 4, count: 1, modifier: -1 },
{ value: 3, label: "Plaie béante", degatsMax: 6, count: 1, modifier: -2 }, plaiebeante: { value: 3, label: "Plaie béante", key: "plaiebeante", degatsMin: 5, degatsMax: 6, count: 1, modifier: -2 },
{ value: 4, label: "Plaie atroce", degatsMax: 6, count: 1, horsCombat: true, modifier: -12 }, plaieatroce: { value: 4, label: "Plaie atroce", key: "plaieatroce", degatsMin: 7, degatsMax: 8, count: 1, horsCombat: true, modifier: -12 },
{ value: 5, label: "Tué net", degatsMax: 100, count: 1, horsCombat: true, mort: true, modifier: -12 } tunenet: { value: 5, label: "Tué net", key: "tuenet", degatsMin: 9, degatsMax: 100, count: 1, horsCombat: true, mort: true, modifier: -12 }
] },
virulence: {
aucune: { label: "Aucune", value: "aucune", modifier: 0 },
fatigue: { label: "Fatigue", value: "fatigue", modifier: 0 },
epuisement: { label: "Epuisement", value: "epuisement", modifier: -1 },
souffrance: { label: "Souffrance", value: "souffrance", modifier: -2 },
agonie: { label: "Agonie", value: "agonie", modifier: -3 }
},
fievre: {
aucune: { label: "Aucune", value: "aucune" },
legere: { label: "Légère", value: "legere" },
forte: { label: "Forte", value: "forte" },
grave: { label: "Grave", value: "grave" }
},
virulencePoison: {
aucune: { label: "Aucune", value: "aucune", modifier: 0 },
nausee: { label: "Nausées & Vertiges", value: "nausee", modifier: 0 },
inflammation: { label: "Inflammations & Vomissements", value: "inflammation", modifier: -1 },
elancement: { label: "Elancements & Hémorragies", value: "elancement", modifier: -2 },
convulsion: { label: "Convulsions & Délire hallucinatoire", value: "convulsion", modifier: -3 },
mort: { label: "Inconscience & Mort", value: "mort", modifier: -12 }
}
} }

View File

@ -5,7 +5,28 @@ export class TeDeumUtility {
/* -------------------------------------------- */ /* -------------------------------------------- */
static async init() { static async init() {
CONFIG.Actor.compendiumBanner = "systems/fvtt-te-deum/images/ui/compendium_banner.webp"
CONFIG.Item.compendiumBanner = "systems/fvtt-te-deum/images/ui/compendium_banner.webp"
CONFIG.Scene.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.Adventure.compendiumBanner = "systems/fvtt-te-deum/images/ui/compendium_banner.webp"
Hooks.on('renderChatLog', (log, html, data) => TeDeumUtility.chatListeners(html)); Hooks.on('renderChatLog', (log, html, data) => TeDeumUtility.chatListeners(html));
Hooks.on("renderActorDirectory", (app, html, data) => {
if (game.user.can('ACTOR_CREATE')) {
const button = document.createElement('button');
button.style.width = '90%';
button.innerHTML = 'Créer un Personnage'
button.addEventListener('click', () => {
let cr = new game.system.tedeum.TeDeumCharacterCreator();
cr.init()
})
html.find('.header-actions').after(button)
}
})
//Hooks.on("getChatLogEntryContext", (html, options) => TeDeumUtility.chatMenuManager(html, options)); //Hooks.on("getChatLogEntryContext", (html, options) => TeDeumUtility.chatMenuManager(html, options));
} }
@ -50,16 +71,23 @@ export class TeDeumUtility {
//console.log("getConfigLabel", configName, key) //console.log("getConfigLabel", configName, key)
return game.system.tedeum.config[configName][key].label return game.system.tedeum.config[configName][key].label
}) })
Handlebars.registerHelper('getConfigLabelArray', function (configName, key) {
//console.log("getConfigLabel", configName, key)
return game.system.tedeum.config[configName][key].label
})
Handlebars.registerHelper('isSpecArmeType', function (key, armeType) { Handlebars.registerHelper('isSpecArmeType', function (key, armeType) {
return game.system.tedeum.config.ARME_SPECIFICITE[key][armeType] return game.system.tedeum.config.ARME_SPECIFICITE[key][armeType]
}) })
Handlebars.registerHelper('getConfigLabelWithGender', function (configName, key, genderKey) { Handlebars.registerHelper('getConfigLabelWithGender', function (configName, key, genderKey) {
return game.system.tedeum.config[configName][key]["label"+genderKey] return game.system.tedeum.config[configName][key]["label" + genderKey]
}) })
Handlebars.registerHelper('getCaracDescription', function (key, value) { Handlebars.registerHelper('getCaracDescription', function (key, value) {
return game.system.tedeum.config.descriptionValeur[Number(value)][key] return game.system.tedeum.config.descriptionValeur[Number(value)][key]
}) })
Handlebars.registerHelper('getEducationEtape', function (key) {
return game.system.tedeum.config.etapesEducation[key].label
})
Handlebars.registerHelper('isGM', function () { Handlebars.registerHelper('isGM', function () {
return game.user.isGM return game.user.isGM
@ -70,7 +98,35 @@ export class TeDeumUtility {
this.competences = competences.map(i => i.toObject()) this.competences = competences.map(i => i.toObject())
this.competencesList = {} this.competencesList = {}
for (let i of this.competences) { for (let i of this.competences) {
this.competencesList[i.name.toLowerCase()] = {name:i.name, id: i._id} this.competencesList[i.name.toLowerCase()] = { name: i.name, id: i._id }
}
this.competencesList = Object.entries(this.competencesList).sort().reduce((o, [k, v]) => (o[k] = v, o), {})
}
/* -------------------------------------------- */
static async importDefaultScene() {
let exists = game.scenes.find(j => j.name == "Te Deum");
if (!exists) {
const scenes = await TeDeumUtility.loadCompendium("fvtt-te-deum.scenes")
let newDocuments = scenes.filter(i => i.name == "Te Deum");
if (newDocuments) {
await game.scenes.documentClass.create(newDocuments);
game.scenes.find(i => i.name == "Te Deum").activate();
}
}
}
/* -------------------------------------------- */
static welcomeMessage() {
if (game.user.isGM) {
ChatMessage.create({
user: game.user.id,
whisper: [game.user.id],
content: `<div id="chat-welcome welcome-message-tedeum"><span class="rdd-roll-part">
<strong>Bienvenu dans Te Deum Pour Un Massacre !</strong>
<div class="chat-welcome">Ce système vous est proposé par Open Sesame Games.<br>
Vous trouverez de l'aide dans @UUID[Compendium.fvtt-te-deum.aides.JournalEntry.uNwJgi4kXBCiZmAH]{Aide pour Te Deum}<br>
ainsi que sur le Discord de Foundry FR : https://discord.gg/pPSDNJk</div>` });
} }
} }
@ -85,22 +141,25 @@ export class TeDeumUtility {
/*-------------------------------------------- */ /*-------------------------------------------- */
static prepareEducationContent(formData) { static prepareEducationContent(formData) {
let nbCompetences = game.system.tedeum.config.etapesEducation[formData.system.etape].nbCompetences let etape = game.system.tedeum.config.etapesEducation[formData.system.etape]
let nbCompetences = etape.nbCompetences
for (let key in formData.system.competences) { for (let key in formData.system.competences) {
formData.system.competences[key].valid = false formData.system.competences[key].valid = false
} }
for (let i = 1; i <= nbCompetences; i++) { for (let i = 1; i <= nbCompetences; i++) {
formData.system.competences[`comp${i}`].valid = true formData.system.competences[`comp${i}`].valid = true
} }
let nbCaracteristiques = game.system.tedeum.config.etapesEducation[formData.system.etape].nbCaracteristiques let nbCaracteristiques = etape.nbCaracteristiques
for (let key in formData.system.caracteristiques) { for (let key in formData.system.caracteristiques) {
formData.system.caracteristiques[key].valid = false formData.system.caracteristiques[key].valid = false
} }
for (let i = 1; i <= nbCaracteristiques; i++) { for (let i = 1; i <= nbCaracteristiques; i++) {
formData.system.caracteristiques[`carac${i}`].valid = true formData.system.caracteristiques[`carac${i}`].valid = true
} }
formData.hasQuestionnaire = game.system.tedeum.config.etapesEducation[formData.system.etape].hasQuestionnaire; formData.hasQuestionnaire = etape.hasQuestionnaire;
formData.hasMultiplier = game.system.tedeum.config.etapesEducation[formData.system.etape].hasMultiplier; formData.hasMultiplier = etape.hasMultiplier;
formData.hasDebouches = etape.hasDebouches;
formData.canCompetencesOpt = etape.canCompetencesOpt;
} }
/*-------------------------------------------- */ /*-------------------------------------------- */
@ -133,36 +192,44 @@ export class TeDeumUtility {
return actor return actor
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static async manageOpposition(rollData) {
if (!this.currentOpposition) {
// Store rollData as current GM opposition
this.currentOpposition = rollData
ui.notifications.info("Opposition démarrée avec " + rollData.alias);
} else {
// Perform the opposition
let rWinner = this.currentOpposition
let rLooser = rollData
if (rWinner.total < rLooser.total) {
rWinner = rollData
rLooser = this.currentOpposition
}
this.currentOpposition = undefined // Reset opposition
let oppositionData = {
winner: rWinner,
looser: rLooser
}
let msg = await this.createChatWithRollMode(rollData.alias, {
content: await renderTemplate(`systems/fvtt-te-deum/templates/chat/chat-opposition-result.hbs`, oppositionData)
})
await msg.setFlag("world", "te-deum-rolldata", rollData)
console.log("Rolldata result", rollData)
}
}
/* -------------------------------------------- */ /* -------------------------------------------- */ /* -------------------------------------------- */ /* -------------------------------------------- */
static async chatListeners(html) { static async chatListeners(html) {
html.on("click", '.button-select-confront', event => { html.on("click", '.chat-command-button', 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")
ui.notifications.info( game.i18n.localize("ECRY.chat.confrontselect")) if (rollData) {
TeDeumUtility.manageConfrontation(rollData) TeDeumUtility.manageOpposition(rollData, messageId)
}
}) })
html.on("click", '.button-apply-cephaly-difficulty', event => {
let messageId = TeDeumUtility.findChatMessageId(event.currentTarget)
let message = game.messages.get(messageId)
let rollData = message.getFlag("world", "te-deum-rolldata")
let difficulty = $("#" + rollData.rollId + "-cephaly-difficulty").val()
TeDeumUtility.manageCephalyDifficulty(rollData, difficulty)
})
html.on("click", '.button-apply-impact', event => {
let messageId = TeDeumUtility.findChatMessageId(event.currentTarget)
let message = game.messages.get(messageId)
let actor = game.actors.get($(event.currentTarget).data("actor-id"))
actor.modifyImpact($(event.currentTarget).data("impact-type"), $(event.currentTarget).data("impact"), 1)
})
html.on("click", '.button-apply-bonus', event => {
let messageId = TeDeumUtility.findChatMessageId(event.currentTarget)
let message = game.messages.get(messageId)
let actor = game.actors.get($(event.currentTarget).data("actor-id"))
actor.modifyConfrontBonus($(event.currentTarget).data("bonus"))
})
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
@ -171,7 +238,8 @@ export class TeDeumUtility {
const templatePaths = [ const templatePaths = [
'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'
] ]
return loadTemplates(templatePaths); return loadTemplates(templatePaths);
} }
@ -248,7 +316,7 @@ export class TeDeumUtility {
console.log("SOCKET MESSAGE", msg) console.log("SOCKET MESSAGE", msg)
if (msg.name == "msg_gm_chat_message") { if (msg.name == "msg_gm_chat_message") {
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 renderTemplate(msg.data.template, rollData),
whisper: game.user.id whisper: game.user.id
@ -352,6 +420,10 @@ export class TeDeumUtility {
/* -------------------------------------------- */ /* -------------------------------------------- */
static modifyDice(dice, bonusMalus) { static modifyDice(dice, bonusMalus) {
let newIndex = game.system.tedeum.config.diceValeur.indexOf(dice) + Number(bonusMalus) let newIndex = game.system.tedeum.config.diceValeur.indexOf(dice) + Number(bonusMalus)
if (newIndex < 0) {
ui.notifications.error("Vos blessures ou maladies vous empêchent de réaliser cette action, vous êtes trop faibles")
return undefined
}
newIndex = Math.min(Math.max(newIndex, 0), game.system.tedeum.config.diceValeur.length - 1) newIndex = Math.min(Math.max(newIndex, 0), game.system.tedeum.config.diceValeur.length - 1)
return game.system.tedeum.config.diceValeur[newIndex] return game.system.tedeum.config.diceValeur[newIndex]
} }
@ -360,7 +432,15 @@ export class TeDeumUtility {
static computeRollFormula(rollData, actor, isConfrontation = false) { static computeRollFormula(rollData, actor, isConfrontation = false) {
let diceFormula = "" let diceFormula = ""
if (rollData.competence) { if (rollData.competence) {
let diceBase = this.modifyDice(rollData.carac.dice, rollData.bonusMalus+rollData.malusBlessures) let localModifier = 0
if (rollData.isViser) {
localModifier += 1
}
if (rollData.isMouvement) {
localModifier -= 1
}
let diceBase = this.modifyDice(rollData.carac.dice, localModifier + Number(rollData.bonusMalus) + rollData.santeModifier)
if (!diceBase) return;
diceFormula = diceBase + "x + " + rollData.competence.system.score diceFormula = diceBase + "x + " + rollData.competence.system.score
} }
if (rollData.enableProvidence) { if (rollData.enableProvidence) {
@ -369,17 +449,64 @@ export class TeDeumUtility {
return diceFormula return diceFormula
} }
/* -------------------------------------------- */
static async getLocalisation(rollData) {
let locRoll = await new Roll("1d20").roll()
await this.showDiceSoNice(locRoll, game.settings.get("core", "rollMode"))
rollData.locRoll = foundry.utils.duplicate(locRoll)
for (let key in game.system.tedeum.config.LOCALISATION) {
let loc = game.system.tedeum.config.LOCALISATION[key]
if (locRoll.total >= loc.score.min && locRoll.total <= loc.score.max) {
rollData.loc = foundry.utils.duplicate(loc)
break
}
}
}
/* -------------------------------------------- */
static async processAttaqueMelee(rollData) {
if (rollData.arme?.system.typeArme != "melee") {
return
}
if (rollData.isSuccess) {
await this.getLocalisation(rollData)
let actor = game.actors.get(rollData.actorId)
let bDegats = actor.getBonusDegats()
let degatsRoll = await new Roll(rollData.arme.system.degats + "+" + bDegats.value).roll()
await this.showDiceSoNice(degatsRoll, game.settings.get("core", "rollMode"))
rollData.degatsRoll = foundry.utils.duplicate(degatsRoll)
rollData.degats = degatsRoll.total
}
}
/* -------------------------------------------- */
static async processAttaqueDistance(rollData) {
if (rollData.arme?.system.typeArme != "tir") {
return
}
if (rollData.isSuccess) {
// Roll the location
await this.getLocalisation(rollData)
// Now the degats
let degatsRoll = await new Roll(rollData.arme.system.degats).roll()
await this.showDiceSoNice(locRoll, game.settings.get("core", "rollMode"))
rollData.degatsRoll = foundry.utils.duplicate(degatsRoll)
rollData.degats = degatsRoll.total
}
}
/* -------------------------------------------- */ /* -------------------------------------------- */
static async rollTeDeum(rollData) { static async rollTeDeum(rollData) {
let actor = game.actors.get(rollData.actorId) let actor = game.actors.get(rollData.actorId)
// Fix difficulty // Fix difficulty
if (!rollData.difficulty || rollData.difficulty == "-") { if (!rollData.difficulty || rollData.difficulty == "-") {
rollData.difficulty = 7 rollData.difficulty = "pardefaut"
} }
rollData.difficulty = game.system.tedeum.config.difficulte[rollData.difficulty].value rollData.difficulty = game.system.tedeum.config.difficulte[rollData.difficulty].value
let diceFormula = this.computeRollFormula(rollData, actor) let diceFormula = this.computeRollFormula(rollData, actor)
if (!diceFormula) return;
console.log("RollData", rollData, diceFormula)
// Performs roll // Performs roll
let myRoll = await new Roll(diceFormula).roll() let myRoll = await new Roll(diceFormula).roll()
@ -391,6 +518,9 @@ export class TeDeumUtility {
await this.computeResults(rollData) await this.computeResults(rollData)
await this.processAttaqueDistance(rollData)
await this.processAttaqueMelee(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 renderTemplate(`systems/fvtt-te-deum/templates/chat/chat-generic-result.hbs`, rollData)
}) })
@ -405,6 +535,15 @@ export class TeDeumUtility {
if (rollData.isReussiteCritique || rollData.isEchecCritique) { if (rollData.isReussiteCritique || rollData.isEchecCritique) {
actor.modifyXP(rollData.carac.key, 1) 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)
}
}
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
@ -493,15 +632,15 @@ export class TeDeumUtility {
/* -------------------------------------------- */ /* -------------------------------------------- */
static getBasicRollData() { static getBasicRollData() {
let rollData = { let rollData = {
rollId: randomID(16), rollId: foundry.utils.randomID(16),
type: "roll-data", type: "roll-data",
rollMode: game.settings.get("core", "rollMode"), rollMode: game.settings.get("core", "rollMode"),
difficulty: "pardefaut", difficulty: "pardefaut",
bonusMalus : "0", bonusMalus: "0",
isReroll : false, isReroll: false,
enableProvidence : false, enableProvidence: false,
malusBlessures: 0, malusBlessures: 0,
config: duplicate(game.system.tedeum.config) config: foundry.utils.duplicate(game.system.tedeum.config)
} }
TeDeumUtility.updateWithTarget(rollData) TeDeumUtility.updateWithTarget(rollData)
return rollData return rollData

View File

@ -34,11 +34,14 @@ export class TeDeumArmeSchema extends foundry.abstract.TypeDataModel {
}); });
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.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, min: 0 });
schema.degats = new fields.StringField({ required: false, blank: true, initial: undefined }); schema.degats = 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);
@ -49,6 +52,8 @@ export class TeDeumArmeSchema extends foundry.abstract.TypeDataModel {
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.description = new fields.HTMLField({ required: true, blank: true }); schema.description = new fields.HTMLField({ required: true, blank: true });
return schema; return schema;

View File

@ -6,6 +6,8 @@ export class TeDeumArmureSchema extends foundry.abstract.TypeDataModel {
const schema = {}; const schema = {};
schema.typeArmure = new fields.StringField({required: true, choices: ["cuir", "maille", "plate"], initial: "cuir"});
schema.localisation = new fields.SchemaField( schema.localisation = new fields.SchemaField(
Object.values(game.system.tedeum.config.LOCALISATION).reduce((obj, loc) => { Object.values(game.system.tedeum.config.LOCALISATION).reduce((obj, loc) => {
obj[loc.id] = new fields.SchemaField({ obj[loc.id] = new fields.SchemaField({
@ -15,11 +17,19 @@ export class TeDeumArmureSchema extends foundry.abstract.TypeDataModel {
}, {}) }, {})
); );
schema.coutArmureLourde = new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 });
schema.superposableCuir = new fields.BooleanField({initial: false});
schema.superposableMaille = new fields.BooleanField({initial: false});
schema.superposablePlate = new fields.BooleanField({initial: false});
schema.protection = new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 }); schema.protection = new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 });
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.description = new fields.HTMLField({ required: true, blank: true }); schema.description = new fields.HTMLField({ required: true, blank: true });
return schema; return schema;

View File

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

View File

@ -14,35 +14,66 @@ export class TeDeumEducationSchema extends foundry.abstract.TypeDataModel {
return obj; return obj;
}, {}) }, {})
); );
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({
caracId: new fields.StringField({ required: true, blank: false, initial: "entregent" }) caracId: new fields.StringField({ required: true, blank: false, initial: "entregent" })
}); });
return caracs; return caracs;
}, {})); }, {}));
schema.competences = new fields.SchemaField(Array.fromRange(9, 1).reduce((comps, i) => {
schema.competences = new fields.SchemaField(Array.fromRange(10, 1).reduce((comps, i) => {
comps[`comp${i}`] = new fields.SchemaField({
compName: new fields.StringField({ required: true, blank: true, initial: "" }),
toSelect: new fields.BooleanField({ initial: false })
});
return comps;
}, {}));
schema.hasCompetencesOpt = new fields.BooleanField({initial: false})
schema.competencesOptNumber = new fields.NumberField({ ...requiredInteger, initial: 1, min:0 })
schema.competencesOpt = new fields.SchemaField(Array.fromRange(14, 1).reduce((comps, i) => {
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: "" })
}); });
return comps; return comps;
}, {})); }, {}));
schema.questionnaire = new fields.SchemaField(Array.fromRange(4, 1).reduce((questions, i) => {
schema.questionnaire = new fields.SchemaField(Array.fromRange(8, 1).reduce((questions, i) => {
questions[`question${i}`] = new fields.SchemaField({ questions[`question${i}`] = new fields.SchemaField({
question: new fields.StringField({ required: true, blank: true, initial: "" }), question: new fields.StringField({ required: true, blank: true, initial: "" }),
reponses: new fields.SchemaField( Array.fromRange(6, 1).reduce((resp, i) => { reponses: new fields.SchemaField( Array.fromRange(6, 1).reduce((resp, i) => {
resp[`reponse${i}`] = new fields.SchemaField({ resp[`reponse${i}`] = new fields.SchemaField({
num: new fields.NumberField({ ...requiredInteger, initial: i, min:i }), num: new fields.NumberField({ ...requiredInteger, initial: i, min:i }),
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 }),
compList: new fields.SchemaField(Array.fromRange(10, 1).reduce((comps, i) => {
comps[`comp${i}`] = new fields.SchemaField({
compName: new fields.StringField({ required: true, blank: true, initial: "" }),
});
return comps;
}, {}))
}); });
return resp; return resp;
}, {})) }, {}))
}); });
return questions; return questions;
}, {})); }, {}));
schema.debouches = new fields.SchemaField(Array.fromRange(24, 1).reduce((debouches, i) => {
debouches[`debouche${i}`] = new fields.SchemaField({
debouche: new fields.StringField({ required: true, blank: true, initial: "" })
})
return debouches;
}, {}));
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.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: "" });
return schema; return schema;
} }

View File

@ -0,0 +1,18 @@
export class TeDeumMaladieSchema extends foundry.abstract.TypeDataModel {
static defineSchema() {
const fields = foundry.data.fields;
const requiredInteger = { required: true, nullable: false, integer: true };
const schema = {};
schema.transmission = new fields.HTMLField({ required: true, blank: true });
schema.difficulteEndurance = new fields.StringField({required:true, initial:"routine"});
schema.virulence = new fields.StringField({required: true, choices: ["fatigue", "epuisement", "souffrance", "agonie"], initial: "fatigue"});
schema.fievre = new fields.StringField({required: true, choices: ["aucune", "legere", "forte", "grave"], initial: "aucune"});
schema.symptomes = new fields.HTMLField({ required: true, blank: true });
schema.appliquee = new fields.BooleanField({initial: false}),
schema.description = new fields.HTMLField({ required: true, blank: true });
return schema;
}
}

View File

@ -23,7 +23,9 @@ export class TeDeumPJSchema extends foundry.abstract.TypeDataModel {
schema.localisation = new fields.SchemaField( schema.localisation = new fields.SchemaField(
Object.values(game.system.tedeum.config.LOCALISATION).reduce((obj, loc) => { Object.values(game.system.tedeum.config.LOCALISATION).reduce((obj, loc) => {
obj[loc.id] =new fields.SchemaField({ obj[loc.id] = new fields.SchemaField({
armure: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0, max: 20 }),
touche: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0, max: 20 }),
blessures: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0, max: 20 }) blessures: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0, max: 20 })
}); });
return obj; return obj;
@ -31,7 +33,7 @@ export class TeDeumPJSchema extends foundry.abstract.TypeDataModel {
); );
schema.fortune = new fields.SchemaField({ schema.fortune = new fields.SchemaField({
"ecu": 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 })
@ -39,13 +41,17 @@ export class TeDeumPJSchema extends foundry.abstract.TypeDataModel {
schema.description = new fields.HTMLField({required: true, blank: true}); schema.description = 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.vetements = new fields.HTMLField({required: true, blank: true}); schema.vetements = new fields.HTMLField({required: true, blank: true});
//schema.descriptiongraces = new fields.HTMLField({required: true, blank: true}); schema.equipmentfree = new fields.HTMLField({required: true, blank: true});
schema.genre = new fields.StringField({required: true, choices: ["Homme", "Femme"], 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: undefined });
schema.statutocial = new fields.StringField({ required: false, blank: true, initial: undefined }); schema.statutocial = new fields.StringField({ required: false, blank: true, initial: undefined });
schema.chargestitre = new fields.StringField({ required: false, blank: true, initial: undefined }); schema.chargestitre = new fields.StringField({ required: false, blank: true, initial: undefined });
schema.charges = new fields.StringField({ required: false, blank: true, initial: undefined }); schema.charges = new fields.StringField({ required: false, blank: true, initial: undefined });
schema.religion = new fields.StringField({ required: false, blank: true, initial: undefined });
schema.lieunaissance = new fields.StringField({ required: false, blank: true, initial: undefined });
return schema; return schema;
} }

View File

@ -0,0 +1,20 @@
export class TeDeumMaladieSchema extends foundry.abstract.TypeDataModel {
static defineSchema() {
const fields = foundry.data.fields;
const requiredInteger = { required: true, nullable: false, integer: true };
const schema = {};
schema.difficulteEndurance = new fields.StringField({required:true, initial:"aucun"});
schema.virulence = new fields.StringField({required: true, choices: ["nausee", "inflammation", "elancement", "convulsion", "mort"], initial: "aucune"});
schema.vertus = new fields.HTMLField({ required: true, blank: true });
schema.toxicite = new fields.HTMLField({ required: true, blank: true });
schema.appliquee = new fields.BooleanField({initial: false}),
schema.prix = new fields.NumberField({ ...requiredDouble, initial: 0, min: 0 });
schema.monnaie = new fields.StringField({ required: true, blank: false, initial: "denier" });
schema.description = new fields.HTMLField({ required: true, blank: true });
return schema;
}
}

View File

@ -69,6 +69,18 @@ export class TeDeumRollDialog extends Dialog {
html.find('#roll-enable-providence').change((event) => { html.find('#roll-enable-providence').change((event) => {
this.rollData.enableProvidence = event.currentTarget.checked this.rollData.enableProvidence = event.currentTarget.checked
}) })
html.find('#roll-portee-tir').change((event) => {
this.rollData.porteeTir = event.currentTarget.value
this.rollData.difficulty = game.system.tedeum.config.ARME_PORTEES[this.rollData.porteeTir].difficulty
this.rollData.porteeLabel = game.system.tedeum.config.ARME_PORTEES[this.rollData.porteeTir].label
})
html.find('#roll-tir-viser').change((event) => {
this.rollData.isViser = event.currentTarget.checked
})
html.find('#roll-tir-mouvement').change((event) => {
this.rollData.isMouvement = event.currentTarget.checked
})
} }

View File

@ -8,7 +8,7 @@ export class TeDeumItemSheet extends ItemSheet {
/** @override */ /** @override */
static get defaultOptions() { static get defaultOptions() {
return mergeObject(super.defaultOptions, { return foundry.utils.mergeObject(super.defaultOptions, {
classes: ["fvtt-te-deum", "sheet", "item"], classes: ["fvtt-te-deum", "sheet", "item"],
template: "systems/fvtt-te-deum/templates/item-sheet.hbs", template: "systems/fvtt-te-deum/templates/item-sheet.hbs",
dragDrop: [{ dragSelector: null, dropSelector: null }], dragDrop: [{ dragSelector: null, dropSelector: null }],
@ -43,8 +43,8 @@ export class TeDeumItemSheet extends ItemSheet {
name: this.object.name, name: this.object.name,
editable: this.isEditable, editable: this.isEditable,
cssClass: this.isEditable ? "editable" : "locked", cssClass: this.isEditable ? "editable" : "locked",
system: duplicate(this.object.system), system: foundry.utils.duplicate(this.object.system),
config: duplicate(game.system.tedeum.config), config: foundry.utils.duplicate(game.system.tedeum.config),
competences: TeDeumUtility.getCompetencesForDropDown(), competences: TeDeumUtility.getCompetencesForDropDown(),
limited: this.object.limited, limited: this.object.limited,
options: this.options, options: this.options,

View File

@ -7,6 +7,9 @@ export const defaultItemImg = {
competence: "systems/fvtt-te-deum/images/icons/competence.webp", competence: "systems/fvtt-te-deum/images/icons/competence.webp",
education: "systems/fvtt-te-deum/images/icons/education.webp", education: "systems/fvtt-te-deum/images/icons/education.webp",
grace: "systems/fvtt-te-deum/images/icons/grace.webp", grace: "systems/fvtt-te-deum/images/icons/grace.webp",
blessure: "systems/fvtt-te-deum/images/icons/blessure.webp",
maladie: "systems/fvtt-te-deum/images/icons/maladie.webp",
simple: "systems/fvtt-te-deum/images/icons/simple.webp",
} }
/** /**

View File

@ -19,12 +19,15 @@ import { TeDeumEquipementSchema } from "./data/tedeum-schema-equipement.js";
import { TeDeumOrigineSchema } from "./data/tedeum-schema-origine.js"; import { TeDeumOrigineSchema } from "./data/tedeum-schema-origine.js";
import { TeDeumEducationSchema } from "./data/tedeum-schema-education.js"; import { TeDeumEducationSchema } from "./data/tedeum-schema-education.js";
import { TeDeumGraceSchema } from "./data/tedeum-schema-grace.js"; import { TeDeumGraceSchema } from "./data/tedeum-schema-grace.js";
import { TeDeumBlessureSchema } from "./data/tedeum-schema-blessure.js";
import { TeDeumMaladieSchema } from "./data/tedeum-schema-maladie.js";
import { TeDeumItem } from "./items/tedeum-item.js"; import { TeDeumItem } from "./items/tedeum-item.js";
import { TeDeumItemSheet } from "./items/tedeum-item-sheet.js"; import { TeDeumItemSheet } from "./items/tedeum-item-sheet.js";
import { TeDeumHotbar } from "./app/tedeum-hotbar.js" import { TeDeumHotbar } from "./app/tedeum-hotbar.js"
import { TeDeumCombat } from "./app/tedeum-combat.js"; import { TeDeumCombat } from "./app/tedeum-combat.js";
import { TeDeumCharacterCreator } from "./app/tedeum-character-creator.js"
import { TeDeumUtility } from "./common/tedeum-utility.js"; import { TeDeumUtility } from "./common/tedeum-utility.js";
import { TEDEUM_CONFIG } from "./common/tedeum-config.js"; import { TEDEUM_CONFIG } from "./common/tedeum-config.js";
@ -40,6 +43,7 @@ Hooks.once("init", async function () {
game.system.tedeum = { game.system.tedeum = {
config: TEDEUM_CONFIG, config: TEDEUM_CONFIG,
TeDeumCharacterCreator,
TeDeumHotbar TeDeumHotbar
} }
console.log(`Initializing TeDeum RPG 2`); console.log(`Initializing TeDeum RPG 2`);
@ -57,7 +61,7 @@ Hooks.once("init", async function () {
TeDeumUtility.onSocketMesssage(data) TeDeumUtility.onSocketMesssage(data)
}); });
//CONFIG.Combat.documentClass = TeDeumCombat CONFIG.Combat.documentClass = TeDeumCombat
CONFIG.Actor.documentClass = TeDeumActor; CONFIG.Actor.documentClass = TeDeumActor;
CONFIG.Item.documentClass = TeDeumItem CONFIG.Item.documentClass = TeDeumItem
CONFIG.Actor.dataModels = { CONFIG.Actor.dataModels = {
@ -71,7 +75,9 @@ Hooks.once("init", async function () {
armure: TeDeumArmureSchema, armure: TeDeumArmureSchema,
origine: TeDeumOrigineSchema, origine: TeDeumOrigineSchema,
education: TeDeumEducationSchema, education: TeDeumEducationSchema,
grace: TeDeumGraceSchema grace: TeDeumGraceSchema,
blessure: TeDeumBlessureSchema,
maladie: TeDeumMaladieSchema,
}; };
console.log("TeDeum RPG | Ready"); console.log("TeDeum RPG | Ready");
@ -86,16 +92,6 @@ Hooks.once("init", async function () {
TeDeumUtility.init() TeDeumUtility.init()
}); });
/* -------------------------------------------- */
function welcomeMessage() {
if (game.user.isGM) {
ChatMessage.create({
user: game.user.id,
whisper: [game.user.id],
content: `<div id="welcome-message-tedeum"><span class="rdd-roll-part">
<strong>Bienvenu dans Te Deum Pour Un Massacre !</strong>` });
}
}
/* -------------------------------------------- */ /* -------------------------------------------- */
/* Foundry VTT Initialization */ /* Foundry VTT Initialization */
@ -119,7 +115,8 @@ Hooks.once("ready", function () {
) )
TeDeumUtility.ready(); TeDeumUtility.ready();
welcomeMessage(); TeDeumUtility.importDefaultScene()
TeDeumUtility.welcomeMessage();
}) })

BIN
packs/aides/000018.ldb Normal file

Binary file not shown.

1
packs/aides/CURRENT Normal file
View File

@ -0,0 +1 @@
MANIFEST-000039

8
packs/aides/LOG Normal file
View File

@ -0,0 +1,8 @@
2025/03/01-19:40:45.555874 7fe59dffb6c0 Recovering log #37
2025/03/01-19:40:45.565732 7fe59dffb6c0 Delete type=3 #35
2025/03/01-19:40:45.565785 7fe59dffb6c0 Delete type=0 #37
2025/03/01-19:41:57.321763 7fe59d7fa6c0 Level-0 table #42: started
2025/03/01-19:41:57.321801 7fe59d7fa6c0 Level-0 table #42: 0 bytes OK
2025/03/01-19:41:57.328249 7fe59d7fa6c0 Delete type=0 #40
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)
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)

8
packs/aides/LOG.old Normal file
View File

@ -0,0 +1,8 @@
2025/03/01-19:35:57.154413 7fe59e7fc6c0 Recovering log #33
2025/03/01-19:35:57.165621 7fe59e7fc6c0 Delete type=3 #31
2025/03/01-19:35:57.165677 7fe59e7fc6c0 Delete type=0 #33
2025/03/01-19:38:46.090031 7fe59d7fa6c0 Level-0 table #38: started
2025/03/01-19:38:46.090085 7fe59d7fa6c0 Level-0 table #38: 0 bytes OK
2025/03/01-19:38:46.096397 7fe59d7fa6c0 Delete type=0 #36
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)
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)

BIN
packs/aides/MANIFEST-000039 Normal file

Binary file not shown.

BIN
packs/armes/000080.ldb Normal file

Binary file not shown.

1
packs/armes/CURRENT Normal file
View File

@ -0,0 +1 @@
MANIFEST-000141

0
packs/armes/LOCK Normal file
View File

7
packs/armes/LOG Normal file
View File

@ -0,0 +1,7 @@
2025/03/01-19:40:45.461315 7fe59effd6c0 Recovering log #139
2025/03/01-19:40:45.471298 7fe59effd6c0 Delete type=3 #137
2025/03/01-19:40:45.471427 7fe59effd6c0 Delete type=0 #139
2025/03/01-19:41:57.262543 7fe59d7fa6c0 Level-0 table #144: started
2025/03/01-19:41:57.262603 7fe59d7fa6c0 Level-0 table #144: 0 bytes OK
2025/03/01-19:41:57.269401 7fe59d7fa6c0 Delete type=0 #142
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)

7
packs/armes/LOG.old Normal file
View File

@ -0,0 +1,7 @@
2025/03/01-19:35:57.054371 7fe59f7fe6c0 Recovering log #135
2025/03/01-19:35:57.064331 7fe59f7fe6c0 Delete type=3 #133
2025/03/01-19:35:57.064442 7fe59f7fe6c0 Delete type=0 #135
2025/03/01-19:38:46.045299 7fe59d7fa6c0 Level-0 table #140: started
2025/03/01-19:38:46.045318 7fe59d7fa6c0 Level-0 table #140: 0 bytes OK
2025/03/01-19:38:46.052039 7fe59d7fa6c0 Delete type=0 #138
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)

BIN
packs/armes/MANIFEST-000141 Normal file

Binary file not shown.

BIN
packs/armures/000080.ldb Normal file

Binary file not shown.

0
packs/armures/000143.log Normal file
View File

1
packs/armures/CURRENT Normal file
View File

@ -0,0 +1 @@
MANIFEST-000141

0
packs/armures/LOCK Normal file
View File

7
packs/armures/LOG Normal file
View File

@ -0,0 +1,7 @@
2025/03/01-19:40:45.474414 7fe59dffb6c0 Recovering log #139
2025/03/01-19:40:45.484515 7fe59dffb6c0 Delete type=3 #137
2025/03/01-19:40:45.484615 7fe59dffb6c0 Delete type=0 #139
2025/03/01-19:41:57.244110 7fe59d7fa6c0 Level-0 table #144: started
2025/03/01-19:41:57.244149 7fe59d7fa6c0 Level-0 table #144: 0 bytes OK
2025/03/01-19:41:57.250209 7fe59d7fa6c0 Delete type=0 #142
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)

7
packs/armures/LOG.old Normal file
View File

@ -0,0 +1,7 @@
2025/03/01-19:35:57.068105 7fe59e7fc6c0 Recovering log #135
2025/03/01-19:35:57.078819 7fe59e7fc6c0 Delete type=3 #133
2025/03/01-19:35:57.078913 7fe59e7fc6c0 Delete type=0 #135
2025/03/01-19:38:46.052161 7fe59d7fa6c0 Level-0 table #140: started
2025/03/01-19:38:46.052188 7fe59d7fa6c0 Level-0 table #140: 0 bytes OK
2025/03/01-19:38:46.058075 7fe59d7fa6c0 Delete type=0 #138
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)

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

View File

@ -1 +1 @@
MANIFEST-000097 MANIFEST-000138

View File

@ -1,8 +1,7 @@
2024/06/04-21:04:01.195163 7f1e64e006c0 Recovering log #94 2025/03/01-19:40:45.446777 7fe59f7fe6c0 Recovering log #136
2024/06/04-21:04:01.205547 7f1e64e006c0 Delete type=3 #92 2025/03/01-19:40:45.457998 7fe59f7fe6c0 Delete type=3 #134
2024/06/04-21:04:01.205638 7f1e64e006c0 Delete type=0 #94 2025/03/01-19:40:45.458083 7fe59f7fe6c0 Delete type=0 #136
2024/06/04-21:04:48.464146 7f1e5da006c0 Level-0 table #100: started 2025/03/01-19:41:57.250328 7fe59d7fa6c0 Level-0 table #141: started
2024/06/04-21:04:48.464176 7f1e5da006c0 Level-0 table #100: 0 bytes OK 2025/03/01-19:41:57.250355 7fe59d7fa6c0 Level-0 table #141: 0 bytes OK
2024/06/04-21:04:48.500422 7f1e5da006c0 Delete type=0 #98 2025/03/01-19:41:57.256324 7fe59d7fa6c0 Delete type=0 #139
2024/06/04-21:04:48.500602 7f1e5da006c0 Manual compaction at level-0 from '!folders!4OPhigzcPv46qbWW' @ 72057594037927935 : 1 .. '!items!zwC0H39ar5Pl1l92' @ 0 : 0; will stop at (end) 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)
2024/06/04-21:04:48.500619 7f1e5da006c0 Manual compaction at level-1 from '!folders!4OPhigzcPv46qbWW' @ 72057594037927935 : 1 .. '!items!zwC0H39ar5Pl1l92' @ 0 : 0; will stop at (end)

View File

@ -1,15 +1,7 @@
2024/06/02-20:22:04.658032 7f2f302006c0 Recovering log #90 2025/03/01-19:35:57.039829 7fe59dffb6c0 Recovering log #132
2024/06/02-20:22:04.712047 7f2f302006c0 Delete type=3 #88 2025/03/01-19:35:57.049894 7fe59dffb6c0 Delete type=3 #130
2024/06/02-20:22:04.712099 7f2f302006c0 Delete type=0 #90 2025/03/01-19:35:57.049949 7fe59dffb6c0 Delete type=0 #132
2024/06/02-20:58:31.396230 7f2f2ee006c0 Level-0 table #95: started 2025/03/01-19:38:46.032600 7fe59d7fa6c0 Level-0 table #137: started
2024/06/02-20:58:31.399756 7f2f2ee006c0 Level-0 table #95: 28482 bytes OK 2025/03/01-19:38:46.032653 7fe59d7fa6c0 Level-0 table #137: 0 bytes OK
2024/06/02-20:58:31.406774 7f2f2ee006c0 Delete type=0 #93 2025/03/01-19:38:46.038775 7fe59d7fa6c0 Delete type=0 #135
2024/06/02-20:58:31.406940 7f2f2ee006c0 Manual compaction at level-0 from '!folders!4OPhigzcPv46qbWW' @ 72057594037927935 : 1 .. '!items!zwC0H39ar5Pl1l92' @ 0 : 0; will stop at (end) 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)
2024/06/02-20:58:31.406967 7f2f2ee006c0 Manual compaction at level-1 from '!folders!4OPhigzcPv46qbWW' @ 72057594037927935 : 1 .. '!items!zwC0H39ar5Pl1l92' @ 0 : 0; will stop at '!items!zwC0H39ar5Pl1l92' @ 390 : 1
2024/06/02-20:58:31.406972 7f2f2ee006c0 Compacting 1@1 + 1@2 files
2024/06/02-20:58:31.410472 7f2f2ee006c0 Generated table #96@1: 113 keys, 15164 bytes
2024/06/02-20:58:31.410495 7f2f2ee006c0 Compacted 1@1 + 1@2 files => 15164 bytes
2024/06/02-20:58:31.416350 7f2f2ee006c0 compacted to: files[ 0 0 1 0 0 0 0 ]
2024/06/02-20:58:31.416439 7f2f2ee006c0 Delete type=2 #5
2024/06/02-20:58:31.416583 7f2f2ee006c0 Delete type=2 #95
2024/06/02-20:58:31.416682 7f2f2ee006c0 Manual compaction at level-1 from '!items!zwC0H39ar5Pl1l92' @ 390 : 1 .. '!items!zwC0H39ar5Pl1l92' @ 0 : 0; will stop at (end)

Binary file not shown.

Binary file not shown.

BIN
packs/education/000143.ldb Normal file

Binary file not shown.

View File

1
packs/education/CURRENT Normal file
View File

@ -0,0 +1 @@
MANIFEST-000148

0
packs/education/LOCK Normal file
View File

7
packs/education/LOG Normal file
View File

@ -0,0 +1,7 @@
2025/03/01-19:40:45.487407 7fe59e7fc6c0 Recovering log #146
2025/03/01-19:40:45.498701 7fe59e7fc6c0 Delete type=3 #144
2025/03/01-19:40:45.498803 7fe59e7fc6c0 Delete type=0 #146
2025/03/01-19:41:57.256411 7fe59d7fa6c0 Level-0 table #151: started
2025/03/01-19:41:57.256434 7fe59d7fa6c0 Level-0 table #151: 0 bytes OK
2025/03/01-19:41:57.262412 7fe59d7fa6c0 Delete type=0 #149
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)

7
packs/education/LOG.old Normal file
View File

@ -0,0 +1,7 @@
2025/03/01-19:35:57.082694 7fe59effd6c0 Recovering log #141
2025/03/01-19:35:57.093326 7fe59effd6c0 Delete type=3 #139
2025/03/01-19:35:57.093376 7fe59effd6c0 Delete type=0 #141
2025/03/01-19:38:46.038876 7fe59d7fa6c0 Level-0 table #147: started
2025/03/01-19:38:46.038898 7fe59d7fa6c0 Level-0 table #147: 0 bytes OK
2025/03/01-19:38:46.045195 7fe59d7fa6c0 Delete type=0 #145
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)

Binary file not shown.

View File

@ -1 +0,0 @@
MANIFEST-000158

View File

@ -1,7 +0,0 @@
2024/06/04-21:04:01.182320 7f1e5f4006c0 Recovering log #156
2024/06/04-21:04:01.193373 7f1e5f4006c0 Delete type=3 #154
2024/06/04-21:04:01.193473 7f1e5f4006c0 Delete type=0 #156
2024/06/04-21:04:48.422044 7f1e5da006c0 Level-0 table #161: started
2024/06/04-21:04:48.422074 7f1e5da006c0 Level-0 table #161: 0 bytes OK
2024/06/04-21:04:48.463998 7f1e5da006c0 Delete type=0 #159
2024/06/04-21:04:48.500588 7f1e5da006c0 Manual compaction at level-0 from 'undefined' @ 72057594037927935 : 1 .. 'undefined' @ 0 : 0; will stop at (end)

View File

@ -1,7 +0,0 @@
2024/06/02-20:22:04.602737 7f2f2f8006c0 Recovering log #152
2024/06/02-20:22:04.655957 7f2f2f8006c0 Delete type=3 #150
2024/06/02-20:22:04.656073 7f2f2f8006c0 Delete type=0 #152
2024/06/02-20:58:31.369733 7f2f2ee006c0 Level-0 table #157: started
2024/06/02-20:58:31.369760 7f2f2ee006c0 Level-0 table #157: 0 bytes OK
2024/06/02-20:58:31.376040 7f2f2ee006c0 Delete type=0 #155
2024/06/02-20:58:31.376155 7f2f2ee006c0 Manual compaction at level-0 from 'undefined' @ 72057594037927935 : 1 .. 'undefined' @ 0 : 0; will stop at (end)

Binary file not shown.

BIN
packs/graces/000009.ldb Normal file

Binary file not shown.

0
packs/graces/000142.log Normal file
View File

1
packs/graces/CURRENT Normal file
View File

@ -0,0 +1 @@
MANIFEST-000140

0
packs/graces/LOCK Normal file
View File

7
packs/graces/LOG Normal file
View File

@ -0,0 +1,7 @@
2025/03/01-19:40:45.502221 7fe59f7fe6c0 Recovering log #138
2025/03/01-19:40:45.511946 7fe59f7fe6c0 Delete type=3 #136
2025/03/01-19:40:45.512076 7fe59f7fe6c0 Delete type=0 #138
2025/03/01-19:41:57.282060 7fe59d7fa6c0 Level-0 table #143: started
2025/03/01-19:41:57.282084 7fe59d7fa6c0 Level-0 table #143: 0 bytes OK
2025/03/01-19:41:57.288122 7fe59d7fa6c0 Delete type=0 #141
2025/03/01-19:41:57.295100 7fe59d7fa6c0 Manual compaction at level-0 from '!items!17mjvwS8R3B6LloG' @ 72057594037927935 : 1 .. '!items!zUYIVOuFpRur9aAR' @ 0 : 0; will stop at (end)

7
packs/graces/LOG.old Normal file
View File

@ -0,0 +1,7 @@
2025/03/01-19:35:57.098663 7fe59dffb6c0 Recovering log #134
2025/03/01-19:35:57.108416 7fe59dffb6c0 Delete type=3 #132
2025/03/01-19:35:57.108524 7fe59dffb6c0 Delete type=0 #134
2025/03/01-19:38:46.058273 7fe59d7fa6c0 Level-0 table #139: started
2025/03/01-19:38:46.058294 7fe59d7fa6c0 Level-0 table #139: 0 bytes OK
2025/03/01-19:38:46.064281 7fe59d7fa6c0 Delete type=0 #137
2025/03/01-19:38:46.083204 7fe59d7fa6c0 Manual compaction at level-0 from '!items!17mjvwS8R3B6LloG' @ 72057594037927935 : 1 .. '!items!zUYIVOuFpRur9aAR' @ 0 : 0; will stop at (end)

Binary file not shown.

BIN
packs/maladies/000009.ldb Normal file

Binary file not shown.

View File

1
packs/maladies/CURRENT Normal file
View File

@ -0,0 +1 @@
MANIFEST-000140

0
packs/maladies/LOCK Normal file
View File

7
packs/maladies/LOG Normal file
View File

@ -0,0 +1,7 @@
2025/03/01-19:40:45.515906 7fe59effd6c0 Recovering log #138
2025/03/01-19:40:45.525965 7fe59effd6c0 Delete type=3 #136
2025/03/01-19:40:45.526045 7fe59effd6c0 Delete type=0 #138
2025/03/01-19:41:57.269782 7fe59d7fa6c0 Level-0 table #143: started
2025/03/01-19:41:57.269820 7fe59d7fa6c0 Level-0 table #143: 0 bytes OK
2025/03/01-19:41:57.275965 7fe59d7fa6c0 Delete type=0 #141
2025/03/01-19:41:57.295052 7fe59d7fa6c0 Manual compaction at level-0 from '!items!1icaxIywAwDXQcMz' @ 72057594037927935 : 1 .. '!items!ysGehYm1VkMWrI22' @ 0 : 0; will stop at (end)

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