Compare commits

...

32 Commits

Author SHA1 Message Date
3cbd777e6a Merge pull request '12.0.26 - Astrobazzarh le Haut-rêvant' (#728) from VincentVk/foundryvtt-reve-de-dragon:v11 into v11
Reviewed-on: public/foundryvtt-reve-de-dragon#728
2024-12-05 16:16:09 +01:00
b377739481 Meilleure détection des sorts (TMR spécifique) 2024-12-04 20:04:47 +01:00
d9cdfef688 Fix: échanges achat-vente "prendre"
simplification des tests de droits pour savoir si on transmet
l'appel de méthode à un MJ connecté.

De manière générale, si on est le owner: pas besoin d'appel remote.
Donc si MJ pas besoin.

Si on a un appel remote, seul un MJ le traite.
2024-12-04 18:55:34 +01:00
d9af32b168 Initialisation valeurs actuelles
Prise encompte de l'endutrance et vie actuelles
2024-12-04 15:55:59 +01:00
f13677106e Calculs des informations dérivées
Calcul automatique des informations dérivées:
- vie max
- endurance max
- bonus dommages

Ces informations ne peuvent plus être saisies.

L'endurance max des animaux est vie+constitution.
Les entités non-incarnées n'ont pas de +dom
2024-12-04 15:55:09 +01:00
e98a793506 Version 12.0.26 - Astrobazzarh le Haut-rêvant
- Changelog
- changement des versions dans system pour test de migration
2024-12-04 01:49:39 +01:00
57d35a0f9a Fix: sorts contenant des apostrophes
Le caractère utilisé dans le texte n'est pas l'apostrophe simple
informatique (utilisé dans les compendiums), et pas transformé
par toLowerCaseNoAccent...
2024-12-04 01:43:44 +01:00
417db33752 Parser: demi-rêve/valeurs actuelles/remise à neuf 2024-12-04 01:09:57 +01:00
bf0eea693a Migration draconic
Utilisation des noms de compétences draconiques standard
2024-12-04 01:09:22 +01:00
28ee8607bb Fix feuille simplifiée case TMR
Cases spéciales des TMRs mal gérée...
2024-12-04 01:09:22 +01:00
91717a3290 Bouton "don de haut-rêve"
Pour permettre au MJ de rendre un personnage haut rêvant
sans avoir à chercher dans les compendiums
2024-12-04 01:09:22 +01:00
39ce66a26c Setup auto-publish action 2024-12-03 14:30:18 +01:00
5265c013c1 Setup auto-publish action 2024-12-03 14:15:43 +01:00
a03cee5d60 Setup auto-publish action 2024-12-03 14:12:19 +01:00
296c4babbb Setup auto-publish action 2024-12-03 14:09:32 +01:00
d9c1804a08 Merge pull request 'Imports créatures et entités de cauchemar' (#727) from VincentVk/foundryvtt-reve-de-dragon:v11 into v11
Reviewed-on: public/foundryvtt-reve-de-dragon#727
2024-12-03 07:31:22 +01:00
fa375f8092 Améliorations parser
- armure équipée
- armes équipées
- ajout des bonus de cases
- dommages des créatures
- ajout des esquives spéciales
- fix édition feuilles de compétences créatures

- déplacement des valeurs de test en fin de fichier
2024-12-03 00:50:39 +01:00
a27e3894a0 Fix Import entités de cauchemar&créatures
- utiliser les carac liées au type d'entités
- fix: +dom&protection 0 ou négatifs
- fix compétences (qui peuvent ne pas avoir d'init)
2024-12-02 22:21:43 +01:00
ce8616c34e Merge compétences créatures/entités
Les deux compendiums n'avaient pas de raison d'être séparés
2024-12-02 22:21:43 +01:00
bbfac286a6 Amelioration parser : heures, cheveux, yeux et sorts 2024-12-01 14:22:40 +01:00
c0563efcfa Merge pull request 'Amélioration du parser' (#725) from VincentVk/foundryvtt-reve-de-dragon:v11 into v11
Reviewed-on: public/foundryvtt-reve-de-dragon#725
2024-12-01 12:38:50 +01:00
c481bad81a Amélioration du parser:
- correction de la taille (ne prennait que avant le 'm'
- ajout du sexe masculin/féminin
- correction heure de naissance (support heure composée, articles)
- support Unicode (nom, HN)
- support groupes de compétences (saut, danse +1)
- ignorer parenthèses dans ccompétences
- armes avec compétences accentuées
2024-11-30 22:32:00 +01:00
37c281b300 Merge pull request 'Version 12.0.24' (#724) from VincentVk/foundryvtt-reve-de-dragon:v11 into v11
Reviewed-on: public/foundryvtt-reve-de-dragon#724
2024-11-30 12:48:20 +01:00
9b1a179a71 Corrections voies draconic
- Utilisation du nom de voie (Oniros au lieu de Voie d'Oniros)
- compatible anciens sorts
- migration des objets existants
- amélioration de l'affichage de la liste des sorts
2024-11-30 00:08:20 +01:00
8be4c3343f Fix: les tas de conteneurs 2024-11-30 00:07:52 +01:00
6af5a85dc1 Corrections des tirages tmr/rencontres
- on n'affiche plus le compendium d'origine des rencontres dans le tchat
- utilisation de ChatMessageData#rolls (compat future v14)
- le résultat d'un d100 n'a pas à afficher de signe '%'
- utilistaion des types de TMR plutôt que les noms en minuscules
2024-11-30 00:07:52 +01:00
c6d64e09d5 Fix: saisie des bonus de cases 2024-11-30 00:07:48 +01:00
56c99c5044 Change zip file path 2024-11-27 10:13:54 +01:00
a7862a25e5 Change zip file path 2024-11-27 10:13:16 +01:00
f4b5a4a4d2 Merge pull request 'Version 12.0.23 - La bibliothèque d'Astrobazzarh' (#723) from VincentVk/foundryvtt-reve-de-dragon:v11 into v11
Reviewed-on: public/foundryvtt-reve-de-dragon#723
2024-11-27 10:12:25 +01:00
6a17586a6c Changelog 12.0.23 2024-11-26 23:55:52 +01:00
40f7ef48c9 Lettre accentuées
Utilisation des majuscules Écriture, Épée
pour exports scriptariums
2024-11-26 23:42:38 +01:00
141 changed files with 1543 additions and 1322 deletions

View File

@ -27,8 +27,8 @@ jobs:
env:
version: ${{steps.get_version.outputs.version-without-v}}
url: https://www.uberwald.me/gitea/${{gitea.repository}}
manifest: https://www.uberwald.me/gitea/${{gitea.repository}}/releases/download//${{github.event.release.tag_name}}/system.json
download: https://www.uberwald.me/gitea/${{gitea.repository}}/releases/download/${{github.event.release.tag_name}}/foundryvtt-reve-de-dragon-${{github.event.release.tag_name}}.zip
manifest: https://www.uberwald.me/gitea/${{gitea.repository}}/releases/download/${{github.event.release.tag_name}}/system.json
download: https://www.uberwald.me/gitea/${{gitea.repository}}/releases/download/${{github.event.release.tag_name}}/rddsystem.zip
- name: Set up Node.js
uses: actions/setup-node@v2
@ -46,7 +46,7 @@ jobs:
apt update -y
apt install -y zip
- run: zip -r ./foundryvtt-reve-de-dragon-${{github.event.release.tag_name}}.zip system.json template.json README.md LICENSE.txt assets/ fonts/ icons lang/ module/ packs/ pic/ sounds/ styles/ templates/
- run: zip -r ./rddsystem.zip system.json template.json README.md LICENSE.txt assets/ fonts/ icons lang/ module/ packs/ pic/ sounds/ styles/ templates/
- name: setup go
uses: actions/setup-go@v3
@ -58,6 +58,17 @@ jobs:
uses: https://gitea.com/actions/release-action@main
with:
files: |-
./foundryvtt-reve-de-dragon-${{github.event.release.tag_name}}.zip
./rddsystem.zip
system.json
api_key: '${{secrets.ALLOW_PUSH_RELEASE}}'
- name: Publish to Foundry server
uses: djlechuck/foundryvtt-publish-package-action@v1
with:
token: ${{ secrets.FOUNDRYVTT_RELEASE_TOKEN }}
id: 'foundryvtt-reve-de-dragon'
version: ${{github.event.release.tag_name}}
manifest: 'https://www.uberwald.me/gitea/${{gitea.repository}}/releases/download/${{github.event.release.tag_name}}/system.json'
notes: 'https://www.uberwald.me/gitea/public/foundryvtt-reve-de-dragon/raw/branch/v11/changelog.md'
compatibility-minimum: '12'
compatibility-verified: '12'

View File

@ -1,4 +1,34 @@
# 12.0
## 12.0.26 - Astrobazzarh le Haut-rêvant
- bouton pour le don de haut-rêve en un clic
- les compétences de draconic ne sont plus précédées de "Voie de"
- migration des compétences & compendiums
- Correction feuille simplifiée qui ne s'affichait pas en ccas de sort variable
## 12.0.24 - Les ajustements d'Astrobazzarh
- amélioration
- meilleure gestion des noms des voies de draconic
- affichage du détail des sorts avec le nom de voie, 'court', la difficulté, le coût
- corrections
- les tas dans les conteneurs peuvent être désempilés sans rendre le conteneur inutilisable
- les conteneurs ne peuvent plus être empilés (pour éviter que le contenu de Schroedinger quand on les sépare)
- on peut maintenant saisir et supprimer les bonus de cases de manière intuitive
## 12.0.23 - La bibliothèque d'Astrobazzarh
- corrections mineures
- meilleure gestion de la parade des armes naturelles
- cas de "User lacks permission to update" pour les blessures et les StatusEffects
- risque de message d'encaissement non affiché
- support de sorts à voies multiples
- correction de compendiums
- résistance des armes mise à jour
- voies multiples pour las sorts de Lecture d'aura, Détection d'aura et Annulation de magie
- améliorations "Scriptarium"
- recherche des compétences sans accents pour permettre les noms accentués (standard Scriptarium)
- affichage r1+ des sorts à coût variable dans la feuille simplifiée
- affichage de Corps à corps pour le combat à mains nues dans la feuille simplifiée
- dans les compendiums, les compétences Écriture et Épée ont une majuscule accentuée. Les Épée dans le compendium d'équipements référence le nom de compétence accentué.
## 12.0.21 - La nomination d'Astrobazzarh
- Les noms pour les messages dans le tchat sont maintenant ceux des tokens plutôt que ceux des acteurs
- Fix: le choix des effets dans les options s'affiche correctement

View File

@ -214,6 +214,8 @@ export class RdDActorSheet extends RdDBaseActorSangSheet {
});
// Boutons spéciaux MJs
this.html.find('.forcer-tmr-aleatoire').click(async event => this.actor.reinsertionAleatoire("Action MJ"))
this.html.find('.don-de-haut-reve').click(async event => this.actor.addDonDeHautReve())
this.html.find('.afficher-tmr').click(async event => this.actor.changeTMRVisible())
}

View File

@ -38,6 +38,8 @@ import { RdDCoeur } from "./coeur/rdd-coeur.js";
import { DialogChoixXpCarac } from "./dialog-choix-xp-carac.js";
import { RdDItemArme } from "./item-arme.js";
import { RdDCombatManager } from "./rdd-combat.js";
import { RdDItemTete } from "./item/tete.js";
import { SystemCompendiums } from "./settings/system-compendiums.js";
export const MAINS_DIRECTRICES = ['Droitier', 'Gaucher', 'Ambidextre']
@ -53,41 +55,27 @@ export class RdDActor extends RdDBaseActorSang {
* Prepare Character type specific data
*/
prepareActorData() {
this.$computeCaracDerivee()
this.$computeIsHautRevant()
}
/* -------------------------------------------- */
$computeCaracDerivee() {
this.system.carac.force.value = Math.min(this.system.carac.force.value, parseInt(this.system.carac.taille.value) + 4);
this.system.carac.melee.value = Math.floor((parseInt(this.system.carac.force.value) + parseInt(this.system.carac.agilite.value)) / 2);
this.system.carac.melee.value = Math.floor((this.getForce() + parseInt(this.system.carac.agilite.value)) / 2);
this.system.carac.tir.value = Math.floor((parseInt(this.system.carac.vue.value) + parseInt(this.system.carac.dexterite.value)) / 2);
this.system.carac.lancer.value = Math.floor((parseInt(this.system.carac.tir.value) + parseInt(this.system.carac.force.value)) / 2);
this.system.carac.derobee.value = Math.floor(parseInt(((21 - this.system.carac.taille.value)) + parseInt(this.system.carac.agilite.value)) / 2);
let bonusDomKey = Math.floor((parseInt(this.system.carac.force.value) + parseInt(this.system.carac.taille.value)) / 2);
let tailleData = RdDCarac.getCaracDerivee(bonusDomKey);
this.system.attributs.plusdom.value = tailleData.plusdom;
this.system.attributs.encombrement.value = (parseInt(this.system.carac.force.value) + parseInt(this.system.carac.taille.value)) / 2;
super.prepareActorData()
this.system.attributs.sconst.value = RdDCarac.calculSConst(this.system.carac.constitution.value);
this.system.attributs.sust.value = RdDCarac.getCaracDerivee(this.system.carac.taille.value).sust;
this.system.sante.vie.max = Math.ceil((parseInt(this.system.carac.taille.value) + parseInt(this.system.carac.constitution.value)) / 2);
this.system.attributs.sconst.value = RdDCarac.calculSConst(this.getConstitution())
this.system.attributs.sust.value = RdDCarac.getCaracDerivee(this.getTaille()).sust
this.system.sante.vie.value = Math.min(this.system.sante.vie.value, this.system.sante.vie.max)
this.system.sante.endurance.max = Math.max(parseInt(this.system.carac.taille.value) + parseInt(this.system.carac.constitution.value), parseInt(this.system.sante.vie.max) + parseInt(this.system.carac.volonte.value));
this.system.sante.endurance.value = Math.min(this.system.sante.endurance.value, this.system.sante.endurance.max);
this.system.sante.fatigue.max = this.getFatigueMax();
this.system.sante.fatigue.max = this.getFatigueMax()
this.system.sante.fatigue.value = Math.min(this.system.sante.fatigue.value, this.system.sante.fatigue.max);
//Compteurs
this.system.reve.reve.max = this.system.carac.reve.value;
this.system.compteurs.chance.max = this.system.carac.chance.value;
}
this.system.reve.reve.max = 3 * this.getReve()
this.system.compteurs.chance.max = this.getChance()
$computeIsHautRevant() {
this.system.attributs.hautrevant.value = this.itemTypes['tete'].find(it => Grammar.equalsInsensitive(it.name, 'don de haut-reve'))
this.system.attributs.hautrevant.value = this.itemTypes[ITEM_TYPES.tete].find(it => RdDItemTete.isDonDeHautReve(it))
? "Haut rêvant"
: "";
}
@ -112,6 +100,8 @@ export class RdDActor extends RdDBaseActorSang {
getChanceActuel() { return this.system.compteurs.chance?.value ?? 10 }
getMoralTotal() { return this.system.compteurs.moral?.value ?? 0 }
getEnduranceMax() { return Math.max(1, Math.max(this.getTaille() + this.getConstitution(), this.getVieMax() + this.getVolonte())) }
/* -------------------------------------------- */
getEtatGeneral(options = { ethylisme: false }) {
const etatGeneral = this.system.compteurs.etat?.value ?? 0
@ -989,6 +979,16 @@ export class RdDActor extends RdDBaseActorSang {
});
}
/* -------------------------------------------- */
async addDonDeHautReve() {
if (!game.user.isGM || this.isHautRevant()) {
return
}
const donHR = await RdDItemTete.teteDonDeHautReve()
if (donHR) {
this.createEmbeddedDocuments('Item', [donHR.toObject()])
}
}
/* -------------------------------------------- */
async reinsertionAleatoire(raison, accessible = tmr => true) {
@ -1083,9 +1083,7 @@ export class RdDActor extends RdDBaseActorSang {
}
/* -------------------------------------------- */
getSConst() {
return RdDCarac.calculSConst(this.system.carac.constitution.value)
}
getSConst() { return RdDCarac.calculSConst(this.getConstitution()) }
async ajoutXpConstitution(xp) {
await this.update({ "system.carac.constitution.xp": Misc.toInt(this.system.carac.constitution.xp) + xp });
@ -1237,16 +1235,14 @@ export class RdDActor extends RdDBaseActorSang {
}
/* -------------------------------------------- */
async consommerNourritureboisson(itemId, choix = { doses: 1, seForcer: false, supprimerSiZero: false }, userId = undefined) {
if (userId != undefined && userId != game.user.id) {
async consommerNourritureboisson(itemId, choix = { doses: 1, seForcer: false, supprimerSiZero: false }) {
if (!this.isOwner) {
RdDBaseActor.remoteActorCall({
tokenId: this.token?.id,
actorId: this.id,
method: 'consommerNourritureboisson',
args: [itemId, choix, userId]
},
userId)
return;
method: 'consommerNourritureboisson', args: [itemId, choix]
})
return
}
const item = this.getItem(itemId)
if (!item.getUtilisationCuisine()) {
@ -2521,7 +2517,11 @@ export class RdDActor extends RdDBaseActorSang {
async onRollTachePremiersSoins(blessureId, rollData) {
if (!this.isOwner) {
return RdDBaseActor.remoteActorCall({ tokenId: this.token?.id, actorId: this.id, method: 'onRollTachePremiersSoins', args: [blessureId, rollData] });
return RdDBaseActor.remoteActorCall({
tokenId: this.token?.id,
actorId: this.id,
method: 'onRollTachePremiersSoins', args: [blessureId, rollData]
})
}
const blessure = this.getItem(blessureId, 'blessure')
console.log('TODO update blessure', this, blessureId, rollData, rollData.tache);
@ -2551,7 +2551,11 @@ export class RdDActor extends RdDBaseActorSang {
async onRollSoinsComplets(blessureId, rollData) {
if (!this.isOwner) {
return RdDBaseActor.remoteActorCall({ tokenId: this.token?.id, actorId: this.id, method: 'onRollSoinsComplets', args: [blessureId, rollData] });
return RdDBaseActor.remoteActorCall({
tokenId: this.token?.id,
actorId: this.id,
method: 'onRollSoinsComplets', args: [blessureId, rollData]
})
}
const blessure = this.getItem(blessureId, 'blessure')
if (blessure && blessure.system.premierssoins.done && !blessure.system.soinscomplets.done) {
@ -3017,15 +3021,16 @@ export class RdDActor extends RdDBaseActorSang {
case 'queue':
case 'ombre':
case 'souffle':
await this.onDeleteOwnedDraconique(item, options, id);
break;
await this.onDeleteOwnedDraconique(item, options, id)
break
case 'casetmr':
await this.onDeleteOwnedCaseTmr(item, options, id);
break;
await this.onDeleteOwnedCaseTmr(item, options, id)
break
case 'empoignade':
await RdDEmpoignade.deleteLinkedEmpoignade(this.id, item)
break;
break
}
super.onDeleteItem(item, options, id)
}
/* -------------------------------------------- */

View File

@ -19,6 +19,7 @@ import { RdDCombat, RdDCombatManager } from "../rdd-combat.js";
import { RdDConfirm } from "../rdd-confirm.js";
import { ENTITE_INCARNE, SHOW_DICE, SYSTEM_RDD } from "../constants.js";
import { RdDItemArme } from "../item-arme.js";
import { RdDCarac } from "../rdd-carac.js";
const POSSESSION_SANS_DRACONIC = {
img: 'systems/foundryvtt-reve-de-dragon/icons/entites/possession.webp',
@ -36,6 +37,13 @@ const POSSESSION_SANS_DRACONIC = {
*/
export class RdDBaseActorReve extends RdDBaseActor {
prepareActorData() {
super.prepareActorData()
this.system.attributs.plusdom.value = this.getBonusDegat()
this.system.sante.endurance.max = this.getEnduranceMax()
this.system.sante.endurance.value = Math.min(this.system.sante.endurance.value, this.system.sante.endurance.max)
}
getCaracChanceActuelle() {
return {
label: 'Chance actuelle',
@ -52,21 +60,26 @@ export class RdDBaseActorReve extends RdDBaseActor {
};
}
getTaille() { return Misc.toInt(this.system.carac.taille?.value) }
getConstitution() { return this.getReve() }
getForce() { return this.getReve() }
getAgilite() { return this.getForce() }
getReve() { return Misc.toInt(this.system.carac.reve?.value) }
getChance() { return this.getReve() }
getReveActuel() { return this.getReve() }
getChanceActuel() { return this.getChance() }
getReve() { return Number(this.system.carac.reve?.value ?? 0) }
getForce() { return this.getReve() }
getTaille() { return Number(this.system.carac.taille?.value ?? 0) }
getAgilite() { return this.getForce() }
getChance() { return this.getReve() }
getEnduranceMax() { return Math.max(1, this.getTaille() + this.getConstitution()) }
getEncombrementMax() { return (this.getForce() + this.getTaille()) / 2 }
getBonusDegat() { return RdDCarac.getCaracDerivee(this.getEncombrementMax()).plusdom }
getMoralTotal() { return 0 }
getBonusDegat() { return Number(this.system.attributs?.plusdom?.value ?? 0) }
getProtectionNaturelle() { return Number(this.system.attributs?.protection?.value ?? 0) }
getSConst() { return 0 }
/* -------------------------------------------- */
getEncombrementMax() { return 0 }
isSurenc() { return false }
computeMalusSurEncombrement() { return 0 }
@ -84,7 +97,7 @@ export class RdDBaseActorReve extends RdDBaseActor {
isActorCombat() { return true }
getCaracInit(competence) {
if (!competence){
if (!competence) {
return 0
}
if (competence.type == ITEM_TYPES.competencecreature) {
@ -445,8 +458,7 @@ export class RdDBaseActorReve extends RdDBaseActor {
RdDBaseActor.remoteActorCall({
tokenId: this.token?.id,
actorId: this.id,
method: 'encaisserDommagesValidationGR',
args: [rollData, armure, show, attackerToken, defenderToken]
method: 'encaisserDommagesValidationGR', args: [rollData, armure, show, attackerToken, defenderToken]
})
} else {
DialogValidationEncaissement.validerEncaissement(this, rollData, armure,

View File

@ -6,6 +6,7 @@ import { RdDBaseActorReve } from "./base-actor-reve.js";
import { RdDDice } from "../rdd-dice.js";
import { RdDItemBlessure } from "../item/blessure.js";
import { ChatUtility } from "../chat-utility.js";
import { Misc } from "../misc.js";
/**
* Classe de base pour les acteurs qui peuvent subir des blessures
@ -14,25 +15,32 @@ import { ChatUtility } from "../chat-utility.js";
*/
export class RdDBaseActorSang extends RdDBaseActorReve {
prepareActorData() {
this.system.sante.vie.max = Math.ceil((this.getTaille() + this.getConstitution()) / 2)
this.system.sante.vie.value = Math.min(this.system.sante.vie.value, this.system.sante.vie.max)
super.prepareActorData()
this.system.attributs.encombrement.value = this.getEncombrementMax()
}
getForce() { return Number(this.system.carac.force?.value ?? 0) }
getForce() { return Misc.toInt(this.system.carac.force?.value) }
getConstitution() { return Misc.toInt(this.system.carac.constitution?.value) }
getVolonte() { return Misc.toInt(this.system.carac.volonte?.value) }
getBonusDegat() { return Number(this.system.attributs?.plusdom?.value ?? 0) }
getProtectionNaturelle() { return Number(this.system.attributs?.protection?.value ?? 0) }
getSConst() { return 0 }
getVieMax() { return Misc.toInt(this.system.sante.vie?.max) }
getEnduranceMax() { return Math.max(1, this.getTaille() + this.getConstitution()) }
getFatigueMax() { return this.getEnduranceMax() * 2 }
getEnduranceMax() { return Math.max(1, Math.min(this.system.sante.endurance.max, MAX_ENDURANCE_FATIGUE)) }
getProtectionNaturelle() { return Misc.toInt(this.system.attributs?.protection?.value) }
getFatigueActuelle() {
if (ReglesOptionnelles.isUsing("appliquer-fatigue")) {
return Math.max(0, Math.min(this.getFatigueMax(), this.system.sante.fatigue?.value ?? 0));
return Math.max(0, Math.min(this.getFatigueMax(), Misc.toInt(this.system.sante.fatigue?.value)))
}
return 0;
}
getFatigueRestante() { return this.getFatigueMax() - this.getFatigueActuelle() }
getFatigueMin() { return this.system.sante.endurance.max - this.system.sante.endurance.value }
getFatigueMax() { return this.getEnduranceMax() * 2 }
malusFatigue() {
if (ReglesOptionnelles.isUsing("appliquer-fatigue")) {
@ -42,7 +50,6 @@ export class RdDBaseActorSang extends RdDBaseActorReve {
}
/* -------------------------------------------- */
getEncombrementMax() { return Number(this.system.attributs?.encombrement?.value ?? 0) }
isSurenc() { return this.computeMalusSurEncombrement() < 0 }
computeMalusSurEncombrement() {

View File

@ -18,6 +18,7 @@ export class RdDBaseActor extends Actor {
.map(it => it[0])
.find(it => it)
}
static $findCaracByName(carac, name) {
const caracList = Object.entries(carac);
let entry = Misc.findFirstLike(name, caracList, { mapper: it => it[0], description: 'caractéristique' });
@ -26,6 +27,16 @@ export class RdDBaseActor extends Actor {
}
return entry && entry.length > 0 ? carac[entry[0]] : undefined;
}
static getDefaultValue(actorType, path) {
if (path.includes('.')) {
path = path.split('.')
}
let obj = game.model.Actor[actorType]
for (let p of path) {
obj = obj ? obj[p] : undefined
}
return obj
}
static getDefaultImg(itemType) {
return game.system.rdd.actorClasses[itemType]?.defaultIcon ?? defaultItemImg[itemType];
@ -45,29 +56,32 @@ export class RdDBaseActor extends Actor {
}
}
static remoteActorCall(callData, userId = undefined) {
userId = userId ?? Misc.firstConnectedGMId();
if (userId == game.user.id) {
RdDBaseActor.onRemoteActorCall(callData, userId);
return false;
static remoteActorCall(callData) {
if (game.user.isGM) {
RdDBaseActor.onRemoteActorCall(callData, game.user.id)
return false
}
else {
game.socket.emit(SYSTEM_SOCKET_ID, { msg: "msg_remote_actor_call", data: callData, userId: userId });
return true;
game.socket.emit(SYSTEM_SOCKET_ID, {
msg: "msg_remote_actor_call",
data: callData,
userId: Misc.firstConnectedGMId()
})
return true
}
}
static onRemoteActorCall(callData, userId) {
const actor = RdDBaseActor.getRealActor(callData?.actorId, callData?.tokenId);
if (userId == game.user.id) {
const actor = RdDBaseActor.getRealActor(callData?.actorId, callData?.tokenId);
if (Misc.isOwnerPlayerOrUniqueConnectedGM(actor)) { // Seul le joueur choisi effectue l'appel: le joueur courant si propriétaire de l'actor, ou le MJ sinon
const args = callData.args;
console.info(`RdDBaseActor.onRemoteActorCall: pour l'Actor ${callData.actorId}, appel de RdDBaseActor.${callData.method}(`, ...args, ')');
actor[callData.method](...args);
}
// Seul le joueur choisi effectue l'appel: le joueur courant si propriétaire de l'actor, ou le MJ sinon
const args = callData.args;
console.info(`RdDBaseActor.onRemoteActorCall: pour l'Actor ${callData.actorId}, appel de RdDBaseActor.${callData.method}(`, ...args, ')');
actor[callData.method](...args);
}
}
static getRealActor(actorId, tokenId) {
if (tokenId) {
let token = canvas.tokens.get(tokenId)
@ -178,7 +192,8 @@ export class RdDBaseActor extends Actor {
this.computeEncTotal()
}
async prepareActorData() { }
prepareActorData() { }
async computeEtatGeneral() { }
/* -------------------------------------------- */
findPlayer() {
@ -210,11 +225,26 @@ export class RdDBaseActor extends Actor {
getMonnaie(id) { return this.findItemLike(id, 'monnaie'); }
getEncombrementMax() { return 0 }
/* -------------------------------------------- */
async updateCarac(caracName, to) {
}
/* -------------------------------------------- */
async onPreUpdateItem(item, change, options, id) { }
async onCreateItem(item, options, id) { }
async onDeleteItem(item, options, id) { }
async onUpdateActor(update, options, actorId) { }
async onDeleteItem(item, options, id) {
if (item.isInventaire()) {
this._removeItemFromConteneur(item)
}
}
_removeItemFromConteneur(item) {
this.items.filter(it => it.isConteneur() && it.system.contenu.includes(item.id))
.forEach(conteneur => {
const nouveauContenu = conteneur.system.contenu.filter(id => id != item.id);
conteneur.update({ 'system.contenu': nouveauContenu });
});
}
async onTimeChanging(oldTimestamp, newTimestamp) {
this.items.filter(it => it.isFinPeriode(oldTimestamp, newTimestamp))
@ -222,21 +252,20 @@ export class RdDBaseActor extends Actor {
}
async creerObjetParMJ(object) {
if (!Misc.isFirstConnectedGM()) {
RdDBaseActor.remoteActorCall({
tokenId: this.token?.id,
actorId: this.id,
method: 'creerObjetParMJ',
args: [object]
});
return;
if (this.isOwner) {
await this.createEmbeddedDocuments('Item', [object])
return
}
await this.createEmbeddedDocuments('Item', [object])
RdDBaseActor.remoteActorCall({
tokenId: this.token?.id,
actorId: this.id,
method: 'creerObjetParMJ', args: [object]
})
}
/* -------------------------------------------- */
async cleanupConteneurs() {
if (Misc.isOwnerPlayerOrUniqueConnectedGM(this)) {
if (Misc.isOwnerPlayer(this)) {
let updates = this.itemTypes['conteneur']
.filter(c => c.system.contenu.filter(id => this.getItem(id) == undefined).length > 0)
.map(c => { return { _id: c._id, 'system.contenu': c.system.contenu.filter(id => this.getItem(id) != undefined) } });
@ -307,7 +336,7 @@ export class RdDBaseActor extends Actor {
ui.notifications.error(`Impossible d'ajouter un gain de ${sols} <0`);
return;
}
if (fromActorId && !game.user.isGM) {
if (fromActorId && !this.isOwner) {
RdDBaseActor.remoteActorCall({
userId: Misc.connectedGMOrUser(),
tokenId: this.token?.id,
@ -342,10 +371,9 @@ export class RdDBaseActor extends Actor {
if (!Misc.isFirstConnectedGM()) {
RdDBaseActor.remoteActorCall({
actorId: achat.vendeurId ?? achat.acheteurId,
method: 'achatVente',
args: [achat]
method: 'achatVente', args: [achat]
});
return;
return
}
const cout = Number(achat.prixTotal ?? 0);
const vendeur = achat.vendeurId ? game.actors.get(achat.vendeurId) : undefined;

View File

@ -25,9 +25,6 @@ export class RdDCommerce extends RdDBaseActor {
}
await super.depenserSols(cout)
}
async consommerNourritureboisson(itemId, choix, userId) {
// ne pas consommer pour un commerce
}
async decrementerQuantiteItem(item, quantite) {
if (this.system.illimite) {

View File

@ -1,6 +1,4 @@
import { ENTITE_INCARNE } from "../constants.js";
import { ITEM_TYPES } from "../item.js";
import { STATUSES } from "../settings/status-effects.js";
import { RdDBaseActorSang } from "./base-actor-sang.js";
export class RdDCreature extends RdDBaseActorSang {
@ -9,6 +7,7 @@ export class RdDCreature extends RdDBaseActorSang {
return "systems/foundryvtt-reve-de-dragon/icons/creatures/bramart.svg";
}
getEnduranceMax() { return Math.max(1, this.getVieMax() + this.getConstitution()) }
isCreature() { return true }
canReceive(item) {

View File

@ -27,6 +27,7 @@ export class RdDEntite extends RdDBaseActorReve {
getForce() { return this.getReve() }
getAgilite() { return this.getReve() }
getChance() { return this.getReve() }
getEnduranceMax() { return Math.max(1, this.getTaille() + this.getReve()) }
getDraconicOuPossession() {
return this.itemTypes[ITEM_TYPES.competencecreature]

View File

@ -76,7 +76,7 @@ const MAPPING_BASE = [
{ column: "derobee", rollClass: 'roll-carac', colName: 'Dérobée', getter: (actor, context) => actor.system.carac.derobee.value },
{ column: "vie", getter: (actor, context) => actor.system.sante.vie.max },
{ column: "endurance", getter: (actor, context) => actor.system.sante.endurance.max },
{ column: "plusdom", colName: '+dom', getter: (actor, context) => actor.system.attributs.plusdom.value },
{ column: "plusdom", colName: '+dom', getter: (actor, context) => actor.getBonusDegat() },
{ column: "protectionnaturelle", colName: 'Protection naturelle', getter: (actor, context) => actor.system.attributs.protection.value > 0 ? actor.system.attributs.protection.value : '' },
{ column: "description", getter: (actor, context) => Mapping.getDescription(actor) },
{ column: "armure", getter: (actor, context) => Mapping.getArmure(actor, context) },
@ -169,10 +169,10 @@ export class Mapping {
arme: arme
}
}
static dommagesArme(actor, arme, maniement){
static dommagesArme(actor, arme, maniement) {
const dmgArme = RdDItemArme.dommagesReels(arme, maniement)
const dommages = Misc.toSignedString(dmgArme + RdDBonus.bonusDmg(actor, maniement, dmgArme))
switch(arme.system.mortalite) {
switch (arme.system.mortalite) {
case 'non-mortel': return `(${dommages})`
case 'empoignade': return '-'
}
@ -238,7 +238,7 @@ export class Mapping {
static prepareSorts(actor) {
const codeVoies = Mapping.getCompetencesCategorie(actor, CATEGORIES_DRACONIC)
.map(it => RdDItemSort.getVoieCode(it))
.map(it => RdDItemSort.getCodeVoie(it.name))
return actor.itemTypes[ITEM_TYPES.sort].map(it => Mapping.prepareSort(it, codeVoies))
.sort(Misc.ascending(it => `${it.voie} : ${it.description}`))
@ -246,7 +246,7 @@ export class Mapping {
static prepareSort(sort, voies) {
return {
voie: RdDItemSort.getCodeDraconic(sort, voies),
voie: RdDItemSort.getCode(sort, voies),
description: Mapping.descriptionSort(sort),
bonus: Mapping.bonusCase(sort)
}
@ -255,21 +255,16 @@ export class Mapping {
static descriptionSort(sort) {
const ptSeuil = Array(sort.system.coutseuil).map(it => '*')
const caseTMR = sort.system.caseTMRspeciale.length > 0 ? Mapping.toVar(sort.system.caseTMRspeciale) : Misc.upperFirst(TMRType[sort.system.caseTMR].name)
const ptreve = Mapping.addSpaceToNonNumeric(sort.system.ptreve)
const diff = Mapping.addSpaceToNonNumeric(sort.system.difficulte)
return `${sort.name}${ptSeuil} (${caseTMR}) R${diff} r${ptreve}`
const coutReve = 'r' + RdDItemSort.addSpaceToNonNumeric(sort.system.ptreve)
const diff = 'R' + RdDItemSort.addSpaceToNonNumeric(sort.system.difficulte)
return `${sort.name}${ptSeuil} (${caseTMR}) ${diff} ${coutReve}`
}
static addSpaceToNonNumeric(value) {
return Number.isNumeric(value) || /[-\d].*/.match(String(value)) ? value : ' ' + Mapping.toVar(value)
}
static toVar(value) {
return value.replace('variable', 'var')
static toVar(caseSpeciale) {
return Grammar.toLowerCaseNoAccent(caseSpeciale).startsWith('var') ? 'var' : caseSpeciale
}
static bonusCase(sort) {
const list = RdDItemSort.bonuscaseStringToList(sort.system.bonuscase).sort(Misc.descending(it => it.bonus))
const list = RdDItemSort.stringToBonuscases(sort.system.bonuscase).sort(Misc.descending(it => it.bonus))
if (list.length > 0) {
const bonus = list[0]
return `+${bonus.bonus}% en ${bonus.case}`

View File

@ -2,6 +2,396 @@
import "./xregexp-all.js";
import { SystemCompendiums } from "../settings/system-compendiums.js";
import { RdDBaseActorReve } from "../actor/base-actor-reve.js";
import { Grammar } from "../grammar.js";
import { Misc } from "../misc.js";
import { ENTITE_INCARNE, ENTITE_NONINCARNE } from "../constants.js";
import { RdDItemTete } from "../item/tete.js";
const WHITESPACES = "\\s+"
const NUMERIC = "[\\+\\-]?\\d+"
const NUMERIC_VALUE = "(?<value>" + NUMERIC + ")"
const XREGEXP_COMP_CREATURE = WHITESPACES + "(?<carac>\\d+)"
+ WHITESPACES + NUMERIC_VALUE
+ "(" + WHITESPACES + "(?<init>\\d+)?\\s+?(?<dommages>[\\+\\-]?\\d+)?" + ")?"
// Skill parser depending on the type of actor
const compParser = {
personnage: "(\\D+)*" + WHITESPACES + NUMERIC_VALUE,
creature: XREGEXP_COMP_CREATURE,
entite: XREGEXP_COMP_CREATURE
}
const XREGEXP_SORT_VOIE = "(?<voies>[OHNT](\\/[OHNT])*)"
const XREGEXP_SORT_NAME = "(?<name>[^\\(]+)"
const XREGEXP_SORT_CASE = "\\((?<case>([A-Za-zÀ-ÖØ-öø-ÿ\\s\\-]+|[A-M]\\d{1,2})+)\\)";
const XREGEXP_SORT = "(" + XREGEXP_SORT_VOIE
+ WHITESPACES + XREGEXP_SORT_NAME
+ WHITESPACES + XREGEXP_SORT_CASE
+ WHITESPACES + "R(?<diff>([\\-\\d]+|(\\w|\\s)+))"
+ WHITESPACES + "r(?<reve>(\\d+(\\+)?|\\s\\w+))"
+ "(" + WHITESPACES + "\\+(?<bonus>\\d+)\\s?%" + WHITESPACES + "en" + WHITESPACES + "(?<bonuscase>[A-M]\\d{1,2})" + ")?"
+ ")"
// Main class for parsing a stat block
export class RdDStatBlockParser {
static openInputDialog() {
let dialog = new Dialog({
title: "Import de stats de PNJ/Créatures",
content: `
<div>
<p>Coller le texte de la stat ici</p>
<textarea id="statBlock" style="width: 100%; height: 200px;"></textarea>
</div>
`,
buttons: {
ok: {
label: "OK",
callback: async (html) => {
let statBlock = html.find("#statBlock")[0].value;
await RdDStatBlockParser.parseStatBlock(statBlock);
dialog.close();
}
},
cancel: {
label: "Cancel"
}
}
});
dialog.render(true);
}
static fixWeirdPDF(statString) {
// Split the statString into lines
let lines = statString.split("\n");
let newLines = [];
let index = 0;
let nextType = "string";
// Loop through each line
for (let i = 0; i < lines.length; i++) {
// remove trailing spaces
lines[i] = lines[i].trim();
// Is it text ?
if (lines[i].match(/^[a-zA-Zéêè\s]+/)) {
if (nextType == "string") {
newLines[index] = lines[i];
nextType = "number";
} else {
console.log("Wrong sequence string detected...", lines[i], nextType);
}
}
// Is it a number ?
if (lines[i].match(/^[\d\s]+/)) {
if (nextType == "number") {
newLines[index] = newLines[index] + lines[i];
nextType = "string";
index++;
} else {
console.log("Wrong sequence number detected...", lines[i], nextType);
}
}
}
}
static getHeureKey(heure) {
for (let h of game.system.rdd.config.heuresRdD) {
if (h.label.toLowerCase() == heure.toLowerCase()) {
return h.value;
}
}
return "vaisseau";
}
static async parseStatBlock(statString) {
//statString = statBlock03;
if (!statString) {
return;
}
// Special function to fix strange/weird copy/paste from PDF readers
// Unused up to now : this.fixWeirdPDF(statString);
// Replace all endline by space in the statString
statString = statString.replace(/\n/g, " ");
// Remove all multiple spaces
statString = statString.replace(/\s{2,}/g, " ");
// Remove all leading and trailing spaces
statString = statString.trim();
// TODO: check for entite
let type = RdDStatBlockParser.parseActorType(statString);
// Now start carac
let actorData = foundry.utils.deepClone(game.model.Actor[type]);
for (let key in actorData.carac) {
let caracDef = actorData.carac[key];
// Parse the stat string for each caracteristic
let carac = XRegExp.exec(statString, XRegExp(caracDef.label + "\\s+(?<value>\\d+)", 'giu'));
if (carac?.value) {
actorData.carac[key].value = Number(carac.value);
}
}
// If creature we need to setup additionnal fields
switch (type) {
case "creature":
RdDStatBlockParser.parseCreature(statString, actorData)
break
case "entite":
RdDStatBlockParser.parseEntite(statString, actorData)
break
}
let items = [];
// Get skills from compendium
const competences = await SystemCompendiums.getCompetences(type);
//console.log("Competences : ", competences);
for (let comp of competences) {
let compMatch = XRegExp.exec(statString, XRegExp(comp.name + compParser[type], 'giu'));
if (compMatch) {
comp = comp.toObject()
comp.system.niveau = Number(compMatch.value);
if (type == "creature" || type == "entite") {
comp.system.carac_value = Number(compMatch.carac);
if (compMatch.dommages != undefined) {
comp.system.dommages = Number(compMatch.dommages);
comp.system.iscombat = true;
}
}
items.push(comp)
}
else if (type == "personnage") {
comp = comp.toObject()
items.push(comp)
}
}
// Now process weapons
const weapons = await SystemCompendiums.getWorldOrCompendiumItems("arme", "equipement")
//console.log("Equipement : ", equipment);
// TODO: les noms d'armes peuvent avoir un suffixe (à une main, lancée) qui détermine la compétence correspondante
// TODO: une arme peut être spécifique ("fourche"), ajouter une compétence dans ces cas là?
for (let weapon of weapons) {
let weapMatch = XRegExp.exec(statString, XRegExp(weapon.name + "\\s+(?<value>\\+\\d+)", 'giu'));
if (weapMatch) {
weapon = weapon.toObject()
weapon.system.equipe = 'true'
items.push(weapon)
// now process the skill
if (weapon.system?.competence != "") {
let wComp = items.find(i => Grammar.equalsInsensitive(i.name, weapon.system.competence))
if (wComp) {
wComp.system.niveau = Number(weapMatch.value);
}
}
if (weapon.system?.tir != "") {
let wComp = items.find(i => Grammar.equalsInsensitive(i.name, weapon.system.tir))
if (wComp) {
wComp.system.niveau = Number(weapMatch.value);
}
}
if (weapon.system?.lancer != "") {
let wComp = items.find(i => Grammar.equalsInsensitive(i.name, weapon.system.lancer))
if (wComp) {
wComp.system.niveau = Number(weapMatch.value);
}
}
}
}
// Now process armors
const armors = await SystemCompendiums.getWorldOrCompendiumItems("armure", "equipement")
for (let armor of armors) {
let matchArmor = XRegExp.exec(statString, XRegExp(armor.name, 'giu'));
if (matchArmor) {
armor = armor.toObject()
armor.system.equipe = true
items.push(armor);
}
}
if (type == "personnage") {
await RdDStatBlockParser.parseHautReve(statString, actorData, items);
RdDStatBlockParser.parsePersonnage(statString, actorData);
}
let name = RdDStatBlockParser.extractName(type, statString);
let newActor = await RdDBaseActorReve.create({ name, type: type, system: actorData, items });
await newActor.remiseANeuf()
await RdDStatBlockParser.setValActuelle(newActor, statString)
// DUmp....
console.log(actorData);
}
static async setValActuelle(newActor, statString) {
const updates = {
}
const endurance = XRegExp.exec(statString, XRegExp("endurance\\s+(?<value>\\d+)\\s+(\\(actuelle\\s*:\\s+(?<actuelle>\\d+)\\))?", 'giu'));
if (endurance?.value) {
if (newActor.getEnduranceMax() != endurance.value) {
ui.notifications.warn(`Vérifier le calcul de l'endurance, calcul: ${newActor.getEnduranceMax()} / import: ${endurance.value}`)
}
}
if (endurance?.actuelle) {
updates['system.sante.endurance.value'] = Number(endurance?.actuelle)
}
const vie = XRegExp.exec(statString, XRegExp("vie\\s+(?<value>\\d+)\\s+(\\(actuelle\\s*:\\s+(?<actuelle>\\d+)\\))?", 'giu'));
if (vie?.value) {
if (newActor.getVieMax() != vie.value) {
ui.notifications.warn(`Vérifier le calcul de la vie, calcul: ${newActor.getVieMax()} / import: ${vie.value}`)
}
}
if (vie?.actuelle) {
updates['system.sante.vie.value'] = Number(vie?.actuelle)
}
await newActor.update(updates)
}
static async parseHautReve(statString, actorData, items) {
let hautRevant = false;
// Attemp to detect spell
let sorts = await SystemCompendiums.getWorldOrCompendiumItems("sort", "sorts-oniros");
sorts = sorts.concat(await SystemCompendiums.getWorldOrCompendiumItems("sort", "sorts-hypnos"));
sorts = sorts.concat(await SystemCompendiums.getWorldOrCompendiumItems("sort", "sorts-narcos"));
sorts = sorts.concat(await SystemCompendiums.getWorldOrCompendiumItems("sort", "sorts-thanatos"));
XRegExp.forEach(statString, XRegExp(XREGEXP_SORT, 'gu' /* keep case sensitive to match the spell draconic skill */),
function (matchSort, i) {
const sortName = Grammar.toLowerCaseNoAccent(matchSort.name).trim().replace("", "'");
let sort = sorts.find(s => Grammar.toLowerCaseNoAccent(s.name) == sortName)
if (sort) {
hautRevant = true;
sort = sort.toObject();
if (matchSort.bonus && matchSort.bonuscase) {
sort.system.bonuscase = `${matchSort.bonuscase}:${matchSort.bonus}`;
}
items.push(sort);
}
else {
ui.notifications.warn(`Impossible de trouver le sort ${matchSort.name} / ${sortName}`)
}
});
if (hautRevant) {
const donHR = await RdDItemTete.teteDonDeHautReve();
if (donHR) {
items.push(donHR.toObject());
}
const demiReve = XRegExp.exec(statString, XRegExp("Demi-rêve\\s+(?<value>[A-M]\\d{1,2})", 'giu'))
actorData.reve.tmrpos.coord = demiReve?.value ?? 'A1'
}
}
static parsePersonnage(statString, actorData) {
actorData.reve.seuil.value = actorData.carac.reve.value
const reveActuel = XRegExp.exec(statString, XRegExp("Rêve actuel\\s+(?<value>\\d+)", 'giu'))
actorData.reve.reve.value = reveActuel?.value ? Number(reveActuel.value) : actorData.reve.seuil.value
const feminin = XRegExp.exec(statString, XRegExp("né(?<value>e?) à", 'giu'));
actorData.sexe = (feminin?.value == 'e') ? 'féminin' : 'masculin';
// Get hour name : heure du XXXXX
const heure = XRegExp.exec(statString, XRegExp("heure (du|de la|des|de l\')\\s*(?<value>[A-Za-zÀ-ÖØ-öø-ÿ\\s]+),", 'giu'));
actorData.heure = this.getHeureKey(heure?.value || "Vaisseau");
// Get age
const age = XRegExp.exec(statString, XRegExp("(?<value>\\d+) ans", 'giu'));
if (age?.value) {
actorData.age = Number(age.value);
}
// Get height
const taille = XRegExp.exec(statString, XRegExp("(?<value>\\d+m\\d+)", 'giu'));
if (taille?.value) {
actorData.taille = taille.value;
}
// Get weight
const poids = XRegExp.exec(statString, XRegExp("(?<value>\\d+) kg", 'giu'));
if (poids?.value) {
actorData.poids = poids.value;
}
// Get cheveux
const cheveux = XRegExp.exec(statString, XRegExp("kg,\\s+(?<value>[A-Za-zÀ-ÖØ-öø-ÿ\\s\\-]+),\\s+yeux", 'giu'));
if (cheveux?.value) {
actorData.cheveux = cheveux.value;
}
// Get yeux
const yeux = XRegExp.exec(statString, XRegExp("yeux\\s+(?<value>[A-Za-zÀ-ÖØ-öø-ÿ\\s\\-]+), Beau", 'giu'));
if (yeux?.value) {
actorData.yeux = yeux.value;
}
// Get beauty
const beaute = XRegExp.exec(statString, XRegExp("beauté\\s+(?<value>\\d+)", 'giu'));
if (beaute?.value) {
actorData.beaute = Number(beaute.value);
}
}
static parseCreature(statString, actorData) {
let protection = XRegExp.exec(statString, XRegExp("protection\\s+(?<value>[\\-]?\\d+)", 'giu'));
if (protection?.value) {
actorData.attributs.protection.value = Number(protection.value);
}
let vitesse = XRegExp.exec(statString, XRegExp("vitesse\\s+(?<value>[\\d\\/]+)", 'giu'));
if (vitesse?.value) {
actorData.attributs.vitesse.value = vitesse.value;
}
}
static parseEntite(statString, actorData) {
actorData.definition.categorieentite = 'cauchemar'
actorData.definition.typeentite = ENTITE_NONINCARNE
let endurance = XRegExp.exec(statString, XRegExp("endurance\\s+(?<value>\\d+)", 'giu'));
if (endurance?.value) {
actorData.sante.endurance.value = Number(endurance.value);
actorData.sante.endurance.max = Number(endurance.value);
actorData.definition.typeentite = ENTITE_INCARNE
}
let vitesse = XRegExp.exec(statString, XRegExp("vitesse\\s+(?<value>[\\d\\/]+)", 'giu'));
if (vitesse?.value) {
actorData.attributs.vitesse.value = vitesse.value;
}
}
static parseActorType(statString) {
let niveau = XRegExp.exec(statString, XRegExp("Niveau\\s+(?<value>[\\+\\-]?\\d+)", 'giu'))
let perception = XRegExp.exec(statString, XRegExp("perception\\s+(?<value>\\d+)", 'giu'))
if (perception?.value) {
return "creature"
}
if (niveau?.value) {
return "entite"
}
return "personnage"
}
static extractName(actorType, statString) {
switch (actorType) {
case "personnage":
// Name is all string before first comma ','
const namePersonnage = XRegExp.exec(statString, XRegExp("(?<value>[\\p{Letter}\\s\\d]+),", 'giu'));
if (namePersonnage?.value) {
return Misc.upperFirst(namePersonnage?.value);
}
}
const name = XRegExp.exec(statString, XRegExp("(?<value>.+)\\s+taille", 'giu'));
return Misc.upperFirst(name?.value || "Importé");
}
static warning(message) {
ui.notifications.warn(message);
}
}
/************************************************************************************/
// Some internal test strings
@ -76,7 +466,7 @@ Corps à corps
(0)
Esquive
+8
Escalade +4 / Saut +5 / Commerce +3 / Équitation
Escalade, Saut +4 / Commerce +3 / Équitation
+6 / Chirurgie 0 / Survie en extérieur +4 / Survie fo-
rêt +6 / Acrobatie -2 / Métallurgie +2 / Natation +3 /
Légendes -1 / Écriture -4
@ -194,240 +584,4 @@ Discrétion
Vigilance
13
+3
`
// Skill parser depending on the type of actor
const compParser = { personnage: "\\s+(?<value>[\\+\\-]?\\d+)", creature: "\\s+(?<carac>\\d+)\\s+(?<value>[\\+\\-]?\\d+)\\s?(?<init>\\d+)?\\s+?(?<dommages>\\+\\d+)?" };
// Main class for parsing a stat block
export class RdDStatBlockParser {
static openInputDialog() {
let dialog = new Dialog({
title: "Import de stats de PNJ/Créatures",
content: `
<div>
<p>Coller le texte de la stat ici</p>
<textarea id="statBlock" style="width: 100%; height: 200px;"></textarea>
</div>
`,
buttons: {
ok: {
label: "OK",
callback: async (html) => {
let statBlock = html.find("#statBlock")[0].value;
await RdDStatBlockParser.parseStatBlock(statBlock);
dialog.close();
}
},
cancel: {
label: "Cancel"
}
}
});
dialog.render(true);
}
static fixWeirdPDF(statString) {
// Split the statString into lines
let lines = statString.split("\n");
let newLines = [];
let index = 0;
let nextType = "string";
// Loop through each line
for (let i = 0; i < lines.length; i++) {
// remove trailing spaces
lines[i] = lines[i].trim();
// Is it text ?
if (lines[i].match(/^[a-zA-Zéêè\s]+/)) {
if ( nextType == "string" ) {
newLines[index] = lines[i];
nextType = "number";
} else {
console.log("Wrong sequence string detected...", lines[i], nextType);
}
}
// Is it a number ?
if (lines[i].match(/^[\d\s]+/)) {
if ( nextType == "number" ) {
newLines[index] = newLines[index] + lines[i];
nextType = "string";
index++;
} else {
console.log("Wrong sequence number detected...", lines[i], nextType);
}
}
}
}
static async parseStatBlock(statString, type = "npc") {
//statString = statBlock03;
if (!statString) {
return;
}
// Special function to fix strange/weird copy/paste from PDF readers
// Unused up to now : this.fixWeirdPDF(statString);
// Replace all endline by space in the statString
statString = statString.replace(/\n/g, " ");
// Remove all multiple spaces
statString = statString.replace(/\s{2,}/g, " ");
// Remove all leading and trailing spaces
statString = statString.trim();
let actorType = "personnage";
let perception = XRegExp.exec(statString.toLowerCase(), XRegExp("perception\\s+(?<value>\\d+)", 'gi'));
if (perception?.value ) {
actorType = "creature";
}
// Now start carac
let actorData = foundry.utils.deepClone(game.model.Actor[actorType]);
for (let key in game.model.Actor.personnage.carac) {
let caracDef = game.model.Actor.personnage.carac[key];
// Parse the stat string for each caracteristic
let carac = XRegExp.exec(statString.toLowerCase(), XRegExp(caracDef.label.toLowerCase()+"\\s+(?<value>\\d+)", 'gi'));
if (carac?.value) {
actorData.carac[key].value = Number(carac.value);
}
}
// If creature we need to setup additionnal fields
if (actorType == "creature") {
let plusDom = XRegExp.exec(statString.toLowerCase(), XRegExp("\\+dom\\s+(?<value>\\+\\d+)", 'gi'));
if (plusDom?.values) {
actorData.attributs.plusdom.value = Number(plusDom.value);
}
let protection = XRegExp.exec(statString.toLowerCase(), XRegExp("protection\\s+(?<value>\\d+)", 'gi'));
if (protection?.value) {
actorData.attributs.protection.value = Number(protection.value);
}
let endurance = XRegExp.exec(statString.toLowerCase(), XRegExp("endurance\\s+(?<value>\\d+)", 'gi'));
if (endurance?.value) {
actorData.sante.endurance.value = Number(endurance.value);
actorData.sante.endurance.max = Number(endurance.value);
}
let vie = XRegExp.exec(statString.toLowerCase(), XRegExp("vie\\s+(?<value>\\d+)", 'gi'));
if (vie.value) {
actorData.sante.vie.value = Number(vie.value);
actorData.sante.vie.max = Number(vie.value);
}
let vitesse = XRegExp.exec(statString.toLowerCase(), XRegExp("vitesse\\s+(?<value>[\\d\\/]+)", 'gi'));
if (vitesse?.value) {
actorData.attributs.vitesse.value = vitesse.value;
}
}
let items = [];
// Get skills from compendium
const competences = await SystemCompendiums.getCompetences(actorType);
//console.log("Competences : ", competences);
let allComp = competences.map(i => i.toObject())
for (let comp of allComp) {
let skill = XRegExp.exec(statString.toLowerCase(), XRegExp(comp.name.toLowerCase()+compParser[actorType], 'gi'));
if (skill) {
comp.system.niveau = Number(skill.value);
if (actorType == "creature") {
comp.system.carac_value = Number(skill.carac);
if (skill.init) {
comp.system.dommages = Number(skill.dommages);
comp.system.iscombat = true;
}
items.push(comp); // Only selective push
}
}
if (actorType == "personnage") {
items.push(comp); // Always push
}
}
// Now process weapons
const weapons = await SystemCompendiums.getWorldOrCompendiumItems("arme", "equipement")
//console.log("Equipement : ", equipment);
for (let w of weapons) {
let weapon = XRegExp.exec(statString.toLowerCase(), XRegExp(w.name.toLowerCase()+"\\s+(?<value>\\+\\d+)", 'gi'));
if (weapon) {
w.system.equipe = true
items.push(w.toObject());
// now process the skill
if ( w.system?.competence != "") {
let wComp = items.find(i => i.name.toLowerCase() == w.system.competence.toLowerCase());
if (wComp) {
wComp.system.niveau = Number(weapon.value);
}
}
if ( w.system?.tir != "") {
let wComp = items.find(i => i.name.toLowerCase() == w.system.tir.toLowerCase());
if (wComp) {
wComp.system.niveau = Number(weapon.value);
}
}
if ( w.system?.lancer != "") {
let wComp = items.find(i => i.name.toLowerCase() == w.system.lancer.toLowerCase());
if (wComp) {
wComp.system.niveau = Number(weapon.value);
}
}
}
}
// Now process armors
const armors = await SystemCompendiums.getWorldOrCompendiumItems("armure", "equipement")
for (let a of armors) {
let armor = XRegExp.exec(statString.toLowerCase(), XRegExp(a.name.toLowerCase(), 'gi'));
if (armor) {
a.system.equipe = true
items.push(a.toObject());
}
}
// Get hour name : heure du XXXXX
let heure = XRegExp.exec(statString.toLowerCase(), XRegExp("heure du\\s+(?<value>\\w+)", 'gi'));
if (heure?.value) {
actorData.heure = heure.value;
}
// Get age
let age = XRegExp.exec(statString.toLowerCase(), XRegExp("(?<value>\\d+) ans", 'gi'));
if (age?.value) {
actorData.age = Number(age.value);
}
// Get height
let taille = XRegExp.exec(statString.toLowerCase(), XRegExp("(?<value>\\d+)m\\d+", 'gi'));
if (taille?.value) {
actorData.taille = taille.value;
}
// Get weight
let poids = XRegExp.exec(statString.toLowerCase(), XRegExp("(?<value>\\d+) kg", 'gi'));
if (poids?.value) {
actorData.poids = poids.value;
}
// Get beauty
let beaute = XRegExp.exec(statString.toLowerCase(), XRegExp("beauté\\s+(?<value>\\d+)", 'gi'));
if (beaute?.value) {
actorData.beaute = Number(beaute.value);
}
// Name is all string before ', né'
let name
if (actorType == "personnage") {
name = XRegExp.exec(statString.toLowerCase(), XRegExp("(?<value>[\\w\\s\\d]+),", 'gi'));
if (!name?.value) {
name = XRegExp.exec(statString.toLowerCase(), XRegExp("(?<value>.+)\\s+taille", 'gi'));
}
name = name?.value || "Importé";
}
if (actorType == "creature") {
name = XRegExp.exec(statString.toLowerCase(), XRegExp("(?<value>.+)\\s+taille", 'gi'));
name = name?.value || "Importé";
}
let newActor = RdDBaseActorReve.create({name: name || "Importé", type:actorType, system: actorData, items: items});
// DUmp....
console.log(actorData);
}
}
`

View File

@ -81,7 +81,7 @@ export class RdDItemCompetenceCreature extends Item {
static isParade(item) {
if (item.type == ITEM_TYPES.competencecreature) {
return armeData.system.categorie_parade || armeData.system.isparade
return item.system.categorie_parade || item.system.isparade
}
return false
}

View File

@ -13,6 +13,7 @@ import { Misc } from "./misc.js";
import { RdDTimestamp } from "./time/rdd-timestamp.js";
import { RdDItemCompetenceCreature } from "./item-competencecreature.js";
import { ITEM_TYPES, RdDItem } from "./item.js";
import { FLEUVE_COORD, TMRUtility } from "./tmr-utility.js";
/**
* Extend the basic ItemSheet for RdD specific items
@ -100,55 +101,59 @@ export class RdDItemSheet extends ItemSheet {
descriptionmj: await TextEditor.enrichHTML(this.item.system.descriptionmj, { async: true }),
isComestible: this.item.getUtilisationCuisine(),
options: RdDSheetUtility.mergeDocumentRights(this.options, this.item, this.isEditable),
competences: await SystemCompendiums.getCompetences('personnage'),
categories: RdDItem.getCategories(this.item.type),
}
if (this.item.type == ITEM_TYPES.competencecreature) {
formData.isparade = RdDItemCompetenceCreature.isParade(this.item)
formData.isdommages = RdDItemCompetenceCreature.isDommages(this.item)
}
const competences = await SystemCompendiums.getCompetences('personnage');
formData.categories = RdDItem.getCategories(this.item.type)
if (this.item.type == 'tache' || this.item.type == 'livre' || this.item.type == 'meditation' || this.item.type == 'oeuvre') {
if (this.item.type == ITEM_TYPES.tache ||
this.item.type == ITEM_TYPES.livre ||
this.item.type == ITEM_TYPES.meditation ||
this.item.type == ITEM_TYPES.oeuvre) {
formData.caracList = foundry.utils.duplicate(game.model.Actor.personnage.carac)
formData.caracList["reve-actuel"] = foundry.utils.duplicate(game.model.Actor.personnage.reve.reve)
formData.competences = competences;
}
if (this.item.type == 'arme') {
formData.competences = competences.filter(it => it.isCompetenceArme())
if (this.item.type == ITEM_TYPES.arme) {
formData.competences = formData.competences.filter(it => it.isCompetenceArme())
}
if (['sort', 'sortreserve'].includes(this.item.type)) {
formData.competences = competences.filter(it => RdDItemCompetence.isDraconic(it));
}
if (this.item.type == 'recettecuisine') {
if (this.item.type == ITEM_TYPES.recettecuisine) {
formData.ingredients = await TextEditor.enrichHTML(this.object.system.ingredients, { async: true })
}
if (this.item.type == 'extraitpoetique') {
if (this.item.type == ITEM_TYPES.extraitpoetique) {
formData.extrait = await TextEditor.enrichHTML(this.object.system.extrait, { async: true })
formData.texte = await TextEditor.enrichHTML(this.object.system.texte, { async: true })
}
if (this.item.type == 'recettealchimique') {
RdDAlchimie.processManipulation(this.item, this.actor && this.actor.id);
if (this.item.type == ITEM_TYPES.recettealchimique) {
RdDAlchimie.processManipulation(this.item, this.actor?.id);
formData.manipulation_update = await TextEditor.enrichHTML(this.object.system.manipulation_update, { async: true })
formData.utilisation = await TextEditor.enrichHTML(this.object.system.utilisation, { async: true })
formData.enchantement = await TextEditor.enrichHTML(this.object.system.enchantement, { async: true })
formData.sureffet = await TextEditor.enrichHTML(this.object.system.sureffet, { async: true })
}
if (this.item.type == 'gemme') {
if (this.item.type == ITEM_TYPES.gemme) {
formData.gemmeTypeList = RdDGemme.getGemmeTypeOptionList();
RdDGemme.calculDataDerivees(this.item);
RdDGemme.calculDataDerivees(this.item)
}
if (this.item.type == 'potion') {
await RdDHerbes.addPotionFormData(formData);
if (this.item.type == ITEM_TYPES.potion) {
RdDHerbes.calculFormData(formData, this.item)
}
if (formData.options.isOwned && this.item.type == 'herbe' && (formData.system.categorie == 'Soin' || formData.system.categorie == 'Repos')) {
formData.isIngredientPotionBase = true;
if (this.item.type == ITEM_TYPES.herbe) {
if (formData.options.isOwned && ['Soin', 'Repos'].includes(formData.system.categorie)) {
formData.isIngredientPotionBase = true;
}
}
if (this.item.type == 'sortreserve') {
if (this.item.type == ITEM_TYPES.sortreserve) {
const sortId = this.item.system.sortid;
formData.competences = formData.competences.filter(it => RdDItemCompetence.isDraconic(it));
formData.sort = formData.options.isOwned ? this.item.actor.items.get(sortId) : game.items.get(sortId);
}
formData.bonusCaseList = RdDItemSort.getBonusCaseList(formData, true);
if (this.item.type == ITEM_TYPES.sort) {
formData.competences = formData.competences.filter(it => RdDItemCompetence.isDraconic(it));
formData.bonusCaseList = RdDItemSort.getBonusCaseList(this.item);
}
return formData;
}
@ -185,6 +190,9 @@ export class RdDItemSheet extends ItemSheet {
}
}
})
this.html.find('.delete-bonus-case').click((event) => {
this.supprimerBonusCase(event.currentTarget.attributes['data-deleteCoord'].value)
})
this.html.find('.date-enchantement').change((event) => {
const jour = Number(this.html.find('input.date-enchantement[name="enchantement.jour"]').val());
@ -264,23 +272,66 @@ export class RdDItemSheet extends ItemSheet {
}
}
async supprimerBonusCase(deleteCoord){
if (this.item.type == ITEM_TYPES.sort) {
const oldList = RdDItemSort.getBonusCaseList(this.item)
const newList = oldList.filter(it => it.case != deleteCoord);
if (newList.length != oldList.length) {
await this.item.update({
'system.bonuscase': RdDItemSort.bonuscasesToString(newList)
})
}
}
}
/* -------------------------------------------- */
/** @override */
_updateObject(event, formData) {
switch (this.item.type) {
case ITEM_TYPES.sort:
// Données de bonus de cases ?
formData['system.bonuscase'] = RdDItemSort.buildBonuscaseFromArrays(formData.bonusValue, formData.caseValue)
formData['system.bonuscase'] = RdDItemSort.bonuscasesToString(RdDItemSheet._listCaseTmr(
formData.caseTmrCoord,
formData.caseTmrBonus,
formData.caseTmrAdd
))
break
case ITEM_TYPES.competence:
if (formData['system.niveau'] == undefined) {
formData['system.niveau'] = formData['system.base']
}
formData['system.niveau'] = formData['system.niveau'] ?? formData['system.base']
break
}
return this.item.update(formData);
}
/* -------------------------------------------- */
/**
* reconstruit les bonus de cases
* @param {*} caseTmrCoord tableau des coordonées
* @param {*} caseTmrBonus tableau des bonus
* @param {*} caseTmrAdd case à ajouter
* @returns list d'objets {coord, bonus}
*/
static _listCaseTmr(caseTmrCoord, caseTmrBonus, caseTmrAdd) {
const listCaseTmrCoord = caseTmrCoord == undefined ? [] : Array.isArray(caseTmrCoord) ? caseTmrCoord : [caseTmrCoord]
const listCaseTmrBonus = caseTmrBonus == undefined ? [] : Array.isArray(caseTmrBonus) ? caseTmrBonus : [caseTmrBonus]
if (caseTmrAdd != undefined && caseTmrAdd != '' && TMRUtility.verifyTMRCoord(caseTmrAdd) && !listCaseTmrCoord.includes(caseTmrAdd)) {
listCaseTmrCoord.push(TMRUtility.getTMR(caseTmrAdd).coord)
listCaseTmrBonus.push(1)
}
const list = [];
const caseChecked = {};
for (let i = 0; i < listCaseTmrBonus.length && i < listCaseTmrCoord.length; i++) {
const coord = listCaseTmrCoord[i] == FLEUVE_COORD ? FLEUVE_COORD : (listCaseTmrCoord[i]?.toUpperCase() ?? 'A1')
const bonus = listCaseTmrBonus[i] ?? 0
if (TMRUtility.verifyTMRCoord(coord) && bonus >= 0 && !caseChecked[coord]) {
caseChecked[coord] = coord
list.push({ case: coord, bonus: bonus })
}
}
return list
}
/* -------------------------------------------- */
async _onDragStart(event) {
}

View File

@ -2,19 +2,32 @@ import { Grammar } from "./grammar.js";
import { RdDItemCompetence } from "./item-competence.js";
import { ITEM_TYPES } from "./item.js";
import { Misc } from "./misc.js";
import { TMRUtility } from "./tmr-utility.js";
import { FLEUVE_COORD, TMRUtility } from "./tmr-utility.js";
const VOIES_DRACONIC = [
export const VOIES_DRACONIC = [
{ code: 'O', label: "Voie d'Oniros", short: 'Oniros', ordre: 'a' },
{ code: 'H', label: "Voie d'Hypnos", short: 'Hypnos', ordre: 'b' },
{ code: 'N', label: "Voie de Narcos", short: 'Narcos', ordre: 'c' },
{ code: 'T', label: "Voie de Thanatos", short: 'Thanatos', ordre: 'd' },
{ code: 'O/H/N/T', label: "Oniros/Hypnos/Narcos/Thanatos", short: 'Oniros/Hypnos/Narcos/Thanatos', ordre: 'e' },
{ code: 'O/H/N', label: "Oniros/Hypnos/Narcos", short: "Oniros/Hypnos/Narcos", ordre: 'f' }
{ code: 'O/H/N/T', label: "Oniros/Hypnos/Narcos/Thanatos", short: 'O/H/N/T', ordre: 'e' },
{ code: 'O/H/N', label: "Oniros/Hypnos/Narcos", short: "O/H/N", ordre: 'f' }
]
/* -------------------------------------------- */
export class RdDItemSort extends Item {
static preloadHandlebars() {
Handlebars.registerHelper('itemSort-spaceIfText', val => RdDItemSort.addSpaceToNonNumeric(val))
Handlebars.registerHelper('itemSort-codeDraconic', voie => RdDItemSort.getCode(voie))
Handlebars.registerHelper('itemSort-shortDraconic', voie => RdDItemSort.getShortVoie(voie))
}
static addSpaceToNonNumeric(value) {
return Number.isNumeric(value) || ['-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'].includes( String(value).charAt[0]) ? value : ' ' + RdDItemSort.toVar(value)
}
static toVar(value) {
return value ? value.replace('variable', 'var') : ''
}
static getDraconicsSort(competencesDraconic, sort) {
// se baser sur la voie du sort?
@ -33,20 +46,23 @@ export class RdDItemSort extends Item {
return (VOIES_DRACONIC.find(it => it.code == code)?.ordre ?? '?')
}
static getVoieCode(voie) {
return VOIES_DRACONIC.find(it => voie.name.includes(it.short))?.code ?? '?'
static getCodeVoie(voie) {
return VOIES_DRACONIC.find(it => [it.code, it.short, it.label].includes(voie))?.code ?? '?'
}
static getCodeDraconic(sort, voies = ['O', 'H', 'N', 'T']) {
static getShortVoie(voie) {
return VOIES_DRACONIC.find(it => [it.code, it.short, it.label].includes(voie))?.short ?? voie
}
static getCode(sort, codeVoies = ['O', 'H', 'N', 'T']) {
switch (Grammar.toLowerCaseNoAccent(sort.name)) {
case "lecture d'aura":
case "detection d'aura":
return RdDItemSort.$voiesConnues('O/H/N/T', voies)
return RdDItemSort.$voiesConnues('O/H/N/T', codeVoies)
case "annulation de magie":
return RdDItemSort.$voiesConnues('O/H/N', voies)
return RdDItemSort.$voiesConnues('O/H/N', codeVoies)
}
const voie = VOIES_DRACONIC.find(it => it.label.includes(sort.system.draconic))
return voie?.code ?? sort.system.draconic
return RdDItemSort.getCodeVoie(sort.system.draconic)
}
static $voiesConnues(voiesSort, voies) {
@ -80,89 +96,60 @@ export class RdDItemSort extends Item {
return variable;
}
/* -------------------------------------------- */
static buildBonusCaseList(bonuscase, newCase) {
const list = RdDItemSort.bonuscaseStringToList(bonuscase)
if (newCase) {
list.push({ case: "Nouvelle", bonus: 0 })
}
return list;
}
/**
* Retourne une liste de bonus/case pour un item-sheet
* @param {} item
*/
static getBonusCaseList(item, newCase = false) {
static getBonusCaseList(item) {
// Gestion spéciale case bonus
if (item.type == ITEM_TYPES.sort) {
return RdDItemSort.buildBonusCaseList(item.system.bonuscase, newCase);
return RdDItemSort.stringToBonuscases(item.system.bonuscase)
}
return undefined;
}
/* -------------------------------------------- */
/** Met à jour les données de formulaire
* si static des bonus de cases sont présents
* */
static buildBonuscaseFromArrays(bonuses, coords) {
if (bonuses) {
const list = [];
const caseCheck = {};
for (let i = 0; i < bonuses.length && i < coords.length; i++) {
const coord = coords[i] == 'Fleuve' ? 'Fleuve' : (coords[i]?.toUpperCase() ?? 'A1');
const bonus = bonuses[i] || 0;
if (TMRUtility.verifyTMRCoord(coord) && bonus > 0 && caseCheck[coord] == undefined) {
caseCheck[coord] = bonus;
list.push({ case: coord, bonus: bonus });
}
}
return RdDItemSort._bonuscaseListToString(list);
}
return undefined;
return [];
}
/* -------------------------------------------- */
static incrementBonusCase(actor, sort, coord) {
if (TMRUtility.getTMR(coord).type == "fleuve") {
coord = 'Fleuve';
if (TMRUtility.isFleuve(coord)) {
coord = FLEUVE_COORD;
}
let list = RdDItemSort.stringToBonuscases(sort.system.bonuscase);
const existing = list.find(it => it.case == coord)
const bonus = Number(existing?.bonus ?? 0) + 1
if (existing) {
existing.bonus = bonus
}
else {
list.push({ case: coord, bonus: 1 })
}
const list = RdDItemSort.buildBonusCaseList(sort.system.bonuscase, false);
const bonus = Number(list.find(it => it.case == coord)?.bonus ?? 0);
const modified = { case: coord, bonus: bonus + 1 };
const bonuscase = RdDItemSort._bonuscaseListToString(
list.filter(it => it.case != coord).concat(modified)
);
// Sauvegarde/update
actor.updateEmbeddedDocuments('Item', [{ _id: sort._id, 'system.bonuscase': bonuscase }]);
actor.updateEmbeddedDocuments('Item', [{ _id: sort._id, 'system.bonuscase': RdDItemSort.bonuscasesToString(list) }]);
}
/* -------------------------------------------- */
static getCaseBonus(sort, coord) {
const isFleuve = TMRUtility.getTMR(coord).type == "fleuve";
let bc = RdDItemSort.buildBonusCaseList(sort.system.bonuscase, false)
.filter(it => it.case == coord || (isFleuve && it.case == 'Fleuve'))
.find(it => true)
const search = TMRUtility.isFleuve(coord)
? it => it.case == 'Fleuve'
: it => it.case == coord;
const bc = RdDItemSort.stringToBonuscases(sort.system.bonuscase)
.find(search)
return Number(bc?.bonus ?? 0);
}
static _bonuscaseListToString(list) {
static bonuscasesToString(list) {
return list.map(it => `${it.case}:${it.bonus}`)
.sort(Misc.ascending())
.join(',');
}
static bonuscaseStringToList(bonuscase) {
static stringToBonuscases(bonuscase) {
if (bonuscase == undefined || bonuscase == '') {
return []
}
return bonuscase.split(',').map(it => {
const b = it.split(':');
return { case: b[0], bonus: b[1] };
});
return bonuscase.split(',')
.map(it => it.split(':'))
.map(it => { return { case: it[0], bonus: it[1] } });
}
}

View File

@ -571,6 +571,7 @@ export class RdDItem extends Item {
else {
await this.quantiteIncDec(item.system.quantite);
}
// TODO: suppression dans les conteneurs!
await item.delete();
}
@ -601,6 +602,9 @@ export class RdDItem extends Item {
if (!other || !this.isInventaire()) {
return [false, undefined];
}
if (this.isConteneur()){
return [false, `Impossible de regrouper des conteneurs, ils ne sont pas empilables`];
}
if (this.system.quantite == undefined) {
return [false, `Impossible de regrouper des ${this.type}, ils ne sont pas empilables`];
}

25
module/item/tete.js Normal file
View File

@ -0,0 +1,25 @@
import { Grammar } from "../grammar.js"
import { ITEM_TYPES, RdDItem } from "../item.js"
import { SystemCompendiums } from "../settings/system-compendiums.js"
const DON_HAUT_REVE = "Don de Haut-Rêve"
export class RdDItemTete extends RdDItem {
static get defaultIcon() {
return "systems/foundryvtt-reve-de-dragon/icons/tete_dragon.webp"
}
static isDonDeHautReve(tete) {
return tete.type == ITEM_TYPES.tete && Grammar.equalsInsensitive(tete.name, DON_HAUT_REVE)
}
static async teteDonDeHautReve() {
const tetes = await SystemCompendiums.getItems("tetes-de-dragon-pour-tous-personnages", ITEM_TYPES.tete)
const tete = tetes.find(it => RdDItemTete.isDonDeHautReve(it))
if (!tete) {
ui.notifications.warn(`Impossible de trouver la tête "${DON_HAUT_REVE}", vérifiez le compendium de têtes pour tous personnages`)
}
return tete
}
}

View File

@ -5,7 +5,7 @@ import { Monnaie } from "./item-monnaie.js";
import { RdDItem, ITEM_TYPES } from "./item.js";
import { RdDTimestamp } from "./time/rdd-timestamp.js";
import { RdDRaretes } from "./item/raretes.js";
import { RdDCalendrier } from "./time/rdd-calendrier.js";
import { VOIES_DRACONIC } from "./item-sort.js";
class Migration {
get code() { return "sample"; }
@ -137,7 +137,7 @@ class _10_0_21_VehiculeStructureResistanceMax extends Migration {
}
class _10_0_33_MigrationNomsDraconic extends Migration {
get code() { return "competences-creature-parade"; }
get code() { return "competences-nom-draconic"; }
get version() { return "10.0.33"; }
migrationNomDraconic(ancien) {
@ -530,6 +530,42 @@ class _11_2_20_MigrationAstrologie extends Migration {
}
}
class _12_0_26_MigrationVoieSorts extends Migration {
get code() { return "migration-voies-sorts" }
get version() { return "12.0.26" }
async migrate() {
await this.applyItemsUpdates(items => items
.filter(it => [ITEM_TYPES.sort, ITEM_TYPES.sortreserve].includes(it.type))
.map(it => this.migrateSort(it))
)
await this.applyItemsUpdates(items => items
.filter(it => ITEM_TYPES.competence == it.type && it.system.categorie == 'draconic')
.map(it => this.migrateDraconic(it))
)
}
migrateDraconic(it) {
return {
_id: it.id,
name: this.convertDraconic(it.name),
}
}
migrateSort(it) {
return {
_id: it.id,
'system.draconic': this.convertDraconic(it.system.draconic),
}
}
convertDraconic(draconic) {
for (let v of VOIES_DRACONIC) {
if ([v.label, v.short, v.code].includes(draconic)) {
return v.short
}
}
return draconic
}
}
export class Migrations {
static getMigrations() {
return [
@ -549,6 +585,7 @@ export class Migrations {
new _10_7_19_CategorieCompetenceCreature(),
new _10_7_19_PossessionsEntiteVictime(),
new _11_2_20_MigrationAstrologie(),
new _12_0_26_MigrationVoieSorts()
];
}

View File

@ -58,9 +58,6 @@ export class Misc {
* @param {*} value value to convert to an integer using parseInt
*/
static toInt(value) {
if (value == undefined) {
return 0;
}
const parsed = parseInt(value);
return isNaN(parsed) ? 0 : parsed;
}
@ -203,11 +200,7 @@ export class Misc {
if (!document.testUserPermission){
return false
}
return game.users.filter(u => document.testUserPermission(u, CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER)) == game.user
}
static isOwnerPlayerOrUniqueConnectedGM(actor) {
return Misc.isFirstOwnerPlayer(actor) ?? Misc.isFirstConnectedGM();
return game.users.find(u => document.testUserPermission(u, CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER)) == game.user
}
/**

View File

@ -64,7 +64,7 @@ export class RdDCarac {
}
static getCaracDerivee(value) {
return TABLE_CARACTERISTIQUES_DERIVEES[Math.min(Math.max(Number(value), 1), 32)];
return TABLE_CARACTERISTIQUES_DERIVEES[Math.min(Math.max(Math.floor(Number(value)), 1), 32)];
}
static computeTotal(carac, beaute = undefined) {

View File

@ -436,7 +436,7 @@ export class RdDCombat {
/* -------------------------------------------- */
static onMsgEncaisser(msg) {
let defender = canvas.tokens.get(msg.defenderToken.id).actor;
if (Misc.isOwnerPlayerOrUniqueConnectedGM(defender)) {
if (Misc.isOwnerPlayer(defender)) {
let attackerRoll = msg.attackerRoll;
let attacker = msg.attackerId ? game.actors.get(msg.attackerId) : undefined;
defender.encaisserDommages(attackerRoll, attacker, msg.attackerToken);
@ -1251,7 +1251,7 @@ export class RdDCombat {
this._onEchecTotal(defenderRoll);
}
if (Misc.isOwnerPlayerOrUniqueConnectedGM(this.defender)) {
if (Misc.isOwnerPlayer(this.defender)) {
attackerRoll.attackerId = this.attackerId;
attackerRoll.defenderTokenId = this.defenderToken.id;

View File

@ -360,13 +360,14 @@ export class RdDCommands {
async getTMRAleatoire(msg, params) {
if (params.length < 2) {
let type = params[0];
const tmr = await TMRUtility.getTMRAleatoire(type ? (it => it.type == type) : (it => true));
return RdDCommands._chatAnswer(msg, `Case aléatoire: ${tmr.coord} - ${tmr.label}`);
}
else {
return false;
let type = params[0]
const solvedTerrain = TMRUtility.findTMRLike(type)?.type
if (solvedTerrain){
const tmr = await TMRUtility.getTMRAleatoire(type ? (it => it.type == solvedTerrain) : (it => true))
return RdDCommands._chatAnswer(msg, `Case aléatoire: ${tmr.coord} - ${tmr.label}`)
}
}
return false;
}
async findTMR(msg, params) {
@ -384,11 +385,11 @@ export class RdDCommands {
async tableRencontres(msg, params) {
if (params && params.length > 0) {
const search = Misc.join(params, ' ');
const solvedTerrain = TMRUtility.findTMRLike(search);
const solvedTerrain = TMRUtility.findTMRLike(search)
if (solvedTerrain == undefined) {
return RdDCommands._chatAnswer(msg, 'Aucune TMR correspondant à ' + search);
}
return await game.system.rdd.rencontresTMR.chatTable(solvedTerrain);
return await game.system.rdd.rencontresTMR.chatTable(solvedTMRType.name)
}
return false;
}

View File

@ -28,9 +28,9 @@ export class RdDHerbes extends Item {
}
/* -------------------------------------------- */
static async addPotionFormData(formData) {
formData.isSoins = formData.system.categorie.includes('Soin');
formData.isRepos = formData.system.categorie.includes('Repos');
static calculFormData(formData, item) {
formData.isSoins = item.system.categorie.includes('Soin');
formData.isRepos = item.system.categorie.includes('Repos');
if (formData.isSoins) {
RdDHerbes.calculBonusHerbe(formData, this.herbesSoins, 12);
}
@ -40,7 +40,7 @@ export class RdDHerbes extends Item {
formData.herbesSoins = RdDHerbes.buildHerbesList(this.herbesSoins, 12);
formData.herbesRepos = RdDHerbes.buildHerbesList(this.herbesRepos, 7);
formData.dateActuelle = game.system.rdd.calendrier.dateCourante();
formData.enchantement = RdDTimestamp.splitIndexDate(formData.system.prdate);
formData.enchantement = RdDTimestamp.splitIndexDate(item.system.prdate);
}
/* -------------------------------------------- */

View File

@ -69,6 +69,8 @@ import { ExportScriptarium } from "./actor/export-scriptarium/export-scriptarium
import { AppPersonnageAleatoire } from "./actor/random/app-personnage-aleatoire.js"
import { RdDActorExportSheet } from "./actor/export-scriptarium/actor-encart-sheet.js"
import { RdDStatBlockParser } from "./apps/rdd-import-stats.js"
import { RdDItemSort } from "./item-sort.js"
import { RdDItemTete } from "./item/tete.js"
/**
* RdD system
@ -96,6 +98,7 @@ export class SystemReveDeDragon {
ombre: RdDItemOmbre,
poison: RdDItemPoison,
queue: RdDItemQueue,
tete: RdDItemTete,
rencontre: RdDRencontre,
service: RdDItemService,
signedraconique: RdDItemSigneDraconique,
@ -122,6 +125,7 @@ export class SystemReveDeDragon {
// preload handlebars templates
RdDUtility.preloadHandlebarsTemplates()
AppPersonnageAleatoire.preloadHandlebars()
RdDItemSort.preloadHandlebars()
/* -------------------------------------------- */
ReglesOptionnelles.initSettings()

View File

@ -20,6 +20,7 @@ import { ExperienceLog } from "./actor/experience-log.js";
import { RdDCoeur } from "./coeur/rdd-coeur.js";
import { APP_ASTROLOGIE_REFRESH } from "./sommeil/app-astrologie.js";
import { RDD_CONFIG } from "./constants.js";
import { RdDBaseActor } from "./actor/base-actor.js";
/* -------------------------------------------- */
// This table starts at 0 -> niveau -10
@ -145,8 +146,8 @@ export class RdDUtility {
'systems/foundryvtt-reve-de-dragon/templates/actor/alchimie.html',
'systems/foundryvtt-reve-de-dragon/templates/actor/astrologie.html',
'systems/foundryvtt-reve-de-dragon/templates/actor/chirurgie.html',
'systems/foundryvtt-reve-de-dragon/templates/actor/non-haut-revant.html',
'systems/foundryvtt-reve-de-dragon/templates/actor/haut-revant.html',
'systems/foundryvtt-reve-de-dragon/templates/actor/non-haut-revant.hbs',
'systems/foundryvtt-reve-de-dragon/templates/actor/haut-revant.hbs',
'systems/foundryvtt-reve-de-dragon/templates/actor/dragon-queues.html',
'systems/foundryvtt-reve-de-dragon/templates/actor/dragon-queue.html',
'systems/foundryvtt-reve-de-dragon/templates/actor/dragon-souffles.html',
@ -288,6 +289,8 @@ export class RdDUtility {
Handlebars.registerHelper('timestamp-formulesDuree', () => RdDTimestamp.formulesDuree());
Handlebars.registerHelper('timestamp-formulesPeriode', () => RdDTimestamp.formulesPeriode());
Handlebars.registerHelper('actor-default', (actorType, ...path) => RdDBaseActor.getDefaultValue(actorType, path.slice(0, -1)));
Handlebars.registerHelper('array-includes', (array, value) => array.includes(value));
Handlebars.registerHelper('min', (...args) => Math.min(...args.slice(0, -1)));
Handlebars.registerHelper('isLastIndex', (index, list) => index + 1 >= list.length);

View File

@ -1,5 +1,6 @@
import { ChatUtility } from "../chat-utility.js";
import { HIDE_DICE, SYSTEM_RDD } from "../constants.js";
import { Grammar } from "../grammar.js";
import { RdDItem } from "../item.js";
import { Misc } from "../misc.js";
import { RdDDice } from "../rdd-dice.js";
@ -32,7 +33,7 @@ export class SystemCompendiums extends FormApplication {
compendium: compendium,
default: SystemCompendiums._getDefaultCompendium(compendium),
setting: SystemCompendiums._getSettingCompendium(compendium)
});
})
game.settings.register(SYSTEM_RDD, definition.setting, {
name: definition.label,
@ -40,8 +41,8 @@ export class SystemCompendiums extends FormApplication {
scope: "world",
config: false,
type: String
});
});
})
})
game.settings.registerMenu(SYSTEM_RDD, "compendium-settings", {
name: "Choisir les compendiums système",
@ -71,26 +72,27 @@ export class SystemCompendiums extends FormApplication {
static async getCompetences(actorType) {
switch (actorType ?? 'personnage') {
case 'personnage': return await SystemCompendiums.getWorldOrCompendiumItems('competence', 'competences');
case 'creature': return await SystemCompendiums.getWorldOrCompendiumItems('competencecreature', 'competences-creatures');
case 'entite': return await SystemCompendiums.getWorldOrCompendiumItems('competencecreature', 'competences-entites');
case 'personnage':
return await SystemCompendiums.getWorldOrCompendiumItems('competence', 'competences')
case 'entite':
case 'creature':
return await SystemCompendiums.getWorldOrCompendiumItems('competencecreature', 'competences-creatures')
case 'vehicule': return [];
}
}
/* -------------------------------------------- */
static async getWorldOrCompendiumItems(itemType, compendium) {
let items = game.items.filter(it => it.type == itemType);
let items = game.items.filter(it => it.type == itemType)
if (compendium) {
const ids = items.map(it => it.id);
const names = items.map(it => it.name.toLowerCase());
const compendiumItems = await SystemCompendiums.getItems(compendium);
items = items.concat(compendiumItems
.filter(it => it.type == itemType)
const ids = items.map(it => it.id)
const names = items.map(it => Grammar.toLowerCaseNoAccent(it.name))
const compendiumItems = await SystemCompendiums.getItems(compendium, itemType)
return items.concat(compendiumItems
.filter(it => !ids.includes(it.id))
.filter(it => !names.includes(it.name.toLowerCase())));
.filter(it => !names.includes(Grammar.equalsInsensitive(it.name))))
}
return items;
return items
}
static async loadDocument(document) {
@ -284,23 +286,20 @@ export class CompendiumTableHelpers {
}
/* -------------------------------------------- */
static async tableRowToChatMessage(row, type = 'Item') {
static async tableRowToChatMessage(row, type, options = { showSource: true }) {
if (!row) {
return;
}
const percentages = (row.total == 100) ? '%' : ''
const flavorContent = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-compendium-table-roll.hbs', {
roll: row.roll,
document: row.document,
percentages,
typeName: Misc.typeName(type, row.document?.type ?? 'objet'),
isGM: game.user.isGM,
options
});
const messageData = {
// flavor: flavorContent,
user: game.user.id,
type: CONST.CHAT_MESSAGE_TYPES.ROLL,
roll: row.roll,
rolls: [row.roll],
sound: CONFIG.sounds.dice,
content: flavorContent
};

View File

@ -26,22 +26,19 @@ export class TMRRencontres {
* @param {*} forcedRoll
*/
async rollRencontre(terrain, forcedRoll) {
terrain = TMRUtility.findTMRLike(terrain);
if (terrain == undefined) {
const tmrType = TMRUtility.findTMRLike(terrain)?.type
if (tmrType == undefined) {
return undefined;
}
if (forcedRoll && (forcedRoll <= 0 || forcedRoll > 100)) {
forcedRoll = undefined;
}
const codeTerrain = Grammar.toLowerCaseNoAccent(terrain)
const filtreMauvaise = codeTerrain == 'mauvaise' ? it => it.system.mauvaiseRencontre : it => !it.system.mauvaiseRencontre;
const frequence = it => it.system.frequence[codeTerrain];
const filtreMauvaise = tmrType == 'mauvaise' ? it => it.system.mauvaiseRencontre : it => !it.system.mauvaiseRencontre;
const frequence = it => it.system.frequence[tmrType];
const row = await this.table.getRandom(frequence, filtreMauvaise, forcedRoll);
if (row) {
console.log("DORM", row);
//row.document.system.computedForce = new Roll(row.document.system.formula).roll({async: false}).total;
await CompendiumTableHelpers.tableRowToChatMessage(row);
await CompendiumTableHelpers.tableRowToChatMessage(row, 'Item', {showSource: false});
}
return row?.document;

View File

@ -2,228 +2,216 @@ import { Misc } from "./misc.js";
import { Grammar } from "./grammar.js";
import { RdDDice } from "./rdd-dice.js";
/* -------------------------------------------- */
const TMRMapping = {
A1: { type: "cite", label: "Cité Vide" },
B1: { type: "plaines", label: "Plaines dAssorh" },
C1: { type: "necropole", label: "Nécropole de Kroak" },
D1: { type: "fleuve", label: "Fleuve de l'Oubli" },
E1: { type: "monts", label: "Monts de Kanaï" },
F1: { type: "cite", label: "Cité Glauque" },
G1: { type: "desolation", label: "Désolation de Jamais" },
H1: { type: "lac", label: "Lac dAnticalme" },
I1: { type: "plaines", label: "Plaines Grises" },
J1: { type: "monts", label: "Monts Fainéants" },
K1: { type: "cite", label: "Cité dOnkause" },
L1: { type: "fleuve", label: "Fleuve de l'Oubli" },
M1: { type: "cite", label: "Cité Jalouse" },
A2: { type: "desert", label: "Désert de Mieux" },
B2: { type: "collines", label: "Collines de Dawell" },
C2: { type: "marais", label: "Marais Glignants" },
D2: { type: "cite", label: "Cité de Frost" },
E2: { type: "plaines", label: "Plaines de Fiask" },
F2: { type: "lac", label: "Lac de Misère" },
G2: { type: "marais", label: "Marais Nuisants" },
H2: { type: "collines", label: "Collines de Parta" },
I2: { type: "foret", label: "Forêt Fade" },
J2: { type: "desert", label: "Désert de Poly" },
K2: { type: "foret", label: "Forêt Tamée" },
L2: { type: "fleuve", label: "Fleuve de l'Oubli" },
M2: { type: "necropole", label: "Nécropole de Logos" },
A3: { type: "desolation", label: "Désolation de Demain" },
B3: { type: "plaines", label: "Plaines de Rubéga" },
C3: { type: "fleuve", label: "Fleuve de l'Oubli" },
D3: { type: "gouffre", label: "Gouffre dOki" },
E3: { type: "foret", label: "Forêt dEstoubh" },
F3: { type: "fleuve", label: "Fleuve de l'Oubli" },
G3: { type: "gouffre", label: "Gouffre de Sun" },
H3: { type: "foret", label: "Forêt de Ganna" },
I3: { type: "monts", label: "Monts Grinçants" },
J3: { type: "cite", label: "Cité Venin" },
K3: { type: "plaines", label: "Plaines de Dois" },
L3: { type: "lac", label: "Lac Laineux" },
M3: { type: "monts", label: "Monts de Vdah" },
A4: { type: "foret", label: "Forêt de Falconax" },
B4: { type: "monts", label: "Monts Crâneurs" },
C4: { type: "pont", label: "Pont de Giolii" },
D4: { type: "lac", label: "Lac de Foam" },
E4: { type: "plaines", label: "Plaines dOrti" },
F4: { type: "fleuve", label: "Fleuve de l'Oubli" },
G4: { type: "sanctuaire", label: "Sanctuaire Blanc" },
H4: { type: "plaines", label: "Plaines de Psark" },
I4: { type: "plaines", label: "Plaines de Xiax" },
J4: { type: "collines", label: "Collines dEncre" },
K4: { type: "pont", label: "Pont de Fah" },
L4: { type: "sanctuaire", label: "Sanctuaire Mauve" },
M4: { type: "gouffre", label: "Gouffre Grisant" },
A5: { type: "plaines", label: "Plaines de Trilkh" },
B5: { type: "collines", label: "Collines de Tanegy" },
C5: { type: "marais", label: "Marais Flouants" },
D5: { type: "fleuve", label: "Fleuve de l'Oubli" },
E5: { type: "monts", label: "Monts Brûlants" },
F5: { type: "cite", label: "Cité de Panople" },
G5: { type: "pont", label: "Pont dIk" },
H5: { type: "desert", label: "Désert de Krane" },
I5: { type: "desolation", label: "Désolation de Toujours" },
J5: { type: "marais", label: "Marais de Jab" },
K5: { type: "fleuve", label: "Fleuve de l'Oubli" },
L5: { type: "collines", label: "Collines Suaves" },
M5: { type: "cite", label: "Cité Rimarde" },
A6: { type: "necropole", label: "Nécropole de Zniak" },
B6: { type: "foret", label: "Forêt de Bust" },
C6: { type: "cite", label: "Cité Pavois" },
D6: { type: "fleuve", label: "Fleuve de l'Oubli" },
E6: { type: "sanctuaire", label: "Sanctuaire de Plaine" },
F6: { type: "fleuve", label: "Fleuve de l'Oubli" },
G6: { type: "marais", label: "Marais Glutants" },
H6: { type: "monts", label: "Monts Gurdes" },
I6: { type: "necropole", label: "Nécropole de Xotar" },
J6: { type: "lac", label: "Lac dIaupe" },
K6: { type: "desolation", label: "Désolation de Poor" },
L6: { type: "foret", label: "Forêt Gueuse" },
M6: { type: "desolation", label: "Désolation de Presque" },
A7: { type: "plaines", label: "Plaines de lArc" },
B7: { type: "marais", label: "Marais Bluants" },
C7: { type: "fleuve", label: "Fleuve de l'Oubli" },
D7: { type: "plaines", label: "Plaines dAffa" },
E7: { type: "foret", label: "Forêt de Glusks" },
F7: { type: "fleuve", label: "Fleuve de l'Oubli" },
G7: { type: "cite", label: "Cité de Terwa" },
H7: { type: "gouffre", label: "Gouffre de Kapfa" },
I7: { type: "plaines", label: "Plaines de Troo" },
J7: { type: "fleuve", label: "Fleuve de l'Oubli" },
K7: { type: "cite", label: "Cité de Kolix" },
L7: { type: "gouffre", label: "Gouffre dEpisophe" },
M7: { type: "desert", label: "Désert de Lave" },
A8: { type: "gouffre", label: "Gouffre de Shok" },
B8: { type: "fleuve", label: "Fleuve de l'Oubli" },
C8: { type: "foret", label: "Forêt Turmide" },
D8: { type: "cite", label: "Cité dOlak" },
E8: { type: "plaines", label: "Plaines dIolise" },
F8: { type: "lac", label: "Lac des Chats" },
G8: { type: "plaines", label: "Plaines Sans Joie" },
H8: { type: "foret", label: "Forêt dOurf" },
I8: { type: "fleuve", label: "Fleuve de l'Oubli" },
J8: { type: "monts", label: "Monts Barask" },
K8: { type: "desert", label: "Désert de Fumée" },
L8: { type: "monts", label: "Monts Tavelés" },
M8: { type: "plaines", label: "Plaines Lavées" },
A9: { type: "collines", label: "Collines de Korrex" },
B9: { type: "lac", label: "Lac de Lucre" },
C9: { type: "monts", label: "Monts Tuméfiés" },
D9: { type: "pont", label: "Pont dOrx" },
E9: { type: "fleuve", label: "Fleuve de l'Oubli" },
F9: { type: "plaines", label: "Plaines de Foe" },
G9: { type: "desolation", label: "Désolation de Sel" },
H9: { type: "collines", label: "Collines de Noirseul" },
I9: { type: "fleuve", label: "Fleuve de l'Oubli" },
J9: { type: "marais", label: "Marais Gronchants" },
K9: { type: "sanctuaire", label: "Sanctuaire Noir" },
L9: { type: "collines", label: "Collines Cornues" },
M9: { type: "necropole", label: "Nécropole de Zonar" },
A10: { type: "sanctuaire", label: "Sanctuaire dOlis" },
B10: { type: "monts", label: "Monts Salés" },
C10: { type: "marais", label: "Marais de Dom" },
D10: { type: "fleuve", label: "Fleuve de l'Oubli" },
E10: { type: "gouffre", label: "Gouffre de Junk" },
F10: { type: "marais", label: "Marais Zultants" },
G10: { type: "cite", label: "Cité de Sergal" },
H10: { type: "plaines", label: "Plaines Noires" },
I10: { type: "lac", label: "Lac Wanito" },
J10: { type: "fleuve", label: "Fleuve de l'Oubli" },
K10: { type: "plaines", label: "Plaines Jaunes" },
L10: { type: "desert", label: "Désert de Nicrop" },
M10: { type: "foret", label: "Forêt de Jajou" },
A11: { type: "desolation", label: "Désolation dHier" },
B11: { type: "cite", label: "Cité de Brilz" },
C11: { type: "pont", label: "Pont de Roï" },
D11: { type: "desolation", label: "Désolation de Partout" },
E11: { type: "lac", label: "Lac de Glinster" },
F11: { type: "cite", label: "Cité de Noape" },
G11: { type: "fleuve", label: "Fleuve de l'Oubli" },
H11: { type: "fleuve", label: "Fleuve de l'Oubli" },
I11: { type: "pont", label: "Pont de Yalm" },
J11: { type: "plaines", label: "Plaines de Miltiar" },
K11: { type: "cite", label: "Cité Tonnerre" },
L11: { type: "collines", label: "Collines de Kol" },
M11: { type: "cite", label: "Cité Crapaud" },
A12: { type: "plaines", label: "Plaines Sages" },
B12: { type: "fleuve", label: "Fleuve de l'Oubli" },
C12: { type: "lac", label: "Lac de Fricassa" },
D12: { type: "collines", label: "Collines dHuaï" },
E12: { type: "monts", label: "Monts Ajourés" },
F12: { type: "necropole", label: "Nécropole de Throat" },
G12: { type: "plaines", label: "Plaines de Lufmil" },
H12: { type: "collines", label: "Collines de Tooth" },
I12: { type: "gouffre", label: "Gouffre Abimeux" },
J12: { type: "cite", label: "Cité Folle" },
K12: { type: "desolation", label: "Désolation dAmour" },
L12: { type: "plaines", label: "Plaines Venteuses" },
M12: { type: "collines", label: "Collines Révulsantes" },
A13: { type: "fleuve", label: "Fleuve de l'Oubli" },
B13: { type: "gouffre", label: "Gouffre des Litiges" },
C13: { type: "desert", label: "Désert de Neige" },
D13: { type: "cite", label: "Cité Sordide" },
E13: { type: "plaines", label: "Plaines de Xnez" },
F13: { type: "foret", label: "Forêt des Cris" },
G13: { type: "plaines", label: "Plaines Calcaires" },
H13: { type: "desolation", label: "Désolation de Rien" },
I13: { type: "monts", label: "Monts Bigleux" },
J13: { type: "gouffre", label: "Gouffre de Gromph" },
K13: { type: "foret", label: "Forêt de Kluth" },
L13: { type: "monts", label: "Monts Dormants" },
M13: { type: "plaines", label: "Plaines dAnjou" },
A14: { type: "collines", label: "Collines de Stolis" },
B14: { type: "necropole", label: "Nécropole de Gorlo" },
C14: { type: "foret", label: "Forêt de Bissam" },
D14: { type: "sanctuaire", label: "Sanctuaire Plat" },
E14: { type: "monts", label: "Monts de Quath" },
F14: { type: "plaines", label: "Plaines Brisées" },
G14: { type: "desert", label: "Désert de Sek" },
H14: { type: "plaines", label: "Plaines Blanches" },
I14: { type: "cite", label: "Cité Destituée" },
J14: { type: "desert", label: "Désert de Sank" },
K14: { type: "necropole", label: "Nécropole dAntinéar" },
L14: { type: "plaines", label: "Plaines de Jislith" },
M14: { type: "desolation", label: "Désolation dAprès" },
A15: { type: "cite", label: "Cité de Mielh" },
C15: { type: "plaines", label: "Plaines de Toué" },
E15: { type: "foret", label: "Forêt des Furies" },
G15: { type: "plaines", label: "Plaines des Soupirs" },
I15: { type: "monts", label: "Monts des Dragées" },
K15: { type: "collines", label: "Collines Pourpres" },
M15: { type: "cite", label: "Cité de Klana" }
export const TMRType = {
cite: { type: 'cite', name: "cité", genre: "f" },
sanctuaire: { type: 'sanctuaire', name: "sanctuaire", genre: 'm' },
plaines: { type: 'plaines', name: "plaines", genre: "fp" },
pont: { type: 'pont', name: "pont", genre: "m" },
collines: { type: 'collines', name: "collines", genre: "p" },
foret: { type: 'foret', name: "forêt", genre: "f" },
monts: { type: 'monts', name: "monts", genre: "p" },
desert: { type: 'desert', name: "désert", genre: "m" },
fleuve: { type: 'fleuve', name: "fleuve", genre: "m" },
lac: { type: 'lac', name: "lac", genre: "m" },
marais: { type: 'marais', name: "marais", genre: "m" },
gouffre: { type: 'gouffre', name: "gouffre", genre: "m" },
necropole: { type: 'necropole', name: "nécropole", genre: "f" },
desolation: { type: 'desolation', name: "désolation", genre: "f" }
}
export const TMRType = {
cite: { name: "cité", genre: "f" },
sanctuaire: { name: "sanctuaire", genre: 'm' },
plaines: { name: "plaines", genre: "fp" },
pont: { name: "pont", genre: "m" },
collines: { name: "collines", genre: "p" },
foret: { name: "forêt", genre: "f" },
monts: { name: "monts", genre: "p" },
desert: { name: "désert", genre: "m" },
fleuve: { name: "fleuve", genre: "m" },
lac: { name: "lac", genre: "m" },
marais: { name: "marais", genre: "m" },
gouffre: { name: "gouffre", genre: "m" },
necropole: { name: "nécropole", genre: "f" },
desolation: { name: "désolation", genre: "f" }
export const FLEUVE_COORD = 'Fleuve'
const TMRMapping = {
Fleuve: { type: TMRType.fleuve.type, label: "Fleuve de l'Oubli" },
A1: { type: TMRType.cite.type, label: "Cité Vide" },
B1: { type: TMRType.plaines.type, label: "Plaines dAssorh" },
C1: { type: TMRType.necropole.type, label: "Nécropole de Kroak" },
D1: { type: TMRType.fleuve.type, label: "Fleuve de l'Oubli" },
E1: { type: TMRType.monts.type, label: "Monts de Kanaï" },
F1: { type: TMRType.cite.type, label: "Cité Glauque" },
G1: { type: TMRType.desolation.type, label: "Désolation de Jamais" },
H1: { type: TMRType.lac.type, label: "Lac dAnticalme" },
I1: { type: TMRType.plaines.type, label: "Plaines Grises" },
J1: { type: TMRType.monts.type, label: "Monts Fainéants" },
K1: { type: TMRType.cite.type, label: "Cité dOnkause" },
L1: { type: TMRType.fleuve.type, label: "Fleuve de l'Oubli" },
M1: { type: TMRType.cite.type, label: "Cité Jalouse" },
A2: { type: TMRType.desert.type, label: "Désert de Mieux" },
B2: { type: TMRType.collines.type, label: "Collines de Dawell" },
C2: { type: TMRType.marais.type, label: "Marais Glignants" },
D2: { type: TMRType.cite.type, label: "Cité de Frost" },
E2: { type: TMRType.plaines.type, label: "Plaines de Fiask" },
F2: { type: TMRType.lac.type, label: "Lac de Misère" },
G2: { type: TMRType.marais.type, label: "Marais Nuisants" },
H2: { type: TMRType.collines.type, label: "Collines de Parta" },
I2: { type: TMRType.foret.type, label: "Forêt Fade" },
J2: { type: TMRType.desert.type, label: "Désert de Poly" },
K2: { type: TMRType.foret.type, label: "Forêt Tamée" },
L2: { type: TMRType.fleuve.type, label: "Fleuve de l'Oubli" },
M2: { type: TMRType.necropole.type, label: "Nécropole de Logos" },
A3: { type: TMRType.desolation.type, label: "Désolation de Demain" },
B3: { type: TMRType.plaines.type, label: "Plaines de Rubéga" },
C3: { type: TMRType.fleuve.type, label: "Fleuve de l'Oubli" },
D3: { type: TMRType.gouffre.type, label: "Gouffre dOki" },
E3: { type: TMRType.foret.type, label: "Forêt dEstoubh" },
F3: { type: TMRType.fleuve.type, label: "Fleuve de l'Oubli" },
G3: { type: TMRType.gouffre.type, label: "Gouffre de Sun" },
H3: { type: TMRType.foret.type, label: "Forêt de Ganna" },
I3: { type: TMRType.monts.type, label: "Monts Grinçants" },
J3: { type: TMRType.cite.type, label: "Cité Venin" },
K3: { type: TMRType.plaines.type, label: "Plaines de Dois" },
L3: { type: TMRType.lac.type, label: "Lac Laineux" },
M3: { type: TMRType.monts.type, label: "Monts de Vdah" },
A4: { type: TMRType.foret.type, label: "Forêt de Falconax" },
B4: { type: TMRType.monts.type, label: "Monts Crâneurs" },
C4: { type: TMRType.pont.type, label: "Pont de Giolii" },
D4: { type: TMRType.lac.type, label: "Lac de Foam" },
E4: { type: TMRType.plaines.type, label: "Plaines dOrti" },
F4: { type: TMRType.fleuve.type, label: "Fleuve de l'Oubli" },
G4: { type: TMRType.sanctuaire.type, label: "Sanctuaire Blanc" },
H4: { type: TMRType.plaines.type, label: "Plaines de Psark" },
I4: { type: TMRType.plaines.type, label: "Plaines de Xiax" },
J4: { type: TMRType.collines.type, label: "Collines dEncre" },
K4: { type: TMRType.pont.type, label: "Pont de Fah" },
L4: { type: TMRType.sanctuaire.type, label: "Sanctuaire Mauve" },
M4: { type: TMRType.gouffre.type, label: "Gouffre Grisant" },
A5: { type: TMRType.plaines.type, label: "Plaines de Trilkh" },
B5: { type: TMRType.collines.type, label: "Collines de Tanegy" },
C5: { type: TMRType.marais.type, label: "Marais Flouants" },
D5: { type: TMRType.fleuve.type, label: "Fleuve de l'Oubli" },
E5: { type: TMRType.monts.type, label: "Monts Brûlants" },
F5: { type: TMRType.cite.type, label: "Cité de Panople" },
G5: { type: TMRType.pont.type, label: "Pont dIk" },
H5: { type: TMRType.desert.type, label: "Désert de Krane" },
I5: { type: TMRType.desolation.type, label: "Désolation de Toujours" },
J5: { type: TMRType.marais.type, label: "Marais de Jab" },
K5: { type: TMRType.fleuve.type, label: "Fleuve de l'Oubli" },
L5: { type: TMRType.collines.type, label: "Collines Suaves" },
M5: { type: TMRType.cite.type, label: "Cité Rimarde" },
A6: { type: TMRType.necropole.type, label: "Nécropole de Zniak" },
B6: { type: TMRType.foret.type, label: "Forêt de Bust" },
C6: { type: TMRType.cite.type, label: "Cité Pavois" },
D6: { type: TMRType.fleuve.type, label: "Fleuve de l'Oubli" },
E6: { type: TMRType.sanctuaire.type, label: "Sanctuaire de Plaine" },
F6: { type: TMRType.fleuve.type, label: "Fleuve de l'Oubli" },
G6: { type: TMRType.marais.type, label: "Marais Glutants" },
H6: { type: TMRType.monts.type, label: "Monts Gurdes" },
I6: { type: TMRType.necropole.type, label: "Nécropole de Xotar" },
J6: { type: TMRType.lac.type, label: "Lac dIaupe" },
K6: { type: TMRType.desolation.type, label: "Désolation de Poor" },
L6: { type: TMRType.foret.type, label: "Forêt Gueuse" },
M6: { type: TMRType.desolation.type, label: "Désolation de Presque" },
A7: { type: TMRType.plaines.type, label: "Plaines de lArc" },
B7: { type: TMRType.marais.type, label: "Marais Bluants" },
C7: { type: TMRType.fleuve.type, label: "Fleuve de l'Oubli" },
D7: { type: TMRType.plaines.type, label: "Plaines dAffa" },
E7: { type: TMRType.foret.type, label: "Forêt de Glusks" },
F7: { type: TMRType.fleuve.type, label: "Fleuve de l'Oubli" },
G7: { type: TMRType.cite.type, label: "Cité de Terwa" },
H7: { type: TMRType.gouffre.type, label: "Gouffre de Kapfa" },
I7: { type: TMRType.plaines.type, label: "Plaines de Troo" },
J7: { type: TMRType.fleuve.type, label: "Fleuve de l'Oubli" },
K7: { type: TMRType.cite.type, label: "Cité de Kolix" },
L7: { type: TMRType.gouffre.type, label: "Gouffre dEpisophe" },
M7: { type: TMRType.desert.type, label: "Désert de Lave" },
A8: { type: TMRType.gouffre.type, label: "Gouffre de Shok" },
B8: { type: TMRType.fleuve.type, label: "Fleuve de l'Oubli" },
C8: { type: TMRType.foret.type, label: "Forêt Turmide" },
D8: { type: TMRType.cite.type, label: "Cité dOlak" },
E8: { type: TMRType.plaines.type, label: "Plaines dIolise" },
F8: { type: TMRType.lac.type, label: "Lac des Chats" },
G8: { type: TMRType.plaines.type, label: "Plaines Sans Joie" },
H8: { type: TMRType.foret.type, label: "Forêt dOurf" },
I8: { type: TMRType.fleuve.type, label: "Fleuve de l'Oubli" },
J8: { type: TMRType.monts.type, label: "Monts Barask" },
K8: { type: TMRType.desert.type, label: "Désert de Fumée" },
L8: { type: TMRType.monts.type, label: "Monts Tavelés" },
M8: { type: TMRType.plaines.type, label: "Plaines Lavées" },
A9: { type: TMRType.collines.type, label: "Collines de Korrex" },
B9: { type: TMRType.lac.type, label: "Lac de Lucre" },
C9: { type: TMRType.monts.type, label: "Monts Tuméfiés" },
D9: { type: TMRType.pont.type, label: "Pont dOrx" },
E9: { type: TMRType.fleuve.type, label: "Fleuve de l'Oubli" },
F9: { type: TMRType.plaines.type, label: "Plaines de Foe" },
G9: { type: TMRType.desolation.type, label: "Désolation de Sel" },
H9: { type: TMRType.collines.type, label: "Collines de Noirseul" },
I9: { type: TMRType.fleuve.type, label: "Fleuve de l'Oubli" },
J9: { type: TMRType.marais.type, label: "Marais Gronchants" },
K9: { type: TMRType.sanctuaire.type, label: "Sanctuaire Noir" },
L9: { type: TMRType.collines.type, label: "Collines Cornues" },
M9: { type: TMRType.necropole.type, label: "Nécropole de Zonar" },
A10: { type: TMRType.sanctuaire.type, label: "Sanctuaire dOlis" },
B10: { type: TMRType.monts.type, label: "Monts Salés" },
C10: { type: TMRType.marais.type, label: "Marais de Dom" },
D10: { type: TMRType.fleuve.type, label: "Fleuve de l'Oubli" },
E10: { type: TMRType.gouffre.type, label: "Gouffre de Junk" },
F10: { type: TMRType.marais.type, label: "Marais Zultants" },
G10: { type: TMRType.cite.type, label: "Cité de Sergal" },
H10: { type: TMRType.plaines.type, label: "Plaines Noires" },
I10: { type: TMRType.lac.type, label: "Lac Wanito" },
J10: { type: TMRType.fleuve.type, label: "Fleuve de l'Oubli" },
K10: { type: TMRType.plaines.type, label: "Plaines Jaunes" },
L10: { type: TMRType.desert.type, label: "Désert de Nicrop" },
M10: { type: TMRType.foret.type, label: "Forêt de Jajou" },
A11: { type: TMRType.desolation.type, label: "Désolation dHier" },
B11: { type: TMRType.cite.type, label: "Cité de Brilz" },
C11: { type: TMRType.pont.type, label: "Pont de Roï" },
D11: { type: TMRType.desolation.type, label: "Désolation de Partout" },
E11: { type: TMRType.lac.type, label: "Lac de Glinster" },
F11: { type: TMRType.cite.type, label: "Cité de Noape" },
G11: { type: TMRType.fleuve.type, label: "Fleuve de l'Oubli" },
H11: { type: TMRType.fleuve.type, label: "Fleuve de l'Oubli" },
I11: { type: TMRType.pont.type, label: "Pont de Yalm" },
J11: { type: TMRType.plaines.type, label: "Plaines de Miltiar" },
K11: { type: TMRType.cite.type, label: "Cité Tonnerre" },
L11: { type: TMRType.collines.type, label: "Collines de Kol" },
M11: { type: TMRType.cite.type, label: "Cité Crapaud" },
A12: { type: TMRType.plaines.type, label: "Plaines Sages" },
B12: { type: TMRType.fleuve.type, label: "Fleuve de l'Oubli" },
C12: { type: TMRType.lac.type, label: "Lac de Fricassa" },
D12: { type: TMRType.collines.type, label: "Collines dHuaï" },
E12: { type: TMRType.monts.type, label: "Monts Ajourés" },
F12: { type: TMRType.necropole.type, label: "Nécropole de Throat" },
G12: { type: TMRType.plaines.type, label: "Plaines de Lufmil" },
H12: { type: TMRType.collines.type, label: "Collines de Tooth" },
I12: { type: TMRType.gouffre.type, label: "Gouffre Abimeux" },
J12: { type: TMRType.cite.type, label: "Cité Folle" },
K12: { type: TMRType.desolation.type, label: "Désolation dAmour" },
L12: { type: TMRType.plaines.type, label: "Plaines Venteuses" },
M12: { type: TMRType.collines.type, label: "Collines Révulsantes" },
A13: { type: TMRType.fleuve.type, label: "Fleuve de l'Oubli" },
B13: { type: TMRType.gouffre.type, label: "Gouffre des Litiges" },
C13: { type: TMRType.desert.type, label: "Désert de Neige" },
D13: { type: TMRType.cite.type, label: "Cité Sordide" },
E13: { type: TMRType.plaines.type, label: "Plaines de Xnez" },
F13: { type: TMRType.foret.type, label: "Forêt des Cris" },
G13: { type: TMRType.plaines.type, label: "Plaines Calcaires" },
H13: { type: TMRType.desolation.type, label: "Désolation de Rien" },
I13: { type: TMRType.monts.type, label: "Monts Bigleux" },
J13: { type: TMRType.gouffre.type, label: "Gouffre de Gromph" },
K13: { type: TMRType.foret.type, label: "Forêt de Kluth" },
L13: { type: TMRType.monts.type, label: "Monts Dormants" },
M13: { type: TMRType.plaines.type, label: "Plaines dAnjou" },
A14: { type: TMRType.collines.type, label: "Collines de Stolis" },
B14: { type: TMRType.necropole.type, label: "Nécropole de Gorlo" },
C14: { type: TMRType.foret.type, label: "Forêt de Bissam" },
D14: { type: TMRType.sanctuaire.type, label: "Sanctuaire Plat" },
E14: { type: TMRType.monts.type, label: "Monts de Quath" },
F14: { type: TMRType.plaines.type, label: "Plaines Brisées" },
G14: { type: TMRType.desert.type, label: "Désert de Sek" },
H14: { type: TMRType.plaines.type, label: "Plaines Blanches" },
I14: { type: TMRType.cite.type, label: "Cité Destituée" },
J14: { type: TMRType.desert.type, label: "Désert de Sank" },
K14: { type: TMRType.necropole.type, label: "Nécropole dAntinéar" },
L14: { type: TMRType.plaines.type, label: "Plaines de Jislith" },
M14: { type: TMRType.desolation.type, label: "Désolation dAprès" },
A15: { type: TMRType.cite.type, label: "Cité de Mielh" },
C15: { type: TMRType.plaines.type, label: "Plaines de Toué" },
E15: { type: TMRType.foret.type, label: "Forêt des Furies" },
G15: { type: TMRType.plaines.type, label: "Plaines des Soupirs" },
I15: { type: TMRType.monts.type, label: "Monts des Dragées" },
K15: { type: TMRType.collines.type, label: "Collines Pourpres" },
M15: { type: TMRType.cite.type, label: "Cité de Klana" }
}
/* -------------------------------------------- */
@ -251,13 +239,16 @@ const TMR_MOVE = {
*/
export class TMRUtility {
static init() {
for (let coord in TMRMapping) {
const tmr = TMRMapping[coord];
tmr.coord = coord;
tmr.oddq = TMRUtility.coordTMRToOddq(coord);
tmr.genre = TMRType[tmr.type].genre;
const tmr = TMRMapping[coord]
tmr.coord = coord
tmr.genre = TMRType[tmr.type].genre
if (coord != FLEUVE_COORD) {
tmr.oddq = TMRUtility.coordTMRToOddq(coord)
}
}
let tmrByType = Misc.classify(Object.values(TMRMapping));
let tmrByType = Misc.classify(Object.values(TMRMapping).filter(it => it.coord != FLEUVE_COORD))
for (const [type, list] of Object.entries(tmrByType)) {
TMRType[type].list = list;
}
@ -265,14 +256,17 @@ export class TMRUtility {
/* -------------------------------------------- */
static verifyTMRCoord(coord) {
return Grammar.equalsInsensitive(coord, 'Fleuve') || TMRUtility.getTMR(coord);
return Grammar.equalsInsensitive(coord, FLEUVE_COORD) || TMRUtility.getTMR(coord);
}
/* -------------------------------------------- */
static getTMR(coord) {
return coord == 'Fleuve' ? TMRMapping['D1'] : TMRMapping[coord];
return coord == FLEUVE_COORD ? TMRMapping['D1'] : TMRMapping[coord];
}
static isFleuve(coord) {
return TMRMapping[coord]?.type == TMRType.fleuve.type
}
static getTMRLabel(coord) {
return TMRUtility.getTMR(coord)?.label ?? (coord + ": case inconnue");
}
@ -290,18 +284,18 @@ export class TMRUtility {
static findTMRLike(type, options = { inclusMauvaise: true }) {
const choix = [...Object.values(TMRType)]
if (options.inclusMauvaise) {
choix.push({ name: 'Mauvaise' });
choix.push({ name: 'Mauvaise', type: 'mauvaise'});
}
const selection = Misc.findAllLike(type, choix).map(it => it.name);
const selection = Misc.findAllLike(type, choix)
if (selection.length == 0) {
ui.notifications.warn(`Un type de TMR doit être indiqué, '${type}' n'est pas trouvé dans ${choix}`);
return undefined;
return undefined
}
if (selection.length > 1) {
ui.notifications.warn(`Plusieurs types de TMR pourraient correspondre à '${type}': ${selection}`);
ui.notifications.warn(`Plusieurs types de TMR pourraient correspondre à '${type}': ${selection.map(it => it.name)}`);
return undefined;
}
return selection[0];
return selection[0]
}
static typeTmrName(type) {
@ -326,7 +320,7 @@ export class TMRUtility {
/* -------------------------------------------- */
static deplacement(coordOrig, moveName) {
const tmrMove = TMR_MOVE[moveName];
if (! tmrMove) {
if (!tmrMove) {
ui.notifications.error(`Le déplacement dans les TMR '${moveName}' est inconnu`)
return coordOrig
}

View File

@ -3670,7 +3670,7 @@ items:
mortalite: mortel
penetration: 0
force: '13'
competence: Epée à 2 mains
competence: Épée à 2 mains
lancer: ''
tir: ''
portee_courte: 0
@ -4001,7 +4001,7 @@ items:
mortalite: mortel
penetration: 0
force: 13/12
competence: Epée à 1 main
competence: Épée à 1 main
lancer: ''
tir: ''
portee_courte: 0
@ -4052,7 +4052,7 @@ items:
mortalite: mortel
penetration: 0
force: '11'
competence: Epée à 1 main
competence: Épée à 1 main
lancer: ''
tir: ''
portee_courte: 0
@ -4099,7 +4099,7 @@ items:
mortalite: mortel
penetration: 0
force: '10'
competence: Epée à 1 main
competence: Épée à 1 main
lancer: ''
tir: ''
portee_courte: 0
@ -4152,7 +4152,7 @@ items:
mortalite: mortel
penetration: 0
force: '11'
competence: Epée à 1 main
competence: Épée à 1 main
lancer: ''
tir: ''
portee_courte: 0
@ -4204,7 +4204,7 @@ items:
mortalite: mortel
penetration: 0
force: '8'
competence: Epée à 1 main
competence: Épée à 1 main
lancer: ''
tir: ''
portee_courte: 0
@ -4260,7 +4260,7 @@ items:
mortalite: mortel
penetration: null
force: 12/11
competence: Epée à 1 main
competence: Épée à 1 main
lancer: ''
tir: ''
portee_courte: 0
@ -4353,7 +4353,7 @@ items:
mortalite: mortel
penetration: 0
force: '10'
competence: Epée à 1 main
competence: Épée à 1 main
lancer: ''
tir: ''
portee_courte: 0

View File

@ -673,7 +673,7 @@ items:
coreVersion: '12.331'
_key: '!actors.items!ryUZTa17LzNv25UY.94P55yZfeipCGbsr'
- _id: qmIpUeedvjC8nGF1
name: Ecriture
name: Écriture
type: competence
sort: 2300000
flags: {}
@ -703,7 +703,7 @@ items:
coreVersion: '12.331'
_key: '!actors.items!ryUZTa17LzNv25UY.qmIpUeedvjC8nGF1'
- _id: fPhPcCP3sbS6mfbS
name: Epée à 1 main
name: Épée à 1 main
type: competence
sort: 2400000
flags: {}
@ -735,7 +735,7 @@ items:
coreVersion: '12.331'
_key: '!actors.items!ryUZTa17LzNv25UY.fPhPcCP3sbS6mfbS'
- _id: MLIEbxSJHkY1m3No
name: Epée à 2 mains
name: Épée à 2 mains
type: competence
sort: 2500000
flags: {}

View File

@ -673,7 +673,7 @@ items:
coreVersion: '12.331'
_key: '!actors.items!ohmz9Jn4jxD88Kll.94P55yZfeipCGbsr'
- _id: qmIpUeedvjC8nGF1
name: Ecriture
name: Écriture
type: competence
sort: 2300000
flags: {}
@ -703,7 +703,7 @@ items:
coreVersion: '12.331'
_key: '!actors.items!ohmz9Jn4jxD88Kll.qmIpUeedvjC8nGF1'
- _id: fPhPcCP3sbS6mfbS
name: Epée à 1 main
name: Épée à 1 main
type: competence
sort: 2400000
flags: {}
@ -735,7 +735,7 @@ items:
coreVersion: '12.331'
_key: '!actors.items!ohmz9Jn4jxD88Kll.fPhPcCP3sbS6mfbS'
- _id: MLIEbxSJHkY1m3No
name: Epée à 2 mains
name: Épée à 2 mains
type: competence
sort: 2500000
flags: {}

View File

@ -673,7 +673,7 @@ items:
coreVersion: '12.331'
_key: '!actors.items!JARnWt2MQWDyRwQt.94P55yZfeipCGbsr'
- _id: qmIpUeedvjC8nGF1
name: Ecriture
name: Écriture
type: competence
sort: 2300000
flags: {}
@ -703,7 +703,7 @@ items:
coreVersion: '12.331'
_key: '!actors.items!JARnWt2MQWDyRwQt.qmIpUeedvjC8nGF1'
- _id: fPhPcCP3sbS6mfbS
name: Epée à 1 main
name: Épée à 1 main
type: competence
sort: 2400000
flags: {}
@ -735,7 +735,7 @@ items:
coreVersion: '12.331'
_key: '!actors.items!JARnWt2MQWDyRwQt.fPhPcCP3sbS6mfbS'
- _id: MLIEbxSJHkY1m3No
name: Epée à 2 mains
name: Épée à 2 mains
type: competence
sort: 2500000
flags: {}
@ -2239,7 +2239,7 @@ items:
mortalite: mortel
penetration: 0
force: 13/12
competence: Epée à 1 main
competence: Épée à 1 main
lancer: ''
tir: ''
portee_courte: 0

View File

@ -651,7 +651,7 @@ items:
coreVersion: '12.331'
_key: '!actors.items!SJb0c8FDcYdd41rB.94P55yZfeipCGbsr'
- _id: qmIpUeedvjC8nGF1
name: Ecriture
name: Écriture
type: competence
sort: 2300000
img: systems/foundryvtt-reve-de-dragon/icons/competence_ecriture.webp
@ -680,7 +680,7 @@ items:
coreVersion: '12.331'
_key: '!actors.items!SJb0c8FDcYdd41rB.qmIpUeedvjC8nGF1'
- _id: fPhPcCP3sbS6mfbS
name: Epée à 1 main
name: Épée à 1 main
type: competence
sort: 2400000
img: systems/foundryvtt-reve-de-dragon/icons/competence_epee_1_main.webp
@ -711,7 +711,7 @@ items:
coreVersion: '12.331'
_key: '!actors.items!SJb0c8FDcYdd41rB.fPhPcCP3sbS6mfbS'
- _id: MLIEbxSJHkY1m3No
name: Epée à 2 mains
name: Épée à 2 mains
type: competence
sort: 2500000
img: systems/foundryvtt-reve-de-dragon/icons/competence_epee_2_mains.webp

View File

@ -673,7 +673,7 @@ items:
coreVersion: '12.331'
_key: '!actors.items!JQCwAOK64Yijwtch.94P55yZfeipCGbsr'
- _id: qmIpUeedvjC8nGF1
name: Ecriture
name: Écriture
type: competence
sort: 2300000
flags: {}
@ -703,7 +703,7 @@ items:
coreVersion: '12.331'
_key: '!actors.items!JQCwAOK64Yijwtch.qmIpUeedvjC8nGF1'
- _id: fPhPcCP3sbS6mfbS
name: Epée à 1 main
name: Épée à 1 main
type: competence
sort: 2400000
flags: {}
@ -735,7 +735,7 @@ items:
coreVersion: '12.331'
_key: '!actors.items!JQCwAOK64Yijwtch.fPhPcCP3sbS6mfbS'
- _id: MLIEbxSJHkY1m3No
name: Epée à 2 mains
name: Épée à 2 mains
type: competence
sort: 2500000
flags: {}

View File

@ -673,7 +673,7 @@ items:
coreVersion: '12.331'
_key: '!actors.items!CRRP8ucJpljX6tq8.94P55yZfeipCGbsr'
- _id: qmIpUeedvjC8nGF1
name: Ecriture
name: Écriture
type: competence
sort: 2300000
flags: {}
@ -703,7 +703,7 @@ items:
coreVersion: '12.331'
_key: '!actors.items!CRRP8ucJpljX6tq8.qmIpUeedvjC8nGF1'
- _id: fPhPcCP3sbS6mfbS
name: Epée à 1 main
name: Épée à 1 main
type: competence
sort: 2400000
flags: {}
@ -735,7 +735,7 @@ items:
coreVersion: '12.331'
_key: '!actors.items!CRRP8ucJpljX6tq8.fPhPcCP3sbS6mfbS'
- _id: MLIEbxSJHkY1m3No
name: Epée à 2 mains
name: Épée à 2 mains
type: competence
sort: 2500000
flags: {}

View File

@ -673,7 +673,7 @@ items:
coreVersion: '12.331'
_key: '!actors.items!51vL4MhEE0asjgF2.94P55yZfeipCGbsr'
- _id: qmIpUeedvjC8nGF1
name: Ecriture
name: Écriture
type: competence
sort: 2300000
flags: {}
@ -703,7 +703,7 @@ items:
coreVersion: '12.331'
_key: '!actors.items!51vL4MhEE0asjgF2.qmIpUeedvjC8nGF1'
- _id: fPhPcCP3sbS6mfbS
name: Epée à 1 main
name: Épée à 1 main
type: competence
sort: 2400000
flags: {}
@ -735,7 +735,7 @@ items:
coreVersion: '12.331'
_key: '!actors.items!51vL4MhEE0asjgF2.fPhPcCP3sbS6mfbS'
- _id: MLIEbxSJHkY1m3No
name: Epée à 2 mains
name: Épée à 2 mains
type: competence
sort: 2500000
flags: {}
@ -2086,7 +2086,7 @@ items:
mortalite: mortel
penetration: 0
force: 12/11
competence: Epée à 1 main
competence: Épée à 1 main
lancer: ''
tir: ''
portee_courte: 0

View File

@ -673,7 +673,7 @@ items:
coreVersion: '12.331'
_key: '!actors.items!NX1nAqKKIcQlyGua.94P55yZfeipCGbsr'
- _id: qmIpUeedvjC8nGF1
name: Ecriture
name: Écriture
type: competence
sort: 2300000
flags: {}
@ -703,7 +703,7 @@ items:
coreVersion: '12.331'
_key: '!actors.items!NX1nAqKKIcQlyGua.qmIpUeedvjC8nGF1'
- _id: fPhPcCP3sbS6mfbS
name: Epée à 1 main
name: Épée à 1 main
type: competence
sort: 2400000
flags: {}
@ -735,7 +735,7 @@ items:
coreVersion: '12.331'
_key: '!actors.items!NX1nAqKKIcQlyGua.fPhPcCP3sbS6mfbS'
- _id: MLIEbxSJHkY1m3No
name: Epée à 2 mains
name: Épée à 2 mains
type: competence
sort: 2500000
flags: {}
@ -2086,7 +2086,7 @@ items:
mortalite: mortel
penetration: 0
force: 12/11
competence: Epée à 1 main
competence: Épée à 1 main
lancer: ''
tir: ''
portee_courte: 0

View File

@ -1,5 +1,5 @@
_id: IeKSXignUpfUTU4m
name: Garde - Epée/bouclier niv.5
name: Garde - Épée/bouclier niv.5
type: personnage
img: systems/foundryvtt-reve-de-dragon/icons/archetypes/fantassin.webp
items:
@ -673,7 +673,7 @@ items:
coreVersion: '12.331'
_key: '!actors.items!IeKSXignUpfUTU4m.94P55yZfeipCGbsr'
- _id: qmIpUeedvjC8nGF1
name: Ecriture
name: Écriture
type: competence
sort: 2300000
flags: {}
@ -703,7 +703,7 @@ items:
coreVersion: '12.331'
_key: '!actors.items!IeKSXignUpfUTU4m.qmIpUeedvjC8nGF1'
- _id: fPhPcCP3sbS6mfbS
name: Epée à 1 main
name: Épée à 1 main
type: competence
sort: 2400000
flags: {}
@ -735,7 +735,7 @@ items:
coreVersion: '12.331'
_key: '!actors.items!IeKSXignUpfUTU4m.fPhPcCP3sbS6mfbS'
- _id: MLIEbxSJHkY1m3No
name: Epée à 2 mains
name: Épée à 2 mains
type: competence
sort: 2500000
flags: {}
@ -2117,7 +2117,7 @@ items:
mortalite: mortel
penetration: 0
force: 12/11
competence: Epée à 1 main
competence: Épée à 1 main
lancer: ''
tir: ''
portee_courte: 0

View File

@ -673,7 +673,7 @@ items:
coreVersion: '12.331'
_key: '!actors.items!2bRaEDuwZezKAyEq.94P55yZfeipCGbsr'
- _id: qmIpUeedvjC8nGF1
name: Ecriture
name: Écriture
type: competence
sort: 2300000
flags: {}
@ -703,7 +703,7 @@ items:
coreVersion: '12.331'
_key: '!actors.items!2bRaEDuwZezKAyEq.qmIpUeedvjC8nGF1'
- _id: fPhPcCP3sbS6mfbS
name: Epée à 1 main
name: Épée à 1 main
type: competence
sort: 2400000
flags: {}
@ -735,7 +735,7 @@ items:
coreVersion: '12.331'
_key: '!actors.items!2bRaEDuwZezKAyEq.fPhPcCP3sbS6mfbS'
- _id: MLIEbxSJHkY1m3No
name: Epée à 2 mains
name: Épée à 2 mains
type: competence
sort: 2500000
flags: {}
@ -2117,7 +2117,7 @@ items:
mortalite: mortel
penetration: 0
force: 12/11
competence: Epée à 1 main
competence: Épée à 1 main
lancer: ''
tir: ''
portee_courte: 0

View File

@ -652,7 +652,7 @@ items:
coreVersion: '12.331'
_key: '!actors.items!pSM0ku0RJNLvHSvF.94P55yZfeipCGbsr'
- _id: qmIpUeedvjC8nGF1
name: Ecriture
name: Écriture
type: competence
sort: 2300000
img: systems/foundryvtt-reve-de-dragon/icons/competence_ecriture.webp
@ -681,7 +681,7 @@ items:
coreVersion: '12.331'
_key: '!actors.items!pSM0ku0RJNLvHSvF.qmIpUeedvjC8nGF1'
- _id: fPhPcCP3sbS6mfbS
name: Epée à 1 main
name: Épée à 1 main
type: competence
sort: 2400000
img: systems/foundryvtt-reve-de-dragon/icons/competence_epee_1_main.webp
@ -712,7 +712,7 @@ items:
coreVersion: '12.331'
_key: '!actors.items!pSM0ku0RJNLvHSvF.fPhPcCP3sbS6mfbS'
- _id: MLIEbxSJHkY1m3No
name: Epée à 2 mains
name: Épée à 2 mains
type: competence
sort: 2500000
img: systems/foundryvtt-reve-de-dragon/icons/competence_epee_2_mains.webp

View File

@ -652,7 +652,7 @@ items:
coreVersion: '12.331'
_key: '!actors.items!5xPFHgrY5AIP9Mnb.94P55yZfeipCGbsr'
- _id: qmIpUeedvjC8nGF1
name: Ecriture
name: Écriture
type: competence
sort: 2300000
img: systems/foundryvtt-reve-de-dragon/icons/competence_ecriture.webp
@ -681,7 +681,7 @@ items:
coreVersion: '12.331'
_key: '!actors.items!5xPFHgrY5AIP9Mnb.qmIpUeedvjC8nGF1'
- _id: fPhPcCP3sbS6mfbS
name: Epée à 1 main
name: Épée à 1 main
type: competence
sort: 2400000
img: systems/foundryvtt-reve-de-dragon/icons/competence_epee_1_main.webp
@ -712,7 +712,7 @@ items:
coreVersion: '12.331'
_key: '!actors.items!5xPFHgrY5AIP9Mnb.fPhPcCP3sbS6mfbS'
- _id: MLIEbxSJHkY1m3No
name: Epée à 2 mains
name: Épée à 2 mains
type: competence
sort: 2500000
img: systems/foundryvtt-reve-de-dragon/icons/competence_epee_2_mains.webp

View File

@ -673,7 +673,7 @@ items:
coreVersion: '12.331'
_key: '!actors.items!U9NNcXQBJmsI9Ttk.94P55yZfeipCGbsr'
- _id: qmIpUeedvjC8nGF1
name: Ecriture
name: Écriture
type: competence
sort: 2300000
flags: {}
@ -703,7 +703,7 @@ items:
coreVersion: '12.331'
_key: '!actors.items!U9NNcXQBJmsI9Ttk.qmIpUeedvjC8nGF1'
- _id: fPhPcCP3sbS6mfbS
name: Epée à 1 main
name: Épée à 1 main
type: competence
sort: 2400000
flags: {}
@ -735,7 +735,7 @@ items:
coreVersion: '12.331'
_key: '!actors.items!U9NNcXQBJmsI9Ttk.fPhPcCP3sbS6mfbS'
- _id: MLIEbxSJHkY1m3No
name: Epée à 2 mains
name: Épée à 2 mains
type: competence
sort: 2500000
flags: {}

View File

@ -651,7 +651,7 @@ items:
coreVersion: '12.331'
_key: '!actors.items!oLDROOdwfctyRusH.94P55yZfeipCGbsr'
- _id: qmIpUeedvjC8nGF1
name: Ecriture
name: Écriture
type: competence
sort: 2300000
img: systems/foundryvtt-reve-de-dragon/icons/competence_ecriture.webp
@ -680,7 +680,7 @@ items:
coreVersion: '12.331'
_key: '!actors.items!oLDROOdwfctyRusH.qmIpUeedvjC8nGF1'
- _id: fPhPcCP3sbS6mfbS
name: Epée à 1 main
name: Épée à 1 main
type: competence
sort: 2400000
img: systems/foundryvtt-reve-de-dragon/icons/competence_epee_1_main.webp
@ -711,7 +711,7 @@ items:
coreVersion: '12.331'
_key: '!actors.items!oLDROOdwfctyRusH.fPhPcCP3sbS6mfbS'
- _id: MLIEbxSJHkY1m3No
name: Epée à 2 mains
name: Épée à 2 mains
type: competence
sort: 2500000
img: systems/foundryvtt-reve-de-dragon/icons/competence_epee_2_mains.webp

View File

@ -651,7 +651,7 @@ items:
coreVersion: '12.331'
_key: '!actors.items!2KN3nKGZ36Qkn7Mf.94P55yZfeipCGbsr'
- _id: qmIpUeedvjC8nGF1
name: Ecriture
name: Écriture
type: competence
sort: 2300000
img: systems/foundryvtt-reve-de-dragon/icons/competence_ecriture.webp
@ -680,7 +680,7 @@ items:
coreVersion: '12.331'
_key: '!actors.items!2KN3nKGZ36Qkn7Mf.qmIpUeedvjC8nGF1'
- _id: fPhPcCP3sbS6mfbS
name: Epée à 1 main
name: Épée à 1 main
type: competence
sort: 2400000
img: systems/foundryvtt-reve-de-dragon/icons/competence_epee_1_main.webp
@ -711,7 +711,7 @@ items:
coreVersion: '12.331'
_key: '!actors.items!2KN3nKGZ36Qkn7Mf.fPhPcCP3sbS6mfbS'
- _id: MLIEbxSJHkY1m3No
name: Epée à 2 mains
name: Épée à 2 mains
type: competence
sort: 2500000
img: systems/foundryvtt-reve-de-dragon/icons/competence_epee_2_mains.webp

View File

@ -674,7 +674,7 @@ items:
coreVersion: '12.331'
_key: '!actors.items!V2WOs8deCYdBT2Jo.94P55yZfeipCGbsr'
- _id: qmIpUeedvjC8nGF1
name: Ecriture
name: Écriture
type: competence
sort: 2300000
flags: {}
@ -704,7 +704,7 @@ items:
coreVersion: '12.331'
_key: '!actors.items!V2WOs8deCYdBT2Jo.qmIpUeedvjC8nGF1'
- _id: fPhPcCP3sbS6mfbS
name: Epée à 1 main
name: Épée à 1 main
type: competence
sort: 2400000
flags: {}
@ -736,7 +736,7 @@ items:
coreVersion: '12.331'
_key: '!actors.items!V2WOs8deCYdBT2Jo.fPhPcCP3sbS6mfbS'
- _id: MLIEbxSJHkY1m3No
name: Epée à 2 mains
name: Épée à 2 mains
type: competence
sort: 2500000
flags: {}

View File

@ -674,7 +674,7 @@ items:
coreVersion: '12.331'
_key: '!actors.items!UNs4RBLYiGbfxd1c.94P55yZfeipCGbsr'
- _id: qmIpUeedvjC8nGF1
name: Ecriture
name: Écriture
type: competence
sort: 2300000
flags: {}
@ -704,7 +704,7 @@ items:
coreVersion: '12.331'
_key: '!actors.items!UNs4RBLYiGbfxd1c.qmIpUeedvjC8nGF1'
- _id: fPhPcCP3sbS6mfbS
name: Epée à 1 main
name: Épée à 1 main
type: competence
sort: 2400000
flags: {}
@ -736,7 +736,7 @@ items:
coreVersion: '12.331'
_key: '!actors.items!UNs4RBLYiGbfxd1c.fPhPcCP3sbS6mfbS'
- _id: MLIEbxSJHkY1m3No
name: Epée à 2 mains
name: Épée à 2 mains
type: competence
sort: 2500000
flags: {}

View File

@ -674,7 +674,7 @@ items:
coreVersion: '12.331'
_key: '!actors.items!jfXs7qaHEWQpIHud.94P55yZfeipCGbsr'
- _id: qmIpUeedvjC8nGF1
name: Ecriture
name: Écriture
type: competence
sort: 2300000
flags: {}
@ -704,7 +704,7 @@ items:
coreVersion: '12.331'
_key: '!actors.items!jfXs7qaHEWQpIHud.qmIpUeedvjC8nGF1'
- _id: fPhPcCP3sbS6mfbS
name: Epée à 1 main
name: Épée à 1 main
type: competence
sort: 2400000
flags: {}
@ -736,7 +736,7 @@ items:
coreVersion: '12.331'
_key: '!actors.items!jfXs7qaHEWQpIHud.fPhPcCP3sbS6mfbS'
- _id: MLIEbxSJHkY1m3No
name: Epée à 2 mains
name: Épée à 2 mains
type: competence
sort: 2500000
flags: {}

View File

@ -673,7 +673,7 @@ items:
coreVersion: '12.331'
_key: '!actors.items!awZg7bGbTjEGRMiw.94P55yZfeipCGbsr'
- _id: qmIpUeedvjC8nGF1
name: Ecriture
name: Écriture
type: competence
sort: 2300000
flags: {}
@ -703,7 +703,7 @@ items:
coreVersion: '12.331'
_key: '!actors.items!awZg7bGbTjEGRMiw.qmIpUeedvjC8nGF1'
- _id: fPhPcCP3sbS6mfbS
name: Epée à 1 main
name: Épée à 1 main
type: competence
sort: 2400000
flags: {}
@ -735,7 +735,7 @@ items:
coreVersion: '12.331'
_key: '!actors.items!awZg7bGbTjEGRMiw.fPhPcCP3sbS6mfbS'
- _id: MLIEbxSJHkY1m3No
name: Epée à 2 mains
name: Épée à 2 mains
type: competence
sort: 2500000
flags: {}

View File

@ -673,7 +673,7 @@ items:
coreVersion: '12.331'
_key: '!actors.items!dMdBctaRRdGJgced.94P55yZfeipCGbsr'
- _id: qmIpUeedvjC8nGF1
name: Ecriture
name: Écriture
type: competence
sort: 2300000
flags: {}
@ -703,7 +703,7 @@ items:
coreVersion: '12.331'
_key: '!actors.items!dMdBctaRRdGJgced.qmIpUeedvjC8nGF1'
- _id: fPhPcCP3sbS6mfbS
name: Epée à 1 main
name: Épée à 1 main
type: competence
sort: 2400000
flags: {}
@ -735,7 +735,7 @@ items:
coreVersion: '12.331'
_key: '!actors.items!dMdBctaRRdGJgced.fPhPcCP3sbS6mfbS'
- _id: MLIEbxSJHkY1m3No
name: Epée à 2 mains
name: Épée à 2 mains
type: competence
sort: 2500000
flags: {}

View File

@ -6,17 +6,16 @@ effects: []
system:
description: ''
descriptionmj: ''
carac_value: 0
niveau: 0
default_diffLibre: 0
categorie: generale
carac_value: 10
niveau: 1
default_diffLibre: -2
categorie: melee
categorie_parade: ''
iscombat: true
isnaturelle: true
ispossession: false
dommages: 0
mortalite: mortel
carac-value: null
isparade: false
ownership:
default: 0

View File

@ -6,17 +6,16 @@ effects: []
system:
description: ''
descriptionmj: ''
carac_value: 0
niveau: 0
default_diffLibre: 0
categorie: ''
carac_value: 10
niveau: 1
default_diffLibre: -2
categorie: melee
categorie_parade: boucliers
iscombat: true
isnaturelle: true
ispossession: false
dommages: 0
mortalite: mortel
carac-value: null
isparade: true
ownership:
default: 0

View File

@ -1,22 +1,21 @@
_id: WsYnwR8GcOxfuCI0
name: Bras-Galet
type: competencecreature
img: systems/foundryvtt-reve-de-dragon/icons/competence_course.webp
img: systems/foundryvtt-reve-de-dragon/icons/compcreature-pierretenue.webp
effects: []
system:
description: ''
descriptionmj: ''
carac_value: 0
niveau: 0
default_diffLibre: 0
categorie: ''
carac_value: 10
niveau: 1
default_diffLibre: -2
categorie: melee
categorie_parade: ''
iscombat: true
isnaturelle: true
ispossession: false
dommages: 1
mortalite: mortel
carac-value: null
isparade: false
ownership:
default: 0

View File

@ -6,10 +6,10 @@ effects: []
system:
description: ''
descriptionmj: ''
carac_value: 0
niveau: 0
default_diffLibre: 0
categorie: ''
carac_value: 10
niveau: 1
default_diffLibre: -2
categorie: melee
categorie_parade: sans-armes
iscombat: true
isnaturelle: true

View File

@ -6,17 +6,16 @@ effects: []
system:
description: ''
descriptionmj: ''
carac_value: 0
niveau: 0
default_diffLibre: 0
categorie: ''
carac_value: 10
niveau: 1
default_diffLibre: -2
categorie: melee
categorie_parade: ''
iscombat: true
isnaturelle: true
ispossession: false
dommages: 1
mortalite: mortel
carac-value: null
isparade: false
ownership:
default: 0

View File

@ -6,9 +6,9 @@ effects: []
system:
description: ''
descriptionmj: ''
carac_value: 0
niveau: 0
default_diffLibre: 0
carac_value: 10
niveau: 1
default_diffLibre: -2
categorie: melee
categorie_parade: dagues
iscombat: true

View File

@ -1,22 +1,21 @@
_id: gPOQd9NI7AFH0whX
name: Epée Bâtarde
name: Épée Bâtarde
type: competencecreature
img: systems/foundryvtt-reve-de-dragon/icons/competence_epee_1_main.webp
effects: []
system:
description: ''
descriptionmj: ''
carac_value: 0
niveau: 0
default_diffLibre: 0
categorie: ''
carac_value: 10
niveau: 1
default_diffLibre: -2
categorie: melee
categorie_parade: epees-lourdes
iscombat: true
isnaturelle: true
isnaturelle: false
ispossession: false
dommages: 4
mortalite: mortel
carac-value: null
isparade: true
ownership:
default: 0

View File

@ -6,8 +6,8 @@ effects: []
system:
description: ''
descriptionmj: ''
carac_value: 0
niveau: 0
carac_value: 10
niveau: 1
default_diffLibre: 0
categorie: generale
categorie_parade: ''

View File

@ -0,0 +1,35 @@
name: Esquive eau
type: competencecreature
img: systems/foundryvtt-reve-de-dragon/icons/competence_esquive.webp
effects: []
system:
description: ''
descriptionmj: ''
carac_value: 10
niveau: 1
default_diffLibre: 0
categorie: generale
categorie_parade: ''
iscombat: false
isnaturelle: true
ispossession: false
dommages: 0
mortalite: mortel
isparade: false
ownership:
default: 0
folder: null
_stats:
compendiumSource: null
duplicateSource: null
coreVersion: '12.331'
systemId: foundryvtt-reve-de-dragon
systemVersion: 12.0.24
createdTime: 1733182927319
modifiedTime: 1733182927336
lastModifiedBy: Hp9ImM4o9YRTSdfu
flags: {}
_id: Qrg3ADB9LOhGthaO
sort: 1300000
_key: '!items!Qrg3ADB9LOhGthaO'

View File

@ -1,15 +1,14 @@
_id: 0Ms9iKxqigNNpZEx
name: Esquive
name: Esquive sol
type: competencecreature
img: systems/foundryvtt-reve-de-dragon/icons/competence_esquive.webp
effects: []
system:
description: ''
descriptionmj: ''
carac_value: 0
niveau: 0
carac_value: 10
niveau: 1
default_diffLibre: 0
categorie: ''
categorie: generale
categorie_parade: ''
iscombat: false
isnaturelle: true
@ -20,10 +19,17 @@ system:
ownership:
default: 0
folder: null
sort: 0
_stats:
systemId: foundryvtt-reve-de-dragon
systemVersion: 12.0.22
compendiumSource: null
duplicateSource: null
coreVersion: '12.331'
_key: '!items!0Ms9iKxqigNNpZEx'
systemId: foundryvtt-reve-de-dragon
systemVersion: 12.0.24
createdTime: 1733182930109
modifiedTime: 1733182930109
lastModifiedBy: Hp9ImM4o9YRTSdfu
flags: {}
_id: siPvW3hAMCJbrYvq
sort: 0
_key: '!items!siPvW3hAMCJbrYvq'

View File

@ -0,0 +1,35 @@
name: Esquive vol
type: competencecreature
img: systems/foundryvtt-reve-de-dragon/icons/competence_esquive.webp
effects: []
system:
description: ''
descriptionmj: ''
carac_value: 10
niveau: 1
default_diffLibre: 0
categorie: generale
categorie_parade: ''
iscombat: false
isnaturelle: true
ispossession: false
dommages: 0
mortalite: mortel
isparade: false
ownership:
default: 0
folder: null
_stats:
compendiumSource: null
duplicateSource: null
coreVersion: '12.331'
systemId: foundryvtt-reve-de-dragon
systemVersion: 12.0.24
createdTime: 1733182932133
modifiedTime: 1733182932133
lastModifiedBy: Hp9ImM4o9YRTSdfu
flags: {}
_id: 3ScoGTkQ0VBOpaX6
sort: 0
_key: '!items!3ScoGTkQ0VBOpaX6'

View File

@ -6,17 +6,16 @@ effects: []
system:
description: ''
descriptionmj: ''
carac_value: 0
niveau: 0
default_diffLibre: 0
categorie: ''
categorie_parade: ''
iscombat: false
carac_value: 10
niveau: 1
default_diffLibre: -2
categorie: melee
categorie_parade: boucliers
iscombat: true
isnaturelle: true
ispossession: false
dommages: 0
mortalite: mortel
carac-value: null
isparade: false
ownership:
default: 0

View File

@ -7,7 +7,7 @@ system:
descriptionmj: ''
carac_value: 14
niveau: 2
default_diffLibre: 0
default_diffLibre: -4
categorie: draconic
categorie_parade: ''
iscombat: true

View File

@ -1,29 +0,0 @@
name: Possession
type: competencecreature
img: systems/foundryvtt-reve-de-dragon/icons/entites/possession.webp
effects: []
system:
description: <p>L'entit&eacute; tente de prendre possession du corps de sa victime.</p>
descriptionmj: ''
carac_value: 14
niveau: 2
default_diffLibre: 0
categorie: draconic
categorie_parade: ''
iscombat: true
isnaturelle: true
ispossession: true
dommages: 0
mortalite: mortel
isparade: false
_id: duVgxI3Cdko0KzAj
folder: null
sort: 0
ownership:
default: 0
_stats:
systemId: foundryvtt-reve-de-dragon
systemVersion: 12.0.22
coreVersion: '12.331'
_key: '!items!duVgxI3Cdko0KzAj'

View File

@ -6,10 +6,10 @@ effects: []
system:
description: <p>Attaque ou parade avec un tentacule.</p>
descriptionmj: ''
carac_value: 0
niveau: 0
default_diffLibre: 0
categorie: ''
carac_value: 10
niveau: 1
default_diffLibre: -2
categorie: melee
categorie_parade: boucliers
iscombat: true
isnaturelle: true

View File

@ -6,9 +6,9 @@ effects: []
system:
description: ''
descriptionmj: ''
carac_value: 0
niveau: 0
default_diffLibre: 0
carac_value: 10
niveau: 1
default_diffLibre: -2
categorie: melee
categorie_parade: ''
iscombat: true

View File

@ -1,29 +0,0 @@
_id: d5SZ09sFaG3cL2Rg
name: Bec
type: competencecreature
img: systems/foundryvtt-reve-de-dragon/icons/compcreature-beak.webp
effects: []
system:
description: ''
descriptionmj: ''
carac_value: 0
niveau: 0
default_diffLibre: 0
categorie: ''
categorie_parade: ''
iscombat: true
isnaturelle: true
ispossession: false
dommages: 0
mortalite: mortel
isparade: false
ownership:
default: 0
folder: null
sort: 0
_stats:
systemId: foundryvtt-reve-de-dragon
systemVersion: 12.0.22
coreVersion: '12.331'
_key: '!items!d5SZ09sFaG3cL2Rg'

View File

@ -1,29 +0,0 @@
_id: lDZ3qUPKN35ob5TH
name: Grande morsure
type: competencecreature
img: systems/foundryvtt-reve-de-dragon/icons/compcreature-morsure.webp
effects: []
system:
description: ''
descriptionmj: ''
carac_value: 0
niveau: 0
default_diffLibre: 0
categorie: ''
categorie_parade: ''
iscombat: true
isnaturelle: true
ispossession: false
dommages: 2
mortalite: mortel
isparade: false
ownership:
default: 0
folder: null
sort: 0
_stats:
systemId: foundryvtt-reve-de-dragon
systemVersion: 12.0.22
coreVersion: '12.331'
_key: '!items!lDZ3qUPKN35ob5TH'

View File

@ -1,29 +0,0 @@
_id: 6eWCVDYLXXO1Z48D
name: Grandes griffes
type: competencecreature
img: systems/foundryvtt-reve-de-dragon/icons/compcreature-griffes.webp
effects: []
system:
description: ''
descriptionmj: ''
carac_value: 0
niveau: 0
default_diffLibre: 0
categorie: ''
categorie_parade: sans-armes
iscombat: true
isnaturelle: true
ispossession: false
dommages: 2
mortalite: mortel
isparade: false
ownership:
default: 0
folder: null
sort: 0
_stats:
systemId: foundryvtt-reve-de-dragon
systemVersion: 12.0.22
coreVersion: '12.331'
_key: '!items!6eWCVDYLXXO1Z48D'

View File

@ -1,30 +0,0 @@
_id: 9Y83OsQgeyR5oCdH
name: Griffes
type: competencecreature
img: systems/foundryvtt-reve-de-dragon/icons/compcreature-griffes.webp
effects: []
system:
description: ''
descriptionmj: ''
carac_value: 0
niveau: 0
default_diffLibre: 0
categorie: ''
categorie_parade: sans-armes
iscombat: true
isnaturelle: true
ispossession: false
dommages: 1
mortalite: mortel
carac-value: null
isparade: false
ownership:
default: 0
folder: null
sort: 0
_stats:
systemId: foundryvtt-reve-de-dragon
systemVersion: 12.0.22
coreVersion: '12.331'
_key: '!items!9Y83OsQgeyR5oCdH'

View File

@ -1,29 +0,0 @@
_id: j1xHCzfIeYKgXxoH
name: Morsure
type: competencecreature
img: systems/foundryvtt-reve-de-dragon/icons/compcreature-morsure.webp
effects: []
system:
description: ''
descriptionmj: ''
carac_value: 0
niveau: 0
default_diffLibre: 0
categorie: ''
categorie_parade: ''
iscombat: true
isnaturelle: true
ispossession: false
dommages: 1
mortalite: mortel
isparade: false
ownership:
default: 0
folder: null
sort: 0
_stats:
systemId: foundryvtt-reve-de-dragon
systemVersion: 12.0.22
coreVersion: '12.331'
_key: '!items!j1xHCzfIeYKgXxoH'

View File

@ -1,29 +0,0 @@
name: Possession
type: competencecreature
img: systems/foundryvtt-reve-de-dragon/icons/entites/possession.webp
effects: []
system:
description: <p>L'entit&eacute; tente de prendre possession du corps de sa victime.</p>
descriptionmj: ''
carac_value: 14
niveau: 2
default_diffLibre: -4
categorie: melee
categorie_parade: ''
iscombat: true
isnaturelle: true
ispossession: true
dommages: 0
mortalite: mortel
isparade: false
ownership:
default: 0
folder: null
sort: 0
_id: wDHR5UHWq568lfGa
_stats:
systemId: foundryvtt-reve-de-dragon
systemVersion: 12.0.22
coreVersion: '12.331'
_key: '!items!wDHR5UHWq568lfGa'

View File

@ -1,4 +1,4 @@
name: Ecriture
name: Écriture
type: competence
img: systems/foundryvtt-reve-de-dragon/icons/competence_ecriture.webp
_id: qmIpUeedvjC8nGF1

View File

@ -1,4 +1,4 @@
name: Epée à 1 main
name: Épée à 1 main
type: competence
img: systems/foundryvtt-reve-de-dragon/icons/competence_epee_1_main.webp
_id: fPhPcCP3sbS6mfbS

View File

@ -1,4 +1,4 @@
name: Epée à 2 mains
name: Épée à 2 mains
type: competence
img: systems/foundryvtt-reve-de-dragon/icons/competence_epee_2_mains.webp
_id: MLIEbxSJHkY1m3No

View File

@ -1,4 +1,4 @@
name: Voie d'Hypnos
name: Hypnos
type: competence
img: systems/foundryvtt-reve-de-dragon/icons/competence_hypnos.webp
_id: bt2cR4aE6lIOeg4F

View File

@ -1,4 +1,4 @@
name: Voie de Narcos
name: Narcos
type: competence
img: systems/foundryvtt-reve-de-dragon/icons/competence_narcos.webp
_id: u1Peok1EYkBcVsmN

View File

@ -1,4 +1,4 @@
name: Voie d'Oniros
name: Oniros
type: competence
img: systems/foundryvtt-reve-de-dragon/icons/competence_oniros.webp
_id: nnR2UHelUaF8dxYn

View File

@ -1,4 +1,4 @@
name: Voie de Thanatos
name: Thanatos
type: competence
img: systems/foundryvtt-reve-de-dragon/icons/competence_thanatos.webp
_id: dPlTQzvU3CEg5qKc

View File

@ -32,7 +32,7 @@ items:
coreVersion: '12.331'
_key: '!actors.items!DEk8ZXP3qP2eHYBa.6G14MO5gckhbo0bX'
- _id: qWjxtD8YUMtXORTC
name: Epée Bâtarde
name: Épée Bâtarde
type: competencecreature
sort: 650000
img: systems/foundryvtt-reve-de-dragon/icons/competence_epee_1_main.webp

View File

@ -5,7 +5,7 @@ sort: 100001
img: systems/foundryvtt-reve-de-dragon/icons/entites/squelette.webp
items:
- _id: QNJH22nturvz1CnL
name: Epée à 2 mains
name: Épée à 2 mains
type: competence
sort: 100000
img: systems/foundryvtt-reve-de-dragon/icons/competence_epee_2_mains.webp
@ -36,7 +36,7 @@ items:
coreVersion: '12.331'
_key: '!actors.items!Fl95F6S0OrCbqQbY.QNJH22nturvz1CnL'
- _id: 9rHJziIIEQlwezim
name: Epée à 2 mains
name: Épée à 2 mains
type: competence
sort: 200000
img: systems/foundryvtt-reve-de-dragon/icons/competence_epee_2_mains.webp

View File

@ -5,7 +5,7 @@ sort: 100001
img: systems/foundryvtt-reve-de-dragon/icons/entites/vaseux.webp
items:
- _id: QNJH22nturvz1CnL
name: Epée à 2 mains
name: Épée à 2 mains
type: competence
sort: 100000
img: systems/foundryvtt-reve-de-dragon/icons/competence_epee_2_mains.webp
@ -36,7 +36,7 @@ items:
coreVersion: '12.331'
_key: '!actors.items!cmWQYuyzVsz02NMt.QNJH22nturvz1CnL'
- _id: 9rHJziIIEQlwezim
name: Epée à 2 mains
name: Épée à 2 mains
type: competence
sort: 200000
img: systems/foundryvtt-reve-de-dragon/icons/competence_epee_2_mains.webp

View File

@ -31,7 +31,7 @@ system:
mortalite: mortel
penetration: 0
force: '13'
competence: Epée à 2 mains
competence: Épée à 2 mains
lancer: ''
tir: ''
portee_courte: 0

View File

@ -37,7 +37,7 @@ system:
mortalite: mortel
penetration: 0
force: '10'
competence: Epée à 1 main
competence: Épée à 1 main
lancer: ''
tir: ''
portee_courte: 0

View File

@ -31,7 +31,7 @@ system:
mortalite: mortel
penetration: 0
force: 13/12
competence: Epée à 1 main
competence: Épée à 1 main
lancer: ''
tir: ''
portee_courte: 0

View File

@ -29,7 +29,7 @@ system:
mortalite: mortel
penetration: 0
force: '11'
competence: Epée à 1 main
competence: Épée à 1 main
lancer: ''
tir: ''
portee_courte: 0

View File

@ -25,7 +25,7 @@ system:
mortalite: mortel
penetration: 0
force: '10'
competence: Epée à 1 main
competence: Épée à 1 main
lancer: ''
tir: ''
portee_courte: 0

View File

@ -29,7 +29,7 @@ system:
mortalite: mortel
penetration: 0
force: '11'
competence: Epée à 1 main
competence: Épée à 1 main
lancer: ''
tir: ''
portee_courte: 0

View File

@ -29,7 +29,7 @@ system:
mortalite: mortel
penetration: 0
force: '8'
competence: Epée à 1 main
competence: Épée à 1 main
lancer: ''
tir: ''
portee_courte: 0

View File

@ -34,7 +34,7 @@ system:
mortalite: mortel
penetration: null
force: 12/11
competence: Epée à 1 main
competence: Épée à 1 main
lancer: ''
tir: ''
portee_courte: 0

View File

@ -18,7 +18,7 @@ system:
- milieu: Villes
rarete: Rare
frequence: 6
competence: Ecriture
competence: Écriture
auteur: Inconnu
difficulte: 0
points_de_tache: 0

View File

@ -651,7 +651,7 @@ items:
coreVersion: '12.331'
_key: '!actors.items!qscItDC5z6Hr2Lrh.94P55yZfeipCGbsr'
- _id: qmIpUeedvjC8nGF1
name: Ecriture
name: Écriture
type: competence
sort: 2300000
img: systems/foundryvtt-reve-de-dragon/icons/competence_ecriture.webp
@ -680,7 +680,7 @@ items:
coreVersion: '12.331'
_key: '!actors.items!qscItDC5z6Hr2Lrh.qmIpUeedvjC8nGF1'
- _id: fPhPcCP3sbS6mfbS
name: Epée à 1 main
name: Épée à 1 main
type: competence
sort: 2400000
img: systems/foundryvtt-reve-de-dragon/icons/competence_epee_1_main.webp
@ -711,7 +711,7 @@ items:
coreVersion: '12.331'
_key: '!actors.items!qscItDC5z6Hr2Lrh.fPhPcCP3sbS6mfbS'
- _id: MLIEbxSJHkY1m3No
name: Epée à 2 mains
name: Épée à 2 mains
type: competence
sort: 2500000
img: systems/foundryvtt-reve-de-dragon/icons/competence_epee_2_mains.webp

View File

@ -650,7 +650,7 @@ items:
coreVersion: '12.331'
_key: '!actors.items!zACge7QxwyJkC6nD.94P55yZfeipCGbsr'
- _id: qmIpUeedvjC8nGF1
name: Ecriture
name: Écriture
type: competence
sort: 2400000
img: systems/foundryvtt-reve-de-dragon/icons/competence_ecriture.webp
@ -679,7 +679,7 @@ items:
coreVersion: '12.331'
_key: '!actors.items!zACge7QxwyJkC6nD.qmIpUeedvjC8nGF1'
- _id: fPhPcCP3sbS6mfbS
name: Epée à 1 main
name: Épée à 1 main
type: competence
sort: 2500000
img: systems/foundryvtt-reve-de-dragon/icons/competence_epee_1_main.webp
@ -710,7 +710,7 @@ items:
coreVersion: '12.331'
_key: '!actors.items!zACge7QxwyJkC6nD.fPhPcCP3sbS6mfbS'
- _id: MLIEbxSJHkY1m3No
name: Epée à 2 mains
name: Épée à 2 mains
type: competence
sort: 2600000
img: systems/foundryvtt-reve-de-dragon/icons/competence_epee_2_mains.webp

View File

@ -651,7 +651,7 @@ items:
coreVersion: '12.331'
_key: '!actors.items!esJWonwDGLFaMRK3.94P55yZfeipCGbsr'
- _id: qmIpUeedvjC8nGF1
name: Ecriture
name: Écriture
type: competence
sort: 2300000
img: systems/foundryvtt-reve-de-dragon/icons/competence_ecriture.webp
@ -680,7 +680,7 @@ items:
coreVersion: '12.331'
_key: '!actors.items!esJWonwDGLFaMRK3.qmIpUeedvjC8nGF1'
- _id: fPhPcCP3sbS6mfbS
name: Epée à 1 main
name: Épée à 1 main
type: competence
sort: 2400000
img: systems/foundryvtt-reve-de-dragon/icons/competence_epee_1_main.webp
@ -711,7 +711,7 @@ items:
coreVersion: '12.331'
_key: '!actors.items!esJWonwDGLFaMRK3.fPhPcCP3sbS6mfbS'
- _id: MLIEbxSJHkY1m3No
name: Epée à 2 mains
name: Épée à 2 mains
type: competence
sort: 2500000
img: systems/foundryvtt-reve-de-dragon/icons/competence_epee_2_mains.webp
@ -1985,7 +1985,7 @@ items:
mortalite: mortel
penetration: 0
force: '11'
competence: Epée à 1 main
competence: Épée à 1 main
lancer: ''
tir: ''
portee_courte: 0

View File

@ -651,7 +651,7 @@ items:
coreVersion: '12.331'
_key: '!actors.items!gscYFtwk73WrGvA5.94P55yZfeipCGbsr'
- _id: qmIpUeedvjC8nGF1
name: Ecriture
name: Écriture
type: competence
sort: 2300000
img: systems/foundryvtt-reve-de-dragon/icons/competence_ecriture.webp
@ -680,7 +680,7 @@ items:
coreVersion: '12.331'
_key: '!actors.items!gscYFtwk73WrGvA5.qmIpUeedvjC8nGF1'
- _id: fPhPcCP3sbS6mfbS
name: Epée à 1 main
name: Épée à 1 main
type: competence
sort: 2400000
img: systems/foundryvtt-reve-de-dragon/icons/competence_epee_1_main.webp
@ -711,7 +711,7 @@ items:
coreVersion: '12.331'
_key: '!actors.items!gscYFtwk73WrGvA5.fPhPcCP3sbS6mfbS'
- _id: MLIEbxSJHkY1m3No
name: Epée à 2 mains
name: Épée à 2 mains
type: competence
sort: 2500000
img: systems/foundryvtt-reve-de-dragon/icons/competence_epee_2_mains.webp
@ -2038,7 +2038,7 @@ items:
mortalite: mortel
penetration: 0
force: 12/11
competence: Epée à 1 main
competence: Épée à 1 main
lancer: ''
tir: ''
portee_courte: 0

View File

@ -651,7 +651,7 @@ items:
coreVersion: '12.331'
_key: '!actors.items!dW4RMKpz2WaXbW3h.94P55yZfeipCGbsr'
- _id: qmIpUeedvjC8nGF1
name: Ecriture
name: Écriture
type: competence
sort: 2300000
img: systems/foundryvtt-reve-de-dragon/icons/competence_ecriture.webp
@ -680,7 +680,7 @@ items:
coreVersion: '12.331'
_key: '!actors.items!dW4RMKpz2WaXbW3h.qmIpUeedvjC8nGF1'
- _id: fPhPcCP3sbS6mfbS
name: Epée à 1 main
name: Épée à 1 main
type: competence
sort: 2400000
img: systems/foundryvtt-reve-de-dragon/icons/competence_epee_1_main.webp
@ -711,7 +711,7 @@ items:
coreVersion: '12.331'
_key: '!actors.items!dW4RMKpz2WaXbW3h.fPhPcCP3sbS6mfbS'
- _id: MLIEbxSJHkY1m3No
name: Epée à 2 mains
name: Épée à 2 mains
type: competence
sort: 2500000
img: systems/foundryvtt-reve-de-dragon/icons/competence_epee_2_mains.webp

View File

@ -651,7 +651,7 @@ items:
coreVersion: '12.331'
_key: '!actors.items!ncXFs8oaZWG68Tzn.94P55yZfeipCGbsr'
- _id: qmIpUeedvjC8nGF1
name: Ecriture
name: Écriture
type: competence
sort: 2300000
img: systems/foundryvtt-reve-de-dragon/icons/competence_ecriture.webp
@ -680,7 +680,7 @@ items:
coreVersion: '12.331'
_key: '!actors.items!ncXFs8oaZWG68Tzn.qmIpUeedvjC8nGF1'
- _id: fPhPcCP3sbS6mfbS
name: Epée à 1 main
name: Épée à 1 main
type: competence
sort: 2400000
img: systems/foundryvtt-reve-de-dragon/icons/competence_epee_1_main.webp
@ -711,7 +711,7 @@ items:
coreVersion: '12.331'
_key: '!actors.items!ncXFs8oaZWG68Tzn.fPhPcCP3sbS6mfbS'
- _id: MLIEbxSJHkY1m3No
name: Epée à 2 mains
name: Épée à 2 mains
type: competence
sort: 2500000
img: systems/foundryvtt-reve-de-dragon/icons/competence_epee_2_mains.webp

View File

@ -651,7 +651,7 @@ items:
coreVersion: '12.331'
_key: '!actors.items!OKMXH6YpPXUyvqzN.94P55yZfeipCGbsr'
- _id: qmIpUeedvjC8nGF1
name: Ecriture
name: Écriture
type: competence
sort: 2300000
img: systems/foundryvtt-reve-de-dragon/icons/competence_ecriture.webp
@ -680,7 +680,7 @@ items:
coreVersion: '12.331'
_key: '!actors.items!OKMXH6YpPXUyvqzN.qmIpUeedvjC8nGF1'
- _id: fPhPcCP3sbS6mfbS
name: Epée à 1 main
name: Épée à 1 main
type: competence
sort: 2400000
img: systems/foundryvtt-reve-de-dragon/icons/competence_epee_1_main.webp
@ -711,7 +711,7 @@ items:
coreVersion: '12.331'
_key: '!actors.items!OKMXH6YpPXUyvqzN.fPhPcCP3sbS6mfbS'
- _id: MLIEbxSJHkY1m3No
name: Epée à 2 mains
name: Épée à 2 mains
type: competence
sort: 2500000
img: systems/foundryvtt-reve-de-dragon/icons/competence_epee_2_mains.webp

View File

@ -651,7 +651,7 @@ items:
coreVersion: '12.331'
_key: '!actors.items!EzV1Zxuwi7jwa6bj.94P55yZfeipCGbsr'
- _id: qmIpUeedvjC8nGF1
name: Ecriture
name: Écriture
type: competence
sort: 2300000
img: systems/foundryvtt-reve-de-dragon/icons/competence_ecriture.webp
@ -680,7 +680,7 @@ items:
coreVersion: '12.331'
_key: '!actors.items!EzV1Zxuwi7jwa6bj.qmIpUeedvjC8nGF1'
- _id: fPhPcCP3sbS6mfbS
name: Epée à 1 main
name: Épée à 1 main
type: competence
sort: 2400000
img: systems/foundryvtt-reve-de-dragon/icons/competence_epee_1_main.webp
@ -711,7 +711,7 @@ items:
coreVersion: '12.331'
_key: '!actors.items!EzV1Zxuwi7jwa6bj.fPhPcCP3sbS6mfbS'
- _id: MLIEbxSJHkY1m3No
name: Epée à 2 mains
name: Épée à 2 mains
type: competence
sort: 2500000
img: systems/foundryvtt-reve-de-dragon/icons/competence_epee_2_mains.webp
@ -2017,7 +2017,7 @@ items:
mortalite: mortel
penetration: 0
force: '8'
competence: Epée à 1 main
competence: Épée à 1 main
lancer: ''
tir: ''
portee_courte: 0

View File

@ -651,7 +651,7 @@ items:
coreVersion: '12.331'
_key: '!actors.items!YQ6vavAVyZecPvGQ.94P55yZfeipCGbsr'
- _id: qmIpUeedvjC8nGF1
name: Ecriture
name: Écriture
type: competence
sort: 2300000
img: systems/foundryvtt-reve-de-dragon/icons/competence_ecriture.webp
@ -680,7 +680,7 @@ items:
coreVersion: '12.331'
_key: '!actors.items!YQ6vavAVyZecPvGQ.qmIpUeedvjC8nGF1'
- _id: fPhPcCP3sbS6mfbS
name: Epée à 1 main
name: Épée à 1 main
type: competence
sort: 2400000
img: systems/foundryvtt-reve-de-dragon/icons/competence_epee_1_main.webp
@ -711,7 +711,7 @@ items:
coreVersion: '12.331'
_key: '!actors.items!YQ6vavAVyZecPvGQ.fPhPcCP3sbS6mfbS'
- _id: MLIEbxSJHkY1m3No
name: Epée à 2 mains
name: Épée à 2 mains
type: competence
sort: 2500000
img: systems/foundryvtt-reve-de-dragon/icons/competence_epee_2_mains.webp

View File

@ -651,7 +651,7 @@ items:
coreVersion: '12.331'
_key: '!actors.items!b7ThiitioBVXxU7D.94P55yZfeipCGbsr'
- _id: qmIpUeedvjC8nGF1
name: Ecriture
name: Écriture
type: competence
sort: 2300000
img: systems/foundryvtt-reve-de-dragon/icons/competence_ecriture.webp
@ -680,7 +680,7 @@ items:
coreVersion: '12.331'
_key: '!actors.items!b7ThiitioBVXxU7D.qmIpUeedvjC8nGF1'
- _id: fPhPcCP3sbS6mfbS
name: Epée à 1 main
name: Épée à 1 main
type: competence
sort: 2400000
img: systems/foundryvtt-reve-de-dragon/icons/competence_epee_1_main.webp
@ -711,7 +711,7 @@ items:
coreVersion: '12.331'
_key: '!actors.items!b7ThiitioBVXxU7D.fPhPcCP3sbS6mfbS'
- _id: MLIEbxSJHkY1m3No
name: Epée à 2 mains
name: Épée à 2 mains
type: competence
sort: 2500000
img: systems/foundryvtt-reve-de-dragon/icons/competence_epee_2_mains.webp

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