Compare commits
74 Commits
fvtt-les-h
...
13.1.0
| Author | SHA1 | Date | |
|---|---|---|---|
| dc3040df26 | |||
| b1bce86604 | |||
| 6066091d8d | |||
| 287b6d83a7 | |||
| d8efba89a1 | |||
| 936d525503 | |||
| b113f630bf | |||
| 939cfb1e86 | |||
| 5f5e0e2a8c | |||
| c993a9a5b1 | |||
| cc7de0e53c | |||
| 4d41986c12 | |||
| d04731f475 | |||
| 44a641a0ca | |||
| 1ad022d193 | |||
| 1c7cf343b1 | |||
| d4b00e3508 | |||
| adc912e6cd | |||
| 51a457ebf6 | |||
| 2e9c558027 | |||
| bcd0758328 | |||
| 2b680a203f | |||
| e3d7874dce | |||
| ab6a5832c0 | |||
| d83a999974 | |||
| b83890a764 | |||
| 5ad3c165e5 | |||
| 2b3e774cbb | |||
| 96f8d2bceb | |||
| e288c90ee4 | |||
| 8916de8613 | |||
| 8598df5a57 | |||
| 8781462c8d | |||
| 8c38aead3e | |||
| 67bf71e6c0 | |||
| 63d15e82bb | |||
| 62c3787cea | |||
| df61abac19 | |||
| a7d1a14c52 | |||
| b0dc6f36e4 | |||
| 5109d2aa91 | |||
| 51c162ecbb | |||
| 44d02b0cd1 | |||
| 9b1600304a | |||
| 2dff59c829 | |||
| 55a2a8e3c3 | |||
| 2da1f56a91 | |||
| 66bd9dd2c8 | |||
| 15427f3747 | |||
| 577eccbbd3 | |||
| 05026d454b | |||
| 6497369d7f | |||
| 5e5ddd1c3b | |||
| a72108db5b | |||
| 6a46faadc2 | |||
| e95f7de0c5 | |||
| 9d3ef8cbeb | |||
| c6ec1b74a2 | |||
| 1b12dc44c9 | |||
| f26cd7670c | |||
| 02f8207fb7 | |||
| 439797e71e | |||
| 1d82a6aa60 | |||
| 11b0f22aa7 | |||
| b0a3cb08cb | |||
| 2f3a8e91bd | |||
| f00825ea91 | |||
| 3fa80b6e57 | |||
| fac6618b74 | |||
| d554656925 | |||
| d8e59e8b90 | |||
| c5f021a941 | |||
| 7b5d7c9119 | |||
| 71649bb52f |
63
.gitea/workflows/release.yaml
Normal file
@@ -0,0 +1,63 @@
|
||||
name: Release Creation
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- run: echo "💡 The ${{ gitea.repository }} repository will cloned to the runner."
|
||||
|
||||
#- uses: actions/checkout@v3
|
||||
- uses: RouxAntoine/checkout@v3.5.4
|
||||
|
||||
# get part of the tag after the `v`
|
||||
- name: Extract tag version number
|
||||
id: get_version
|
||||
uses: battila7/get-version-action@v2
|
||||
|
||||
# Substitute the Manifest and Download URLs in the system.json
|
||||
- name: Substitute Manifest and Download Links For Versioned Ones
|
||||
id: sub_manifest_link_version
|
||||
uses: microsoft/variable-substitution@v1
|
||||
with:
|
||||
files: 'system.json'
|
||||
env:
|
||||
version: ${{steps.get_version.outputs.version-without-v}}
|
||||
url: https://www.uberwald.me/gitea/${{gitea.repository}}
|
||||
manifest: https://www.uberwald.me/gitea/public/fvtt-les-heritiers/releases/download/latest/system.json
|
||||
download: https://www.uberwald.me/gitea/${{gitea.repository}}/releases/download/${{github.event.release.tag_name}}/fvtt-les-heritiers.zip
|
||||
|
||||
# Create a zip file with all files required by the module to add to the release
|
||||
- run: |
|
||||
apt update -y
|
||||
apt install -y zip
|
||||
|
||||
- run: zip -r ./fvtt-les-heritiers.zip system.json README.md LICENCE.txt assets/ lang/ modules/ packs/ styles/ templates/
|
||||
|
||||
- name: setup go
|
||||
uses: https://github.com/actions/setup-go@v4
|
||||
with:
|
||||
go-version: '>=1.20.1'
|
||||
|
||||
- name: Use Go Action
|
||||
id: use-go-action
|
||||
uses: https://gitea.com/actions/release-action@main
|
||||
with:
|
||||
files: |-
|
||||
./fvtt-les-heritiers.zip
|
||||
system.json
|
||||
api_key: '${{secrets.ALLOW_PUSH_RELEASE}}'
|
||||
|
||||
- name: Publish to Foundry server
|
||||
uses: https://github.com/djlechuck/foundryvtt-publish-package-action@v1
|
||||
with:
|
||||
token: ${{ secrets.FOUNDRYVTT_RELEASE_TOKEN }}
|
||||
id: 'fvtt-les-heritiers'
|
||||
version: ${{github.event.release.tag_name}}
|
||||
manifest: 'https://www.uberwald.me/gitea/public/fvtt-les-heritiers/releases/download/latest/system.json'
|
||||
notes: 'https://www.uberwald.me/gitea/${{gitea.repository}}/releases/download/${{github.event.release.tag_name}}/fvtt-les-heritiers.zip'
|
||||
compatibility-minimum: '13'
|
||||
compatibility-verified: '13'
|
||||
2
.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
.history/
|
||||
node_modules
|
||||
10
README.md
@@ -1,8 +1,8 @@
|
||||
# Système Foundry pour Hawkmoon (French RPG, Titam France/Sombres Projets)
|
||||
# Système Foundry pour Les Héritiers (French RPG, Titam France/Sombres Projets)
|
||||
|
||||
## EN
|
||||
|
||||
Unofficial system for Hawkmoon (French version from Titam France).
|
||||
Unofficial system for Les Heritiers (from Titam France).
|
||||
|
||||
This system has been approved by Département des Sombres Projets ( http://www.titam-france.fr/ ), thanks !
|
||||
|
||||
@@ -10,7 +10,7 @@ Books are mandatory to play and are available at : http://www.titam-france.fr
|
||||
|
||||
## FR
|
||||
|
||||
Système non-officiel pour le JDR Hawkmoon (Titam France/Sombres Projets).
|
||||
Système non-officiel pour le JDR Les Héritiers (Titam France/Sombres Projets).
|
||||
|
||||
Ce système a été autorisé par le Département des Sombres Projets ( http://www.titam-france.fr/ ), merci à eux !
|
||||
|
||||
@@ -18,7 +18,7 @@ Les livres du jeu sont nécessaires pour jouer, et sont disponibles ici : http:/
|
||||
|
||||
# Credits
|
||||
|
||||
Hawkmoon, le jeu de rôle du Troisième Millénaire, is a property of Titam France/Sombres Projets.
|
||||
Les Héritiers, is a property of Titam France/Sombres Projets.
|
||||
|
||||
# Developmement
|
||||
|
||||
@@ -26,4 +26,4 @@ LeRatierBretonnien
|
||||
|
||||
# Tests, icones et saisie des données
|
||||
|
||||
Prêtre, Blondin, Zechrub/Chris, Kyllian, Lightbringer
|
||||
Prêtre, Carter
|
||||
|
||||
BIN
assets/icons/aventurier.webp
Normal file
|
After Width: | Height: | Size: 83 KiB |
BIN
assets/icons/combattant.webp
Normal file
|
After Width: | Height: | Size: 88 KiB |
BIN
assets/icons/equipement.webp
Normal file
|
After Width: | Height: | Size: 90 KiB |
BIN
assets/icons/erudit.webp
Normal file
|
After Width: | Height: | Size: 87 KiB |
BIN
assets/icons/gentleman.webp
Normal file
|
After Width: | Height: | Size: 85 KiB |
BIN
assets/icons/profil.webp
Normal file
|
After Width: | Height: | Size: 90 KiB |
BIN
assets/icons/roublard.webp
Normal file
|
After Width: | Height: | Size: 76 KiB |
BIN
assets/icons/sort.webp
Normal file
|
After Width: | Height: | Size: 88 KiB |
BIN
assets/scenes/8DjkNeeujp2qff1N-thumb.webp
Normal file
|
After Width: | Height: | Size: 7.2 KiB |
BIN
assets/scenes/ZjIQTg8S4hLZ4kXN-thumb.webp
Normal file
|
After Width: | Height: | Size: 5.8 KiB |
BIN
assets/scenes/aanMTXv8znDyE6qb-thumb.webp
Normal file
|
After Width: | Height: | Size: 5.2 KiB |
BIN
assets/scenes/ypDutqjqZcr7lx6I-thumb.webp
Normal file
|
After Width: | Height: | Size: 4.4 KiB |
BIN
assets/ui/heritiers_background_01.webp
Normal file
|
After Width: | Height: | Size: 192 KiB |
35
gulpfile.js
Normal file
@@ -0,0 +1,35 @@
|
||||
const gulp = require('gulp');
|
||||
const less = require('gulp-less');
|
||||
const sourcemaps = require('gulp-sourcemaps');
|
||||
|
||||
// Paths
|
||||
const paths = {
|
||||
styles: {
|
||||
src: 'less/**/*.less',
|
||||
dest: 'styles/'
|
||||
}
|
||||
};
|
||||
|
||||
// Compile LESS to CSS
|
||||
function styles() {
|
||||
return gulp.src('less/heritiers.less')
|
||||
.pipe(sourcemaps.init())
|
||||
.pipe(less())
|
||||
.pipe(sourcemaps.write('.'))
|
||||
.pipe(gulp.dest(paths.styles.dest));
|
||||
}
|
||||
|
||||
// Watch files
|
||||
function watchFiles() {
|
||||
gulp.watch(paths.styles.src, styles);
|
||||
}
|
||||
|
||||
// Define complex tasks
|
||||
const build = gulp.series(styles);
|
||||
const watch = gulp.series(build, watchFiles);
|
||||
|
||||
// Export tasks
|
||||
exports.styles = styles;
|
||||
exports.build = build;
|
||||
exports.watch = watch;
|
||||
exports.default = build;
|
||||
47
lang/fr.json
@@ -1,31 +1,24 @@
|
||||
{
|
||||
"ACTOR": {
|
||||
"TypePersonnage": "Personnage",
|
||||
"TypeCellule": "Cellule",
|
||||
"TypeCreature": "Créature"
|
||||
},
|
||||
|
||||
"ITEM": {
|
||||
"TypeArtefact": "Artefact",
|
||||
"TypeArme": "Arme",
|
||||
"TypeTalent": "Talent",
|
||||
"TypeHistorique": "Historique",
|
||||
"TypeProfil": "Profil",
|
||||
"TypeCompetence": "Compétence",
|
||||
"TypeProtection": "Protection",
|
||||
"TypeMonnaie": "Monnaie",
|
||||
"TypeEquipement": "Equipement",
|
||||
"TypeRessource": "Ressource",
|
||||
"TypeContact": "Contact"
|
||||
|
||||
},
|
||||
|
||||
"HAWKMOON": {
|
||||
"ui": {
|
||||
"editContact": "Modifier le contact",
|
||||
"deleteContact": "Supprimer le contact",
|
||||
"editTrait": "Modifier le trait",
|
||||
"deleteTrait": "Supprimer le trait"
|
||||
"TYPES": {
|
||||
"Actor": {
|
||||
"personnage": "Personnage",
|
||||
"pnj": "PNJ"
|
||||
},
|
||||
"Item": {
|
||||
"accessoire": "Accessoire",
|
||||
"arme": "Arme",
|
||||
"atoutfeerique": "Atout féerique",
|
||||
"avantage": "Avantage",
|
||||
"capacitenaturelle": "Capacité naturelle",
|
||||
"competence": "Compétence",
|
||||
"contact": "Contact",
|
||||
"desavantage": "Désavantage",
|
||||
"equipement": "Equipement",
|
||||
"fee": "Fée",
|
||||
"pouvoir": "Pouvoir",
|
||||
"profil": "Profil",
|
||||
"protection": "Protection",
|
||||
"sort": "Sort"
|
||||
}
|
||||
}
|
||||
}
|
||||
4
less/heritiers.less
Normal file
@@ -0,0 +1,4 @@
|
||||
// Main LESS file for Les Héritiers system
|
||||
// Temporarily importing the full converted simple.css while we refactor
|
||||
|
||||
@import "simple-converted";
|
||||
2809
less/simple-converted.less
Normal file
213
modules/applications/heritiers-roll-dialog.mjs
Normal file
@@ -0,0 +1,213 @@
|
||||
import { HeritiersUtility } from "../heritiers-utility.js"
|
||||
|
||||
/**
|
||||
* Dialogue de jet de dé pour Les Héritiers - Version AppV2
|
||||
*/
|
||||
export class HeritiersRollDialog {
|
||||
|
||||
/**
|
||||
* Create and display the roll dialog
|
||||
* @param {HeritiersActor} actor - The actor making the roll
|
||||
* @param {Object} rollData - Data for the roll
|
||||
* @returns {Promise<Object>} - Returns a dialog-like object for compatibility
|
||||
*/
|
||||
static async create(actor, rollData) {
|
||||
// Préparer le contexte pour le template
|
||||
const context = {
|
||||
...rollData,
|
||||
img: actor.img,
|
||||
name: actor.name,
|
||||
config: game.system.lesheritiers.config,
|
||||
}
|
||||
|
||||
// Rendre le template en HTML
|
||||
const content = await foundry.applications.handlebars.renderTemplate(
|
||||
"systems/fvtt-les-heritiers/templates/roll-dialog-generic.hbs",
|
||||
context
|
||||
)
|
||||
|
||||
// Préparer les boutons selon le mode et le niveau
|
||||
const buttons = this._prepareButtons(rollData)
|
||||
|
||||
// Utiliser DialogV2.wait avec le HTML rendu
|
||||
return foundry.applications.api.DialogV2.wait({
|
||||
window: { title: "Test de Capacité", icon: "fa-solid fa-dice" },
|
||||
classes: ["heritiers-roll-dialog"],
|
||||
position: { width: 420 },
|
||||
modal: false,
|
||||
content,
|
||||
buttons,
|
||||
rejectClose: false
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Préparer les boutons selon le mode et le niveau de compétence
|
||||
* @param {Object} rollData - Data for the roll
|
||||
* @returns {Array} - Array of button configurations
|
||||
* @private
|
||||
*/
|
||||
static _prepareButtons(rollData) {
|
||||
const buttons = []
|
||||
|
||||
// Bouton d8 toujours disponible
|
||||
buttons.push({
|
||||
action: "rolld8",
|
||||
label: "1d8",
|
||||
icon: "fa-solid fa-dice-d8",
|
||||
default: true,
|
||||
callback: (event, button, dialog) => {
|
||||
this._updateRollDataFromForm(rollData, button.form.elements)
|
||||
this._executeRoll(rollData, "d8")
|
||||
}
|
||||
})
|
||||
|
||||
// Bouton d10 si niveau > 0 ou pouvoir
|
||||
const enableD10 = rollData.mode === "pouvoir" || rollData.competence?.system.niveau > 0
|
||||
if (enableD10) {
|
||||
buttons.push({
|
||||
action: "rolld10",
|
||||
label: "1d10",
|
||||
icon: "fa-solid fa-dice-d10",
|
||||
callback: (event, button, dialog) => {
|
||||
this._updateRollDataFromForm(rollData, button.form.elements)
|
||||
this._executeRoll(rollData, "d10")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Bouton d12 si niveau > 1 ou pouvoir
|
||||
const enableD12 = rollData.mode === "pouvoir" || rollData.competence?.system.niveau > 1
|
||||
if (enableD12) {
|
||||
buttons.push({
|
||||
action: "rolld12",
|
||||
label: "1d12",
|
||||
icon: "fa-solid fa-dice-d12",
|
||||
callback: (event, button, dialog) => {
|
||||
this._updateRollDataFromForm(rollData, button.form.elements)
|
||||
this._executeRoll(rollData, "d12")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Bouton Tricherie si disponible
|
||||
if (rollData.tricherie) {
|
||||
buttons.push({
|
||||
action: "rollTricherie",
|
||||
label: "Lancer 1 Tricherie",
|
||||
icon: "fa-solid fa-mask",
|
||||
callback: (event, button, dialog) => {
|
||||
this._updateRollDataFromForm(rollData, button.form.elements)
|
||||
this._executeRoll(rollData, "tricherie")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Bouton Héritage si disponible
|
||||
if (rollData.heritage) {
|
||||
buttons.push({
|
||||
action: "rollHeritage",
|
||||
label: "Lancer 1 Héritage",
|
||||
icon: "fa-solid fa-crown",
|
||||
callback: (event, button, dialog) => {
|
||||
this._updateRollDataFromForm(rollData, button.form.elements)
|
||||
this._executeRoll(rollData, "heritage")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Si mode carac uniquement, on ne garde que d8
|
||||
if (rollData.mode === "carac") {
|
||||
return [
|
||||
{
|
||||
action: "rolld8",
|
||||
label: "Lancer 1d8",
|
||||
icon: "fa-solid fa-dice-d8",
|
||||
default: true,
|
||||
callback: (event, button, dialog) => {
|
||||
this._updateRollDataFromForm(rollData, button.form.elements)
|
||||
this._executeRoll(rollData, "d8")
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
return buttons
|
||||
}
|
||||
|
||||
/**
|
||||
* Mettre à jour rollData avec les valeurs du formulaire
|
||||
* @param {Object} rollData - L'objet rollData à mettre à jour
|
||||
* @param {HTMLFormControlsCollection} formElements - Les éléments du formulaire
|
||||
* @private
|
||||
*/
|
||||
static _updateRollDataFromForm(rollData, formElements) {
|
||||
// Seuil de Difficulté
|
||||
if (formElements.sdValue) {
|
||||
rollData.sdValue = Number(formElements.sdValue.value)
|
||||
}
|
||||
|
||||
// Caractéristique
|
||||
if (formElements.caracKey) {
|
||||
rollData.caracKey = String(formElements.caracKey.value)
|
||||
}
|
||||
|
||||
// Bonus/Malus contextuel
|
||||
if (formElements['bonus-malus-context']) {
|
||||
rollData.bonusMalusContext = Number(formElements['bonus-malus-context'].value)
|
||||
}
|
||||
|
||||
// Attaque à plusieurs
|
||||
if (formElements['bonus-attaque-plusieurs']) {
|
||||
rollData.bonusAttaquePlusieurs = Number(formElements['bonus-attaque-plusieurs'].value)
|
||||
}
|
||||
|
||||
// Spécialité
|
||||
if (formElements.useSpecialite !== undefined) {
|
||||
rollData.useSpecialite = formElements.useSpecialite.checked
|
||||
}
|
||||
|
||||
// Points d'usage du pouvoir
|
||||
if (formElements.pouvoirPointsUsage) {
|
||||
rollData.pouvoirPointsUsage = Number(formElements.pouvoirPointsUsage.value)
|
||||
}
|
||||
|
||||
// Attaque dans le dos
|
||||
if (formElements.attaqueDos !== undefined) {
|
||||
rollData.attaqueDos = formElements.attaqueDos.checked
|
||||
}
|
||||
|
||||
// Seconde arme
|
||||
if (formElements['bonus-attaque-seconde-arme']) {
|
||||
rollData.secondeArme = String(formElements['bonus-attaque-seconde-arme'].value)
|
||||
}
|
||||
|
||||
// Attaque ciblée
|
||||
if (formElements['attaque-cible']) {
|
||||
rollData.attaqueCible = String(formElements['attaque-cible'].value)
|
||||
}
|
||||
|
||||
// Attaque à deux armes
|
||||
if (formElements['bonus-attaque-deux-armes']) {
|
||||
rollData.attaqueDeuxArmes = Number(formElements['bonus-attaque-deux-armes'].value)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Exécuter le jet de dés
|
||||
* @param {Object} rollData - Data for the roll
|
||||
* @param {String} dice - Type de dé (d8, d10, d12, tricherie, heritage)
|
||||
* @private
|
||||
*/
|
||||
static _executeRoll(rollData, dice) {
|
||||
if (dice === "heritage") {
|
||||
rollData.useHeritage = true
|
||||
} else if (dice === "tricherie") {
|
||||
rollData.useTricherie = true
|
||||
} else {
|
||||
rollData.mainDice = dice
|
||||
}
|
||||
|
||||
HeritiersUtility.rollHeritiers(rollData)
|
||||
}
|
||||
}
|
||||
23
modules/applications/sheets/_module.mjs
Normal file
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
* Export all application sheets for Les Héritiers
|
||||
*/
|
||||
|
||||
// Actor Sheets
|
||||
export { default as HeritiersPersonnageSheet } from './personnage-sheet.mjs';
|
||||
export { default as HeritiersPnjSheet } from './pnj-sheet.mjs';
|
||||
|
||||
// Item Sheets
|
||||
export { default as HeritiersAccessoireSheet } from './accessoire-sheet.mjs';
|
||||
export { default as HeritiersArmeSheet } from './arme-sheet.mjs';
|
||||
export { default as HeritiersAtoutFeeriqueSheet } from './atoutfeerique-sheet.mjs';
|
||||
export { default as HeritiersAvantageSheet } from './avantage-sheet.mjs';
|
||||
export { default as HeritiersCapaciteNaturelleSheet } from './capacitenaturelle-sheet.mjs';
|
||||
export { default as HeritiersCompetenceSheet } from './competence-sheet.mjs';
|
||||
export { default as HeritiersContactSheet } from './contact-sheet.mjs';
|
||||
export { default as HeritiersDesavantageSheet } from './desavantage-sheet.mjs';
|
||||
export { default as HeritiersEquipementSheet } from './equipement-sheet.mjs';
|
||||
export { default as HeritiersFeeSheet } from './fee-sheet.mjs';
|
||||
export { default as HeritiersPouvoirSheet } from './pouvoir-sheet.mjs';
|
||||
export { default as HeritiersProfilSheet } from './profil-sheet.mjs';
|
||||
export { default as HeritiersProtectionSheet } from './protection-sheet.mjs';
|
||||
export { default as HeritiersSortSheet } from './sort-sheet.mjs';
|
||||
19
modules/applications/sheets/accessoire-sheet.mjs
Normal file
@@ -0,0 +1,19 @@
|
||||
import HeritiersItemSheet from "./base-item-sheet.mjs"
|
||||
|
||||
export default class HeritiersAccessoireSheet extends HeritiersItemSheet {
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
...super.DEFAULT_OPTIONS,
|
||||
window: {
|
||||
...super.DEFAULT_OPTIONS.window,
|
||||
title: "SHEETS.Item.accessoire",
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
sheet: {
|
||||
template: "systems/fvtt-les-heritiers/templates/item-accessoire-sheet.hbs",
|
||||
},
|
||||
}
|
||||
}
|
||||
19
modules/applications/sheets/arme-sheet.mjs
Normal file
@@ -0,0 +1,19 @@
|
||||
import HeritiersItemSheet from "./base-item-sheet.mjs"
|
||||
|
||||
export default class HeritiersArmeSheet extends HeritiersItemSheet {
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
...super.DEFAULT_OPTIONS,
|
||||
window: {
|
||||
...super.DEFAULT_OPTIONS.window,
|
||||
title: "SHEETS.Item.arme",
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
sheet: {
|
||||
template: "systems/fvtt-les-heritiers/templates/item-arme-sheet.hbs",
|
||||
},
|
||||
}
|
||||
}
|
||||
19
modules/applications/sheets/atoutfeerique-sheet.mjs
Normal file
@@ -0,0 +1,19 @@
|
||||
import HeritiersItemSheet from "./base-item-sheet.mjs"
|
||||
|
||||
export default class HeritiersAtoutFeeriqueSheet extends HeritiersItemSheet {
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
...super.DEFAULT_OPTIONS,
|
||||
window: {
|
||||
...super.DEFAULT_OPTIONS.window,
|
||||
title: "SHEETS.Item.atoutfeerique",
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
sheet: {
|
||||
template: "systems/fvtt-les-heritiers/templates/item-atoutfeerique-sheet.hbs",
|
||||
},
|
||||
}
|
||||
}
|
||||
19
modules/applications/sheets/avantage-sheet.mjs
Normal file
@@ -0,0 +1,19 @@
|
||||
import HeritiersItemSheet from "./base-item-sheet.mjs"
|
||||
|
||||
export default class HeritiersAvantageSheet extends HeritiersItemSheet {
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
...super.DEFAULT_OPTIONS,
|
||||
window: {
|
||||
...super.DEFAULT_OPTIONS.window,
|
||||
title: "SHEETS.Item.avantage",
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
sheet: {
|
||||
template: "systems/fvtt-les-heritiers/templates/item-avantage-sheet.hbs",
|
||||
},
|
||||
}
|
||||
}
|
||||
675
modules/applications/sheets/base-actor-sheet.mjs
Normal file
@@ -0,0 +1,675 @@
|
||||
const { HandlebarsApplicationMixin } = foundry.applications.api
|
||||
|
||||
import { HeritiersUtility } from "../../heritiers-utility.js"
|
||||
|
||||
export default class HeritiersActorSheet extends HandlebarsApplicationMixin(foundry.applications.sheets.ActorSheetV2) {
|
||||
/**
|
||||
* Different sheet modes.
|
||||
* @enum {number}
|
||||
*/
|
||||
static SHEET_MODES = { EDIT: 0, PLAY: 1 }
|
||||
|
||||
constructor(options = {}) {
|
||||
super(options)
|
||||
this.#dragDrop = this.#createDragDropHandlers()
|
||||
this._sheetMode = this.constructor.SHEET_MODES.PLAY
|
||||
}
|
||||
|
||||
#dragDrop
|
||||
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ["fvtt-les-heritiers", "sheet", "actor"],
|
||||
position: {
|
||||
width: 780,
|
||||
height: 840,
|
||||
},
|
||||
window: {
|
||||
resizable: true,
|
||||
},
|
||||
form: {
|
||||
submitOnChange: true,
|
||||
closeOnSubmit: false,
|
||||
},
|
||||
dragDrop: [{ dragSelector: ".item-list .item", dropSelector: "form" }],
|
||||
actions: {
|
||||
editImage: HeritiersActorSheet.#onEditImage,
|
||||
toggleSheet: HeritiersActorSheet.#onToggleSheet,
|
||||
editItem: HeritiersActorSheet.#onEditItem,
|
||||
deleteItem: HeritiersActorSheet.#onDeleteItem,
|
||||
createItem: HeritiersActorSheet.#onCreateItem,
|
||||
equipItem: HeritiersActorSheet.#onEquipItem,
|
||||
modifyQuantity: HeritiersActorSheet.#onModifyQuantity,
|
||||
quantityIncrease: HeritiersActorSheet.#onQuantityIncrease,
|
||||
quantityDecrease: HeritiersActorSheet.#onQuantityDecrease,
|
||||
pvIncrease: HeritiersActorSheet.#onPvIncrease,
|
||||
pvDecrease: HeritiersActorSheet.#onPvDecrease,
|
||||
rollInitiative: HeritiersActorSheet.#onRollInitiative,
|
||||
rollCarac: HeritiersActorSheet.#onRollCarac,
|
||||
rollRang: HeritiersActorSheet.#onRollRang,
|
||||
rollRootCompetence: HeritiersActorSheet.#onRollRootCompetence,
|
||||
rollCompetence: HeritiersActorSheet.#onRollCompetence,
|
||||
rollSort: HeritiersActorSheet.#onRollSort,
|
||||
rollAttaqueArme: HeritiersActorSheet.#onRollAttaqueArme,
|
||||
rollAttaqueBrutaleArme: HeritiersActorSheet.#onRollAttaqueBrutaleArme,
|
||||
rollAttaqueChargeArme: HeritiersActorSheet.#onRollAttaqueChargeArme,
|
||||
rollAssomerArme: HeritiersActorSheet.#onRollAssomerArme,
|
||||
rollPouvoir: HeritiersActorSheet.#onRollPouvoir,
|
||||
toggleMasque: HeritiersActorSheet.#onToggleMasque,
|
||||
dialogRecupUsage: HeritiersActorSheet.#onDialogRecupUsage,
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the sheet currently in 'Play' mode?
|
||||
* @type {boolean}
|
||||
*/
|
||||
get isPlayMode() {
|
||||
if (this._sheetMode === undefined) this._sheetMode = this.constructor.SHEET_MODES.PLAY
|
||||
return this._sheetMode === this.constructor.SHEET_MODES.PLAY
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the sheet currently in 'Edit' mode?
|
||||
* @type {boolean}
|
||||
*/
|
||||
get isEditMode() {
|
||||
if (this._sheetMode === undefined) this._sheetMode = this.constructor.SHEET_MODES.PLAY
|
||||
return this._sheetMode === this.constructor.SHEET_MODES.EDIT
|
||||
}
|
||||
|
||||
/**
|
||||
* Tab groups state
|
||||
* @type {object}
|
||||
*/
|
||||
tabGroups = { primary: "competences" }
|
||||
|
||||
/** @override */
|
||||
async _prepareContext() {
|
||||
const actor = this.document
|
||||
|
||||
const context = {
|
||||
actor: actor,
|
||||
system: actor.system,
|
||||
source: actor.toObject(),
|
||||
fields: actor.schema.fields,
|
||||
systemFields: actor.system.schema.fields,
|
||||
isEditable: this.isEditable,
|
||||
isEditMode: this.isEditMode,
|
||||
isPlayMode: this.isPlayMode,
|
||||
isGM: game.user.isGM,
|
||||
config: CONFIG.HERITIERS,
|
||||
enrichedDescription: await foundry.applications.ux.TextEditor.implementation.enrichHTML(actor.system.biodata?.description || "", { async: true }),
|
||||
enrichedHabitat: await foundry.applications.ux.TextEditor.implementation.enrichHTML(actor.system.biodata?.habitat || "", { async: true }),
|
||||
enrichedRevesetranges: await foundry.applications.ux.TextEditor.implementation.enrichHTML(actor.system.biodata?.revesetranges || "", { async: true }),
|
||||
enrichedSecretsdecouverts: await foundry.applications.ux.TextEditor.implementation.enrichHTML(actor.system.biodata?.secretsdecouverts || "", { async: true }),
|
||||
enrichedQuestions: await foundry.applications.ux.TextEditor.implementation.enrichHTML(actor.system.biodata?.questions || "", { async: true }),
|
||||
enrichedPlayernotes: await foundry.applications.ux.TextEditor.implementation.enrichHTML(actor.system.biodata?.playernotes || "", { async: true }),
|
||||
}
|
||||
|
||||
return context
|
||||
}
|
||||
|
||||
/** @override */
|
||||
_onRender(context, options) {
|
||||
super._onRender(context, options)
|
||||
|
||||
// Activate drag & drop handlers
|
||||
this.#dragDrop.forEach(d => d.bind(this.element))
|
||||
|
||||
// Manual tab navigation
|
||||
const html = this.element
|
||||
const tabLinks = html.querySelectorAll('.sheet-tabs a.item[data-tab]')
|
||||
const tabContents = html.querySelectorAll('.sheet-body .tab[data-group="primary"]')
|
||||
|
||||
// Hide all tabs initially
|
||||
tabContents.forEach(tab => {
|
||||
tab.classList.remove('active')
|
||||
tab.style.display = 'none'
|
||||
})
|
||||
|
||||
// Show active tab
|
||||
const activeTab = this.tabGroups.primary
|
||||
const activeTabContent = html.querySelector(`.tab[data-group="primary"][data-tab="${activeTab}"]`)
|
||||
if (activeTabContent) {
|
||||
activeTabContent.classList.add('active')
|
||||
activeTabContent.style.display = 'block'
|
||||
}
|
||||
|
||||
// Activate the corresponding nav link
|
||||
tabLinks.forEach(link => {
|
||||
if (link.dataset.tab === activeTab) {
|
||||
link.classList.add('active')
|
||||
} else {
|
||||
link.classList.remove('active')
|
||||
}
|
||||
})
|
||||
|
||||
// Tab click handler
|
||||
tabLinks.forEach(link => {
|
||||
link.addEventListener('click', (event) => {
|
||||
event.preventDefault()
|
||||
const tab = link.dataset.tab
|
||||
|
||||
// Update state
|
||||
this.tabGroups.primary = tab
|
||||
|
||||
// Hide all tabs
|
||||
tabContents.forEach(t => {
|
||||
t.classList.remove('active')
|
||||
t.style.display = 'none'
|
||||
})
|
||||
|
||||
// Show selected tab
|
||||
const selectedTab = html.querySelector(`.tab[data-group="primary"][data-tab="${tab}"]`)
|
||||
if (selectedTab) {
|
||||
selectedTab.classList.add('active')
|
||||
selectedTab.style.display = 'block'
|
||||
}
|
||||
|
||||
// Update nav links
|
||||
tabLinks.forEach(l => {
|
||||
if (l.dataset.tab === tab) {
|
||||
l.classList.add('active')
|
||||
} else {
|
||||
l.classList.remove('active')
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
// Inline item editing
|
||||
html.querySelectorAll('.edit-item-data').forEach(input => {
|
||||
input.addEventListener('change', (event) => {
|
||||
const li = event.target.closest('.item')
|
||||
const itemId = li?.dataset.itemId
|
||||
const itemType = li?.dataset.itemType
|
||||
const itemField = event.target.dataset.itemField
|
||||
const dataType = event.target.dataset.dtype
|
||||
const value = event.target.value
|
||||
if (itemId && itemType && itemField) {
|
||||
this.actor.editItemField(itemId, itemType, itemField, dataType, value)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// #region Drag & Drop
|
||||
|
||||
/**
|
||||
* Create drag-and-drop workflow handlers for this Application
|
||||
* @returns {DragDrop[]} An array of DragDrop handlers
|
||||
* @private
|
||||
*/
|
||||
#createDragDropHandlers() {
|
||||
return this.options.dragDrop.map((d) => {
|
||||
d.permissions = {
|
||||
dragstart: this._canDragStart.bind(this),
|
||||
drop: this._canDragDrop.bind(this),
|
||||
}
|
||||
d.callbacks = {
|
||||
dragstart: this._onDragStart.bind(this),
|
||||
drop: this._onDrop.bind(this),
|
||||
}
|
||||
return new foundry.applications.ux.DragDrop(d)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Define whether a user is able to begin a dragstart workflow for a given drag selector
|
||||
* @param {string} selector The candidate HTML selector for dragging
|
||||
* @returns {boolean} Can the current user drag this selector?
|
||||
* @protected
|
||||
*/
|
||||
_canDragStart(selector) {
|
||||
return this.isEditable
|
||||
}
|
||||
|
||||
/**
|
||||
* Define whether a user is able to conclude a drag-and-drop workflow for a given drop selector
|
||||
* @param {string} selector The candidate HTML selector for the drop target
|
||||
* @returns {boolean} Can the current user drop on this selector?
|
||||
* @protected
|
||||
*/
|
||||
_canDragDrop(selector) {
|
||||
return this.isEditable
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback actions which occur at the beginning of a drag start workflow.
|
||||
* @param {DragEvent} event The originating DragEvent
|
||||
* @protected
|
||||
*/
|
||||
_onDragStart(event) {
|
||||
const li = event.currentTarget.closest(".item")
|
||||
if (!li?.dataset.itemId) return
|
||||
const item = this.actor.items.get(li.dataset.itemId)
|
||||
if (!item) return
|
||||
|
||||
const dragData = item.toDragData()
|
||||
event.dataTransfer.setData("text/plain", JSON.stringify(dragData))
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback actions which occur when a dragged element is dropped on a target.
|
||||
* @param {DragEvent} event The originating DragEvent
|
||||
* @protected
|
||||
*/
|
||||
async _onDrop(event) {
|
||||
const data = foundry.applications.ux.TextEditor.implementation.getDragEventData(event)
|
||||
const actor = this.actor
|
||||
|
||||
// Handle different data types
|
||||
switch (data.type) {
|
||||
case "Item":
|
||||
return this._onDropItem(event, data)
|
||||
case "Actor":
|
||||
return this._onDropActor(event, data)
|
||||
case "ActiveEffect":
|
||||
return this._onDropActiveEffect(event, data)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle dropping an Item on the actor sheet
|
||||
* @param {DragEvent} event
|
||||
* @param {object} data
|
||||
* @private
|
||||
*/
|
||||
async _onDropItem(event, data) {
|
||||
if (!this.actor.isOwner) return false
|
||||
|
||||
let item = await fromUuid(data.uuid)
|
||||
if (item.pack) {
|
||||
item = await HeritiersUtility.searchItem(item)
|
||||
}
|
||||
|
||||
const itemData = item.toObject ? item.toObject() : item
|
||||
return this.actor.createEmbeddedDocuments("Item", [itemData])
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle dropping an Actor on the sheet
|
||||
* @param {DragEvent} event
|
||||
* @param {object} data
|
||||
* @private
|
||||
*/
|
||||
async _onDropActor(event, data) {
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle dropping an ActiveEffect on the sheet
|
||||
* @param {DragEvent} event
|
||||
* @param {object} data
|
||||
* @private
|
||||
*/
|
||||
async _onDropActiveEffect(event, data) {
|
||||
return false
|
||||
}
|
||||
|
||||
// #endregion
|
||||
|
||||
// #region Action Handlers
|
||||
|
||||
/**
|
||||
* Toggle between edit and play mode
|
||||
* @param {Event} event
|
||||
* @param {HTMLElement} target
|
||||
* @private
|
||||
*/
|
||||
static #onToggleSheet(event, target) {
|
||||
const wasEditMode = this.isEditMode
|
||||
this._sheetMode = wasEditMode ? this.constructor.SHEET_MODES.PLAY : this.constructor.SHEET_MODES.EDIT
|
||||
this.render({ force: true })
|
||||
}
|
||||
|
||||
/**
|
||||
* Edit the actor image
|
||||
* @param {Event} event
|
||||
* @param {HTMLElement} target
|
||||
* @private
|
||||
*/
|
||||
static async #onEditImage(event, target) {
|
||||
const fp = new FilePicker({
|
||||
type: "image",
|
||||
current: this.actor.img,
|
||||
callback: (path) => {
|
||||
this.actor.update({ img: path })
|
||||
},
|
||||
})
|
||||
return fp.browse()
|
||||
}
|
||||
|
||||
/**
|
||||
* Edit an item
|
||||
* @param {Event} event
|
||||
* @param {HTMLElement} target
|
||||
* @private
|
||||
*/
|
||||
static async #onEditItem(event, target) {
|
||||
const li = target.closest(".item")
|
||||
const itemId = li?.dataset.itemId
|
||||
if (!itemId) return
|
||||
const item = this.actor.items.get(itemId)
|
||||
if (item) item.sheet.render(true)
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete an item
|
||||
* @param {Event} event
|
||||
* @param {HTMLElement} target
|
||||
* @private
|
||||
*/
|
||||
static async #onDeleteItem(event, target) {
|
||||
const li = target.closest(".item")
|
||||
await HeritiersUtility.confirmDelete(this, li)
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new item
|
||||
* @param {Event} event
|
||||
* @param {HTMLElement} target
|
||||
* @private
|
||||
*/
|
||||
static async #onCreateItem(event, target) {
|
||||
const itemType = target.dataset.type
|
||||
|
||||
// Cas spécial pour les sorts avec une compétence spécifique
|
||||
if (itemType === "sort" && target.dataset.sortCompetence) {
|
||||
const sortCompetence = target.dataset.sortCompetence
|
||||
await this.actor.createEmbeddedDocuments('Item', [{
|
||||
name: `Nouveau ${itemType} de ${sortCompetence}`,
|
||||
type: itemType,
|
||||
system: { competence: sortCompetence }
|
||||
}], { renderSheet: true })
|
||||
return
|
||||
}
|
||||
|
||||
await this.actor.createEmbeddedDocuments("Item", [{ name: `Nouveau ${itemType}`, type: itemType }], { renderSheet: true })
|
||||
}
|
||||
|
||||
/**
|
||||
* Equip/unequip an item
|
||||
* @param {Event} event
|
||||
* @param {HTMLElement} target
|
||||
* @private
|
||||
*/
|
||||
static async #onEquipItem(event, target) {
|
||||
const li = target.closest(".item")
|
||||
const itemId = li?.dataset.itemId
|
||||
if (itemId) {
|
||||
await this.actor.equipItem(itemId)
|
||||
this.render()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Modify item quantity
|
||||
* @param {Event} event
|
||||
* @param {HTMLElement} target
|
||||
* @private
|
||||
*/
|
||||
static async #onModifyQuantity(event, target) {
|
||||
const li = target.closest(".item")
|
||||
const itemId = li?.dataset.itemId
|
||||
const value = Number(target.dataset.quantiteValue)
|
||||
if (itemId) {
|
||||
await this.actor.incDecQuantity(itemId, value)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Increase item quantity
|
||||
* @param {Event} event
|
||||
* @param {HTMLElement} target
|
||||
* @private
|
||||
*/
|
||||
static async #onQuantityIncrease(event, target) {
|
||||
const li = target.closest(".item")
|
||||
const itemId = li?.dataset.itemId
|
||||
if (itemId) {
|
||||
await this.actor.incDecQuantity(itemId, 1)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrease item quantity
|
||||
* @param {Event} event
|
||||
* @param {HTMLElement} target
|
||||
* @private
|
||||
*/
|
||||
static async #onQuantityDecrease(event, target) {
|
||||
const li = target.closest(".item")
|
||||
const itemId = li?.dataset.itemId
|
||||
if (itemId) {
|
||||
await this.actor.incDecQuantity(itemId, -1)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Increase PV
|
||||
* @param {Event} event
|
||||
* @param {HTMLElement} target
|
||||
* @private
|
||||
*/
|
||||
static async #onPvIncrease(event, target) {
|
||||
const currentPv = this.actor.system.pv.value || 0
|
||||
const maxPv = this.actor.system.pv.max || 0
|
||||
const newPv = Math.min(currentPv + 1, maxPv)
|
||||
await this.actor.update({ 'system.pv.value': newPv })
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrease PV
|
||||
* @param {Event} event
|
||||
* @param {HTMLElement} target
|
||||
* @private
|
||||
*/
|
||||
static async #onPvDecrease(event, target) {
|
||||
const currentPv = this.actor.system.pv.value || 0
|
||||
const newPv = Math.max(currentPv - 1, 0)
|
||||
await this.actor.update({ 'system.pv.value': newPv })
|
||||
}
|
||||
|
||||
/**
|
||||
* Roll initiative
|
||||
* @param {Event} event
|
||||
* @param {HTMLElement} target
|
||||
* @private
|
||||
*/
|
||||
static async #onRollInitiative(event, target) {
|
||||
await this.actor.rollInitiative()
|
||||
}
|
||||
|
||||
/**
|
||||
* Roll caractéristique
|
||||
* @param {Event} event
|
||||
* @param {HTMLElement} target
|
||||
* @private
|
||||
*/
|
||||
static async #onRollCarac(event, target) {
|
||||
const key = target.dataset.key
|
||||
if (key) {
|
||||
await this.actor.rollCarac(key, false)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Roll rang
|
||||
* @param {Event} event
|
||||
* @param {HTMLElement} target
|
||||
* @private
|
||||
*/
|
||||
static async #onRollRang(event, target) {
|
||||
const key = target.dataset.rangKey
|
||||
if (key) {
|
||||
await this.actor.rollRang(key)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Roll root competence
|
||||
* @param {Event} event
|
||||
* @param {HTMLElement} target
|
||||
* @private
|
||||
*/
|
||||
static async #onRollRootCompetence(event, target) {
|
||||
const compKey = target.dataset.attrKey
|
||||
if (compKey) {
|
||||
await this.actor.rollRootCompetence(compKey)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Roll competence
|
||||
* @param {Event} event
|
||||
* @param {HTMLElement} target
|
||||
* @private
|
||||
*/
|
||||
static async #onRollCompetence(event, target) {
|
||||
const li = target.closest(".item")
|
||||
const compId = li?.dataset.itemId
|
||||
if (compId) {
|
||||
await this.actor.rollCompetence(compId)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Roll sort
|
||||
* @param {Event} event
|
||||
* @param {HTMLElement} target
|
||||
* @private
|
||||
*/
|
||||
static async #onRollSort(event, target) {
|
||||
const li = target.closest(".item")
|
||||
const sortId = li?.dataset.itemId
|
||||
if (sortId) {
|
||||
await this.actor.rollSort(sortId)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Roll attaque arme
|
||||
* @param {Event} event
|
||||
* @param {HTMLElement} target
|
||||
* @private
|
||||
*/
|
||||
static async #onRollAttaqueArme(event, target) {
|
||||
const li = target.closest(".item")
|
||||
const armeId = li?.dataset.itemId
|
||||
if (armeId) {
|
||||
await this.actor.rollAttaqueArme(armeId)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Roll attaque brutale arme
|
||||
* @param {Event} event
|
||||
* @param {HTMLElement} target
|
||||
* @private
|
||||
*/
|
||||
static async #onRollAttaqueBrutaleArme(event, target) {
|
||||
const li = target.closest(".item")
|
||||
const armeId = li?.dataset.itemId
|
||||
if (armeId) {
|
||||
await this.actor.rollAttaqueBrutaleArme(armeId)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Roll attaque charge arme
|
||||
* @param {Event} event
|
||||
* @param {HTMLElement} target
|
||||
* @private
|
||||
*/
|
||||
static async #onRollAttaqueChargeArme(event, target) {
|
||||
const li = target.closest(".item")
|
||||
const armeId = li?.dataset.itemId
|
||||
if (armeId) {
|
||||
await this.actor.rollAttaqueChargeArme(armeId)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Roll assomer arme
|
||||
* @param {Event} event
|
||||
* @param {HTMLElement} target
|
||||
* @private
|
||||
*/
|
||||
static async #onRollAssomerArme(event, target) {
|
||||
const li = target.closest(".item")
|
||||
const armeId = li?.dataset.itemId
|
||||
if (armeId) {
|
||||
await this.actor.rollAssomerArme(armeId)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Roll pouvoir
|
||||
* @param {Event} event
|
||||
* @param {HTMLElement} target
|
||||
* @private
|
||||
*/
|
||||
static async #onRollPouvoir(event, target) {
|
||||
const li = target.closest(".item")
|
||||
const pouvoirId = li?.dataset.itemId
|
||||
if (pouvoirId) {
|
||||
await this.actor.rollPouvoir(pouvoirId)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle masque
|
||||
* @param {Event} event
|
||||
* @param {HTMLElement} target
|
||||
* @private
|
||||
*/
|
||||
static async #onToggleMasque(event, target) {
|
||||
await this.actor.toggleMasqueStatut()
|
||||
this.render()
|
||||
}
|
||||
|
||||
/**
|
||||
* Dialog récupération usage
|
||||
* @param {Event} event
|
||||
* @param {HTMLElement} target
|
||||
* @private
|
||||
*/
|
||||
static async #onDialogRecupUsage(event, target) {
|
||||
new Dialog({
|
||||
title: "Récupération des Points d'Usage",
|
||||
content: "<p>Combien de Points d'Usage souhaitez-vous récupérer ?</p>",
|
||||
buttons: {
|
||||
one: {
|
||||
icon: '<i class="fas fa-check"></i>',
|
||||
label: "1 Point",
|
||||
callback: () => {
|
||||
this.actor.recupUsage(1)
|
||||
}
|
||||
},
|
||||
two: {
|
||||
icon: '<i class="fas fa-check"></i>',
|
||||
label: "2 Points",
|
||||
callback: () => {
|
||||
this.actor.recupUsage(2)
|
||||
}
|
||||
},
|
||||
three: {
|
||||
icon: '<i class="fas fa-check"></i>',
|
||||
label: "3 Points",
|
||||
callback: () => {
|
||||
this.actor.recupUsage(3)
|
||||
}
|
||||
},
|
||||
cancel: {
|
||||
icon: '<i class="fas fa-times"></i>',
|
||||
label: "Annuler"
|
||||
}
|
||||
},
|
||||
default: "one"
|
||||
}).render(true)
|
||||
}
|
||||
|
||||
// #endregion
|
||||
}
|
||||
212
modules/applications/sheets/base-item-sheet.mjs
Normal file
@@ -0,0 +1,212 @@
|
||||
const { HandlebarsApplicationMixin } = foundry.applications.api
|
||||
|
||||
export default class HeritiersItemSheet extends HandlebarsApplicationMixin(foundry.applications.sheets.ItemSheetV2) {
|
||||
constructor(options = {}) {
|
||||
super(options)
|
||||
this.#dragDrop = this.#createDragDropHandlers()
|
||||
}
|
||||
|
||||
#dragDrop
|
||||
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ["fvtt-les-heritiers", "item"],
|
||||
position: {
|
||||
width: 620,
|
||||
height: 600,
|
||||
},
|
||||
form: {
|
||||
submitOnChange: true,
|
||||
},
|
||||
window: {
|
||||
resizable: true,
|
||||
},
|
||||
tabs: [
|
||||
{
|
||||
navSelector: 'nav[data-group="primary"]',
|
||||
contentSelector: "section.sheet-body",
|
||||
initial: "description",
|
||||
},
|
||||
],
|
||||
dragDrop: [{ dragSelector: "[data-drag]", dropSelector: null }],
|
||||
actions: {
|
||||
editImage: HeritiersItemSheet.#onEditImage,
|
||||
postItem: HeritiersItemSheet.#onPostItem,
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Tab groups state
|
||||
* @type {object}
|
||||
*/
|
||||
tabGroups = { primary: "description" }
|
||||
|
||||
/** @override */
|
||||
async _prepareContext() {
|
||||
const context = {
|
||||
fields: this.document.schema.fields,
|
||||
systemFields: this.document.system.schema.fields,
|
||||
item: this.document,
|
||||
system: this.document.system,
|
||||
source: this.document.toObject(),
|
||||
enrichedDescription: await foundry.applications.ux.TextEditor.implementation.enrichHTML(this.document.system.description, { async: true }),
|
||||
isEditMode: true,
|
||||
isEditable: this.isEditable,
|
||||
isGM: game.user.isGM,
|
||||
config: CONFIG.HERITIERS,
|
||||
}
|
||||
return context
|
||||
}
|
||||
|
||||
/** @override */
|
||||
_onRender(context, options) {
|
||||
super._onRender(context, options)
|
||||
this.#dragDrop.forEach((d) => d.bind(this.element))
|
||||
|
||||
// Activate tab navigation manually
|
||||
const nav = this.element.querySelector('nav.tabs[data-group]')
|
||||
if (nav) {
|
||||
const group = nav.dataset.group
|
||||
// Activate the current tab
|
||||
const activeTab = this.tabGroups[group] || "description"
|
||||
nav.querySelectorAll('[data-tab]').forEach(link => {
|
||||
const tab = link.dataset.tab
|
||||
link.classList.toggle('active', tab === activeTab)
|
||||
link.addEventListener('click', (event) => {
|
||||
event.preventDefault()
|
||||
this.tabGroups[group] = tab
|
||||
this.render()
|
||||
})
|
||||
})
|
||||
|
||||
// Show/hide tab content
|
||||
this.element.querySelectorAll('[data-group="' + group + '"][data-tab]').forEach(content => {
|
||||
content.classList.toggle('active', content.dataset.tab === activeTab)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// #region Drag-and-Drop Workflow
|
||||
/**
|
||||
* Create drag-and-drop workflow handlers for this Application
|
||||
* @returns {DragDrop[]} An array of DragDrop handlers
|
||||
* @private
|
||||
*/
|
||||
#createDragDropHandlers() {
|
||||
return this.options.dragDrop.map((d) => {
|
||||
d.permissions = {
|
||||
dragstart: this._canDragStart.bind(this),
|
||||
drop: this._canDragDrop.bind(this),
|
||||
}
|
||||
d.callbacks = {
|
||||
dragstart: this._onDragStart.bind(this),
|
||||
dragover: this._onDragOver.bind(this),
|
||||
drop: this._onDrop.bind(this),
|
||||
}
|
||||
return new foundry.applications.ux.DragDrop(d)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Can the User start a drag workflow for a given drag selector?
|
||||
* @param {string} selector The candidate HTML selector for the drag event
|
||||
* @returns {boolean} Can the current user drag this selector?
|
||||
* @protected
|
||||
*/
|
||||
_canDragStart(selector) {
|
||||
return this.isEditable
|
||||
}
|
||||
|
||||
/**
|
||||
* Can the User drop an entry at a given drop selector?
|
||||
* @param {string} selector The candidate HTML selector for the drop event
|
||||
* @returns {boolean} Can the current user drop on this selector?
|
||||
* @protected
|
||||
*/
|
||||
_canDragDrop(selector) {
|
||||
return this.isEditable
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for dragstart events.
|
||||
* @param {DragEvent} event The drag start event
|
||||
* @protected
|
||||
*/
|
||||
_onDragStart(event) {
|
||||
const target = event.currentTarget
|
||||
const dragData = { type: "Item", uuid: this.document.uuid }
|
||||
event.dataTransfer.setData("text/plain", JSON.stringify(dragData))
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for dragover events.
|
||||
* @param {DragEvent} event The drag over event
|
||||
* @protected
|
||||
*/
|
||||
_onDragOver(event) {
|
||||
// Default behavior is fine
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for drop events.
|
||||
* @param {DragEvent} event The drop event
|
||||
* @protected
|
||||
*/
|
||||
async _onDrop(event) {
|
||||
const data = foundry.applications.ux.TextEditor.implementation.getDragEventData(event)
|
||||
const item = await fromUuid(data.uuid)
|
||||
if (!item) return
|
||||
|
||||
console.log("Item dropped:", item)
|
||||
}
|
||||
// #endregion
|
||||
|
||||
// #region Action Handlers
|
||||
/**
|
||||
* Edit the item image
|
||||
* @param {Event} event The triggering event
|
||||
* @param {HTMLElement} target The target element
|
||||
* @private
|
||||
*/
|
||||
static async #onEditImage(event, target) {
|
||||
const fp = new FilePicker({
|
||||
type: "image",
|
||||
current: this.document.img,
|
||||
callback: (path) => {
|
||||
this.document.update({ img: path })
|
||||
},
|
||||
})
|
||||
return fp.browse()
|
||||
}
|
||||
|
||||
/**
|
||||
* Post item to chat
|
||||
* @param {Event} event The triggering event
|
||||
* @param {HTMLElement} target The target element
|
||||
* @private
|
||||
*/
|
||||
static async #onPostItem(event, target) {
|
||||
let chatData = foundry.utils.duplicate(this.document)
|
||||
if (this.document.actor) {
|
||||
chatData.actor = { id: this.document.actor.id }
|
||||
}
|
||||
// Don't post any image for the item if the default image is used
|
||||
if (chatData.img.includes("/blank.png") || chatData.img.includes("/mystery-man")) {
|
||||
chatData.img = null
|
||||
}
|
||||
// JSON object for easy creation
|
||||
chatData.jsondata = JSON.stringify({
|
||||
compendium: "postedItem",
|
||||
payload: chatData,
|
||||
})
|
||||
|
||||
const html = await renderTemplate('systems/fvtt-les-heritiers/templates/post-item.html', chatData)
|
||||
const chatOptions = {
|
||||
user: game.user.id,
|
||||
content: html,
|
||||
}
|
||||
ChatMessage.create(chatOptions)
|
||||
}
|
||||
|
||||
// #endregion
|
||||
}
|
||||
19
modules/applications/sheets/capacitenaturelle-sheet.mjs
Normal file
@@ -0,0 +1,19 @@
|
||||
import HeritiersItemSheet from "./base-item-sheet.mjs"
|
||||
|
||||
export default class HeritiersCapaciteNaturelleSheet extends HeritiersItemSheet {
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
...super.DEFAULT_OPTIONS,
|
||||
window: {
|
||||
...super.DEFAULT_OPTIONS.window,
|
||||
title: "SHEETS.Item.capacitenaturelle",
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
sheet: {
|
||||
template: "systems/fvtt-les-heritiers/templates/item-capacitenaturelle-sheet.hbs",
|
||||
},
|
||||
}
|
||||
}
|
||||
65
modules/applications/sheets/competence-sheet.mjs
Normal file
@@ -0,0 +1,65 @@
|
||||
import HeritiersItemSheet from "./base-item-sheet.mjs"
|
||||
|
||||
export default class HeritiersCompetenceSheet extends HeritiersItemSheet {
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
...super.DEFAULT_OPTIONS,
|
||||
window: {
|
||||
...super.DEFAULT_OPTIONS.window,
|
||||
title: "SHEETS.Item.competence",
|
||||
},
|
||||
actions: {
|
||||
addSpecialite: HeritiersCompetenceSheet.#onAddSpecialite,
|
||||
deleteSpecialite: HeritiersCompetenceSheet.#onDeleteSpecialite,
|
||||
editSpecialite: HeritiersCompetenceSheet.#onEditSpecialite,
|
||||
editSpecialiteDescription: HeritiersCompetenceSheet.#onEditSpecialiteDescription,
|
||||
}
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
sheet: {
|
||||
template: "systems/fvtt-les-heritiers/templates/item-competence-sheet.hbs",
|
||||
},
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/* Event Handlers */
|
||||
/* -------------------------------------------- */
|
||||
|
||||
static async #onAddSpecialite(event, target) {
|
||||
let spec = foundry.utils.duplicate(this.item.system.specialites) || []
|
||||
spec.push({ name: "Nouvelle Spécialité", id: foundry.utils.randomID(16), used: false })
|
||||
await this.item.update({ 'system.specialites': spec })
|
||||
}
|
||||
|
||||
static async #onDeleteSpecialite(event, target) {
|
||||
const li = target.closest(".specialite-item")
|
||||
let index = parseInt(li.dataset.specialiteIndex)
|
||||
let spec = foundry.utils.duplicate(this.item.system.specialites) || []
|
||||
spec.splice(index, 1)
|
||||
await this.item.update({ 'system.specialites': spec })
|
||||
}
|
||||
|
||||
static async #onEditSpecialite(event, target) {
|
||||
const li = target.closest(".specialite-item")
|
||||
let index = parseInt(li.dataset.specialiteIndex)
|
||||
let spec = foundry.utils.duplicate(this.item.system.specialites) || []
|
||||
if (spec[index]) {
|
||||
spec[index].name = target.value
|
||||
spec[index].id = spec[index].id || foundry.utils.randomID(16)
|
||||
await this.item.update({ 'system.specialites': spec })
|
||||
}
|
||||
}
|
||||
|
||||
static async #onEditSpecialiteDescription(event, target) {
|
||||
const li = target.closest(".specialite-item")
|
||||
let index = parseInt(li.dataset.specialiteIndex)
|
||||
let spec = foundry.utils.duplicate(this.item.system.specialites) || []
|
||||
if (spec[index]) {
|
||||
spec[index].description = target.value
|
||||
spec[index].id = spec[index].id || foundry.utils.randomID(16)
|
||||
await this.item.update({ 'system.specialites': spec })
|
||||
}
|
||||
}
|
||||
}
|
||||
19
modules/applications/sheets/contact-sheet.mjs
Normal file
@@ -0,0 +1,19 @@
|
||||
import HeritiersItemSheet from "./base-item-sheet.mjs"
|
||||
|
||||
export default class HeritiersContactSheet extends HeritiersItemSheet {
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
...super.DEFAULT_OPTIONS,
|
||||
window: {
|
||||
...super.DEFAULT_OPTIONS.window,
|
||||
title: "SHEETS.Item.contact",
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
sheet: {
|
||||
template: "systems/fvtt-les-heritiers/templates/item-contact-sheet.hbs",
|
||||
},
|
||||
}
|
||||
}
|
||||
19
modules/applications/sheets/desavantage-sheet.mjs
Normal file
@@ -0,0 +1,19 @@
|
||||
import HeritiersItemSheet from "./base-item-sheet.mjs"
|
||||
|
||||
export default class HeritiersDesavantageSheet extends HeritiersItemSheet {
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
...super.DEFAULT_OPTIONS,
|
||||
window: {
|
||||
...super.DEFAULT_OPTIONS.window,
|
||||
title: "SHEETS.Item.desavantage",
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
sheet: {
|
||||
template: "systems/fvtt-les-heritiers/templates/item-desavantage-sheet.hbs",
|
||||
},
|
||||
}
|
||||
}
|
||||
19
modules/applications/sheets/equipement-sheet.mjs
Normal file
@@ -0,0 +1,19 @@
|
||||
import HeritiersItemSheet from "./base-item-sheet.mjs"
|
||||
|
||||
export default class HeritiersEquipementSheet extends HeritiersItemSheet {
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
...super.DEFAULT_OPTIONS,
|
||||
window: {
|
||||
...super.DEFAULT_OPTIONS.window,
|
||||
title: "SHEETS.Item.equipement",
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
sheet: {
|
||||
template: "systems/fvtt-les-heritiers/templates/item-equipement-sheet.hbs",
|
||||
},
|
||||
}
|
||||
}
|
||||
19
modules/applications/sheets/fee-sheet.mjs
Normal file
@@ -0,0 +1,19 @@
|
||||
import HeritiersItemSheet from "./base-item-sheet.mjs"
|
||||
|
||||
export default class HeritiersFeeSheet extends HeritiersItemSheet {
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
...super.DEFAULT_OPTIONS,
|
||||
window: {
|
||||
...super.DEFAULT_OPTIONS.window,
|
||||
title: "SHEETS.Item.fee",
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
sheet: {
|
||||
template: "systems/fvtt-les-heritiers/templates/item-fee-sheet.hbs",
|
||||
},
|
||||
}
|
||||
}
|
||||
59
modules/applications/sheets/personnage-sheet.mjs
Normal file
@@ -0,0 +1,59 @@
|
||||
import HeritiersActorSheet from "./base-actor-sheet.mjs"
|
||||
|
||||
export default class HeritiersPersonnageSheet extends HeritiersActorSheet {
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
...super.DEFAULT_OPTIONS,
|
||||
classes: [...super.DEFAULT_OPTIONS.classes],
|
||||
window: {
|
||||
...super.DEFAULT_OPTIONS.window,
|
||||
title: "SHEETS.Actor.personnage",
|
||||
},
|
||||
actions: {
|
||||
...super.DEFAULT_OPTIONS.actions,
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
sheet: {
|
||||
template: "systems/fvtt-les-heritiers/templates/actor-sheet.hbs",
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
tabGroups = { primary: "competences" }
|
||||
|
||||
/** @override */
|
||||
async _prepareContext() {
|
||||
const context = await super._prepareContext()
|
||||
const actor = this.document
|
||||
|
||||
// Add personnage-specific data
|
||||
context.skills = actor.getSkills()
|
||||
context.utileSkillsMental = actor.organizeUtileSkills("mental")
|
||||
context.utileSkillsPhysical = actor.organizeUtileSkills("physical")
|
||||
context.competencesMagie = game.system.lesheritiers.config.competencesMagie || []
|
||||
context.futileSkills = actor.organizeFutileSkills()
|
||||
context.contacts = actor.organizeContacts()
|
||||
context.armes = foundry.utils.duplicate(actor.getWeapons())
|
||||
context.monnaies = foundry.utils.duplicate(actor.getMonnaies())
|
||||
context.pouvoirs = foundry.utils.duplicate(actor.getPouvoirs())
|
||||
context.fee = foundry.utils.duplicate(actor.getFee() || {})
|
||||
context.protections = foundry.utils.duplicate(actor.getArmors())
|
||||
context.combat = actor.getCombatValues()
|
||||
context.equipements = foundry.utils.duplicate(actor.getEquipments())
|
||||
context.avantages = foundry.utils.duplicate(actor.getAvantages())
|
||||
context.atouts = foundry.utils.duplicate(actor.getAtouts())
|
||||
context.capacites = foundry.utils.duplicate(actor.getCapacites())
|
||||
context.desavantages = foundry.utils.duplicate(actor.getDesavantages())
|
||||
context.profils = foundry.utils.duplicate(actor.getProfils())
|
||||
context.pvMalus = actor.getPvMalus()
|
||||
context.heritage = game.settings.get("fvtt-les-heritiers", "heritiers-heritage")
|
||||
context.initiative = actor.getFlag("world", "last-initiative") || -1
|
||||
context.magieList = actor.prepareMagie()
|
||||
context.isPNJ = false
|
||||
|
||||
return context
|
||||
}
|
||||
}
|
||||
59
modules/applications/sheets/pnj-sheet.mjs
Normal file
@@ -0,0 +1,59 @@
|
||||
import HeritiersActorSheet from "./base-actor-sheet.mjs"
|
||||
|
||||
export default class HeritiersPnjSheet extends HeritiersActorSheet {
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
...super.DEFAULT_OPTIONS,
|
||||
classes: [...super.DEFAULT_OPTIONS.classes],
|
||||
window: {
|
||||
...super.DEFAULT_OPTIONS.window,
|
||||
title: "SHEETS.Actor.pnj",
|
||||
},
|
||||
actions: {
|
||||
...super.DEFAULT_OPTIONS.actions,
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
sheet: {
|
||||
template: "systems/fvtt-les-heritiers/templates/actor-pnj-sheet.hbs",
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
tabGroups = { primary: "competences" }
|
||||
|
||||
/** @override */
|
||||
async _prepareContext() {
|
||||
const context = await super._prepareContext()
|
||||
const actor = this.document
|
||||
|
||||
// Add PNJ-specific data
|
||||
context.skills = actor.getSkills()
|
||||
context.utileSkillsMental = actor.organizeUtileSkills("mental")
|
||||
context.utileSkillsPhysical = actor.organizeUtileSkills("physical")
|
||||
context.competencesMagie = game.system.lesheritiers.config.competencesMagie || []
|
||||
context.futileSkills = actor.organizeFutileSkills()
|
||||
context.contacts = actor.organizeContacts()
|
||||
context.armes = foundry.utils.duplicate(actor.getWeapons())
|
||||
context.monnaies = foundry.utils.duplicate(actor.getMonnaies())
|
||||
context.pouvoirs = foundry.utils.duplicate(actor.getPouvoirs())
|
||||
context.fee = foundry.utils.duplicate(actor.getFee() || {})
|
||||
context.protections = foundry.utils.duplicate(actor.getArmors())
|
||||
context.combat = actor.getCombatValues()
|
||||
context.equipements = foundry.utils.duplicate(actor.getEquipments())
|
||||
context.avantages = foundry.utils.duplicate(actor.getAvantages())
|
||||
context.atouts = foundry.utils.duplicate(actor.getAtouts())
|
||||
context.capacites = foundry.utils.duplicate(actor.getCapacites())
|
||||
context.desavantages = foundry.utils.duplicate(actor.getDesavantages())
|
||||
context.profils = foundry.utils.duplicate(actor.getProfils())
|
||||
context.pvMalus = actor.getPvMalus()
|
||||
context.heritage = game.settings.get("fvtt-les-heritiers", "heritiers-heritage")
|
||||
context.initiative = actor.getFlag("world", "last-initiative") || -1
|
||||
context.magieList = actor.prepareMagie()
|
||||
context.isPNJ = true
|
||||
|
||||
return context
|
||||
}
|
||||
}
|
||||
19
modules/applications/sheets/pouvoir-sheet.mjs
Normal file
@@ -0,0 +1,19 @@
|
||||
import HeritiersItemSheet from "./base-item-sheet.mjs"
|
||||
|
||||
export default class HeritiersPouvoirSheet extends HeritiersItemSheet {
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
...super.DEFAULT_OPTIONS,
|
||||
window: {
|
||||
...super.DEFAULT_OPTIONS.window,
|
||||
title: "SHEETS.Item.pouvoir",
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
sheet: {
|
||||
template: "systems/fvtt-les-heritiers/templates/item-pouvoir-sheet.hbs",
|
||||
},
|
||||
}
|
||||
}
|
||||
19
modules/applications/sheets/profil-sheet.mjs
Normal file
@@ -0,0 +1,19 @@
|
||||
import HeritiersItemSheet from "./base-item-sheet.mjs"
|
||||
|
||||
export default class HeritiersProfilSheet extends HeritiersItemSheet {
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
...super.DEFAULT_OPTIONS,
|
||||
window: {
|
||||
...super.DEFAULT_OPTIONS.window,
|
||||
title: "SHEETS.Item.profil",
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
sheet: {
|
||||
template: "systems/fvtt-les-heritiers/templates/item-profil-sheet.hbs",
|
||||
},
|
||||
}
|
||||
}
|
||||
19
modules/applications/sheets/protection-sheet.mjs
Normal file
@@ -0,0 +1,19 @@
|
||||
import HeritiersItemSheet from "./base-item-sheet.mjs"
|
||||
|
||||
export default class HeritiersProtectionSheet extends HeritiersItemSheet {
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
...super.DEFAULT_OPTIONS,
|
||||
window: {
|
||||
...super.DEFAULT_OPTIONS.window,
|
||||
title: "SHEETS.Item.protection",
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
sheet: {
|
||||
template: "systems/fvtt-les-heritiers/templates/item-protection-sheet.hbs",
|
||||
},
|
||||
}
|
||||
}
|
||||
27
modules/applications/sheets/sort-sheet.mjs
Normal file
@@ -0,0 +1,27 @@
|
||||
import HeritiersItemSheet from "./base-item-sheet.mjs"
|
||||
import { HeritiersUtility } from "../../heritiers-utility.js"
|
||||
|
||||
export default class HeritiersSortSheet extends HeritiersItemSheet {
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
...super.DEFAULT_OPTIONS,
|
||||
window: {
|
||||
...super.DEFAULT_OPTIONS.window,
|
||||
title: "SHEETS.Item.sort",
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
sheet: {
|
||||
template: "systems/fvtt-les-heritiers/templates/item-sort-sheet.hbs",
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
async _prepareContext() {
|
||||
const context = await super._prepareContext()
|
||||
context.competencesMagie = HeritiersUtility.getCompetencesMagie() || []
|
||||
return context
|
||||
}
|
||||
}
|
||||
@@ -1,176 +0,0 @@
|
||||
/**
|
||||
* Extend the basic ActorSheet with some very simple modifications
|
||||
* @extends {ActorSheet}
|
||||
*/
|
||||
|
||||
import { HeritiersUtility } from "./heritiers-utility.js";
|
||||
|
||||
/* -------------------------------------------- */
|
||||
export class HeritiersActorSheet extends ActorSheet {
|
||||
|
||||
/** @override */
|
||||
static get defaultOptions() {
|
||||
|
||||
return mergeObject(super.defaultOptions, {
|
||||
classes: ["fvtt-les-heritiers", "sheet", "actor"],
|
||||
template: "systems/fvtt-les-heritiers/templates/actor-sheet.html",
|
||||
width: 640,
|
||||
height: 720,
|
||||
tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "stats" }],
|
||||
dragDrop: [{ dragSelector: ".item-list .item", dropSelector: null }],
|
||||
editScore: false
|
||||
})
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async getData() {
|
||||
const objectData = duplicate(this.object)
|
||||
|
||||
let formData = {
|
||||
title: this.title,
|
||||
id: objectData.id,
|
||||
type: objectData.type,
|
||||
img: objectData.img,
|
||||
name: objectData.name,
|
||||
editable: this.isEditable,
|
||||
cssClass: this.isEditable ? "editable" : "locked",
|
||||
system: objectData.system,
|
||||
effects: this.object.effects.map(e => foundry.utils.deepClone(e.data)),
|
||||
limited: this.object.limited,
|
||||
skills: this.actor.getSkills(),
|
||||
utileSkills :this.actor.organizeUtileSkills(),
|
||||
futileSkills :this.actor.organizeFutileSkills(),
|
||||
armes: duplicate(this.actor.getWeapons()),
|
||||
monnaies: duplicate(this.actor.getMonnaies()),
|
||||
protections: duplicate(this.actor.getArmors()),
|
||||
combat: this.actor.getCombatValues(),
|
||||
equipements: duplicate(this.actor.getEquipments()),
|
||||
avantages: duplicate(this.actor.getAvantages()),
|
||||
atouts: duplicate(this.actor.getAtouts()),
|
||||
capacites: duplicate(this.actor.getCapacites()),
|
||||
desavantages: duplicate(this.actor.getDesavantages()),
|
||||
pvMalus: this.actor.getPvMalus(),
|
||||
initiative: this.actor.getFlag("world", "last-initiative") || -1,
|
||||
description: await TextEditor.enrichHTML(this.object.system.biodata.description, {async: true}),
|
||||
habitat: await TextEditor.enrichHTML(this.object.system.biodata.habitat, {async: true}),
|
||||
options: this.options,
|
||||
owner: this.document.isOwner,
|
||||
editScore: this.options.editScore,
|
||||
isGM: game.user.isGM
|
||||
}
|
||||
this.formData = formData;
|
||||
|
||||
console.log("PC : ", formData, this.object);
|
||||
return formData;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
getCelluleTalents( ) {
|
||||
let talents = []
|
||||
for(let cellule of game.actors) {
|
||||
if (cellule.type == "cellule") {
|
||||
let found = cellule.system.members.find( it => it.id == this.actor.id)
|
||||
if (found) {
|
||||
talents = talents.concat( cellule.getTalents() )
|
||||
}
|
||||
}
|
||||
}
|
||||
return talents
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/** @override */
|
||||
activateListeners(html) {
|
||||
super.activateListeners(html);
|
||||
|
||||
// Everything below here is only needed if the sheet is editable
|
||||
if (!this.options.editable) return;
|
||||
|
||||
// Update Inventory Item
|
||||
html.find('.item-edit').click(ev => {
|
||||
const li = $(ev.currentTarget).parents(".item")
|
||||
let itemId = li.data("item-id")
|
||||
const item = this.actor.items.get( itemId )
|
||||
item.sheet.render(true)
|
||||
})
|
||||
// Delete Inventory Item
|
||||
html.find('.item-delete').click(ev => {
|
||||
const li = $(ev.currentTarget).parents(".item");
|
||||
HeritiersUtility.confirmDelete(this, li);
|
||||
})
|
||||
html.find('.edit-item-data').change(ev => {
|
||||
const li = $(ev.currentTarget).parents(".item")
|
||||
let itemId = li.data("item-id")
|
||||
let itemType = li.data("item-type")
|
||||
let itemField = $(ev.currentTarget).data("item-field")
|
||||
let dataType = $(ev.currentTarget).data("dtype")
|
||||
let value = ev.currentTarget.value
|
||||
this.actor.editItemField(itemId, itemType, itemField, dataType, value)
|
||||
})
|
||||
|
||||
html.find('.adversite-modify').click(event => {
|
||||
const li = $(event.currentTarget).parents(".item")
|
||||
let adv = li.data("adversite")
|
||||
let value = Number($(event.currentTarget).data("adversite-value"))
|
||||
this.actor.incDecAdversite(adv, value)
|
||||
})
|
||||
|
||||
html.find('.quantity-modify').click(event => {
|
||||
const li = $(event.currentTarget).parents(".item")
|
||||
const value = Number($(event.currentTarget).data("quantite-value"))
|
||||
this.actor.incDecQuantity( li.data("item-id"), value );
|
||||
})
|
||||
|
||||
html.find('.roll-initiative').click((event) => {
|
||||
this.actor.rollInitiative()
|
||||
})
|
||||
|
||||
html.find('.roll-carac').click((event) => {
|
||||
const key = $(event.currentTarget).data("key")
|
||||
this.actor.rollCarac(key, false)
|
||||
})
|
||||
html.find('.roll-competence').click((event) => {
|
||||
const li = $(event.currentTarget).parents(".item")
|
||||
let compId = li.data("item-id")
|
||||
this.actor.rollCompetence(compId)
|
||||
})
|
||||
|
||||
html.find('.item-add').click((event) => {
|
||||
const itemType = $(event.currentTarget).data("type")
|
||||
this.actor.createEmbeddedDocuments('Item', [{ name: `Nouveau ${itemType}`, type: itemType }], { renderSheet: true })
|
||||
})
|
||||
|
||||
html.find('.lock-unlock-sheet').click((event) => {
|
||||
this.options.editScore = !this.options.editScore;
|
||||
this.render(true);
|
||||
});
|
||||
html.find('.item-equip').click(ev => {
|
||||
const li = $(ev.currentTarget).parents(".item");
|
||||
this.actor.equipItem( li.data("item-id") );
|
||||
this.render(true);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/** @override */
|
||||
setPosition(options = {}) {
|
||||
const position = super.setPosition(options);
|
||||
const sheetBody = this.element.find(".sheet-body");
|
||||
const bodyHeight = position.height - 192;
|
||||
sheetBody.css("height", bodyHeight);
|
||||
return position;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/*async _onDropItem(event, dragData) {
|
||||
let data = event.dataTransfer.getData('text/plain')
|
||||
let dataItem = JSON.parse( data)
|
||||
let item = fromUuidSync(dataItem.uuid)
|
||||
if (item.pack) {
|
||||
item = await HeritiersUtility.searchItem(item)
|
||||
}
|
||||
super._onDropItem(event, dragData)
|
||||
}*/
|
||||
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -------------------------------------------- */
|
||||
import { HeritiersUtility } from "./heritiers-utility.js";
|
||||
import { HeritiersRollDialog } from "./heritiers-roll-dialog.js";
|
||||
import { HeritiersRollDialog } from "./applications/heritiers-roll-dialog.mjs";
|
||||
|
||||
/* -------------------------------------------- */
|
||||
const __degatsBonus = [-2, -2, -1, -1, 0, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 8, 8, 9, 9, 10, 10]
|
||||
@@ -17,8 +17,8 @@ export class HeritiersActor extends Actor {
|
||||
/**
|
||||
* Override the create() function to provide additional SoS functionality.
|
||||
*
|
||||
* This overrided create() function adds initial items
|
||||
* Namely: Basic skills, money,
|
||||
* This overrided create() function adds initial items
|
||||
* Namely: Basic skills, money,
|
||||
*
|
||||
* @param {Object} data Barebones actor data which this function adds onto.
|
||||
* @param {Object} options (Unused) Additional options which customize the creation workflow.
|
||||
@@ -39,13 +39,14 @@ export class HeritiersActor extends Actor {
|
||||
|
||||
if (data.type == 'personnage') {
|
||||
const skills = await HeritiersUtility.loadCompendium("fvtt-les-heritiers.competences")
|
||||
data.items = skills.map(i => i.toObject())
|
||||
data.items = []
|
||||
for (let skill of skills) {
|
||||
if (skill.system.categorie == "utile" && skill.system.profil != "magie") {
|
||||
data.items.push(skill.toObject())
|
||||
}
|
||||
}
|
||||
}
|
||||
if (data.type == 'creature') {
|
||||
const skills = await HeritiersUtility.loadCompendium("fvtt-les-heritiers.skills-creatures")
|
||||
data.items = skills.map(i => i.toObject())
|
||||
data.items.push({ name: "Arme naturelle 1", type: 'arme', img: "systems/fvtt-les-heritiers/assets/icons/melee.webp", system: { typearme: "contact", bonusmaniementoff: 0, seuildefense: 0, degats: "0" } })
|
||||
data.items.push({ name: "Arme naturelle 2", type: 'arme', img: "systems/fvtt-les-heritiers/assets/icons/melee.webp", system: { typearme: "contact", bonusmaniementoff: 0, seuildefense: 0, degats: "0" } })
|
||||
if (data.type == 'pnj') {
|
||||
}
|
||||
|
||||
return super.create(data, options);
|
||||
@@ -53,26 +54,8 @@ export class HeritiersActor extends Actor {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
prepareArme(arme) {
|
||||
arme = duplicate(arme)
|
||||
let combat = this.getCombatValues()
|
||||
if (arme.system.typearme == "contact" || arme.system.typearme == "contactjet") {
|
||||
let bonusDefense = 0
|
||||
arme.system.competence = duplicate(this.items.find(item => item.type == "competence" && item.name.toLowerCase() == "mêlée"))
|
||||
arme.system.attrKey = "pui"
|
||||
arme.system.totalDegats = arme.system.degats + "+" + combat.bonusDegatsTotal
|
||||
arme.system.totalOffensif = this.system.attributs.pui.value + arme.system.competence.system.niveau + arme.system.bonusmaniementoff
|
||||
arme.system.totalDefensif = combat.defenseTotal + arme.system.competence.system.niveau + arme.system.seuildefense + bonusDefense
|
||||
arme.system.isdefense = true
|
||||
}
|
||||
if (arme.system.typearme == "jet" || arme.system.typearme == "tir") {
|
||||
arme.system.competence = duplicate(this.items.find(item => item.type == "competence" && item.name.toLowerCase() == "armes à distance"))
|
||||
arme.system.attrKey = "adr"
|
||||
arme.system.totalOffensif = this.system.attributs.adr.value + arme.system.competence.system.niveau + arme.system.bonusmaniementoff
|
||||
arme.system.totalDegats = arme.system.degats
|
||||
if (arme.system.isdefense) {
|
||||
arme.system.totalDefensif = combat.defenseTotal + arme.system.competence.system.niveau + arme.system.seuildefense
|
||||
}
|
||||
}
|
||||
arme = foundry.utils.duplicate(arme)
|
||||
arme.system.isMelee = HeritiersUtility.isArmeMelee(arme)
|
||||
return arme
|
||||
}
|
||||
|
||||
@@ -87,13 +70,23 @@ export class HeritiersActor extends Actor {
|
||||
return armes
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
getOtherMeleeWeapons(excludeArme) {
|
||||
let armes = []
|
||||
for (let arme of this.items) {
|
||||
if (HeritiersUtility.isArmeMelee(arme) && arme.id != excludeArme._id) {
|
||||
armes.push(this.prepareArme(arme))
|
||||
}
|
||||
}
|
||||
return armes
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
getMonnaies() {
|
||||
return this.items.filter(it => it.type == "monnaie")
|
||||
}
|
||||
|
||||
/* ----------------------- --------------------- */
|
||||
addMember(actorId) {
|
||||
let members = duplicate(this.system.members)
|
||||
let members = foundry.utils.duplicate(this.system.members)
|
||||
members.push({ id: actorId })
|
||||
this.update({ 'system.members': members })
|
||||
}
|
||||
@@ -103,38 +96,141 @@ export class HeritiersActor extends Actor {
|
||||
}
|
||||
|
||||
/* ----------------------- --------------------- */
|
||||
getItemSorted(types) {
|
||||
let items = this.items.filter(item => types.includes(item.type)) || []
|
||||
HeritiersUtility.sortArrayObjectsByName(items)
|
||||
return items
|
||||
}
|
||||
getEquipments() {
|
||||
return this.items.filter(item => item.type == "equipement")
|
||||
return this.getItemSorted(["equipement", "accessoire"])
|
||||
}
|
||||
getAvantages() {
|
||||
return this.items.filter(item => item.type == "avantage")
|
||||
return this.getItemSorted(["avantage"])
|
||||
}
|
||||
getDesavantages() {
|
||||
return this.items.filter(item => item.type == "desavantage")
|
||||
return this.getItemSorted(["desavantage"])
|
||||
}
|
||||
getMonnaies() {
|
||||
return this.items.filter(item => item.type == "monnaie")
|
||||
return this.getItemSorted(["monnaie"])
|
||||
}
|
||||
getArmors() {
|
||||
return this.items.filter(item => item.type == "protection")
|
||||
return this.getItemSorted(["protection"])
|
||||
}
|
||||
getTalents() {
|
||||
return this.items.filter(item => item.type == "talent")
|
||||
return this.getItemSorted(["talent"])
|
||||
}
|
||||
getContacts() {
|
||||
return this.items.filter(item => item.type == "contact")
|
||||
return this.getItemSorted(["contact"])
|
||||
}
|
||||
getAtouts() {
|
||||
return this.items.filter(item => item.type == "atoutfeerique")
|
||||
return this.getItemSorted(["atoutfeerique"])
|
||||
}
|
||||
getCapacites() {
|
||||
return this.items.filter(item => item.type == "capacitenaturelle")
|
||||
return this.getItemSorted(["capacitenaturelle"])
|
||||
}
|
||||
getFee() {
|
||||
return this.items.find(item => item.type == "fee")
|
||||
}
|
||||
getProfils() {
|
||||
return this.getItemSorted(["profil"])
|
||||
}
|
||||
getPouvoirs() {
|
||||
let pouvoirs = []
|
||||
for (let item of this.items) {
|
||||
if (item.type == "pouvoir") {
|
||||
let itemObj = foundry.utils.duplicate(item)
|
||||
itemObj.maxUsage = this.getPouvoirUsageMax(item)
|
||||
pouvoirs.push(itemObj)
|
||||
}
|
||||
}
|
||||
HeritiersUtility.sortArrayObjectsByName(pouvoirs)
|
||||
return pouvoirs
|
||||
}
|
||||
getSorts() {
|
||||
return this.getItemSorted(["sort"])
|
||||
}
|
||||
getCompetencesMagie() {
|
||||
let comp = []
|
||||
for (let item of this.items) {
|
||||
if (item.type == "competence" && item.system.profil == "magie") {
|
||||
let itemObj = foundry.utils.duplicate(item)
|
||||
comp.push(itemObj)
|
||||
}
|
||||
}
|
||||
HeritiersUtility.sortArrayObjectsByName(comp)
|
||||
return comp
|
||||
}
|
||||
|
||||
prepareMagie() {
|
||||
let magieList = []
|
||||
for (let item of this.items) {
|
||||
if (item.type == "competence" && item.system.profil == "magie") {
|
||||
let magie = {}
|
||||
magie.name = item.name
|
||||
magie.competence = foundry.utils.duplicate(item)
|
||||
magie.rang = Math.round(item.system.niveau / 2);
|
||||
magie.rangGenericName = game.system.lesheritiers.config.rangName[magie.rang];
|
||||
console.log("Magie", item.name, item.system.niveau, magie.rang, magie.rangGenericName)
|
||||
//magie.rangSpecificName = game.system.lesheritiers.config.rangNameSpecific[item.name][magie.rangGenericName];
|
||||
magie.sorts = {}
|
||||
if (item.name == "Magie du Clan") {
|
||||
magie.sorts = {
|
||||
"soufflecombat": {
|
||||
1: { nomNiveau: magie.competence.system.nomniveausouffle.soufflecombat["1"], sorts: [] },
|
||||
2: { nomNiveau: magie.competence.system.nomniveausouffle.soufflecombat["2"], sorts: [] },
|
||||
3: { nomNiveau: magie.competence.system.nomniveausouffle.soufflecombat["3"], sorts: [] },
|
||||
4: { nomNiveau: magie.competence.system.nomniveausouffle.soufflecombat["4"], sorts: [] }
|
||||
},
|
||||
"soufflemouvement": {
|
||||
1: { nomNiveau: magie.competence.system.nomniveausouffle.soufflemouvement["1"], sorts: [] },
|
||||
2: { nomNiveau: magie.competence.system.nomniveausouffle.soufflemouvement["2"], sorts: [] },
|
||||
3: { nomNiveau: magie.competence.system.nomniveausouffle.soufflemouvement["3"], sorts: [] },
|
||||
4: { nomNiveau: magie.competence.system.nomniveausouffle.soufflemouvement["4"], sorts: [] }
|
||||
},
|
||||
"souffleesprit": {
|
||||
1: { nomNiveau: magie.competence.system.nomniveausouffle.souffleesprit["1"], sorts: [] },
|
||||
2: { nomNiveau: magie.competence.system.nomniveausouffle.souffleesprit["2"], sorts: [] },
|
||||
3: { nomNiveau: magie.competence.system.nomniveausouffle.souffleesprit["3"], sorts: [] },
|
||||
4: { nomNiveau: magie.competence.system.nomniveausouffle.souffleesprit["4"], sorts: [] }
|
||||
}
|
||||
}
|
||||
for (let sort of this.items) {
|
||||
if (sort.type == "sort" && sort.system.competence == item.name) {
|
||||
let sortObj = foundry.utils.duplicate(sort)
|
||||
sortObj.sdValue = HeritiersUtility.getSDSortValue(Number(sort.system.niveau))
|
||||
if (!magie.sorts[sort.system?.souffle]) {
|
||||
console.warn("Sort with unknown souffle ", sort.system.souffle, sort)
|
||||
continue
|
||||
}
|
||||
magie.sorts[sort.system.souffle][Number(sort.system.niveau)].sorts.push(sortObj)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
magie.sorts = {
|
||||
1: { nomNiveau: magie.competence.system.nomniveau["1"], sorts: [] },
|
||||
2: { nomNiveau: magie.competence.system.nomniveau["2"], sorts: [] },
|
||||
3: { nomNiveau: magie.competence.system.nomniveau["3"], sorts: [] },
|
||||
4: { nomNiveau: magie.competence.system.nomniveau["4"], sorts: [] }
|
||||
}
|
||||
for (let sort of this.items) {
|
||||
if (sort.type == "sort" && sort.system.competence == item.name) {
|
||||
let sortObj = foundry.utils.duplicate(sort)
|
||||
sortObj.sdValue = HeritiersUtility.getSDSortValue(Number(sort.system.niveau))
|
||||
magie.sorts[Number(sort.system.niveau)].sorts.push(sortObj)
|
||||
}
|
||||
}
|
||||
}
|
||||
magieList.push(magie)
|
||||
}
|
||||
}
|
||||
return magieList
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
getSkills() {
|
||||
let comp = []
|
||||
for (let item of this.items) {
|
||||
item = duplicate(item)
|
||||
item = foundry.utils.duplicate(item)
|
||||
if (item.type == "competence") {
|
||||
comp.push(item)
|
||||
}
|
||||
@@ -143,19 +239,75 @@ export class HeritiersActor extends Actor {
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
organizeUtileSkills() {
|
||||
prepareUtileSkill(item) {
|
||||
let specList = []
|
||||
if (item?.system?.categorie == "utile") {
|
||||
for (let spec of item.system.specialites) {
|
||||
specList.push(spec.name)
|
||||
}
|
||||
}
|
||||
item.nbSpec = specList.length
|
||||
item.specList = specList.toString()
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
organizeMagicSkills() {
|
||||
let comp = {}
|
||||
for (let key in game.system.lesheritiers.config.competenceProfil) {
|
||||
comp[key] = []
|
||||
if (game.system.lesheritiers.config.competenceProfil[key].kind == "magical")
|
||||
comp[key] = { skills: [], niveau: 0 }
|
||||
}
|
||||
for (let item of this.items) {
|
||||
if (item.type == "competence") {
|
||||
if (item.system.categorie == "utile") {
|
||||
comp[item.system.profil].push(item)
|
||||
if (item.system.categorie == "utile" && comp[item.system.profil]) {
|
||||
this.prepareUtileSkill(item)
|
||||
comp[item.system.profil].skills.push(item)
|
||||
}
|
||||
}
|
||||
}
|
||||
return comp
|
||||
|
||||
for (let key in comp) {
|
||||
HeritiersUtility.sortArrayObjectsByName(comp[key].skills)
|
||||
}
|
||||
return Object.fromEntries(Object.entries(comp).sort())
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
organizeUtileSkills(kind = "mental") {
|
||||
let comp = {}
|
||||
for (let key in game.system.lesheritiers.config.competenceProfil) {
|
||||
if (game.system.lesheritiers.config.competenceProfil[key].kind == kind)
|
||||
comp[key] = { skills: [], niveau: this.system.competences[key].niveau }
|
||||
}
|
||||
for (let item of this.items) {
|
||||
if (item.type == "competence") {
|
||||
if (item.system.categorie == "utile" && comp[item.system.profil]) {
|
||||
this.prepareUtileSkill(item)
|
||||
comp[item.system.profil].skills.push(item)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (let key in comp) {
|
||||
HeritiersUtility.sortArrayObjectsByName(comp[key].skills)
|
||||
}
|
||||
return Object.fromEntries(Object.entries(comp).sort())
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
organizeContacts() {
|
||||
let contactList = {}
|
||||
for (let item of this.items) {
|
||||
if (item.type == "contact") {
|
||||
let c = contactList[item.system.contacttype] || { label: game.system.lesheritiers.config.contactType[item.system.contacttype], list: [] }
|
||||
c.list.push(item)
|
||||
contactList[item.system.contacttype] = c
|
||||
}
|
||||
}
|
||||
for (let key in contactList) {
|
||||
HeritiersUtility.sortArrayObjectsByName(contactList[key].list)
|
||||
}
|
||||
return contactList
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
@@ -168,6 +320,7 @@ export class HeritiersActor extends Actor {
|
||||
}
|
||||
}
|
||||
}
|
||||
HeritiersUtility.sortArrayObjectsByName(comp)
|
||||
return HeritiersUtility.sortByName(comp)
|
||||
}
|
||||
|
||||
@@ -210,8 +363,35 @@ export class HeritiersActor extends Actor {
|
||||
super.prepareData();
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
getMaxRangMagie() {
|
||||
let niv = 0
|
||||
let bestMagie
|
||||
for (let comp of this.items) {
|
||||
if (comp.type == "competence" && comp.system.profil == "magie") {
|
||||
if (comp.system.niveau > niv) {
|
||||
bestMagie = comp
|
||||
niv = comp.system.niveau
|
||||
}
|
||||
}
|
||||
}
|
||||
if (bestMagie) {
|
||||
return Math.round(bestMagie.system.niveau / 2)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
prepareDerivedData() {
|
||||
// Calculate derived PV max
|
||||
let pvMax = (this.system.caracteristiques.con.rang * 3) + 9 + this.system.pv.mod
|
||||
this.system.pv.max = pvMax
|
||||
|
||||
// Calculate derived Points d'Âme max
|
||||
if (this.system.biodata.magie || this.type == "pnj") {
|
||||
let pointsAmes = this.system.caracteristiques.esp.rang + this.system.caracteristiques.san.rang + this.getMaxRangMagie()
|
||||
this.system.magie.pointsame.max = pointsAmes
|
||||
}
|
||||
|
||||
if (this.type == 'personnage') {
|
||||
}
|
||||
@@ -229,7 +409,7 @@ export class HeritiersActor extends Actor {
|
||||
getItemById(id) {
|
||||
let item = this.items.find(item => item.id == id);
|
||||
if (item) {
|
||||
item = duplicate(item)
|
||||
item = foundry.utils.duplicate(item)
|
||||
}
|
||||
return item;
|
||||
}
|
||||
@@ -237,7 +417,7 @@ export class HeritiersActor extends Actor {
|
||||
/* -------------------------------------------- */
|
||||
async equipItem(itemId) {
|
||||
let item = this.items.find(item => item.id == itemId)
|
||||
if (item && item.system) {
|
||||
if (item?.system) {
|
||||
let update = { _id: item.id, "system.equipped": !item.system.equipped }
|
||||
await this.updateEmbeddedDocuments('Item', [update]); // Updates one EmbeddedEntity
|
||||
}
|
||||
@@ -248,10 +428,12 @@ export class HeritiersActor extends Actor {
|
||||
let item = this.items.find(item => item.id == itemId)
|
||||
if (item) {
|
||||
console.log("Item ", item, itemField, dataType, value)
|
||||
if (dataType.toLowerCase() == "number") {
|
||||
value = Number(value)
|
||||
} else {
|
||||
value = String(value)
|
||||
if (dataType) {
|
||||
if (dataType.toLowerCase() == "number") {
|
||||
value = Number(value)
|
||||
} else {
|
||||
value = String(value)
|
||||
}
|
||||
}
|
||||
let update = { _id: item.id, [`system.${itemField}`]: value };
|
||||
this.updateEmbeddedDocuments("Item", [update])
|
||||
@@ -261,15 +443,15 @@ export class HeritiersActor extends Actor {
|
||||
/* -------------------------------------------- */
|
||||
getPvMalus() {
|
||||
if (this.system.pv.value > 0) {
|
||||
if (this.system.pv.value < this.system.pv.max / 2) {
|
||||
return -1
|
||||
}
|
||||
if (this.system.pv.value < 5) {
|
||||
return -2
|
||||
return { name: "Santé", value: -2 }
|
||||
}
|
||||
return 0
|
||||
if (this.system.pv.value < this.system.pv.max / 2) {
|
||||
return { name: "Santé", value: -1 }
|
||||
}
|
||||
return { name: "Santé", value: 0 }
|
||||
}
|
||||
return "Moribond(e)"
|
||||
return { name: "Moribond(e)", value: -50 }
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
@@ -285,7 +467,7 @@ export class HeritiersActor extends Actor {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
getCarac(attrKey) {
|
||||
return duplicate(this.system.caracteristiques)
|
||||
return foundry.utils.duplicate(this.system.caracteristiques)
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
@@ -296,7 +478,7 @@ export class HeritiersActor extends Actor {
|
||||
/* -------------------------------------------- */
|
||||
async equipGear(equipmentId) {
|
||||
let item = this.items.find(item => item.id == equipmentId);
|
||||
if (item && item.system.data) {
|
||||
if (item?.system) {
|
||||
let update = { _id: item.id, "system.equipped": !item.system.equipped };
|
||||
await this.updateEmbeddedDocuments('Item', [update]); // Updates one EmbeddedEntity
|
||||
}
|
||||
@@ -306,13 +488,13 @@ export class HeritiersActor extends Actor {
|
||||
getSubActors() {
|
||||
let subActors = [];
|
||||
for (let id of this.system.subactors) {
|
||||
subActors.push(duplicate(game.actors.get(id)));
|
||||
subActors.push(foundry.utils.duplicate(game.actors.get(id)));
|
||||
}
|
||||
return subActors;
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
async addSubActor(subActorId) {
|
||||
let subActors = duplicate(this.system.subactors);
|
||||
let subActors = foundry.utils.duplicate(this.system.subactors);
|
||||
subActors.push(subActorId);
|
||||
await this.update({ 'system.subactors': subActors });
|
||||
}
|
||||
@@ -334,11 +516,12 @@ export class HeritiersActor extends Actor {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async incDecAdversite(adv, incDec = 0) {
|
||||
let adversite = duplicate(this.system.adversite)
|
||||
let adversite = foundry.utils.duplicate(this.system.adversite)
|
||||
adversite[adv] += Number(incDec)
|
||||
adversite[adv] = Math.max(adversite[adv], 0)
|
||||
this.update({ 'system.adversite': adversite })
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async incDecQuantity(objetId, incDec = 0) {
|
||||
let objetQ = this.items.get(objetId)
|
||||
@@ -381,7 +564,7 @@ export class HeritiersActor extends Actor {
|
||||
/* -------------------------------------------- */
|
||||
async setPredilectionUsed(compId, predIdx) {
|
||||
let comp = this.items.get(compId)
|
||||
let pred = duplicate(comp.system.predilections)
|
||||
let pred = foundry.utils.duplicate(comp.system.predilections)
|
||||
pred[predIdx].used = true
|
||||
await this.updateEmbeddedDocuments('Item', [{ _id: compId, 'system.predilections': pred }])
|
||||
}
|
||||
@@ -403,7 +586,7 @@ export class HeritiersActor extends Actor {
|
||||
}
|
||||
if (arme.system.totalDefensif > maxDef) {
|
||||
maxDef = arme.system.totalDefensif
|
||||
bestArme = duplicate(arme)
|
||||
bestArme = foundry.utils.duplicate(arme)
|
||||
}
|
||||
}
|
||||
return bestArme
|
||||
@@ -418,7 +601,7 @@ export class HeritiersActor extends Actor {
|
||||
for (let auto of talent.system.automations) {
|
||||
if (auto.eventtype === "prepare-roll") {
|
||||
if (auto.competence.toLowerCase() == competence.name.toLowerCase()) {
|
||||
talent = duplicate(talent)
|
||||
talent = foundry.utils.duplicate(talent)
|
||||
talent.system.bonus = auto.bonus
|
||||
talent.system.baCost = auto.baCost
|
||||
talents.push(talent)
|
||||
@@ -429,7 +612,23 @@ export class HeritiersActor extends Actor {
|
||||
}
|
||||
return talents
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
getCurrentParade() {
|
||||
if (this.system.statutmasque == "masque") {
|
||||
return this.system.combat.parade.masquee
|
||||
}
|
||||
return this.system.combat.parade.demasquee
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
getCurrentEsquive() {
|
||||
if (this.system.statutmasque == "masque") {
|
||||
return this.system.combat.esquive.masquee
|
||||
}
|
||||
return this.system.combat.esquive.demasquee
|
||||
}
|
||||
getCurrentResistancePhysique() {
|
||||
return this.system.combat.resistancephysique.value
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
getTricherie() {
|
||||
return this.system.rang.tricherie.value
|
||||
@@ -442,9 +641,27 @@ export class HeritiersActor extends Actor {
|
||||
incDecTricherie(value) {
|
||||
let tricherie = this.system.rang.tricherie
|
||||
tricherie.value += value
|
||||
if (tricherie.value < 0 || tricherie.value > tricherie.max) {
|
||||
ui.notifications.warn("Pas assez de points de Tricherie !")
|
||||
return false
|
||||
}
|
||||
tricherie.value = Math.max(tricherie.value, 0)
|
||||
tricherie.value = Math.min(tricherie.value, tricherie.max)
|
||||
this.update({ 'system.rang.tricherie': tricherie })
|
||||
return true
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
getPireCompetence(compName1, compName2) {
|
||||
let comp1 = this.items.find(it => it.name == compName1)
|
||||
let comp2 = this.items.find(it => it.name == compName2)
|
||||
if (comp1 && comp2) {
|
||||
if (comp1.system.niveau > comp2.system.niveau) {
|
||||
return comp1
|
||||
} else {
|
||||
return comp2
|
||||
}
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
@@ -460,41 +677,66 @@ export class HeritiersActor extends Actor {
|
||||
rollData.tricherie = this.getTricherie()
|
||||
rollData.heritage = this.getHeritages()
|
||||
rollData.useTricherie = false
|
||||
rollData.useSpecialite = false
|
||||
rollData.useHeritage = false
|
||||
rollData.pvMalus = this.getPvMalus()
|
||||
rollData.pouvoirPointsUsage = 1
|
||||
rollData.rulesMalus.push(this.getPvMalus())
|
||||
|
||||
if (compId) {
|
||||
rollData.competence = duplicate(this.items.get(compId) || {})
|
||||
rollData.competence = foundry.utils.duplicate(this.items.get(compId) || {})
|
||||
this.prepareUtileSkill(rollData.competence)
|
||||
rollData.actionImg = rollData.competence?.img
|
||||
}
|
||||
if (compName) {
|
||||
rollData.competence = duplicate(this.items.find(item => item.name.toLowerCase() == compName.toLowerCase()) || {})
|
||||
rollData.actionImg = rollData.competence?.img
|
||||
rollData.competence = foundry.utils.duplicate(this.items.find(item => item.name.toLowerCase() == compName.toLowerCase()) || {})
|
||||
if (rollData.competence?.name) {
|
||||
this.prepareUtileSkill(rollData.competence)
|
||||
rollData.actionImg = rollData.competence?.img
|
||||
} else {
|
||||
rollData.competence = undefined
|
||||
}
|
||||
}
|
||||
HeritiersUtility.updateWithTarget(rollData)
|
||||
|
||||
return rollData
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
async rollInitiative() {
|
||||
let rollData = this.getCommonRollData(undefined, "Art de la guerre")
|
||||
rollData.mode = "init"
|
||||
rollData.mode = "init"
|
||||
if (this.system.caracteristiques["san"].value > this.system.caracteristiques["per"].value) {
|
||||
rollData.caracKey = "san"
|
||||
} else {
|
||||
rollData.caracKey = "per"
|
||||
}
|
||||
rollData.carac = this.system.caracteristiques[rollData.caracKey]
|
||||
let rollDialog = await HeritiersRollDialog.create(this, rollData)
|
||||
rollDialog.render(true)
|
||||
await HeritiersRollDialog.create(this, rollData)
|
||||
}
|
||||
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async rollCarac(key, isInit = false) {
|
||||
let rollData = this.getCommonRollData()
|
||||
rollData.mode = "carac"
|
||||
rollData.mode = "carac"
|
||||
rollData.carac = this.system.caracteristiques[key]
|
||||
rollData.caracKey = key
|
||||
let rollDialog = await HeritiersRollDialog.create(this, rollData)
|
||||
rollDialog.render(true)
|
||||
await HeritiersRollDialog.create(this, rollData)
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async rollRang(key, isInit = false) {
|
||||
let rollData = this.getCommonRollData()
|
||||
rollData.mode = "rang"
|
||||
rollData.rang = this.system.rang[key]
|
||||
rollData.rangKey = key
|
||||
await HeritiersRollDialog.create(this, rollData)
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
async rollRootCompetence(compKey) {
|
||||
let rollData = this.getCommonRollData()
|
||||
rollData.mode = "competence"
|
||||
rollData.competence = { name: this.system.competences[compKey].label, system: { niveau: this.system.competences[compKey].niveau } }
|
||||
console.log("RollDatra", rollData)
|
||||
await HeritiersRollDialog.create(this, rollData)
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
@@ -502,50 +744,310 @@ export class HeritiersActor extends Actor {
|
||||
let rollData = this.getCommonRollData(compId)
|
||||
rollData.mode = "competence"
|
||||
console.log("RollDatra", rollData)
|
||||
let rollDialog = await HeritiersRollDialog.create(this, rollData)
|
||||
rollDialog.render(true)
|
||||
await HeritiersRollDialog.create(this, rollData)
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async rollArmeOffensif(armeId) {
|
||||
let arme = this.items.get(armeId)
|
||||
if (arme.type == "arme") {
|
||||
arme = this.prepareArme(arme)
|
||||
inDecCarac(key, incDec) {
|
||||
let carac = this.system.caracteristiques[key]
|
||||
carac.value += incDec
|
||||
if (carac.value < 0 || carac.value > carac.rang) {
|
||||
ui.notifications.warn("Pas assez de points dans cette caractéristique ou rang max atteint !")
|
||||
return false
|
||||
}
|
||||
let rollData = this.getCommonRollData(arme.system.attrKey, arme.system.competence._id)
|
||||
rollData.arme = arme
|
||||
HeritiersUtility.updateWithTarget(rollData)
|
||||
console.log("ARME!", rollData)
|
||||
let rollDialog = await HeritiersRollDialog.create(this, rollData)
|
||||
rollDialog.render(true)
|
||||
carac.value = Math.max(carac.value, 0)
|
||||
carac.value = Math.min(carac.value, carac.rang)
|
||||
this.update({ [`system.caracteristiques.${key}`]: carac })
|
||||
return true
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async rollArmeDegats(armeId, targetVigueur = undefined) {
|
||||
let arme = this.items.get(armeId)
|
||||
if (arme.type == "arme") {
|
||||
arme = this.prepareArme(arme)
|
||||
async rollSort(sortId) {
|
||||
let sort = this.items.get(sortId)
|
||||
let comp = this.items.find(it => it.type == "competence" && it.name.toLowerCase() == sort.system.competence.toLowerCase())
|
||||
if (!comp) {
|
||||
ui.notifications.warn("Compétence de magie associée non trouvée !")
|
||||
return
|
||||
}
|
||||
console.log("DEGATS", arme)
|
||||
let roll = new Roll("1d10+" + arme.system.totalDegats).roll({ async: false })
|
||||
await HeritiersUtility.showDiceSoNice(roll, game.settings.get("core", "rollMode"));
|
||||
let nbEtatPerdus = 0
|
||||
if (targetVigueur) {
|
||||
nbEtatPerdus = Math.floor(roll.total / targetVigueur)
|
||||
if (sort.system.informatif) {
|
||||
if (sort.system.texteinformatif) {
|
||||
let chatData = { user: game.user.id, speaker: { actor: this, alias: this.name }, content: `<div class="heritiers-informatif-sort"><h4>Sort informatif !</h4>${sort.system.texteinformatif}</div>` }
|
||||
ChatMessage.create(chatData)
|
||||
} else {
|
||||
ui.notifications.info("Ce sort est uniquement informatif et ne peut pas être lancé.")
|
||||
}
|
||||
return
|
||||
}
|
||||
let rollData = {
|
||||
arme: arme,
|
||||
finalResult: roll.total,
|
||||
alias: this.name,
|
||||
actorImg: this.img,
|
||||
actorId: this.id,
|
||||
actionImg: arme.img,
|
||||
targetVigueur: targetVigueur,
|
||||
nbEtatPerdus: nbEtatPerdus
|
||||
}
|
||||
HeritiersUtility.createChatWithRollMode(rollData.alias, {
|
||||
content: await renderTemplate(`systems/fvtt-les-heritiers/templates/chat-degats-result.html`, rollData)
|
||||
})
|
||||
|
||||
let rollData = this.getCommonRollData(comp.id)
|
||||
rollData.mode = "sort"
|
||||
rollData.sort = foundry.utils.duplicate(sort)
|
||||
rollData.sdValue = HeritiersUtility.getSDSortValue(Number(sort.system.niveau))
|
||||
if (Number(sort.system.sdspecial) && Number(sort.system.sdspecial) > 0) {
|
||||
rollData.sdValue = Number(sort.system.sdspecial)
|
||||
}
|
||||
rollData.sortPointsAme = Number(sort.system.niveau)
|
||||
rollData.totalEsprit = 1
|
||||
if (sort.system.competence == "Grand Langage") {
|
||||
rollData.sortPointsAme *= 2
|
||||
rollData.totalEsprit = Math.floor((rollData.sortPointsAme) / 3)
|
||||
}
|
||||
if (rollData.sortPointsAme > this.system.magie.pointsame.value) {
|
||||
// Vérifier si au moins 1 point d'Esprit est disponible
|
||||
if (this.system.caracteristiques.esp.value <= rollData.totalEsprit) {
|
||||
ui.notifications.warn(`Pas assez de Points d'Esprit ni de Points d'Ame pour lancer ce sort (requis: ${rollData.totalEsprit}, disponible: ${this.system.caracteristiques.esp.value})`)
|
||||
return
|
||||
} else {
|
||||
rollData.spendEsprit = true
|
||||
ui.notifications.warn(`Vous n'avez pas assez de Points d'Ame pour lancer ce sort (requis: ${rollData.sortPointsAme}, disponible: ${this.system.magie.pointsame.value}).`)
|
||||
ui.notifications.warn(`${rollData.totalEsprit} Points d'Esprit seront utilisés à la place si vous effectuez le lancer.`)
|
||||
}
|
||||
}
|
||||
|
||||
if (sort.system.carac2 != "none") {
|
||||
// get the best carac between carac1 and carac2
|
||||
if (this.system.caracteristiques[sort.system.carac1].value > this.system.caracteristiques[sort.system.carac2].value) {
|
||||
rollData.caracKey = sort.system.carac1
|
||||
} else {
|
||||
rollData.caracKey = sort.system.carac2
|
||||
}
|
||||
rollData.caracMessage = "Ce sort peut être lancé avec " + game.system.lesheritiers.config.caracList[sort.system.carac1] + " ou " + game.system.lesheritiers.config.caracList[sort.system.carac2] + ". La meilleure caractéristique a été selectionnée."
|
||||
} else {
|
||||
rollData.caracKey = sort.system.carac1
|
||||
}
|
||||
console.log("RollData", rollData)
|
||||
await HeritiersRollDialog.create(this, rollData)
|
||||
}
|
||||
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async rollAttaqueArme(armeId) {
|
||||
let arme = this.items.get(armeId)
|
||||
if (arme) {
|
||||
arme = foundry.utils.duplicate(arme)
|
||||
arme.system.isMelee = HeritiersUtility.isArmeMelee(arme)
|
||||
let competenceName = "Tir"
|
||||
let key = "prec"
|
||||
if (arme.system.isMelee) {
|
||||
competenceName = "Mêlée"
|
||||
key = "agi"
|
||||
}
|
||||
let rollData = this.getCommonRollData(undefined, competenceName)
|
||||
rollData.carac = this.system.caracteristiques[key]
|
||||
rollData.caracKey = key
|
||||
rollData.arme = arme
|
||||
rollData.mode = "arme"
|
||||
rollData.attackType = "Attaque normale"
|
||||
rollData.armes = this.getOtherMeleeWeapons(arme)
|
||||
if (rollData.defenderTokenId && arme.system.isMelee) {
|
||||
rollData.cacheDifficulte = true
|
||||
}
|
||||
console.log(">>>> ARME", rollData)
|
||||
await HeritiersRollDialog.create(this, rollData)
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async rollAttaqueBrutaleArme(armeId) {
|
||||
let arme = this.items.get(armeId)
|
||||
if (arme) {
|
||||
let key = "for"
|
||||
let competenceName = "Mêlée"
|
||||
arme.system.isMelee = HeritiersUtility.isArmeMelee(arme)
|
||||
let rollData = this.getCommonRollData(undefined, competenceName)
|
||||
rollData.carac = this.system.caracteristiques[key]
|
||||
rollData.caracKey = key
|
||||
rollData.arme = foundry.utils.duplicate(arme)
|
||||
rollData.mode = "attaquebrutale"
|
||||
rollData.attackType = "Attaque brutale"
|
||||
rollData.armes = this.getOtherMeleeWeapons(arme)
|
||||
rollData.rulesMalus.push({ name: "Attaque brutale", value: -2 })
|
||||
await HeritiersRollDialog.create(this, rollData)
|
||||
}
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
async rollAttaqueChargeArme(armeId) {
|
||||
let arme = this.items.get(armeId)
|
||||
if (arme) {
|
||||
let key = "agi"
|
||||
arme.system.isMelee = HeritiersUtility.isArmeMelee(arme)
|
||||
let pireCompetence = this.getPireCompetence("Mêlée", "Mouvement")
|
||||
let rollData = this.getCommonRollData(undefined, pireCompetence.name)
|
||||
rollData.carac = this.system.caracteristiques[key]
|
||||
rollData.caracKey = key
|
||||
rollData.arme = foundry.utils.duplicate(arme)
|
||||
rollData.armes = this.getOtherMeleeWeapons(arme)
|
||||
rollData.mode = "attaquecharge"
|
||||
rollData.attackType = "Attaque en charge"
|
||||
await HeritiersRollDialog.create(this, rollData)
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async rollAssomerArme(armeId) {
|
||||
let arme = this.items.get(armeId)
|
||||
if (arme) {
|
||||
let competenceName = "Mêlée"
|
||||
//arme.system.isMelee = HeritiersUtility.isArmeMelee(arme)
|
||||
let rollData = this.getCommonRollData(undefined, competenceName)
|
||||
rollData.carac = this.system.caracteristiques["agi"]
|
||||
rollData.caracKey = "agi"
|
||||
rollData.arme = foundry.utils.duplicate(arme)
|
||||
rollData.mode = "assommer"
|
||||
rollData.attackType = "Assommer"
|
||||
if (rollData.defenderTokenId) {
|
||||
rollData.cacheDifficulte = true
|
||||
}
|
||||
await HeritiersRollDialog.create(this, rollData)
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
pouvoirPassifDialog(pouvoir) {
|
||||
let rollData = this.getCommonRollData()
|
||||
rollData.pouvoir = pouvoir
|
||||
rollData.mode = "pouvoirpassif"
|
||||
rollData.pouvoirPointsUsage = 0
|
||||
rollData.noRoll = true
|
||||
|
||||
let d = new Dialog({
|
||||
title: "Activer le pouvoir passif " + pouvoir.name,
|
||||
content: "<p>Choisissez le nombre de Points d'Usage</p>",
|
||||
buttons: {
|
||||
one: {
|
||||
icon: '<i class="fas fa-check"></i>',
|
||||
label: "1 Point d'Usage",
|
||||
callback: () => {
|
||||
rollData.pouvoirPointsUsage = 1;
|
||||
HeritiersUtility.rollHeritiers(rollData);
|
||||
}
|
||||
},
|
||||
two: {
|
||||
icon: '<i class="fas fa-check"></i>',
|
||||
label: "2 Points d'Usage",
|
||||
callback: () => {
|
||||
rollData.pouvoirPointsUsage = 2;
|
||||
HeritiersUtility.rollHeritiers(rollData);
|
||||
}
|
||||
},
|
||||
three: {
|
||||
icon: '<i class="fas fa-check"></i>',
|
||||
label: "3 Points d'Usage",
|
||||
callback: () => {
|
||||
rollData.pouvoirPointsUsage = 3;
|
||||
HeritiersUtility.rollHeritiers(rollData);
|
||||
}
|
||||
},
|
||||
four: {
|
||||
icon: '<i class="fas fa-check"></i>',
|
||||
label: "4 Points d'Usage",
|
||||
callback: () => {
|
||||
rollData.pouvoirPointsUsage = 4;
|
||||
HeritiersUtility.rollHeritiers(rollData);
|
||||
}
|
||||
},
|
||||
close: {
|
||||
icon: '<i class="fas fa-times"></i>',
|
||||
label: "Annuler",
|
||||
callback: () => {
|
||||
}
|
||||
}
|
||||
},
|
||||
default: "one",
|
||||
render: html => console.log("Pouvoir passif"),
|
||||
close: html => console.log("No option")
|
||||
});
|
||||
d.render(true);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async rollPouvoir(pouvoirId) {
|
||||
let pouvoir = this.items.get(pouvoirId)
|
||||
if (pouvoir) {
|
||||
if (pouvoir.system.pouvoirtype == "passif") {
|
||||
this.pouvoirPassifDialog(pouvoir)
|
||||
return
|
||||
}
|
||||
|
||||
let rollData = this.getCommonRollData(undefined, undefined)
|
||||
|
||||
rollData.pouvoirMaxUsage = this.getPouvoirUsageMax(pouvoir)
|
||||
rollData.pouvoir = foundry.utils.duplicate(pouvoir)
|
||||
rollData.mode = "pouvoir"
|
||||
|
||||
if (pouvoir.system.feeriemasque != "autre") {
|
||||
rollData.pouvoirBase = foundry.utils.duplicate(this.system.rang[pouvoir.system.feeriemasque.toLowerCase()])
|
||||
rollData.pouvoirBase.label = "Féerie"
|
||||
if (pouvoir.system.istest && !pouvoir.system.carac) {
|
||||
ui.notifications.warn("Le pouvoir actif " + pouvoir.name + " n'a pas de caractéristique associée")
|
||||
}
|
||||
if (pouvoir.system.istest) {
|
||||
rollData.carac = foundry.utils.duplicate(this.system.caracteristiques[pouvoir.system.carac])
|
||||
rollData.caracKey = pouvoir.system.carac
|
||||
} else {
|
||||
rollData.noRoll = true
|
||||
HeritiersUtility.rollHeritiers(rollData);
|
||||
return;
|
||||
//this.incDecPointsUsage(pouvoir.id, -rollData.pouvoirPointsUsage)
|
||||
//ui.notifications.warn("Le pouvoir actif " + pouvoir.name + " a été utilisé, dépense de " + pouvoirPointsUsage + " points d'usage")
|
||||
}
|
||||
}
|
||||
await HeritiersRollDialog.create(this, rollData)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
incDecPointsAme(value) {
|
||||
let newValue = this.system.magie.pointsame.value + value
|
||||
newValue = Math.max(newValue, 0)
|
||||
newValue = Math.min(newValue, this.system.magie.pointsame.max)
|
||||
this.update({ 'system.magie.pointsame.value': newValue })
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
incDecPV(value) {
|
||||
let newValue = this.system.pv.value + value
|
||||
newValue = Math.max(newValue, 0)
|
||||
newValue = Math.min(newValue, this.system.pv.max)
|
||||
this.update({ 'system.pv.value': newValue })
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
incDecPointsUsage(pouvoirId, value) {
|
||||
let pouvoir = this.items.get(pouvoirId)
|
||||
let newValue = pouvoir.system.pointsusagecourant + value
|
||||
newValue = Math.max(newValue, 0)
|
||||
newValue = Math.min(newValue, this.getPouvoirUsageMax(pouvoir))
|
||||
this.updateEmbeddedDocuments('Item', [{ _id: pouvoirId, 'system.pointsusagecourant': newValue }])
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
getPouvoirUsage(pouvoirId) {
|
||||
let pouvoir = this.items.get(pouvoirId)
|
||||
return pouvoir.system.pointsusagecourant
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
getPouvoirUsageMax(pouvoir) {
|
||||
if (pouvoir.system.masquetype == "masque") {
|
||||
return this.system.rang.masque.value
|
||||
}
|
||||
return this.system.rang.feerie.value
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
recupUsage(value) {
|
||||
let updates = []
|
||||
for (let pouvoir of this.items) {
|
||||
if (pouvoir.type == "pouvoir") {
|
||||
let newValue = pouvoir.system.pointsusagecourant + value
|
||||
newValue = Math.max(newValue, 0)
|
||||
newValue = Math.min(newValue, this.getPouvoirUsageMax(pouvoir))
|
||||
updates.push({ _id: pouvoir.id, 'system.pointsusagecourant': newValue })
|
||||
}
|
||||
}
|
||||
if (updates.length > 0) {
|
||||
this.updateEmbeddedDocuments('Item', updates)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* -------------------------------------------- */
|
||||
|
||||
import { HeritiersUtility } from "./heritiers-utility.js";
|
||||
import { HeritiersRollDialog } from "./heritiers-roll-dialog.js";
|
||||
import { HeritiersRollDialog } from "./applications/heritiers-roll-dialog.mjs";
|
||||
|
||||
/* -------------------------------------------- */
|
||||
export class HeritiersCommands {
|
||||
|
||||
@@ -8,26 +8,35 @@ export const HERITIERS_CONFIG = {
|
||||
"prec": "Précision",
|
||||
"esp": "Esprit",
|
||||
"per": "Perception",
|
||||
"pres": "Présence",
|
||||
"pres": "Prestance",
|
||||
"san": "Sang-Froid"
|
||||
},
|
||||
|
||||
competenceCategorie : {
|
||||
competenceCategorie: {
|
||||
"utile": "Utile",
|
||||
"futile": "Futile"
|
||||
},
|
||||
|
||||
competenceProfil : {
|
||||
"aventurier": "Aventurier",
|
||||
"roublard": "Roublard",
|
||||
"combattant": "Combattant",
|
||||
"erudit": "Erudit",
|
||||
"savant": "Savant",
|
||||
"gentleman": "Gentleman"
|
||||
contactType: {
|
||||
contact: "Contact",
|
||||
allie: "Allié",
|
||||
ennemi: "Ennemi",
|
||||
interet: "Personne d'interêt"
|
||||
},
|
||||
|
||||
competenceProfil: {
|
||||
"aventurier": { kind: "physical", name: "Aventurier" },
|
||||
"roublard": { kind: "physical", name: "Roublard" },
|
||||
"combattant": { kind: "physical", name: "Combattant" },
|
||||
"erudit": { kind: "mental", name: "Erudit" },
|
||||
"savant": { kind: "mental", name: "Savant" },
|
||||
"gentleman": { kind: "mental", name: "Gentleman" },
|
||||
"magie": { kind: "magical", name: "Magie" },
|
||||
},
|
||||
baseTestPouvoir: {
|
||||
"feerie": "Féerie",
|
||||
"Masque": "Masque"
|
||||
"masque": "Masque",
|
||||
"autre": "Autre"
|
||||
},
|
||||
resistancePouvoir: {
|
||||
"aucune": "Aucune",
|
||||
@@ -42,6 +51,10 @@ export const HERITIERS_CONFIG = {
|
||||
"passif": "Passif",
|
||||
"metamorphose": "Métamorphose"
|
||||
},
|
||||
statutMasque: {
|
||||
"masque": "Masqué",
|
||||
"demasque": "Démasqué"
|
||||
},
|
||||
niveauPouvoir: {
|
||||
"normal": "Normal",
|
||||
"profond": "Profond",
|
||||
@@ -52,24 +65,43 @@ export const HERITIERS_CONFIG = {
|
||||
"demasque": "Démasqué"
|
||||
},
|
||||
seuilsDifficulte: {
|
||||
"0": "Aucun/Non applicable",
|
||||
"5": "Enfantine",
|
||||
"6": "Triviale",
|
||||
"8": "Aisée",
|
||||
"10": "Normale",
|
||||
"12": "Compliquée",
|
||||
"14": "Difficile",
|
||||
"16": "Très Difficile",
|
||||
"18": "Critique",
|
||||
"20": "Insurmontable",
|
||||
"22": "Surhumaine",
|
||||
"24": "Epique",
|
||||
"26": "Légendaire",
|
||||
"28": "Mythique",
|
||||
"30": "Divine"
|
||||
"-1": "Aucun/Non applicable",
|
||||
"5": "Enfantine (5)",
|
||||
"6": "Triviale (6)",
|
||||
"7": "Moins Triviale (7)",
|
||||
"8": "Aisée (8)",
|
||||
"9": "Moins Aisée (9)",
|
||||
"10": "Normale (10)",
|
||||
"11": "Moins Normale (11)",
|
||||
"12": "Compliquée (12)",
|
||||
"13": "Plus Compliquée (13)",
|
||||
"14": "Difficile (14)",
|
||||
"15": "Plus Difficile (15)",
|
||||
"16": "Très Difficile (16)",
|
||||
"17": "Très Très Difficile (17)",
|
||||
"18": "Critique (18)",
|
||||
"19": "Plus Critique (19)",
|
||||
"20": "Insurmontable (20)",
|
||||
"21": "Très Insurmontable (21)",
|
||||
"22": "Surhumaine (22)",
|
||||
"23": "Très Surhumaine (23)",
|
||||
"24": "Epique (24)",
|
||||
"25": "Plus Epique (25)",
|
||||
"26": "Légendaire (26)",
|
||||
"27": "Très Légendaire (27)",
|
||||
"28": "Mythique (28)",
|
||||
"29": "Plus Mythique (29)",
|
||||
"30": "Divine (30)"
|
||||
},
|
||||
|
||||
categorieArme : {
|
||||
attaqueCible: {
|
||||
"none": "Aucune",
|
||||
"membre": "Membre",
|
||||
"main": "Main",
|
||||
"tete": "Tête/Coeur"
|
||||
},
|
||||
|
||||
categorieArme: {
|
||||
"trait": "Arme de trait",
|
||||
"poing": "Arme de poing",
|
||||
"epaule": "Arme d'épaule",
|
||||
@@ -77,7 +109,7 @@ export const HERITIERS_CONFIG = {
|
||||
"blanche": "Arme blanche",
|
||||
"improvise": "Arme improvisée",
|
||||
"explosif": "Explosif"
|
||||
},
|
||||
},
|
||||
typeArme: {
|
||||
"naturelle": "Arme naturelle",
|
||||
"trait": "Trait",
|
||||
@@ -99,21 +131,152 @@ export const HERITIERS_CONFIG = {
|
||||
"controlee": "Contrôlée (C)",
|
||||
"prohibee": "Prohibée (P)"
|
||||
},
|
||||
armeDissimulation :{
|
||||
armeDissimulation: {
|
||||
"tresfacile": "Très facile (TF)",
|
||||
"facile": "Facile (F)",
|
||||
"difficile": "Difficile (D)",
|
||||
"impossible": "Impossible (I)"
|
||||
},
|
||||
typeProtection : {
|
||||
typeProtection: {
|
||||
"balle": "Protège ds balles",
|
||||
"melee": "Protège en mélée",
|
||||
"tout": "Tout type de dégats"
|
||||
},
|
||||
typeFee: {
|
||||
"traditionnelle": "Traditionnelle",
|
||||
"moderne": "Moderne"
|
||||
"moderne": "Moderne",
|
||||
"orientale": "Orientale"
|
||||
},
|
||||
typeContact: {
|
||||
"contact": "Contact",
|
||||
"allie": "Allié",
|
||||
"ennemi": "Ennemi",
|
||||
"interet": "Personne d'interêt"
|
||||
},
|
||||
niveauContact: {
|
||||
"1": "1",
|
||||
"2": "2",
|
||||
"3": "3",
|
||||
},
|
||||
pointsUsageList: {
|
||||
"1": "1",
|
||||
"2": "2",
|
||||
"3": "3",
|
||||
"4": "4",
|
||||
},
|
||||
attaquePlusieursList: {
|
||||
"0": "0",
|
||||
"1": "+1",
|
||||
"2": "+2",
|
||||
},
|
||||
attaque2ArmesListe: [
|
||||
{ value: "0", label: "Aucun" },
|
||||
{ value: "-4", label: "Deux armes à 1 main" },
|
||||
{ value: "-2", label: "Deux armes naturelles" },
|
||||
{ value: "-2", label: "Avec spécialisation \"Mauvaise Main\"" }
|
||||
],
|
||||
typeProfil: {
|
||||
"mineur": "Mineur",
|
||||
"majeur": "Majeur",
|
||||
},
|
||||
bonusMalusContext: [
|
||||
{ value: "-6", label: "-6" },
|
||||
{ value: "-5", label: "-5" },
|
||||
{ value: "-4", label: "-4" },
|
||||
{ value: "-3", label: "-3" },
|
||||
{ value: "-2", label: "-2" },
|
||||
{ value: "-1", label: "-1" },
|
||||
{ value: "0", label: "0" },
|
||||
{ value: "1", label: "+1" },
|
||||
{ value: "2", label: "+2" },
|
||||
{ value: "3", label: "+3" },
|
||||
{ value: "4", label: "+4" },
|
||||
{ value: "5", label: "+5" },
|
||||
{ value: "6", label: "+6" }
|
||||
],
|
||||
listNiveauSort: {
|
||||
"1": "1",
|
||||
"2": "2",
|
||||
"3": "3",
|
||||
"4": "4"
|
||||
},
|
||||
listRangSort: {
|
||||
"1": "1",
|
||||
"2": "2",
|
||||
"3": "3",
|
||||
"4": "4",
|
||||
"5": "5",
|
||||
"6": "6",
|
||||
"7": "7"
|
||||
},
|
||||
listNiveau: {
|
||||
"0": "0",
|
||||
"1": "1",
|
||||
"2": "2",
|
||||
"3": "3",
|
||||
"4": "4",
|
||||
"5": "5",
|
||||
"6": "6",
|
||||
"7": "7",
|
||||
"8": "8",
|
||||
"9": "9",
|
||||
"10": "10"
|
||||
},
|
||||
rangName: [
|
||||
"Novice",
|
||||
"Novice",
|
||||
"Adepte",
|
||||
"Maître",
|
||||
"Grand Maître"
|
||||
],
|
||||
rangNameSpecific: {
|
||||
"Druidisme": {
|
||||
"Novice": "Eubage",
|
||||
"Adepte": "Saronide",
|
||||
"Maître": "Ovate",
|
||||
"Grand Maître": "Archidruide"
|
||||
},
|
||||
"Faëomancie": {
|
||||
"Novice": "Marmiton",
|
||||
"Adepte": "Queux",
|
||||
"Maître": "Chef",
|
||||
"Grand Maître": "Maître-queux"
|
||||
},
|
||||
"Nécromancie": {
|
||||
"Novice": "Inexpertus",
|
||||
"Adepte": "Discipulus",
|
||||
"Maître": "Dominus",
|
||||
"Grand Maître": "Magister"
|
||||
},
|
||||
"Necromancie": {
|
||||
"Novice": "Inexpertus",
|
||||
"Adepte": "Discipulus",
|
||||
"Maître": "Dominus",
|
||||
"Grand Maître": "Magister"
|
||||
},
|
||||
"Magie du Clan": {
|
||||
"Novice": "Apprenti",
|
||||
"Adepte": "Disciple",
|
||||
"Maître": "Maître",
|
||||
"Grand Maître": "Éminence"
|
||||
},
|
||||
"Théurgie": {
|
||||
"Novice": "Frère",
|
||||
"Adepte": "Père",
|
||||
"Maître": "Saint",
|
||||
"Grand Maître": "Apôtre"
|
||||
},
|
||||
"Grand Langage": {
|
||||
"Novice": "Éveillé",
|
||||
"Adepte": "Initié",
|
||||
"Maître": "Sage",
|
||||
"Grand Maître": "Docteur"
|
||||
}
|
||||
},
|
||||
soufflesMagieDuClan: {
|
||||
"soufflecombat": "Souffle du Combat",
|
||||
"soufflemouvement": "Souffle du Mouvement",
|
||||
"souffleesprit": "Souffle de l'Esprit"
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
/**
|
||||
* Extend the basic ActorSheet with some very simple modifications
|
||||
* @extends {ActorSheet}
|
||||
*/
|
||||
|
||||
import { HeritiersActorSheet } from "./heritiers-actor-sheet.js";
|
||||
import { HeritiersUtility } from "./heritiers-utility.js";
|
||||
|
||||
/* -------------------------------------------- */
|
||||
export class HeritiersCreatureSheet extends HeritiersActorSheet {
|
||||
|
||||
/** @override */
|
||||
static get defaultOptions() {
|
||||
|
||||
return mergeObject(super.defaultOptions, {
|
||||
classes: ["fvtt-les-heritiers", "sheet", "actor"],
|
||||
template: "systems/fvtt-les-heritiers/templates/creature-sheet.html",
|
||||
width: 640,
|
||||
height: 720,
|
||||
tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "stats" }],
|
||||
dragDrop: [{ dragSelector: ".item-list .item", dropSelector: null }],
|
||||
editScore: false
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,200 +0,0 @@
|
||||
import { HeritiersUtility } from "./heritiers-utility.js";
|
||||
|
||||
/**
|
||||
* Extend the basic ItemSheet with some very simple modifications
|
||||
* @extends {ItemSheet}
|
||||
*/
|
||||
export class HeritiersItemSheet extends ItemSheet {
|
||||
|
||||
/** @override */
|
||||
static get defaultOptions() {
|
||||
|
||||
return mergeObject(super.defaultOptions, {
|
||||
classes: ["fvtt-les-heritiers", "sheet", "item"],
|
||||
template: "systems/fvtt-les-heritiers/templates/item-sheet.html",
|
||||
dragDrop: [{ dragSelector: null, dropSelector: null }],
|
||||
width: 620,
|
||||
height: 550,
|
||||
tabs: [{navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "description"}]
|
||||
});
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
_getHeaderButtons() {
|
||||
let buttons = super._getHeaderButtons();
|
||||
// Add "Post to chat" button
|
||||
// We previously restricted this to GM and editable items only. If you ever find this comment because it broke something: eh, sorry!
|
||||
buttons.unshift(
|
||||
{
|
||||
class: "post",
|
||||
icon: "fas fa-comment",
|
||||
onclick: ev => { }
|
||||
})
|
||||
return buttons
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/** @override */
|
||||
setPosition(options = {}) {
|
||||
const position = super.setPosition(options);
|
||||
const sheetBody = this.element.find(".sheet-body");
|
||||
const bodyHeight = position.height - 192;
|
||||
sheetBody.css("height", bodyHeight);
|
||||
if (this.item.type.includes('weapon')) {
|
||||
position.width = 640;
|
||||
}
|
||||
return position;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async getData() {
|
||||
const objectData = duplicate(this.object)
|
||||
let formData = {
|
||||
title: this.title,
|
||||
id: this.id,
|
||||
type: objectData.type,
|
||||
img: objectData.img,
|
||||
name: objectData.name,
|
||||
editable: this.isEditable,
|
||||
cssClass: this.isEditable ? "editable" : "locked",
|
||||
system: objectData.system,
|
||||
limited: this.object.limited,
|
||||
options: this.options,
|
||||
owner: this.document.isOwner,
|
||||
config: game.system.lesheritiers.config,
|
||||
description: await TextEditor.enrichHTML(this.object.system.description, {async: true}),
|
||||
mr: (this.object.type == 'specialisation'),
|
||||
isGM: game.user.isGM
|
||||
}
|
||||
|
||||
//this.options.editable = !(this.object.origin == "embeddedItem");
|
||||
console.log("ITEM DATA", formData, this);
|
||||
return formData;
|
||||
}
|
||||
|
||||
|
||||
/* -------------------------------------------- */
|
||||
_getHeaderButtons() {
|
||||
let buttons = super._getHeaderButtons();
|
||||
buttons.unshift({
|
||||
class: "post",
|
||||
icon: "fas fa-comment",
|
||||
onclick: ev => this.postItem()
|
||||
});
|
||||
return buttons
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
postItem() {
|
||||
let chatData = duplicate(HeritiersUtility.data(this.item));
|
||||
if (this.actor) {
|
||||
chatData.actor = { id: this.actor.id };
|
||||
}
|
||||
// Don't post any image for the item (which would leave a large gap) if the default image is used
|
||||
if (chatData.img.includes("/blank.png")) {
|
||||
chatData.img = null;
|
||||
}
|
||||
// JSON object for easy creation
|
||||
chatData.jsondata = JSON.stringify(
|
||||
{
|
||||
compendium: "postedItem",
|
||||
payload: chatData,
|
||||
});
|
||||
|
||||
renderTemplate('systems/fvtt-Heritiers-rpg/templates/post-item.html', chatData).then(html => {
|
||||
let chatOptions = HeritiersUtility.chatDataSetup(html);
|
||||
ChatMessage.create(chatOptions)
|
||||
});
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/** @override */
|
||||
activateListeners(html) {
|
||||
super.activateListeners(html);
|
||||
|
||||
// Everything below here is only needed if the sheet is editable
|
||||
if (!this.options.editable) return;
|
||||
|
||||
|
||||
// Update Inventory Item
|
||||
html.find('.item-edit').click(ev => {
|
||||
const li = $(ev.currentTarget).parents(".item")
|
||||
const item = this.object.options.actor.getOwnedItem(li.data("item-id"))
|
||||
item.sheet.render(true);
|
||||
});
|
||||
|
||||
html.find('.delete-subitem').click(ev => {
|
||||
this.deleteSubitem(ev);
|
||||
})
|
||||
|
||||
html.find('#add-specialite').click(ev => {
|
||||
let spec = duplicate(this.object.system.specialites)
|
||||
spec.push( { name: "Nouvelle Spécialité", id: randomID(16), used: false })
|
||||
this.object.update( { 'system.specialites': spec })
|
||||
})
|
||||
html.find('.delete-specialite').click(ev => {
|
||||
const li = $(ev.currentTarget).parents(".specialite-item")
|
||||
let index = li.data("specialite-index")
|
||||
let spec = duplicate(this.object.system.specialites)
|
||||
spec.splice(index,1)
|
||||
this.object.update( { 'system.specialites': spec })
|
||||
})
|
||||
html.find('.edit-specialite').change(ev => {
|
||||
const li = $(ev.currentTarget).parents(".specialite-item")
|
||||
let index = li.data("specialite-index")
|
||||
let spec = duplicate(this.object.system.specialites)
|
||||
spec[index].name = ev.currentTarget.value
|
||||
spec[index].id = spec[index].id || randomID(16)
|
||||
this.object.update( { 'system.specialites': spec })
|
||||
})
|
||||
html.find('.edit-specialite-description').change(ev => {
|
||||
const li = $(ev.currentTarget).parents(".specialite-item")
|
||||
let index = li.data("specialite-index")
|
||||
let spec = duplicate(this.object.system.specialites)
|
||||
spec[index].description = ev.currentTarget.value
|
||||
spec[index].id = spec[index].id || randomID(16)
|
||||
this.object.update( { 'system.specialites': spec })
|
||||
})
|
||||
|
||||
html.find('#add-automation').click(ev => {
|
||||
let autom = duplicate(this.object.system.automations)
|
||||
autom.push( { eventtype: "on-drop", name: "Automatisation 1", competence: "", minLevel: 0, id: randomID(16) })
|
||||
this.object.update( { 'system.automations': autom })
|
||||
})
|
||||
html.find('.delete-automation').click(ev => {
|
||||
const li = $(ev.currentTarget).parents(".automation-item")
|
||||
let index = li.data("automation-index")
|
||||
let autom = duplicate(this.object.system.automations)
|
||||
autom.splice(index,1)
|
||||
this.object.update( { 'system.automations': autom })
|
||||
})
|
||||
html.find('.automation-edit-field').change(ev => {
|
||||
let index = $(ev.currentTarget).data("automation-index")
|
||||
let field = $(ev.currentTarget).data("automation-field")
|
||||
let auto = duplicate(this.object.system.automations)
|
||||
auto[index][field] = ev.currentTarget.value
|
||||
auto[index].id = auto[index].id || randomID(16)
|
||||
this.object.update( { 'system.automations': auto })
|
||||
})
|
||||
|
||||
// Update Inventory Item
|
||||
html.find('.item-delete').click(ev => {
|
||||
const li = $(ev.currentTarget).parents(".item");
|
||||
let itemId = li.data("item-id");
|
||||
let itemType = li.data("item-type");
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
get template() {
|
||||
let type = this.item.type;
|
||||
return `systems/fvtt-les-heritiers/templates/item-${type}-sheet.html`;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/** @override */
|
||||
_updateObject(event, formData) {
|
||||
return this.object.update(formData);
|
||||
}
|
||||
}
|
||||
@@ -15,8 +15,10 @@ export const defaultItemImg = {
|
||||
arme: "systems/fvtt-les-heritiers/assets/icons/weapon.webp",
|
||||
accessoire: "systems/fvtt-les-heritiers/assets/icons/item.webp",
|
||||
protection: "systems/fvtt-les-heritiers/assets/icons/armor.webp",
|
||||
fee: "systems/fvtt-les-heritiers/assets/icons/faery_type.webp"
|
||||
|
||||
fee: "systems/fvtt-les-heritiers/assets/icons/faery_type.webp",
|
||||
profil: "systems/fvtt-les-heritiers/assets/icons/profil.webp",
|
||||
equipement: "systems/fvtt-les-heritiers/assets/icons/equipement.webp",
|
||||
sort: "systems/fvtt-les-heritiers/assets/icons/sort.webp",
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -9,14 +9,17 @@
|
||||
/* -------------------------------------------- */
|
||||
// Import Modules
|
||||
import { HeritiersActor } from "./heritiers-actor.js";
|
||||
import { HeritiersItemSheet } from "./heritiers-item-sheet.js";
|
||||
import { HeritiersActorSheet } from "./heritiers-actor-sheet.js";
|
||||
import { HeritiersCreatureSheet } from "./heritiers-creature-sheet.js";
|
||||
import { HeritiersItem } from "./heritiers-item.js";
|
||||
import { HeritiersUtility } from "./heritiers-utility.js";
|
||||
import { HeritiersCombat } from "./heritiers-combat.js";
|
||||
import { HeritiersItem } from "./heritiers-item.js";
|
||||
import { HERITIERS_CONFIG } from "./heritiers-config.js";
|
||||
|
||||
// Import DataModels
|
||||
import * as models from "./models/index.mjs";
|
||||
|
||||
// Import AppV2 Sheets
|
||||
import * as sheets from "./applications/sheets/_module.mjs";
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/* Foundry VTT Initialization */
|
||||
/* -------------------------------------------- */
|
||||
@@ -30,7 +33,7 @@ Hooks.once("init", async function () {
|
||||
HeritiersUtility.preloadHandlebarsTemplates()
|
||||
|
||||
/* -------------------------------------------- */
|
||||
// Set an initiative formula for the system
|
||||
// Set an initiative formula for the system
|
||||
CONFIG.Combat.initiative = {
|
||||
formula: "1d10",
|
||||
decimals: 1
|
||||
@@ -45,20 +48,62 @@ Hooks.once("init", async function () {
|
||||
// Define custom Entity classes
|
||||
CONFIG.Combat.documentClass = HeritiersCombat
|
||||
CONFIG.Actor.documentClass = HeritiersActor
|
||||
CONFIG.Actor.dataModels = {
|
||||
personnage: models.PersonnageDataModel,
|
||||
pnj: models.PnjDataModel
|
||||
}
|
||||
|
||||
CONFIG.Item.documentClass = HeritiersItem
|
||||
CONFIG.Item.dataModels = {
|
||||
accessoire: models.AccessoireDataModel,
|
||||
arme: models.ArmeDataModel,
|
||||
atoutfeerique: models.AtoutFeeriqueDataModel,
|
||||
avantage: models.AvantageDataModel,
|
||||
capacitenaturelle: models.CapaciteNaturelleDataModel,
|
||||
competence: models.CompetenceDataModel,
|
||||
contact: models.ContactDataModel,
|
||||
desavantage: models.DesavantageDataModel,
|
||||
equipement: models.EquipementDataModel,
|
||||
fee: models.FeeDataModel,
|
||||
pouvoir: models.PouvoirDataModel,
|
||||
profil: models.ProfilDataModel,
|
||||
protection: models.ProtectionDataModel,
|
||||
sort: models.SortDataModel
|
||||
}
|
||||
|
||||
// Create an object of bonus/malus from -6 to +6 signed
|
||||
HERITIERS_CONFIG.bonusMalus = Array.from({ length: 7 }, (v, k) => toString(k - 6))
|
||||
CONFIG.HERITIERS = HERITIERS_CONFIG
|
||||
|
||||
game.system.lesheritiers = {
|
||||
HeritiersUtility,
|
||||
config: HERITIERS_CONFIG
|
||||
config: HERITIERS_CONFIG,
|
||||
models,
|
||||
sheets
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
// Register sheet application classes
|
||||
Actors.unregisterSheet("core", ActorSheet);
|
||||
Actors.registerSheet("fvtt-les-heritiers", HeritiersActorSheet, { types: ["personnage"], makeDefault: true })
|
||||
Actors.registerSheet("fvtt-les-heritiers", HeritiersCreatureSheet, { types: ["creature"], makeDefault: true })
|
||||
foundry.documents.collections.Actors.unregisterSheet("core", foundry.appv1.sheets.ActorSheet);
|
||||
foundry.documents.collections.Actors.registerSheet("fvtt-les-heritiers", sheets.HeritiersPersonnageSheet, { types: ["personnage"], makeDefault: true })
|
||||
foundry.documents.collections.Actors.registerSheet("fvtt-les-heritiers", sheets.HeritiersPnjSheet, { types: ["pnj"], makeDefault: true })
|
||||
|
||||
Items.unregisterSheet("core", ItemSheet);
|
||||
Items.registerSheet("fvtt-les-heritiers", HeritiersItemSheet, { makeDefault: true })
|
||||
// Register AppV2 Item Sheets
|
||||
foundry.documents.collections.Items.unregisterSheet("core", foundry.appv1.sheets.ItemSheet);
|
||||
foundry.documents.collections.Items.registerSheet("fvtt-les-heritiers", sheets.HeritiersAccessoireSheet, { types: ["accessoire"], makeDefault: true })
|
||||
foundry.documents.collections.Items.registerSheet("fvtt-les-heritiers", sheets.HeritiersArmeSheet, { types: ["arme"], makeDefault: true })
|
||||
foundry.documents.collections.Items.registerSheet("fvtt-les-heritiers", sheets.HeritiersAtoutFeeriqueSheet, { types: ["atoutfeerique"], makeDefault: true })
|
||||
foundry.documents.collections.Items.registerSheet("fvtt-les-heritiers", sheets.HeritiersAvantageSheet, { types: ["avantage"], makeDefault: true })
|
||||
foundry.documents.collections.Items.registerSheet("fvtt-les-heritiers", sheets.HeritiersCapaciteNaturelleSheet, { types: ["capacitenaturelle"], makeDefault: true })
|
||||
foundry.documents.collections.Items.registerSheet("fvtt-les-heritiers", sheets.HeritiersCompetenceSheet, { types: ["competence"], makeDefault: true })
|
||||
foundry.documents.collections.Items.registerSheet("fvtt-les-heritiers", sheets.HeritiersContactSheet, { types: ["contact"], makeDefault: true })
|
||||
foundry.documents.collections.Items.registerSheet("fvtt-les-heritiers", sheets.HeritiersDesavantageSheet, { types: ["desavantage"], makeDefault: true })
|
||||
foundry.documents.collections.Items.registerSheet("fvtt-les-heritiers", sheets.HeritiersEquipementSheet, { types: ["equipement"], makeDefault: true })
|
||||
foundry.documents.collections.Items.registerSheet("fvtt-les-heritiers", sheets.HeritiersFeeSheet, { types: ["fee"], makeDefault: true })
|
||||
foundry.documents.collections.Items.registerSheet("fvtt-les-heritiers", sheets.HeritiersPouvoirSheet, { types: ["pouvoir"], makeDefault: true })
|
||||
foundry.documents.collections.Items.registerSheet("fvtt-les-heritiers", sheets.HeritiersProfilSheet, { types: ["profil"], makeDefault: true })
|
||||
foundry.documents.collections.Items.registerSheet("fvtt-les-heritiers", sheets.HeritiersProtectionSheet, { types: ["protection"], makeDefault: true })
|
||||
foundry.documents.collections.Items.registerSheet("fvtt-les-heritiers", sheets.HeritiersSortSheet, { types: ["sort"], makeDefault: true })
|
||||
|
||||
HeritiersUtility.init()
|
||||
|
||||
@@ -69,40 +114,52 @@ function welcomeMessage() {
|
||||
ChatMessage.create({
|
||||
user: game.user.id,
|
||||
whisper: [game.user.id],
|
||||
content: `<div id="welcome-message-heritiers"><span class="rdd-roll-part">
|
||||
<strong>Bienvenue dans Les Heritiers et la Belle Epoque !</strong>
|
||||
<p>Les livres du JDR Les Heritiers sont nécessaires pour jouer : https://www.titam-france.fr</p>
|
||||
<p>Les Heritiers est jeu de rôle publié par Titam France/Sombres projets, tout les droits leur appartiennent.</p>
|
||||
<p>Système développé par LeRatierBretonnien, support sur le <a href="https://discord.gg/pPSDNJk">Discord FR de Foundry</a>.</p>
|
||||
` });
|
||||
content: `
|
||||
<div class="heritiers-chat-card heritiers-welcome-card">
|
||||
<div class="chat-card-header welcome-header">
|
||||
<div class="welcome-icon-wrapper">
|
||||
<i class="fas fa-book-open welcome-icon"></i>
|
||||
</div>
|
||||
<div class="chat-actor-info">
|
||||
<h3 class="chat-actor-name">Bienvenue dans Les Héritiers !</h3>
|
||||
<div class="chat-action-name">et la Belle Époque</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="chat-card-content welcome-content">
|
||||
<div class="welcome-section">
|
||||
<i class="fas fa-info-circle"></i>
|
||||
<p>Les livres du JDR <strong>Les Héritiers</strong> sont nécessaires pour jouer.</p>
|
||||
</div>
|
||||
|
||||
<div class="welcome-section">
|
||||
<i class="fas fa-copyright"></i>
|
||||
<p><em>Les Héritiers</em> est un jeu de rôle publié par <strong>Titam France / Sombres Projets</strong>. Tous les droits leur appartiennent.</p>
|
||||
</div>
|
||||
|
||||
<div class="welcome-section">
|
||||
<i class="fas fa-code"></i>
|
||||
<p>Système développé par <strong>LeRatierBretonnien</strong></p>
|
||||
<p>Support sur le <a href="https://discord.gg/pPSDNJk" target="_blank"><i class="fab fa-discord"></i> Discord FR de Foundry</a></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
});
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
// Register world usage statistics
|
||||
function registerUsageCount(registerKey) {
|
||||
if (game.user.isGM) {
|
||||
game.settings.register(registerKey, "world-key", {
|
||||
name: "Unique world key",
|
||||
scope: "world",
|
||||
config: false,
|
||||
default: "",
|
||||
type: String
|
||||
});
|
||||
|
||||
let worldKey = game.settings.get(registerKey, "world-key")
|
||||
if (worldKey == undefined || worldKey == "") {
|
||||
worldKey = randomID(32)
|
||||
game.settings.set(registerKey, "world-key", worldKey)
|
||||
}
|
||||
// Simple API counter
|
||||
let regURL = `https://www.uberwald.me/fvtt_appcount/count.php?name="${registerKey}"&worldKey="${worldKey}"&version="${game.release.generation}.${game.release.build}"&system="${game.system.id}"&systemversion="${game.system.version}"`
|
||||
//$.ajaxSetup({
|
||||
//headers: { 'Access-Control-Allow-Origin': '*' }
|
||||
//})
|
||||
$.ajax(regURL)
|
||||
async function importDefaultScene() {
|
||||
let exists = game.scenes.find(j => j.name == "Accueil");
|
||||
if (!exists) {
|
||||
const scenes = await HeritiersUtility.loadCompendium("fvtt-les-heritiers.scenes")
|
||||
let newDocuments = scenes.filter(i => i.name == "Accueil");
|
||||
await game.scenes.documentClass.create(newDocuments);
|
||||
game.scenes.find(i => i.name == "Accueil").activate();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/* Foundry VTT Initialization */
|
||||
/* -------------------------------------------- */
|
||||
@@ -119,14 +176,15 @@ Hooks.once("ready", function () {
|
||||
});
|
||||
}
|
||||
|
||||
registerUsageCount('fvtt-les-heritiers')
|
||||
welcomeMessage()
|
||||
import("https://www.uberwald.me/fvtt_appcount/count-class-ready.js").then(moduleCounter => {
|
||||
console.log("ClassCounter loaded", moduleCounter)
|
||||
moduleCounter.ClassCounter.registerUsageCount()
|
||||
}).catch(err =>
|
||||
console.log("No stats available, giving up.")
|
||||
)
|
||||
welcomeMessage();
|
||||
importDefaultScene();
|
||||
|
||||
// CSS patch for v9
|
||||
if (game.version) {
|
||||
let sidebar = document.getElementById("sidebar");
|
||||
sidebar.style.width = "min-content";
|
||||
}
|
||||
});
|
||||
|
||||
/* -------------------------------------------- */
|
||||
@@ -136,10 +194,9 @@ Hooks.on("chatMessage", (html, content, msg) => {
|
||||
if (content[0] == '/') {
|
||||
let regExp = /(\S+)/g;
|
||||
let commands = content.match(regExp);
|
||||
if (game.system.mournblade.commands.processChatCommand(commands, content, msg)) {
|
||||
if (game.system.lesheritiers.commands.processChatCommand(commands, content, msg)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
|
||||
@@ -1,97 +0,0 @@
|
||||
import { HeritiersUtility } from "./heritiers-utility.js";
|
||||
|
||||
export class HeritiersRollDialog extends Dialog {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async create(actor, rollData) {
|
||||
|
||||
let options = { classes: ["HeritiersDialog"], width: 320, height: 'fit-content', 'z-index': 99999 };
|
||||
let html = await renderTemplate('systems/fvtt-les-heritiers/templates/roll-dialog-generic.html', rollData);
|
||||
|
||||
return new HeritiersRollDialog(actor, rollData, html, options);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
constructor(actor, rollData, html, options, close = undefined) {
|
||||
let conf = {
|
||||
title: "Test de Capacité",
|
||||
content: html,
|
||||
buttons:
|
||||
{
|
||||
rolld8: {
|
||||
icon: '<i class="fas fa-check"></i>',
|
||||
label: "Lancer 1d8",
|
||||
callback: () => { this.roll("d8") }
|
||||
},
|
||||
rolld10: {
|
||||
icon: '<i class="fas fa-check"></i>',
|
||||
label: "Lancer 1d10",
|
||||
callback: () => { this.roll("d10") }
|
||||
},
|
||||
rolld12: {
|
||||
icon: '<i class="fas fa-check"></i>',
|
||||
label: "Lancer 1d12",
|
||||
callback: () => { this.roll("d12") }
|
||||
},
|
||||
cancel: {
|
||||
icon: '<i class="fas fa-times"></i>',
|
||||
label: "Annuler",
|
||||
callback: () => { this.close() }
|
||||
}
|
||||
},
|
||||
close: close
|
||||
}
|
||||
// Overwrite in case of carac only -> 1d10
|
||||
if (rollData.mode == "carac") {
|
||||
conf.buttons = {
|
||||
rolld8: {
|
||||
icon: '<i class="fas fa-check"></i>',
|
||||
label: "Lancer 1d8",
|
||||
callback: () => { this.roll("d8") }
|
||||
},
|
||||
cancel: {
|
||||
icon: '<i class="fas fa-times"></i>',
|
||||
label: "Annuler",
|
||||
callback: () => { this.close() }
|
||||
}
|
||||
}
|
||||
}
|
||||
super(conf, options);
|
||||
|
||||
this.actor = actor
|
||||
this.rollData = rollData
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
roll(dice) {
|
||||
this.rollData.mainDice = dice
|
||||
HeritiersUtility.rollHeritiers(this.rollData)
|
||||
}
|
||||
|
||||
|
||||
/* -------------------------------------------- */
|
||||
activateListeners(html) {
|
||||
super.activateListeners(html);
|
||||
|
||||
var dialog = this;
|
||||
function onLoad() {
|
||||
}
|
||||
$(function () { onLoad(); });
|
||||
|
||||
html.find('#sdValue').change(async (event) => {
|
||||
this.rollData.sdValue = Number(event.currentTarget.value)
|
||||
})
|
||||
html.find('#caracKey').change(async (event) => {
|
||||
this.rollData.caracKey = String(event.currentTarget.value)
|
||||
})
|
||||
html.find('#bonus-malus-context').change((event) => {
|
||||
this.rollData.bonusMalusContext = Number(event.currentTarget.value)
|
||||
})
|
||||
html.find('#useTricherie').change((event) => {
|
||||
this.rollData.useTricherie = event.currentTarget.checked
|
||||
})
|
||||
html.find('#useHeritage').change((event) => {
|
||||
this.rollData.useHeritage = event.currentTarget.checked
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,45 @@
|
||||
import { HeritiersCombat } from "./heritiers-combat.js";
|
||||
import { HeritiersCommands } from "./heritiers-commands.js";
|
||||
|
||||
const __facesAdjacentes = {
|
||||
"d8": {
|
||||
1: [4, 8, 6],
|
||||
2: [7, 5, 3],
|
||||
3: [2, 8, 6],
|
||||
4: [1, 5, 7],
|
||||
5: [2, 4, 8],
|
||||
6: [1, 7, 3],
|
||||
7: [2, 4, 6],
|
||||
8: [1, 3, 5]
|
||||
},
|
||||
"d10": {
|
||||
1: [4, 6, 9, 7],
|
||||
2: [6, 8, 5, 9],
|
||||
3: [7, 5, 8, 10],
|
||||
4: [10, 6, 7, 1],
|
||||
5: [3, 9, 2, 8],
|
||||
6: [1, 4, 2, 9],
|
||||
7: [1, 3, 4, 10],
|
||||
8: [2, 10, 5, 3],
|
||||
9: [1, 5, 6, 2],
|
||||
10: [8, 4, 3, 7]
|
||||
},
|
||||
"d12": {
|
||||
1: [2, 3, 4, 5, 6],
|
||||
2: [1, 6, 8, 12, 3],
|
||||
3: [1, 4, 11, 12, 2],
|
||||
4: [1, 5, 10, 11, 3],
|
||||
5: [1, 6, 9, 10, 4],
|
||||
6: [1, 2, 8, 9, 5],
|
||||
7: [8, 9, 10, 11, 12],
|
||||
8: [2, 6, 9, 7, 12],
|
||||
9: [5, 10, 7, 8, 6],
|
||||
10: [4, 11, 7, 9, 5],
|
||||
11: [7, 10, 4, 3, 12],
|
||||
12: [2, 8, 7, 11, 3]
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
export class HeritiersUtility {
|
||||
|
||||
@@ -9,7 +48,7 @@ export class HeritiersUtility {
|
||||
/* -------------------------------------------- */
|
||||
static async init() {
|
||||
Hooks.on('renderChatLog', (log, html, data) => HeritiersUtility.chatListeners(html))
|
||||
Hooks.on("getChatLogEntryContext", (html, options) => HeritiersUtility.chatRollMenu(html, options))
|
||||
/* Unused for Heitiers : Hooks.on("getChatMessageContextOptions", (html, options) => HeritiersUtility.chatRollMenu(html, options))*/
|
||||
|
||||
this.rollDataStore = {}
|
||||
this.defenderStore = {}
|
||||
@@ -37,22 +76,25 @@ export class HeritiersUtility {
|
||||
Handlebars.registerHelper('mul', function (a, b) {
|
||||
return parseInt(a) * parseInt(b);
|
||||
})
|
||||
Handlebars.registerHelper('and', function (...args) {
|
||||
// Last argument is Handlebars options object, ignore it
|
||||
return args.slice(0, -1).every(Boolean);
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static sortByName(table) {
|
||||
static sortByName(table) {
|
||||
return table.sort(function (a, b) {
|
||||
let fa = a.name.toLowerCase(),
|
||||
fb = b.name.toLowerCase();
|
||||
if (fa < fb) {
|
||||
return -1;
|
||||
}
|
||||
if (fa > fb) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
return a.name.localeCompare(b.name);
|
||||
})
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static sortArrayObjectsByName(myArray) {
|
||||
myArray.sort((a, b) => {
|
||||
return a.name.localeCompare(b.name);
|
||||
})
|
||||
}
|
||||
|
||||
@@ -66,6 +108,42 @@ export class HeritiersUtility {
|
||||
const skills = await HeritiersUtility.loadCompendium("fvtt-les-heritiers.competences")
|
||||
this.skills = skills.map(i => i.toObject())
|
||||
|
||||
this.competencesMagie = this.skills.filter(s => s.system.profil == "magie")
|
||||
|
||||
game.settings.register("fvtt-les-heritiers", "heritiers-heritage", {
|
||||
name: "Points d'héritage",
|
||||
hint: "Points d'héritage du groupe",
|
||||
scope: "world",
|
||||
config: true,
|
||||
default: 0,
|
||||
type: Number
|
||||
})
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static getSDSortValue(niveau) {
|
||||
if (niveau <= 1) return 12;
|
||||
if (niveau == 2) return 14;
|
||||
if (niveau == 3) return 16;
|
||||
if (niveau > 3) return 18;
|
||||
return 18;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static getCompetencesMagie() {
|
||||
return this.competencesMagie
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static buildCompetencesMagie() {
|
||||
let competences = foundry.utils.duplicate(this.getCompetencesMagie())
|
||||
for (let comp of competences) {
|
||||
// Calcul du rang
|
||||
let rang = Math.round(comp.system.niveau / 2);
|
||||
competences.system.rang = rang;
|
||||
competences.system.rangGenericName = game.system.lesheritiers.config.rangName[rang];
|
||||
competences.system.rangSpecificName = game.system.lesheritiers.config.rangNameSpecific[comp.Name][competences.system.rangGenericName];
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
@@ -87,18 +165,29 @@ export class HeritiersUtility {
|
||||
/* -------------------------------------------- */
|
||||
static async chatListeners(html) {
|
||||
|
||||
html.on("click", '.predilection-reroll', async event => {
|
||||
$(html).on("click", '.predilection-reroll', async event => {
|
||||
let predIdx = $(event.currentTarget).data("predilection-index")
|
||||
let messageId = HeritiersUtility.findChatMessageId(event.currentTarget)
|
||||
let message = game.messages.get(messageId)
|
||||
let rollData = message.getFlag("world", "heritiers-roll")
|
||||
let actor = this.getActorFromRollData(rollData)
|
||||
await actor.setPredilectionUsed(rollData.competence._id, predIdx)
|
||||
rollData.competence = duplicate(actor.getCompetence(rollData.competence._id))
|
||||
rollData.competence = foundry.utils.duplicate(actor.getCompetence(rollData.competence._id))
|
||||
HeritiersUtility.rollHeritiers(rollData)
|
||||
})
|
||||
|
||||
html.on("click", '.roll-chat-degat', async event => {
|
||||
$(html).on("click", '.roll-tricherie-2', async event => {
|
||||
let messageId = HeritiersUtility.findChatMessageId(event.currentTarget)
|
||||
let message = game.messages.get(messageId)
|
||||
let rollData = message.getFlag("world", "heritiers-roll")
|
||||
let actor = this.getActorFromRollData(rollData)
|
||||
if (await actor.incDecTricherie(-2)) {
|
||||
rollData.forcedValue = Number($(event.currentTarget).data("dice-value"))
|
||||
HeritiersUtility.rollHeritiers(rollData)
|
||||
}
|
||||
})
|
||||
|
||||
$(html).on("click", '.roll-chat-degat', async event => {
|
||||
let messageId = HeritiersUtility.findChatMessageId(event.currentTarget)
|
||||
let message = game.messages.get(messageId)
|
||||
let rollData = message.getFlag("world", "heritiers-roll")
|
||||
@@ -111,13 +200,14 @@ export class HeritiersUtility {
|
||||
static async preloadHandlebarsTemplates() {
|
||||
|
||||
const templatePaths = [
|
||||
'systems/fvtt-les-heritiers/templates/editor-notes-gm.html',
|
||||
'systems/fvtt-les-heritiers/templates/partial-item-header.html',
|
||||
'systems/fvtt-les-heritiers/templates/partial-item-description.html',
|
||||
'systems/fvtt-les-heritiers/templates/partial-item-nav.html',
|
||||
'systems/fvtt-les-heritiers/templates/partial-list-niveau.html'
|
||||
'systems/fvtt-les-heritiers/templates/editor-notes-gm.hbs',
|
||||
'systems/fvtt-les-heritiers/templates/partial-item-header.hbs',
|
||||
'systems/fvtt-les-heritiers/templates/partial-item-description.hbs',
|
||||
'systems/fvtt-les-heritiers/templates/partial-item-nav.hbs',
|
||||
'systems/fvtt-les-heritiers/templates/partial-utile-skills.hbs',
|
||||
'systems/fvtt-les-heritiers/templates/partial-actor-equipment.hbs'
|
||||
]
|
||||
return loadTemplates(templatePaths);
|
||||
return foundry.applications.handlebars.loadTemplates(templatePaths);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
@@ -194,14 +284,14 @@ export class HeritiersUtility {
|
||||
|
||||
let id = rollData.rollId;
|
||||
let oldRollData = this.rollDataStore[id] || {};
|
||||
let newRollData = mergeObject(oldRollData, rollData);
|
||||
let newRollData = foundry.utils.mergeObject(oldRollData, rollData);
|
||||
this.rollDataStore[id] = newRollData;
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
static saveRollData(rollData) {
|
||||
game.socket.emit("system.fvtt-les-heritiers", {
|
||||
name: "msg_update_roll", data: rollData
|
||||
}); // Notify all other clients of the roll
|
||||
}); // Notify all other clients of the roll
|
||||
this.updateRollData(rollData);
|
||||
}
|
||||
|
||||
@@ -212,7 +302,6 @@ export class HeritiersUtility {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static onSocketMesssage(msg) {
|
||||
//console.log("SOCKET MESSAGE", msg.name, game.user.character.id, msg.data.defenderId);
|
||||
if (msg.name == "msg_update_defense_state") {
|
||||
this.updateDefenseState(msg.data.defenderId, msg.data.rollId);
|
||||
}
|
||||
@@ -269,123 +358,289 @@ export class HeritiersUtility {
|
||||
/* -------------------------------------------- */
|
||||
static computeMonnaieDetails(valueSC) {
|
||||
let po = Math.floor(valueSC / 400)
|
||||
let pa = Math.floor((valueSC - (po*400)) / 20)
|
||||
let sc = valueSC - (po*400) - (pa*20)
|
||||
let pa = Math.floor((valueSC - (po * 400)) / 20)
|
||||
let sc = valueSC - (po * 400) - (pa * 20)
|
||||
return {
|
||||
po: po, pa: pa, sc: sc, valueSC: valueSC
|
||||
po: po, pa: pa, sc: sc, valueSC: valueSC
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static incDecHeritage() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static computeResult(actor, rollData) {
|
||||
rollData.diceResult = -1
|
||||
let resTab = []
|
||||
for ( let res of rollData.roll.terms[0].results) {
|
||||
rollData.diceResult = Math.max(res.result, rollData.diceResult)
|
||||
resTab.push(res.result)
|
||||
}
|
||||
let isFailure = false
|
||||
if (rollData.mainDice.includes("d10")) {
|
||||
if ( rollData.diceResult == 1) {
|
||||
rollData.finalResult -= 3
|
||||
isFailure = true
|
||||
}
|
||||
}
|
||||
if (rollData.mainDice.includes("d12")) {
|
||||
if ( rollData.diceResult == 1 || rollData.diceResult == 2) {
|
||||
rollData.finalResult -= 5
|
||||
isFailure = true
|
||||
}
|
||||
}
|
||||
// Heritage/Tricherie management
|
||||
let isTricherieHeritage = rollData.useHeritage || rollData.useTricherie
|
||||
|
||||
rollData.marge = 0
|
||||
if (!isFailure && (rollData.useHeritage || rollData.useTricherie)) {
|
||||
|
||||
if (isTricherieHeritage) {
|
||||
let resTab = [rollData.roll.terms[0].results[0].result, rollData.roll.terms[0].results[1].result, rollData.roll.terms[0].results[2].result]
|
||||
rollData.diceResult = resTab[0] + "," + resTab[1] + "," + resTab[2]
|
||||
let foundryTotal = resTab[0] + resTab[1] + resTab[2]
|
||||
if (resTab[1] == 1) { resTab[1] -= 4 }
|
||||
if (resTab[2] == 1) { resTab[2] -= 6 }
|
||||
if (resTab[2] == 2) { resTab[2] -= 7 }
|
||||
rollData.diceValue = Math.max(Math.max(resTab[0], resTab[1]), resTab[2])
|
||||
rollData.finalResult = rollData.roll.total - foundryTotal + rollData.diceValue
|
||||
|
||||
// Gestion des résultats spéciaux
|
||||
resTab = resTab.sort()
|
||||
if ( (resTab[0] == resTab[1]) && (resTab[1] == resTab[2])) {
|
||||
if ((resTab[0] == resTab[1]) && (resTab[1] == resTab[2])) {
|
||||
rollData.marge = 7
|
||||
rollData.isSuccess = true
|
||||
rollData.isCriticalSuccess = true
|
||||
rollData.isCriticalSuccess = true
|
||||
rollData.isBrelan = true
|
||||
}
|
||||
if ((resTab[0]+1 == resTab[1]) && (resTab[1]+1 == resTab[2]) ) {
|
||||
if ((resTab[0] + 1 == resTab[1]) && (resTab[1] + 1 == resTab[2])) {
|
||||
rollData.marge = 7
|
||||
rollData.isSuccess = true
|
||||
rollData.isCriticalSuccess = true
|
||||
}
|
||||
if ( rollData.useTricherie) {
|
||||
rollData.isCriticalSuccess = true
|
||||
rollData.isSuite = true
|
||||
}
|
||||
if (rollData.useTricherie) {
|
||||
actor.incDecTricherie(-1)
|
||||
}
|
||||
if ( rollData.useHeritage) {
|
||||
if (rollData.useHeritage) {
|
||||
this.incDecHeritage()
|
||||
}
|
||||
}
|
||||
//rollData.finalResult = Math.max(rollData.finalResult, 0)
|
||||
//console.log("Result : ", rollData)
|
||||
if (rollData.marge == 0 && rollData.sdValue > 0 ) {
|
||||
rollData.marge = rollData.finalResult - rollData.sdValue
|
||||
rollData.isSuccess = (rollData.finalResult >= rollData.sdValue)
|
||||
rollData.isCriticalSuccess = ((rollData.finalResult - rollData.sdValue) >= 7)
|
||||
rollData.isCriticalFailure = ((rollData.finalResult - rollData.sdValue) <= -7)
|
||||
|
||||
} else {
|
||||
rollData.finalResult = rollData.roll.total
|
||||
let rollValue = rollData.forcedValue || rollData.roll.terms[0].results[0].result
|
||||
rollData.diceResult = rollValue
|
||||
rollData.diceValue = rollValue
|
||||
if (rollData.mainDice.includes("d10")) {
|
||||
if (rollValue == 1) {
|
||||
rollData.finalResult -= 3 + rollValue // substract 3 and the 1 value that has been added
|
||||
}
|
||||
}
|
||||
if (rollData.mainDice.includes("d12")) {
|
||||
if (rollValue == 1 || rollValue == 2) {
|
||||
rollData.finalResult -= 5 + rollValue // Remove also the dice result has it has been added already
|
||||
}
|
||||
}
|
||||
if (!rollData.forcedValue) {
|
||||
rollData.adjacentFaces = foundry.utils.duplicate(__facesAdjacentes[rollData.mainDice][rollData.diceValue])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static computeArmeDegats(rollData, actor) {
|
||||
rollData.degatsArme = rollData.arme.system.degats + rollData.marge
|
||||
if (rollData.attaqueDeuxArmes != 0 && rollData.secondeArme) {
|
||||
let secondeArme = actor.items.get(secondeArme)
|
||||
if (secondeArme) {
|
||||
rollData.degatsArme += secondeArme.system.degats
|
||||
rollData.degatsArme += actor.system.caracteristiques.for.value
|
||||
}
|
||||
} else {
|
||||
if (rollData.arme.system.categorie == "lourde") {
|
||||
rollData.degatsArme += actor.system.caracteristiques.for.value
|
||||
}
|
||||
if (rollData.arme.system.categorie == "blanche" || rollData.arme.system.categorie == "improvise") {
|
||||
rollData.degatsArme += Math.max(0, actor.system.caracteristiques.for.value - 2)
|
||||
}
|
||||
if (rollData.mode == "attaquecharge") {
|
||||
rollData.degatsArme += 3
|
||||
}
|
||||
}
|
||||
if (rollData.attaqueCible == "membre") {
|
||||
rollData.degatsArme -= 2
|
||||
}
|
||||
if (rollData.attaqueCible == "main") {
|
||||
rollData.degatsArme -= 3
|
||||
}
|
||||
if (rollData.attaqueCible == "tete") {
|
||||
rollData.degatsArme *= 3
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static computeMarge(rollData, seuil) {
|
||||
if (rollData.marge == 0 && seuil >= 0) {
|
||||
rollData.marge = rollData.finalResult - seuil
|
||||
rollData.isSuccess = (rollData.finalResult >= seuil)
|
||||
rollData.isCriticalSuccess = ((rollData.finalResult - seuil) >= 7)
|
||||
rollData.isCriticalFailure = ((rollData.finalResult - seuil) <= -7)
|
||||
// Si compétence > 0 et d8 -> echec critique impossible
|
||||
if (rollData?.competence?.system.niveau > 0 && rollData?.mainDice == "d8") {
|
||||
rollData.isCriticalFailure = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async displayUneDefense(rollData, actor, nomDefense, valeurDefense) {
|
||||
rollData.defenderMode = nomDefense
|
||||
rollData.defenderValue = valeurDefense
|
||||
rollData.marge = 0
|
||||
this.computeMarge(rollData, valeurDefense)
|
||||
if (rollData.isSuccess) {
|
||||
this.computeArmeDegats(rollData, actor)
|
||||
}
|
||||
this.createChatWithRollMode(rollData.alias, {
|
||||
content: await foundry.applications.handlebars.renderTemplate(`systems/fvtt-les-heritiers/templates/chat-cc-result.hbs`, rollData)
|
||||
}, rollData, "selfroll")
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
static async displayAsssomer(rollData, actor, nomAttaque, etatAssomer, valeurDefense) {
|
||||
rollData.defenderMode = nomAttaque
|
||||
rollData.etatAssommer = etatAssomer
|
||||
rollData.defenderValue = valeurDefense
|
||||
rollData.marge = 0
|
||||
this.computeMarge(rollData, valeurDefense)
|
||||
rollData.dureeAssommer = (rollData.marge) ? rollData.marge * 2 : 1
|
||||
this.createChatWithRollMode(rollData.alias, {
|
||||
content: await foundry.applications.handlebars.renderTemplate(`systems/fvtt-les-heritiers/templates/chat-assommer-result.hbs`, rollData)
|
||||
}, rollData, "selfroll")
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
static async rollHeritiers(rollData) {
|
||||
|
||||
let actor = this.getActorFromRollData(rollData)
|
||||
|
||||
if (rollData.mode == "pouvoir" && actor.getPouvoirUsage(rollData.pouvoir._id) < rollData.pouvoirPointsUsage) {
|
||||
ui.notifications.warn("Pas assez de points d'usage pour ce pouvoir.")
|
||||
return
|
||||
}
|
||||
|
||||
//rollData.actionImg = "systems/fvtt-les-heritiers/assets/icons/" + actor.system.attributs[rollData.attrKey].labelnorm + ".webp"
|
||||
rollData.carac = duplicate(actor.system.caracteristiques[rollData.caracKey])
|
||||
if (rollData.caracKey == "pre") rollData.caracKey = "pres"; // Patch tomanage wrong carac key
|
||||
rollData.carac = foundry.utils.duplicate(actor.system.caracteristiques[rollData.caracKey])
|
||||
|
||||
rollData.nbDice = (rollData.useTricherie || rollData.useHeritage) ? 3 : 1
|
||||
rollData.diceFormula = rollData.nbDice + rollData.mainDice + "kh1"
|
||||
//console.log("BEFORE COMP", rollData)
|
||||
if (rollData.competence) {
|
||||
let compmod = (rollData.competence.system.niveau == 0) ? -3 : 0
|
||||
rollData.diceFormula += `+${rollData.carac.value}+${rollData.competence.system.niveau}+${rollData.bonusMalusContext}+${compmod}`
|
||||
if (rollData.forcedValue) {
|
||||
rollData.diceFormula = rollData.forcedValue
|
||||
} else {
|
||||
rollData.diceFormula += `+${rollData.carac.value}+${rollData.bonusMalusContext}`
|
||||
}
|
||||
rollData.diceFormula += `+${rollData.pvMalus}`
|
||||
|
||||
if (rollData.arme && rollData.arme.type == "arme") {
|
||||
rollData.diceFormula += `+${rollData.arme.system.bonusmaniementoff}`
|
||||
if (rollData.useTricherie || rollData.useHeritage) {
|
||||
rollData.diceFormula = "{1d8, 1d10, 1d12}"
|
||||
} else {
|
||||
rollData.diceFormula = "1" + rollData.mainDice + "kh1"
|
||||
}
|
||||
}
|
||||
|
||||
let myRoll = new Roll(rollData.diceFormula).roll({ async: false })
|
||||
await this.showDiceSoNice(myRoll, game.settings.get("core", "rollMode"))
|
||||
rollData.roll = myRoll
|
||||
console.log(">>>> ", myRoll)
|
||||
let rangValue = 0
|
||||
if (rollData.rang) {
|
||||
rangValue = rollData.rang.value
|
||||
}
|
||||
if (rollData.competence) {
|
||||
let compmod = 0 // Bonus de compétence à 0 dans Les Heritiers
|
||||
let specBonus = (rollData.useSpecialite) ? 1 : 0
|
||||
rollData.diceFormula += `+${rollData.carac.value}+${rangValue}+${rollData.competence.system.niveau}+${specBonus}+${rollData.bonusMalusContext}+${compmod}`
|
||||
} else if (rollData.pouvoirBase) {
|
||||
rollData.diceFormula += `+${rollData.carac.value}+${rollData.pouvoirBase.value}+${rangValue}+${rollData.bonusMalusContext}`
|
||||
} else {
|
||||
rollData.diceFormula += `+${rollData.carac.value}+${rangValue}+${rollData.bonusMalusContext}`
|
||||
}
|
||||
let ruleMalus = 0
|
||||
for (let malus of rollData.rulesMalus) {
|
||||
ruleMalus += malus.value
|
||||
}
|
||||
rollData.diceFormula += `+${ruleMalus}`
|
||||
|
||||
// Gestion bonus attaque à plusieurs
|
||||
let bonusAttaque = rollData.bonusAttaquePlusieurs
|
||||
if (rollData.attaqueDos) {
|
||||
bonusAttaque = 2
|
||||
if (rollData.bonusAttaquePlusieurs) {
|
||||
bonusAttaque = 3 // Valeur max, cf règle page 197
|
||||
}
|
||||
}
|
||||
rollData.diceFormula += `+${bonusAttaque}`
|
||||
|
||||
// Gestion attaque avec 2 armes
|
||||
if (rollData.attaqueDeuxArmes != 0) {
|
||||
rollData.diceFormula += `+${rollData.attaqueDeuxArmes}`
|
||||
}
|
||||
// Gestion des attaques ciblées
|
||||
if (rollData.attaqueCible != "none") {
|
||||
if (rollData.attaqueCible == "membre") {
|
||||
rollData.diceFormula += `-2`
|
||||
}
|
||||
if (rollData.attaqueCible == "main") {
|
||||
rollData.diceFormula += `-3`
|
||||
}
|
||||
if (rollData.attaqueCible == "tete") {
|
||||
rollData.diceFormula += `-6`
|
||||
}
|
||||
}
|
||||
|
||||
if (!rollData.noRoll) {
|
||||
let myRoll = await new Roll(rollData.diceFormula).roll()
|
||||
await this.showDiceSoNice(myRoll, game.settings.get("core", "rollMode"))
|
||||
rollData.roll = foundry.utils.duplicate(myRoll)
|
||||
console.log(">>>> ", myRoll)
|
||||
this.computeResult(actor, rollData)
|
||||
this.computeMarge(rollData, rollData.sdValue) // Calcul de la marge si seuil présent
|
||||
// Compute weapon damage for successful attacks
|
||||
if (rollData.arme && rollData.isSuccess) {
|
||||
this.computeArmeDegats(rollData, actor)
|
||||
}
|
||||
}
|
||||
|
||||
rollData.finalResult = myRoll.total
|
||||
this.computeResult(actor, rollData)
|
||||
if (rollData.mode == "init") {
|
||||
actor.setFlag("world", "last-initiative", rollData.finalResult)
|
||||
}
|
||||
|
||||
// Gestion pouvoir et points d'usage
|
||||
if (rollData.mode == "pouvoir" || rollData.mode == "pouvoirpassif") {
|
||||
actor.incDecPointsUsage(rollData.pouvoir._id, -rollData.pouvoirPointsUsage)
|
||||
}
|
||||
// Gestion sort et points d'âme
|
||||
if (rollData.mode == "sort") {
|
||||
if (rollData.spendEsprit) {
|
||||
actor.inDecCarac("esp", -rollData.totalEsprit)
|
||||
} else {
|
||||
actor.incDecPointsAme(-rollData.sortPointsAme)
|
||||
if (rollData.sort.system.competence == "Magie du Clan") {
|
||||
actor.incDecPV(-2)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.createChatWithRollMode(rollData.alias, {
|
||||
content: await renderTemplate(`systems/fvtt-les-heritiers/templates/chat-generic-result.html`, rollData)
|
||||
content: await foundry.applications.handlebars.renderTemplate(`systems/fvtt-les-heritiers/templates/chat-generic-result.hbs`, rollData)
|
||||
}, rollData)
|
||||
|
||||
// Gestion attaque standard
|
||||
if ((rollData.mode == "arme" || rollData.mode == "attaquebrutale" || rollData.mode == "attaquecharge") &&
|
||||
rollData.defenderTokenId && rollData.arme) {
|
||||
if (rollData.arme.system.categorie != "trait" && rollData.arme.system.categorie != "poing" && rollData.arme.system.categorie != "epaule") {
|
||||
await this.displayUneDefense(rollData, actor, "Parade", rollData.defenderParade)
|
||||
await this.displayUneDefense(rollData, actor, "Esquive", rollData.defenderEsquive)
|
||||
} else if (rollData.sdValue) {
|
||||
this.displayUneDefense(rollData, actor, "A Distance", rollData.sdValue)
|
||||
} else {
|
||||
ui.notifications.warn("Pas de difficulté positionnée pour l'attaque à distance.")
|
||||
}
|
||||
}
|
||||
// Gestion assomer
|
||||
if (rollData.mode == "assommer" && rollData.defenderTokenId && rollData.arme) {
|
||||
await this.displayAsssomer(rollData, actor, "Assommer", "Surprise", rollData.defenderResistancePhysique)
|
||||
await this.displayAsssomer(rollData, actor, "Assommer", "Conscient, Résistance+6", rollData.defenderResistancePhysique + 6)
|
||||
await this.displayAsssomer(rollData, actor, "Assommer", "Conscient, Parade", rollData.defenderParade)
|
||||
await this.displayAsssomer(rollData, actor, "Assommer", "Conscient, Esquive", rollData.defenderEsquive + 6)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async bonusRollHeritiers(rollData) {
|
||||
rollData.bonusFormula = rollData.addedBonus
|
||||
|
||||
let bonusRoll = new Roll(rollData.bonusFormula).roll({ async: false })
|
||||
let bonusRoll = await new Roll(rollData.bonusFormula).roll()
|
||||
await this.showDiceSoNice(bonusRoll, game.settings.get("core", "rollMode"));
|
||||
rollData.bonusRoll = bonusRoll
|
||||
rollData.bonusRoll = foundry.utils.duplicate(bonusRoll)
|
||||
|
||||
rollData.finalResult += rollData.bonusRoll.total
|
||||
|
||||
this.computeResult(rollData)
|
||||
|
||||
this.createChatWithRollMode(rollData.alias, {
|
||||
content: await renderTemplate(`systems/fvtt-les-heritiers/templates/chat-generic-result.html`, rollData)
|
||||
content: await foundry.applications.handlebars.renderTemplate(`systems/fvtt-les-heritiers/templates/chat-generic-result.hbs`, rollData)
|
||||
}, rollData)
|
||||
|
||||
}
|
||||
@@ -395,6 +650,10 @@ export class HeritiersUtility {
|
||||
return game.users.filter(filter).map(user => user._id);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static isArmeMelee(arme) {
|
||||
return (arme.type == "arme" && (arme.system.categorie == "lourde" || arme.system.categorie == "blanche" || arme.system.categorie == "improvise"))
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
static getWhisperRecipients(rollMode, name) {
|
||||
switch (rollMode) {
|
||||
@@ -412,7 +671,7 @@ export class HeritiersUtility {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static blindMessageToGM(chatOptions) {
|
||||
let chatGM = duplicate(chatOptions);
|
||||
let chatGM = foundry.utils.duplicate(chatOptions);
|
||||
chatGM.whisper = this.getUsers(user => user.isGM);
|
||||
chatGM.content = "Blinde message of " + game.user.name + "<br>" + chatOptions.content;
|
||||
console.log("blindMessageToGM", chatGM);
|
||||
@@ -476,11 +735,17 @@ export class HeritiersUtility {
|
||||
/* -------------------------------------------- */
|
||||
static getBasicRollData() {
|
||||
let rollData = {
|
||||
rollId: randomID(16),
|
||||
rollId: foundry.utils.randomID(16),
|
||||
rollMode: game.settings.get("core", "rollMode"),
|
||||
sdList: game.system.lesheritiers.config.seuilsDifficulte,
|
||||
sdValue: 0,
|
||||
bonusMalusContext: 0
|
||||
sdValue: -1,
|
||||
bonusAttaquePlusieurs: 0,
|
||||
attaqueDeuxArmes: 0,
|
||||
attaqueDos: false,
|
||||
bonusMalusContext: 0,
|
||||
attaqueCible: "none",
|
||||
config: game.system.lesheritiers.config,
|
||||
rulesMalus: []
|
||||
}
|
||||
return rollData
|
||||
}
|
||||
@@ -491,18 +756,18 @@ export class HeritiersUtility {
|
||||
if (target) {
|
||||
rollData.defenderTokenId = target.id
|
||||
let defender = game.canvas.tokens.get(rollData.defenderTokenId).actor
|
||||
rollData.armeDefense = defender.getBestDefenseValue()
|
||||
rollData.targetVigueur = defender.getVigueur()
|
||||
if (rollData.armeDefense) {
|
||||
rollData.difficulte = rollData.armeDefense.system.totalDefensif
|
||||
} else {
|
||||
ui.notifications.warn("Aucune arme de défense équipée, difficulté manuelle à positionner.")
|
||||
}
|
||||
rollData.defenderName = defender.name
|
||||
rollData.defenderParade = defender.getCurrentParade()
|
||||
rollData.defenderEsquive = defender.getCurrentEsquive()
|
||||
rollData.defenderResistancePhysique = defender.getCurrentResistancePhysique()
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static createChatWithRollMode(name, chatOptions, rollData = undefined) {
|
||||
static createChatWithRollMode(name, chatOptions, rollData = undefined, rollMode = undefined) {
|
||||
if (rollMode == undefined) {
|
||||
rollMode = game.settings.get("core", "rollMode")
|
||||
}
|
||||
this.createChatMessage(name, game.settings.get("core", "rollMode"), chatOptions, rollData)
|
||||
}
|
||||
|
||||
@@ -548,13 +813,13 @@ export class HeritiersUtility {
|
||||
static chatRollMenu(html, options) {
|
||||
let canApply = li => canvas.tokens.controlled.length && li.find(".heritiers-roll").length
|
||||
let canApplyBA = function (li) {
|
||||
let message = game.messages.get(li.attr("data-message-id"))
|
||||
let message = game.messages.get($(li).attr("data-message-id"))
|
||||
let rollData = message.getFlag("world", "heritiers-roll")
|
||||
let actor = this.getActorFromRollData(rollData)
|
||||
return (!rollData.isReroll && actor.getBonneAventure() > 0)
|
||||
}
|
||||
let canApplyPE = function (li) {
|
||||
let message = game.messages.get(li.attr("data-message-id"))
|
||||
let message = game.messages.get($(li).attr("data-message-id"))
|
||||
let rollData = message.getFlag("world", "heritiers-roll")
|
||||
let actor = this.getActorFromRollData(rollData)
|
||||
return (!rollData.isReroll && actor.getEclat() > 0)
|
||||
@@ -588,25 +853,30 @@ export class HeritiersUtility {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async confirmDelete(actorSheet, li) {
|
||||
let itemId = li.data("item-id");
|
||||
let msgTxt = "<p>Are you sure to remove this Item ?";
|
||||
// Support both jQuery and native elements
|
||||
let itemId = li.dataset ? li.dataset.itemId : li.data("item-id");
|
||||
let msgTxt = "<p>Certain de supprimer cet item ?";
|
||||
let buttons = {
|
||||
delete: {
|
||||
icon: '<i class="fas fa-check"></i>',
|
||||
label: "Yes, remove it",
|
||||
label: "Oui !",
|
||||
callback: () => {
|
||||
actorSheet.actor.deleteEmbeddedDocuments("Item", [itemId]);
|
||||
li.slideUp(200, () => actorSheet.render(false));
|
||||
if (li.slideUp) {
|
||||
li.slideUp(200, () => actorSheet.render(false));
|
||||
} else {
|
||||
actorSheet.render(false);
|
||||
}
|
||||
}
|
||||
},
|
||||
cancel: {
|
||||
icon: '<i class="fas fa-times"></i>',
|
||||
label: "Cancel"
|
||||
label: "Non !"
|
||||
}
|
||||
}
|
||||
msgTxt += "</p>";
|
||||
let d = new Dialog({
|
||||
title: "Confirm removal",
|
||||
title: "Confirmer la suppression",
|
||||
content: msgTxt,
|
||||
buttons: buttons,
|
||||
default: "cancel"
|
||||
@@ -614,21 +884,56 @@ export class HeritiersUtility {
|
||||
d.render(true);
|
||||
}
|
||||
|
||||
/************************************************************************************/
|
||||
static async __create_talents_table() {
|
||||
let compName = "fvtt-les-heritiers.talents-cellule"
|
||||
const compData = await HeritiersUtility.loadCompendium(compName)
|
||||
let talents = compData.map(i => i.toObject())
|
||||
|
||||
let htmlTab = "<table border='1'><tbody>";
|
||||
for (let entryData of talents) {
|
||||
console.log(entryData)
|
||||
htmlTab += `<tr><td>@UUID[Compendium.${compName}.${entryData._id}]{${entryData.name}}</td>`
|
||||
htmlTab += `<td>${entryData.system.description}</td>`;
|
||||
//htmlTab += `<td>${entryData.system.resumebonus}</td>`;
|
||||
htmlTab += "</tr>\n";
|
||||
static loadSort() {
|
||||
// Create afolder in the item directory if it doesn't exist
|
||||
if (!game.folders.getName("Magie du Clan")) {
|
||||
Folder.create({
|
||||
name: "Magie du Clan",
|
||||
type: "Item",
|
||||
color: "#3b1361"
|
||||
});
|
||||
}
|
||||
htmlTab += "</table>";
|
||||
await JournalEntry.create({ name: 'Liste des Talents de Cellule', content: htmlTab });
|
||||
|
||||
// Load the srcdata/sorts-druidisme.json file
|
||||
return fetch("systems/fvtt-les-heritiers/srcdata/sort_magieduclan.json")
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
console.log("Sorts Magie du Clan loaded:", data);
|
||||
this.sortDruidisme = data;
|
||||
// Loop through the spell and create the "sort "item based on the JSON content
|
||||
data.forEach(spell => {
|
||||
spell.name = spell.name;
|
||||
spell.type = "sort";
|
||||
spell.system = {
|
||||
niveau: spell.niveau,
|
||||
competence: spell.competence,
|
||||
carac1: spell.carac1,
|
||||
carac2: spell.carac2,
|
||||
description: spell.description,
|
||||
ingredients: spell.ingredients,
|
||||
portee: spell.portee,
|
||||
duree: spell.duree,
|
||||
concentration: spell.concentration,
|
||||
critique: spell.critique,
|
||||
resistance: spell.resistance,
|
||||
coutactivation: spell.coutactivation
|
||||
};
|
||||
spell.img = "systems/fvtt-les-heritiers/assets/icons/sort.webp";
|
||||
spell.folder = game.folders.getName("Magie du Clan").id;
|
||||
|
||||
// Create the item in the world
|
||||
Item.create(spell)
|
||||
.then(item => {
|
||||
console.log("Sort created:", item);
|
||||
})
|
||||
.catch(error => {
|
||||
console.error("Error creating sort item:", error);
|
||||
});
|
||||
})
|
||||
})
|
||||
.catch(error => {
|
||||
console.error("Error loading druidism spells:", error);
|
||||
return [];
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
16
modules/models/accessoire.mjs
Normal file
@@ -0,0 +1,16 @@
|
||||
/**
|
||||
* Data model pour les accessoires
|
||||
*/
|
||||
export default class AccessoireDataModel extends foundry.abstract.TypeDataModel {
|
||||
static defineSchema() {
|
||||
const fields = foundry.data.fields;
|
||||
return {
|
||||
description: new fields.HTMLField({ initial: "" }),
|
||||
rarete: new fields.NumberField({ initial: 0, integer: true }),
|
||||
quantite: new fields.NumberField({ initial: 0, integer: true }),
|
||||
prix: new fields.NumberField({ initial: 0, integer: true }),
|
||||
equipped: new fields.BooleanField({ initial: false }),
|
||||
lieu: new fields.NumberField({ initial: 0, integer: true })
|
||||
};
|
||||
}
|
||||
}
|
||||
30
modules/models/arme.mjs
Normal file
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* Data model pour les armes
|
||||
*/
|
||||
export default class ArmeDataModel extends foundry.abstract.TypeDataModel {
|
||||
static defineSchema() {
|
||||
const fields = foundry.data.fields;
|
||||
return {
|
||||
description: new fields.HTMLField({ initial: "" }),
|
||||
rarete: new fields.NumberField({ initial: 0, integer: true }),
|
||||
quantite: new fields.NumberField({ initial: 0, integer: true }),
|
||||
prix: new fields.NumberField({ initial: 0, integer: true }),
|
||||
equipped: new fields.BooleanField({ initial: false }),
|
||||
categorie: new fields.StringField({ initial: "" }),
|
||||
armetype: new fields.StringField({ initial: "" }),
|
||||
degats: new fields.NumberField({ initial: 0, integer: true }),
|
||||
precision: new fields.NumberField({ initial: 0, integer: true }),
|
||||
cadence: new fields.StringField({ initial: "" }),
|
||||
enraiement: new fields.StringField({ initial: "" }),
|
||||
magasin: new fields.NumberField({ initial: 0, integer: true }),
|
||||
charge: new fields.NumberField({ initial: 0, integer: true }),
|
||||
portee: new fields.StringField({ initial: "" }),
|
||||
legalite: new fields.StringField({ initial: "" }),
|
||||
dissimulation: new fields.StringField({ initial: "" }),
|
||||
zone: new fields.NumberField({ initial: 0, integer: true }),
|
||||
temps: new fields.StringField({ initial: "" }),
|
||||
allumage: new fields.StringField({ initial: "" }),
|
||||
special: new fields.StringField({ initial: "" })
|
||||
};
|
||||
}
|
||||
}
|
||||
11
modules/models/atoutfeerique.mjs
Normal file
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* Data model pour les atouts féériques
|
||||
*/
|
||||
export default class AtoutFeeriqueDataModel extends foundry.abstract.TypeDataModel {
|
||||
static defineSchema() {
|
||||
const fields = foundry.data.fields;
|
||||
return {
|
||||
description: new fields.HTMLField({ initial: "" })
|
||||
};
|
||||
}
|
||||
}
|
||||
11
modules/models/avantage.mjs
Normal file
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* Data model pour les avantages
|
||||
*/
|
||||
export default class AvantageDataModel extends foundry.abstract.TypeDataModel {
|
||||
static defineSchema() {
|
||||
const fields = foundry.data.fields;
|
||||
return {
|
||||
description: new fields.HTMLField({ initial: "" })
|
||||
};
|
||||
}
|
||||
}
|
||||
11
modules/models/base-item.mjs
Normal file
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* Base data model pour les items
|
||||
*/
|
||||
export default class BaseItemDataModel extends foundry.abstract.TypeDataModel {
|
||||
static defineSchema() {
|
||||
const fields = foundry.data.fields;
|
||||
return {
|
||||
description: new fields.HTMLField({ initial: "" })
|
||||
};
|
||||
}
|
||||
}
|
||||
21
modules/models/capacitenaturelle.mjs
Normal file
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* Data model pour les capacités naturelles
|
||||
*/
|
||||
export default class CapaciteNaturelleDataModel extends foundry.abstract.TypeDataModel {
|
||||
static defineSchema() {
|
||||
const fields = foundry.data.fields;
|
||||
return {
|
||||
pouvoirtype: new fields.StringField({ initial: "" }),
|
||||
activation: new fields.StringField({ initial: "" }),
|
||||
cibles: new fields.StringField({ initial: "" }),
|
||||
effet: new fields.StringField({ initial: "" }),
|
||||
duree: new fields.StringField({ initial: "" }),
|
||||
portee: new fields.StringField({ initial: "" }),
|
||||
resistance: new fields.StringField({ initial: "" }),
|
||||
resistanceautre: new fields.StringField({ initial: "" }),
|
||||
isvirulence: new fields.BooleanField({ initial: false }),
|
||||
virulence: new fields.StringField({ initial: "" }),
|
||||
description: new fields.HTMLField({ initial: "" })
|
||||
};
|
||||
}
|
||||
}
|
||||
43
modules/models/competence.mjs
Normal file
@@ -0,0 +1,43 @@
|
||||
/**
|
||||
* Data model pour les compétences
|
||||
*/
|
||||
export default class CompetenceDataModel extends foundry.abstract.TypeDataModel {
|
||||
static defineSchema() {
|
||||
const fields = foundry.data.fields;
|
||||
return {
|
||||
categorie: new fields.StringField({ initial: "" }),
|
||||
profil: new fields.StringField({ initial: "" }),
|
||||
niveau: new fields.NumberField({ initial: 0, integer: true }),
|
||||
nomniveau: new fields.SchemaField({
|
||||
1: new fields.StringField({ initial: "" }),
|
||||
2: new fields.StringField({ initial: "" }),
|
||||
3: new fields.StringField({ initial: "" }),
|
||||
4: new fields.StringField({ initial: "" })
|
||||
}),
|
||||
nomniveausouffle: new fields.SchemaField({
|
||||
soufflecombat: new fields.SchemaField({
|
||||
1: new fields.StringField({ initial: "" }),
|
||||
2: new fields.StringField({ initial: "" }),
|
||||
3: new fields.StringField({ initial: "" }),
|
||||
4: new fields.StringField({ initial: "" })
|
||||
}),
|
||||
soufflemouvement: new fields.SchemaField({
|
||||
1: new fields.StringField({ initial: "" }),
|
||||
2: new fields.StringField({ initial: "" }),
|
||||
3: new fields.StringField({ initial: "" }),
|
||||
4: new fields.StringField({ initial: "" })
|
||||
}),
|
||||
souffleesprit: new fields.SchemaField({
|
||||
1: new fields.StringField({ initial: "" }),
|
||||
2: new fields.StringField({ initial: "" }),
|
||||
3: new fields.StringField({ initial: "" }),
|
||||
4: new fields.StringField({ initial: "" })
|
||||
})
|
||||
}),
|
||||
predilection: new fields.BooleanField({ initial: false }),
|
||||
specialites: new fields.ArrayField(new fields.ObjectField(), { initial: [] }),
|
||||
ismagie: new fields.BooleanField({ initial: false }),
|
||||
description: new fields.HTMLField({ initial: "" })
|
||||
};
|
||||
}
|
||||
}
|
||||
12
modules/models/contact.mjs
Normal file
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* Data model pour les contacts
|
||||
*/
|
||||
export default class ContactDataModel extends foundry.abstract.TypeDataModel {
|
||||
static defineSchema() {
|
||||
const fields = foundry.data.fields;
|
||||
return {
|
||||
contacttype: new fields.StringField({ initial: "contact" }),
|
||||
description: new fields.HTMLField({ initial: "" })
|
||||
};
|
||||
}
|
||||
}
|
||||
11
modules/models/desavantage.mjs
Normal file
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* Data model pour les désavantages
|
||||
*/
|
||||
export default class DesavantageDataModel extends foundry.abstract.TypeDataModel {
|
||||
static defineSchema() {
|
||||
const fields = foundry.data.fields;
|
||||
return {
|
||||
description: new fields.HTMLField({ initial: "" })
|
||||
};
|
||||
}
|
||||
}
|
||||
15
modules/models/equipement.mjs
Normal file
@@ -0,0 +1,15 @@
|
||||
/**
|
||||
* Data model pour les équipements
|
||||
*/
|
||||
export default class EquipementDataModel extends foundry.abstract.TypeDataModel {
|
||||
static defineSchema() {
|
||||
const fields = foundry.data.fields;
|
||||
return {
|
||||
description: new fields.HTMLField({ initial: "" }),
|
||||
rarete: new fields.NumberField({ initial: 0, integer: true }),
|
||||
quantite: new fields.NumberField({ initial: 0, integer: true }),
|
||||
prix: new fields.NumberField({ initial: 0, integer: true }),
|
||||
equipped: new fields.BooleanField({ initial: false })
|
||||
};
|
||||
}
|
||||
}
|
||||
19
modules/models/fee.mjs
Normal file
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* Data model pour les fées
|
||||
*/
|
||||
export default class FeeDataModel extends foundry.abstract.TypeDataModel {
|
||||
static defineSchema() {
|
||||
const fields = foundry.data.fields;
|
||||
return {
|
||||
feetype: new fields.NumberField({ initial: 0, integer: true }),
|
||||
avantages: new fields.StringField({ initial: "" }),
|
||||
desavantages: new fields.StringField({ initial: "" }),
|
||||
pouvoirsfeeriquesmasque: new fields.StringField({ initial: "" }),
|
||||
pouvoirsfeeriquesdemasque: new fields.StringField({ initial: "" }),
|
||||
atoutsfeeriques: new fields.StringField({ initial: "" }),
|
||||
competences: new fields.StringField({ initial: "" }),
|
||||
capacitenaturelles: new fields.StringField({ initial: "" }),
|
||||
description: new fields.HTMLField({ initial: "" })
|
||||
};
|
||||
}
|
||||
}
|
||||
24
modules/models/index.mjs
Normal file
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* Index des DataModels pour Les Héritiers
|
||||
* Ce fichier centralise tous les exports des modèles de données
|
||||
*/
|
||||
|
||||
// Modèles d'acteurs
|
||||
export { default as PersonnageDataModel } from './personnage.mjs';
|
||||
export { default as PnjDataModel } from './pnj.mjs';
|
||||
|
||||
// Modèles d'items
|
||||
export { default as AccessoireDataModel } from './accessoire.mjs';
|
||||
export { default as ArmeDataModel } from './arme.mjs';
|
||||
export { default as AtoutFeeriqueDataModel } from './atoutfeerique.mjs';
|
||||
export { default as AvantageDataModel } from './avantage.mjs';
|
||||
export { default as CapaciteNaturelleDataModel } from './capacitenaturelle.mjs';
|
||||
export { default as CompetenceDataModel } from './competence.mjs';
|
||||
export { default as ContactDataModel } from './contact.mjs';
|
||||
export { default as DesavantageDataModel } from './desavantage.mjs';
|
||||
export { default as EquipementDataModel } from './equipement.mjs';
|
||||
export { default as FeeDataModel } from './fee.mjs';
|
||||
export { default as PouvoirDataModel } from './pouvoir.mjs';
|
||||
export { default as ProfilDataModel } from './profil.mjs';
|
||||
export { default as ProtectionDataModel } from './protection.mjs';
|
||||
export { default as SortDataModel } from './sort.mjs';
|
||||
234
modules/models/personnage.mjs
Normal file
@@ -0,0 +1,234 @@
|
||||
/**
|
||||
* Data model pour les personnages
|
||||
*/
|
||||
export default class PersonnageDataModel extends foundry.abstract.TypeDataModel {
|
||||
static defineSchema() {
|
||||
const fields = foundry.data.fields;
|
||||
return {
|
||||
// Template biodata
|
||||
biodata: new fields.SchemaField({
|
||||
name: new fields.StringField({ initial: "" }),
|
||||
activite: new fields.StringField({ initial: "" }),
|
||||
nomhumain: new fields.StringField({ initial: "" }),
|
||||
activites: new fields.StringField({ initial: "" }),
|
||||
fortune: new fields.NumberField({ initial: 0, integer: true }),
|
||||
traitscaracteres: new fields.StringField({ initial: "" }),
|
||||
tailledemasquee: new fields.StringField({ initial: "" }),
|
||||
taillemasquee: new fields.StringField({ initial: "" }),
|
||||
poidsmasquee: new fields.StringField({ initial: "" }),
|
||||
poidsdemasquee: new fields.StringField({ initial: "" }),
|
||||
apparencemasquee: new fields.StringField({ initial: "" }),
|
||||
apparencedemasquee: new fields.StringField({ initial: "" }),
|
||||
titrefamille: new fields.StringField({ initial: "" }),
|
||||
langues: new fields.StringField({ initial: "" }),
|
||||
factionfeerique: new fields.StringField({ initial: "" }),
|
||||
typetaille: new fields.StringField({ initial: "" }),
|
||||
age: new fields.NumberField({ initial: 0, integer: true }),
|
||||
poids: new fields.StringField({ initial: "" }),
|
||||
taille: new fields.StringField({ initial: "" }),
|
||||
cheveux: new fields.StringField({ initial: "" }),
|
||||
sexe: new fields.StringField({ initial: "" }),
|
||||
yeux: new fields.StringField({ initial: "" }),
|
||||
description: new fields.HTMLField({ initial: "" }),
|
||||
revesetranges: new fields.HTMLField({ initial: "" }),
|
||||
secretsdecouverts: new fields.HTMLField({ initial: "" }),
|
||||
questions: new fields.HTMLField({ initial: "" }),
|
||||
habitat: new fields.HTMLField({ initial: "" }),
|
||||
notes: new fields.HTMLField({ initial: "" }),
|
||||
statut: new fields.StringField({ initial: "" }),
|
||||
playernotes: new fields.HTMLField({ initial: "" }),
|
||||
gmnotes: new fields.HTMLField({ initial: "" }),
|
||||
magie: new fields.BooleanField({ initial: false })
|
||||
}),
|
||||
// Template core
|
||||
subactors: new fields.ArrayField(new fields.StringField(), { initial: [] }),
|
||||
caracteristiques: new fields.SchemaField({
|
||||
agi: new fields.SchemaField({
|
||||
label: new fields.StringField({ initial: "Agilité" }),
|
||||
labelnorm: new fields.StringField({ initial: "agilite" }),
|
||||
abbrev: new fields.StringField({ initial: "agi" }),
|
||||
kind: new fields.StringField({ initial: "physical" }),
|
||||
value: new fields.NumberField({ initial: 1, integer: true }),
|
||||
rang: new fields.NumberField({ initial: 0, integer: true }),
|
||||
max: new fields.NumberField({ initial: 1, integer: true })
|
||||
}),
|
||||
con: new fields.SchemaField({
|
||||
label: new fields.StringField({ initial: "Constitution" }),
|
||||
labelnorm: new fields.StringField({ initial: "constitution" }),
|
||||
abbrev: new fields.StringField({ initial: "con" }),
|
||||
kind: new fields.StringField({ initial: "physical" }),
|
||||
value: new fields.NumberField({ initial: 1, integer: true }),
|
||||
rang: new fields.NumberField({ initial: 0, integer: true }),
|
||||
max: new fields.NumberField({ initial: 1, integer: true })
|
||||
}),
|
||||
for: new fields.SchemaField({
|
||||
label: new fields.StringField({ initial: "Force" }),
|
||||
labelnorm: new fields.StringField({ initial: "force" }),
|
||||
abbrev: new fields.StringField({ initial: "for" }),
|
||||
kind: new fields.StringField({ initial: "physical" }),
|
||||
value: new fields.NumberField({ initial: 1, integer: true }),
|
||||
rang: new fields.NumberField({ initial: 0, integer: true }),
|
||||
max: new fields.NumberField({ initial: 1, integer: true })
|
||||
}),
|
||||
prec: new fields.SchemaField({
|
||||
label: new fields.StringField({ initial: "Précision" }),
|
||||
labelnorm: new fields.StringField({ initial: "precision" }),
|
||||
abbrev: new fields.StringField({ initial: "prec" }),
|
||||
kind: new fields.StringField({ initial: "physical" }),
|
||||
value: new fields.NumberField({ initial: 1, integer: true }),
|
||||
rang: new fields.NumberField({ initial: 0, integer: true }),
|
||||
max: new fields.NumberField({ initial: 1, integer: true })
|
||||
}),
|
||||
esp: new fields.SchemaField({
|
||||
label: new fields.StringField({ initial: "Esprit" }),
|
||||
labelnorm: new fields.StringField({ initial: "esprit" }),
|
||||
abbrev: new fields.StringField({ initial: "esp" }),
|
||||
kind: new fields.StringField({ initial: "mental" }),
|
||||
value: new fields.NumberField({ initial: 1, integer: true }),
|
||||
rang: new fields.NumberField({ initial: 0, integer: true }),
|
||||
max: new fields.NumberField({ initial: 1, integer: true })
|
||||
}),
|
||||
per: new fields.SchemaField({
|
||||
label: new fields.StringField({ initial: "Perception" }),
|
||||
labelnorm: new fields.StringField({ initial: "perception" }),
|
||||
abbrev: new fields.StringField({ initial: "per" }),
|
||||
kind: new fields.StringField({ initial: "mental" }),
|
||||
value: new fields.NumberField({ initial: 1, integer: true }),
|
||||
rang: new fields.NumberField({ initial: 0, integer: true }),
|
||||
max: new fields.NumberField({ initial: 1, integer: true })
|
||||
}),
|
||||
pres: new fields.SchemaField({
|
||||
label: new fields.StringField({ initial: "Prestance" }),
|
||||
labelnorm: new fields.StringField({ initial: "pres" }),
|
||||
abbrev: new fields.StringField({ initial: "pres" }),
|
||||
kind: new fields.StringField({ initial: "mental" }),
|
||||
value: new fields.NumberField({ initial: 1, integer: true }),
|
||||
rang: new fields.NumberField({ initial: 0, integer: true }),
|
||||
max: new fields.NumberField({ initial: 1, integer: true })
|
||||
}),
|
||||
san: new fields.SchemaField({
|
||||
label: new fields.StringField({ initial: "Sang-Froid" }),
|
||||
labelnorm: new fields.StringField({ initial: "sangfroid" }),
|
||||
abbrev: new fields.StringField({ initial: "san" }),
|
||||
kind: new fields.StringField({ initial: "mental" }),
|
||||
value: new fields.NumberField({ initial: 1, integer: true }),
|
||||
rang: new fields.NumberField({ initial: 0, integer: true }),
|
||||
max: new fields.NumberField({ initial: 1, integer: true })
|
||||
})
|
||||
}),
|
||||
statutmasque: new fields.StringField({ initial: "masque" }),
|
||||
rang: new fields.SchemaField({
|
||||
tricherie: new fields.SchemaField({
|
||||
label: new fields.StringField({ initial: "Tricherie" }),
|
||||
value: new fields.NumberField({ initial: 0, integer: true }),
|
||||
max: new fields.NumberField({ initial: 0, integer: true })
|
||||
}),
|
||||
feerie: new fields.SchemaField({
|
||||
label: new fields.StringField({ initial: "Féerie" }),
|
||||
value: new fields.NumberField({ initial: 0, integer: true }),
|
||||
max: new fields.NumberField({ initial: 0, integer: true })
|
||||
}),
|
||||
masque: new fields.SchemaField({
|
||||
label: new fields.StringField({ initial: "Masque" }),
|
||||
value: new fields.NumberField({ initial: 0, integer: true }),
|
||||
max: new fields.NumberField({ initial: 0, integer: true })
|
||||
}),
|
||||
heritage: new fields.SchemaField({
|
||||
label: new fields.StringField({ initial: "Héritage" }),
|
||||
value: new fields.NumberField({ initial: 0, integer: true }),
|
||||
max: new fields.NumberField({ initial: 0, integer: true }),
|
||||
scenarios: new fields.NumberField({ initial: 0, integer: true })
|
||||
})
|
||||
}),
|
||||
pv: new fields.SchemaField({
|
||||
value: new fields.NumberField({ initial: 0, integer: true }),
|
||||
max: new fields.NumberField({ initial: 0, integer: true }),
|
||||
mod: new fields.NumberField({ initial: 0, integer: true })
|
||||
}),
|
||||
competences: new fields.SchemaField({
|
||||
aventurier: new fields.SchemaField({
|
||||
label: new fields.StringField({ initial: "Aventurier" }),
|
||||
niveau: new fields.NumberField({ initial: 0, integer: true }),
|
||||
rang: new fields.NumberField({ initial: 0, integer: true }),
|
||||
pp: new fields.NumberField({ initial: 0, integer: true })
|
||||
}),
|
||||
combattant: new fields.SchemaField({
|
||||
label: new fields.StringField({ initial: "Combattant" }),
|
||||
niveau: new fields.NumberField({ initial: 0, integer: true }),
|
||||
rang: new fields.NumberField({ initial: 0, integer: true }),
|
||||
pp: new fields.NumberField({ initial: 0, integer: true })
|
||||
}),
|
||||
erudit: new fields.SchemaField({
|
||||
label: new fields.StringField({ initial: "Erudit" }),
|
||||
niveau: new fields.NumberField({ initial: 0, integer: true }),
|
||||
rang: new fields.NumberField({ initial: 0, integer: true }),
|
||||
pp: new fields.NumberField({ initial: 0, integer: true })
|
||||
}),
|
||||
gentleman: new fields.SchemaField({
|
||||
label: new fields.StringField({ initial: "Gentleman" }),
|
||||
niveau: new fields.NumberField({ initial: 0, integer: true }),
|
||||
rang: new fields.NumberField({ initial: 0, integer: true }),
|
||||
pp: new fields.NumberField({ initial: 0, integer: true })
|
||||
}),
|
||||
roublard: new fields.SchemaField({
|
||||
label: new fields.StringField({ initial: "Roublard" }),
|
||||
niveau: new fields.NumberField({ initial: 0, integer: true }),
|
||||
rang: new fields.NumberField({ initial: 0, integer: true }),
|
||||
pp: new fields.NumberField({ initial: 0, integer: true })
|
||||
}),
|
||||
savant: new fields.SchemaField({
|
||||
label: new fields.StringField({ initial: "Savant" }),
|
||||
niveau: new fields.NumberField({ initial: 0, integer: true }),
|
||||
rang: new fields.NumberField({ initial: 0, integer: true }),
|
||||
pp: new fields.NumberField({ initial: 0, integer: true })
|
||||
})
|
||||
}),
|
||||
magie: new fields.SchemaField({
|
||||
pointsame: new fields.SchemaField({
|
||||
value: new fields.NumberField({ initial: 0, integer: true }),
|
||||
max: new fields.NumberField({ initial: 0, integer: true })
|
||||
})
|
||||
}),
|
||||
experience: new fields.SchemaField({
|
||||
value: new fields.NumberField({ initial: 0, integer: true }),
|
||||
pourtricher: new fields.NumberField({ initial: 0, integer: true })
|
||||
}),
|
||||
combat: new fields.SchemaField({
|
||||
esquive: new fields.SchemaField({
|
||||
masquee: new fields.NumberField({ initial: 0, integer: true }),
|
||||
demasquee: new fields.NumberField({ initial: 0, integer: true })
|
||||
}),
|
||||
parade: new fields.SchemaField({
|
||||
masquee: new fields.NumberField({ initial: 0, integer: true }),
|
||||
demasquee: new fields.NumberField({ initial: 0, integer: true }),
|
||||
value: new fields.NumberField({ initial: 0, integer: true })
|
||||
}),
|
||||
resistancephysique: new fields.SchemaField({
|
||||
value: new fields.NumberField({ initial: 0, integer: true })
|
||||
}),
|
||||
resistancepsychique: new fields.SchemaField({
|
||||
value: new fields.NumberField({ initial: 0, integer: true })
|
||||
}),
|
||||
protection: new fields.SchemaField({
|
||||
value: new fields.NumberField({ initial: 0, integer: true })
|
||||
}),
|
||||
effetssecondaires: new fields.StringField({ initial: "" }),
|
||||
dissimulation: new fields.SchemaField({
|
||||
value: new fields.NumberField({ initial: 0, integer: true })
|
||||
}),
|
||||
initiative: new fields.SchemaField({
|
||||
masquee: new fields.NumberField({ initial: 0, integer: true }),
|
||||
demasquee: new fields.NumberField({ initial: 0, integer: true })
|
||||
}),
|
||||
corpsacorps: new fields.SchemaField({
|
||||
masquee: new fields.NumberField({ initial: 0, integer: true }),
|
||||
demasquee: new fields.NumberField({ initial: 0, integer: true })
|
||||
}),
|
||||
tir: new fields.SchemaField({
|
||||
masquee: new fields.NumberField({ initial: 0, integer: true }),
|
||||
demasquee: new fields.NumberField({ initial: 0, integer: true })
|
||||
})
|
||||
})
|
||||
};
|
||||
}
|
||||
}
|
||||
10
modules/models/pnj.mjs
Normal file
@@ -0,0 +1,10 @@
|
||||
/**
|
||||
* Data model pour les PNJ
|
||||
* Utilise le même schéma que les personnages
|
||||
*/
|
||||
import PersonnageDataModel from './personnage.mjs';
|
||||
|
||||
export default class PnjDataModel extends PersonnageDataModel {
|
||||
// Les PNJ utilisent exactement le même schéma que les personnages
|
||||
// On hérite simplement de PersonnageDataModel
|
||||
}
|
||||
29
modules/models/pouvoir.mjs
Normal file
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* Data model pour les pouvoirs
|
||||
*/
|
||||
export default class PouvoirDataModel extends foundry.abstract.TypeDataModel {
|
||||
static defineSchema() {
|
||||
const fields = foundry.data.fields;
|
||||
return {
|
||||
pouvoirtype: new fields.StringField({ initial: "" }),
|
||||
masquetype: new fields.StringField({ initial: "" }),
|
||||
niveau: new fields.StringField({ initial: "" }),
|
||||
activation: new fields.StringField({ initial: "" }),
|
||||
istest: new fields.BooleanField({ initial: false }),
|
||||
feeriemasque: new fields.StringField({ initial: "feerie" }),
|
||||
zoneffet: new fields.StringField({ initial: "" }),
|
||||
testautre: new fields.StringField({ initial: "" }),
|
||||
carac: new fields.StringField({ initial: "pre" }),
|
||||
duree: new fields.StringField({ initial: "" }),
|
||||
cibles: new fields.StringField({ initial: "" }),
|
||||
effet: new fields.StringField({ initial: "" }),
|
||||
portee: new fields.StringField({ initial: "" }),
|
||||
resistance: new fields.StringField({ initial: "" }),
|
||||
resistanceautre: new fields.StringField({ initial: "" }),
|
||||
pointsusagecourant: new fields.NumberField({ initial: -1, integer: true }),
|
||||
isvirulence: new fields.BooleanField({ initial: false }),
|
||||
virulence: new fields.StringField({ initial: "" }),
|
||||
description: new fields.HTMLField({ initial: "" })
|
||||
};
|
||||
}
|
||||
}
|
||||
12
modules/models/profil.mjs
Normal file
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* Data model pour les profils
|
||||
*/
|
||||
export default class ProfilDataModel extends foundry.abstract.TypeDataModel {
|
||||
static defineSchema() {
|
||||
const fields = foundry.data.fields;
|
||||
return {
|
||||
profiltype: new fields.StringField({ initial: "majeur" }),
|
||||
description: new fields.HTMLField({ initial: "" })
|
||||
};
|
||||
}
|
||||
}
|
||||
20
modules/models/protection.mjs
Normal file
@@ -0,0 +1,20 @@
|
||||
/**
|
||||
* Data model pour les protections
|
||||
*/
|
||||
export default class ProtectionDataModel extends foundry.abstract.TypeDataModel {
|
||||
static defineSchema() {
|
||||
const fields = foundry.data.fields;
|
||||
return {
|
||||
description: new fields.HTMLField({ initial: "" }),
|
||||
rarete: new fields.NumberField({ initial: 0, integer: true }),
|
||||
quantite: new fields.NumberField({ initial: 0, integer: true }),
|
||||
prix: new fields.NumberField({ initial: 0, integer: true }),
|
||||
equipped: new fields.BooleanField({ initial: false }),
|
||||
points: new fields.NumberField({ initial: 0, integer: true }),
|
||||
protectiontype: new fields.StringField({ initial: "" }),
|
||||
effetsecondaire: new fields.StringField({ initial: "" }),
|
||||
malusagilite: new fields.NumberField({ initial: 0, integer: true }),
|
||||
dissimulation: new fields.StringField({ initial: "" })
|
||||
};
|
||||
}
|
||||
}
|
||||
27
modules/models/sort.mjs
Normal file
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* Data model pour les sorts
|
||||
*/
|
||||
export default class SortDataModel extends foundry.abstract.TypeDataModel {
|
||||
static defineSchema() {
|
||||
const fields = foundry.data.fields;
|
||||
return {
|
||||
niveau: new fields.StringField({ initial: "1" }),
|
||||
rang: new fields.StringField({ initial: "1" }),
|
||||
competence: new fields.StringField({ initial: "Druidisme" }),
|
||||
carac1: new fields.StringField({ initial: "esp" }),
|
||||
carac2: new fields.StringField({ initial: "none" }),
|
||||
sdspecial: new fields.StringField({ initial: "" }),
|
||||
duree: new fields.StringField({ initial: "" }),
|
||||
portee: new fields.StringField({ initial: "" }),
|
||||
concentration: new fields.StringField({ initial: "" }),
|
||||
informatif: new fields.BooleanField({ initial: false }),
|
||||
texteinformatif: new fields.StringField({ initial: "" }),
|
||||
critique: new fields.StringField({ initial: "" }),
|
||||
ingredients: new fields.StringField({ initial: "" }),
|
||||
resistance: new fields.StringField({ initial: "" }),
|
||||
coutactivation: new fields.StringField({ initial: "" }),
|
||||
souffle: new fields.StringField({ initial: "" }),
|
||||
description: new fields.HTMLField({ initial: "" })
|
||||
};
|
||||
}
|
||||
}
|
||||
4971
package-lock.json
generated
Normal file
16
package.json
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"name": "fvtt-les-heritiers",
|
||||
"version": "13.0.7",
|
||||
"description": "Les Héritiers RPG for FoundryVTT (French)",
|
||||
"scripts": {
|
||||
"build": "gulp build",
|
||||
"watch": "gulp watch"
|
||||
},
|
||||
"author": "Uberwald/LeRatierBretonnien",
|
||||
"license": "SEE LICENSE IN LICENCE.txt",
|
||||
"devDependencies": {
|
||||
"gulp": "^4.0.2",
|
||||
"gulp-less": "^5.0.0",
|
||||
"gulp-sourcemaps": "^3.0.0"
|
||||
}
|
||||
}
|
||||
31
packs/archetypes-fees.db
Normal file
BIN
packs/archetypes-fees/000179.ldb
Normal file
0
packs/archetypes-fees/000314.log
Normal file
1
packs/archetypes-fees/CURRENT
Normal file
@@ -0,0 +1 @@
|
||||
MANIFEST-000312
|
||||
0
packs/archetypes-fees/LOCK
Normal file
8
packs/archetypes-fees/LOG
Normal file
@@ -0,0 +1,8 @@
|
||||
2026/01/10-22:45:42.655574 7fd463fff6c0 Recovering log #310
|
||||
2026/01/10-22:45:42.666271 7fd463fff6c0 Delete type=0 #310
|
||||
2026/01/10-22:45:42.666327 7fd463fff6c0 Delete type=3 #308
|
||||
2026/01/10-22:49:23.124832 7fd4627fc6c0 Level-0 table #315: started
|
||||
2026/01/10-22:49:23.124856 7fd4627fc6c0 Level-0 table #315: 0 bytes OK
|
||||
2026/01/10-22:49:23.132096 7fd4627fc6c0 Delete type=0 #313
|
||||
2026/01/10-22:49:23.151717 7fd4627fc6c0 Manual compaction at level-0 from '!items!1NhJH4IJpxsGmLB8' @ 72057594037927935 : 1 .. '!items!y1yOenfAJTsb3r6e' @ 0 : 0; will stop at (end)
|
||||
2026/01/10-22:49:23.151765 7fd4627fc6c0 Manual compaction at level-1 from '!items!1NhJH4IJpxsGmLB8' @ 72057594037927935 : 1 .. '!items!y1yOenfAJTsb3r6e' @ 0 : 0; will stop at (end)
|
||||
8
packs/archetypes-fees/LOG.old
Normal file
@@ -0,0 +1,8 @@
|
||||
2026/01/10-17:13:21.499762 7fd462ffd6c0 Recovering log #306
|
||||
2026/01/10-17:13:21.510831 7fd462ffd6c0 Delete type=3 #304
|
||||
2026/01/10-17:13:21.511011 7fd462ffd6c0 Delete type=0 #306
|
||||
2026/01/10-22:35:10.944218 7fd4627fc6c0 Level-0 table #311: started
|
||||
2026/01/10-22:35:10.944249 7fd4627fc6c0 Level-0 table #311: 0 bytes OK
|
||||
2026/01/10-22:35:10.950116 7fd4627fc6c0 Delete type=0 #309
|
||||
2026/01/10-22:35:10.963623 7fd4627fc6c0 Manual compaction at level-0 from '!items!1NhJH4IJpxsGmLB8' @ 72057594037927935 : 1 .. '!items!y1yOenfAJTsb3r6e' @ 0 : 0; will stop at (end)
|
||||
2026/01/10-22:35:10.963688 7fd4627fc6c0 Manual compaction at level-1 from '!items!1NhJH4IJpxsGmLB8' @ 72057594037927935 : 1 .. '!items!y1yOenfAJTsb3r6e' @ 0 : 0; will stop at (end)
|
||||
BIN
packs/archetypes-fees/MANIFEST-000312
Normal file
BIN
packs/armes-et-protection/000179.ldb
Normal file
0
packs/armes-et-protection/000314.log
Normal file
1
packs/armes-et-protection/CURRENT
Normal file
@@ -0,0 +1 @@
|
||||
MANIFEST-000312
|
||||
0
packs/armes-et-protection/LOCK
Normal file
8
packs/armes-et-protection/LOG
Normal file
@@ -0,0 +1,8 @@
|
||||
2026/01/10-22:45:42.682529 7fd478fff6c0 Recovering log #310
|
||||
2026/01/10-22:45:42.692944 7fd478fff6c0 Delete type=0 #310
|
||||
2026/01/10-22:45:42.692994 7fd478fff6c0 Delete type=3 #308
|
||||
2026/01/10-22:49:23.158820 7fd4627fc6c0 Level-0 table #315: started
|
||||
2026/01/10-22:49:23.158855 7fd4627fc6c0 Level-0 table #315: 0 bytes OK
|
||||
2026/01/10-22:49:23.164806 7fd4627fc6c0 Delete type=0 #313
|
||||
2026/01/10-22:49:23.178845 7fd4627fc6c0 Manual compaction at level-0 from '!items!1ETVaPBtjDtzelK1' @ 72057594037927935 : 1 .. '!items!zbsVCsWxRzkzzG1N' @ 0 : 0; will stop at (end)
|
||||
2026/01/10-22:49:23.178875 7fd4627fc6c0 Manual compaction at level-1 from '!items!1ETVaPBtjDtzelK1' @ 72057594037927935 : 1 .. '!items!zbsVCsWxRzkzzG1N' @ 0 : 0; will stop at (end)
|
||||
8
packs/armes-et-protection/LOG.old
Normal file
@@ -0,0 +1,8 @@
|
||||
2026/01/10-17:13:21.528896 7fd478fff6c0 Recovering log #306
|
||||
2026/01/10-17:13:21.539812 7fd478fff6c0 Delete type=3 #304
|
||||
2026/01/10-17:13:21.539902 7fd478fff6c0 Delete type=0 #306
|
||||
2026/01/10-22:35:10.963778 7fd4627fc6c0 Level-0 table #311: started
|
||||
2026/01/10-22:35:10.963855 7fd4627fc6c0 Level-0 table #311: 0 bytes OK
|
||||
2026/01/10-22:35:10.969945 7fd4627fc6c0 Delete type=0 #309
|
||||
2026/01/10-22:35:10.989919 7fd4627fc6c0 Manual compaction at level-0 from '!items!1ETVaPBtjDtzelK1' @ 72057594037927935 : 1 .. '!items!zbsVCsWxRzkzzG1N' @ 0 : 0; will stop at (end)
|
||||
2026/01/10-22:35:10.989967 7fd4627fc6c0 Manual compaction at level-1 from '!items!1ETVaPBtjDtzelK1' @ 72057594037927935 : 1 .. '!items!zbsVCsWxRzkzzG1N' @ 0 : 0; will stop at (end)
|
||||
BIN
packs/armes-et-protection/MANIFEST-000312
Normal file
@@ -5,9 +5,12 @@
|
||||
{"name":"Serviteur débrouillard","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p>Le phénix a un serviteur humain dévoué et pragmatique, qui est pour lui un Allié et un Féal, c’est-à-dire qu’il est au courant de l’existence des fées et respecte la Loi du Silence. Il l’aide à interagir avec le monde moderne. Ses Caractéristiques sont celles d’un Larbin (4 Caractéristiques et Compétences au rang 3, 4 Caractéristiques et Compétences au rang 2).</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.OoFLDb6WBg1Pk0DW"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.5","coreVersion":"10.291","createdTime":1672492110830,"modifiedTime":1672495712298,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"1Lz2lIvwM1vLC1cm"}
|
||||
{"name":"Amie des fées modernes","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p>La fée électricité a tenté de chercher un soutien dans la société féérique en se regroupant avec d’autres fées modernes. Elle a au moins une fée moderne pour Contact dans chaque grande cour féérique. La nature et l’identité du Contact sont laissées à la discrétion du Docte.</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.ftdAB57s05c00RRq"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.5","coreVersion":"10.291","createdTime":1672493252829,"modifiedTime":1672495504712,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"1yZBaCs4H3Zl812E"}
|
||||
{"name":"Sixième sens architectural","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p>La gargouille étant souvent gardienne d’un lieu ancien pourvu de passages secrets ou cachettes diverses, elle a un don pour repérer les anomalies dans un édifice pouvant en receler. Elle bénéficie d’un bonus de + 2 aux tests d’Observation + Perception lorsqu’il s’agit de repérer un passage secret ou une cachette dans les murs.</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.dQCu1V3smDAfOHWc"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.5","coreVersion":"10.291","createdTime":1672494629074,"modifiedTime":1672495719095,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"2RwrRpVXNENJOSWI"}
|
||||
{"name":"Terrier (femme-Renarde)","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p>La femme-renarde possède un terrier dans lequel elle peut se réfugier, se cacher ou se reposer sous forme de renard. Il se situe en général à égale distance de l’habitation de son ami humain et de son autel particulier, formant un triangle équilatéral.</p>"},"effects":[],"flags":{"core":{"sourceId":"Compendium.fvtt-les-heritiers.archetypes-fees.VR4AJOG0aMb9eozC"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.13","coreVersion":"10.291","createdTime":1678168073691,"modifiedTime":1678209846478,"lastModifiedBy":"xGnwWyEbO2k89UsP"},"ownership":{"default":0,"3jSVOAZZNxArxD7h":3,"xGnwWyEbO2k89UsP":3},"folder":null,"sort":0,"_id":"2T3NFtgfnMvqa3hD"}
|
||||
{"name":"Marginal innocent","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p>Votre marginalité au sein de la société féérique est un atout : vous pouvez jouer la carte de la neutralité, de la candeur, de l’ignorance dans un monde rempli d’intrigues. Vous bénéficiez ainsi de l’indulgence des fées expérimentées en cas de faute ou de manquement à l’étiquette. Cela se traduit par un bonus de + 1 aux tests de Classe ou Séduction lorsqu’un comportement ou une réponse est attendue et aux tests de Comédie pour jouer les naïfs auprès d’une fée.</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.aQbYoIF6Xc1lrWVG"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.5","coreVersion":"10.291","createdTime":1672487719210,"modifiedTime":1672495683999,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"3eG0HwHaeMNzYkcc"}
|
||||
{"name":"Arme fétiche (Orc)","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p>L’orc a une arme favorite à laquelle il a donné un nom, qu’il a fait améliorer spécialement pour lui. Elle occasionne un point de dégât supplémentaire que sa valeur normale et le rassure en situation de stress : il a un bonus de + 1 aux tests impliquant son Sang-froid quand il l’a en main.</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.GTgHRk3TXtFoqvbh"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.5","coreVersion":"10.291","createdTime":1672491735251,"modifiedTime":1672495580392,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"3vSBTIWmXFlnBNny"}
|
||||
{"name":"Bibliothèque portative","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p>Peu le savent mais le corps du jiangshi est entièrement couvert de calligraphies, à l’exception de la tête, des pieds et des mains. Le texte change en fonction de l’oeuvre que veut consulter le jiangshi. Son score de Féériedétermine la puissance de cet atout :</p>\n<ul>\n<li>4 : il peut convoquer n’importe quel livre lu auparavant ;</li>\n<li>5 : n’importe quel livre dont il connaît au moins le titre ;</li>\n<li>6 : n’importe quel livre classique ;</li>\n<li>7 : il peut convoquer même des livres rares et mystérieux dans des langues qu’il connaît ;</li>\n<li>8 : n’importe quel livre dont il a connaissance et dans n’importe quelle langue sauf les livres interdits par le Docte.</li>\n</ul>"},"effects":[],"flags":{"core":{"sourceId":"Compendium.fvtt-les-heritiers.archetypes-fees.McMF1LCQZKJ83DHy"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.13","coreVersion":"10.291","createdTime":1678182643916,"modifiedTime":1678209794676,"lastModifiedBy":"xGnwWyEbO2k89UsP"},"ownership":{"default":0,"3jSVOAZZNxArxD7h":3,"xGnwWyEbO2k89UsP":3},"folder":null,"sort":0,"_id":"46Yh4tMaXiwdaWg4"}
|
||||
{"name":"Spécialités typiques (Golem)","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p><em>Maîtrise de soi </em>dans Fortitude ; <em>Stratégie </em>dans Art de la guerre.</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.kodlSepaG2eaTZvF"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.5","coreVersion":"10.291","createdTime":1672494835443,"modifiedTime":1672495740222,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"4Hgz7ujM95ymzDGN"}
|
||||
{"name":"Cri de mauvais augure","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p>La femme-renarde peut émettre des cris qui ressemblent à des pleurs de nouveau-né ou à des rires étranges et effrayants.<br>Ceux qui l’entendent, sans la voir, ont un malus de - 2 s’ils échouent à un test de Fortitude + Sang- Froid contre un de SD : 10 + Féérie de la renarde.</p>"},"effects":[],"flags":{"core":{"sourceId":"Compendium.fvtt-les-heritiers.archetypes-fees.S8NVs72lCSXC1pf9"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.13","coreVersion":"10.291","createdTime":1678168112273,"modifiedTime":1678209812848,"lastModifiedBy":"xGnwWyEbO2k89UsP"},"ownership":{"default":0,"3jSVOAZZNxArxD7h":3,"xGnwWyEbO2k89UsP":3},"folder":null,"sort":0,"_id":"4PDx4uTOOSGWoIs9"}
|
||||
{"name":"Spécialités typiques (Elfe)","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p><em>Culture générale</em> dans Culture ; <em>Beau monde</em> dans Entregent.</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.uSzPFcj4rNCF7gu3"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.5","coreVersion":"10.291","createdTime":1672488802012,"modifiedTime":1672495728227,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"4QYr9WdzwJIvZ3uk"}
|
||||
{"name":"Accointance gobeline","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p>L’orc est un stratège et il a besoin de matériel lourd et de munitions. Il a pour contact un gang de gobelins qui le ravitaille de bonne grâce sans demander de prix exorbitants.</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.nveIbdnjHddMBFV1"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.5","coreVersion":"10.291","createdTime":1672491623868,"modifiedTime":1672495453830,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"4iMqREX0CUfJkVkC"}
|
||||
{"name":"Voix enjôleuse","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p>L’ondine a naturellement une voix enjôleuse, qui lui fait bénéficier d’un bonus de + 2 pour toutes les tentatives de séduction utilisant la voix.</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.BbdYNWgypsDBlQVY"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.5","coreVersion":"10.291","createdTime":1672491531317,"modifiedTime":1672495776382,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"4pUV636cKiTa4MGn"}
|
||||
@@ -30,6 +33,7 @@
|
||||
{"name":"Identité discrète","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p>La fée électricité a préféré masquer son identité féérique pour éviter les ennuis dans les cours les plus traditionalistes. Elle possède donc une identité féérique fictive et se fait passer pour un autre type de créature. Elle est connue sous cette fausse identité et peut fournir des preuves de sa fausse nature.</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.aPNjuLpttqwcB99h"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.5","coreVersion":"10.291","createdTime":1672493290353,"modifiedTime":1672495649767,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"BMcAZ2NJ9yN2181U"}
|
||||
{"name":"Spécialités typiques (Phenix)","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p><em>Armes blanches légères</em> dans Mêlée ; <em>Histoire </em>dans Culture.</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.EgHkdud1dg3QH5US"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.5","coreVersion":"10.291","createdTime":1672492233776,"modifiedTime":1672495755569,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"C12DLUxVOyQYUTmo"}
|
||||
{"name":"Bonimenteur","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p>La jovialité naturelle du farfadet lui permet de bénéficier d’un bonus de + 1 pour convaincre quelqu’un de sa bonne foi (même quand il ment) et de + 2 quand il incite quelqu’un à boire.</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.pBexZVPenA0cYeGd"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.5","coreVersion":"10.291","createdTime":1672488872051,"modifiedTime":1672495585328,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"C7pTX0RXqkZ5CKht"}
|
||||
{"name":"Ami taoïste","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p>Le Jiangshi possède un ami taoïste qui lui apporte son aide, notamment dans toutes ses démarches vis-à-vis des prêtres. C’est lui qui fournit le talisman qu’il porte sur le front et qui lui permet de résister à sa peur face à son ami.</p>"},"effects":[],"flags":{"core":{"sourceId":"Compendium.fvtt-les-heritiers.archetypes-fees.0OK5ToXTr0iDT17L"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.13","coreVersion":"10.291","createdTime":1678182753059,"modifiedTime":1678209768266,"lastModifiedBy":"xGnwWyEbO2k89UsP"},"ownership":{"default":0,"3jSVOAZZNxArxD7h":3,"xGnwWyEbO2k89UsP":3},"folder":null,"sort":0,"_id":"CHmT5laJvhQmbbW7"}
|
||||
{"name":"Ami ogre gourmet","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p>Le meilleur ami du troll est un ogre ventripotent qui tient un restaurant pas très loin de chez lui, lui fait des prix et est toujours prêt à lui rendre service. Il compte comme un Contact mais n’est pas un Combattant : il ne prendra pas de risque quand il apporte son aide. </p>"},"effects":[],"flags":{"core":{"sourceId":"Item.tSk4XU8Kgc8iTTGY"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.5","coreVersion":"10.291","createdTime":1672492793071,"modifiedTime":1672495501695,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"ClyV1NhOS6yZRj3n"}
|
||||
{"name":"Spécialités typiques (Vampyr)","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p><em>Étiquette </em>dans Classe ; <em>Commander </em>dans Autorité.</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.vaDq6J2PrYCaywQM"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.5","coreVersion":"10.291","createdTime":1672493107316,"modifiedTime":1672495767339,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"Dbvq0i2lfuwqde8I"}
|
||||
{"name":"Contacts nobles","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p>Le gobelin travaille pour la Monarchie et ravitaille quelques nobles en armes et autres marchandises illicites. Il commence le jeu avec trois Contacts possédant le titre de Chevalier, Marquis ou Comte.</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.ub54zB7UxTvo1nwy"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.5","coreVersion":"10.291","createdTime":1672489314028,"modifiedTime":1672495607049,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"Ds5yCifYPlqqelkL"}
|
||||
@@ -39,7 +43,11 @@
|
||||
{"name":"Amis dans la pègre","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p>Le smog s’est lié au milieu du crime et notamment à un petit gang de quatre malfaiteurs qui sont ses amis, c’est-à-dire un peu plus que des Contacts, mais un peu moins que des Alliés. Ils pourront éventuellement l’aider pour un combat s’ils y trouvent aussi leur compte. Ce sont des Larbins.</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.BhIPMAgARq7YwFGh"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.5","coreVersion":"10.291","createdTime":1672495240715,"modifiedTime":1672495508264,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"GFnBctn1HdETOzps"}
|
||||
{"name":"Spécialités typiques (Gobelin)","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p><em>Embuscade </em>dans Art de la Guerre et <em>Pièges*</em> dans Larcin.</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.tbif2IrH4qqYAsh9"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.5","coreVersion":"10.291","createdTime":1672489364700,"modifiedTime":1672495739155,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"GJrxhCCB9SJJdTkZ"}
|
||||
{"name":"Vilain petit canard de la noblesse féérique","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p>Vous êtes le rejeton d’une grande famille (Frédon, Aldébard, Carwent, Baudemagu, Bermellon, Glaucos, Golderon, Gwendelon, Gwestiniog) mais avez été la déception de vos parents quand vous êtes né sous l’apparence d’un simple humain. Cette noblesse pourra cependant vous ouvrir des portes. Vous portez un des noms féériques ci-dessus gratuitement, ce qui réduit votre désavantage « Infériorité politique » à un malus de - 1 au lieu de - 2. Vous êtes au fait des relations diplomatiques entre les grandes familles féériques et bénéficiez de la Spécialité gratuite Politique pour Entregent et d’un rang gratuit en Héraldique (Compétence futile).</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.h2RBGHTnP3cQX18o"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.5","coreVersion":"10.291","createdTime":1672487678018,"modifiedTime":1672495774249,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"GaPJJgjz3lnlq9pf"}
|
||||
{"name":"Confesseur de comptoir","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p>Le goupil arrive aisément à inspirer la confiance et les confidences. Il bénéfice d’un bonus de + 1 aux relations sociales avec des inconnus dans le but d’obtenir des informations.</p>"},"effects":[],"flags":{"core":{"sourceId":"Compendium.fvtt-les-heritiers.archetypes-fees.znPCEPy6LnN5FjEd"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.13","coreVersion":"10.291","createdTime":1678205709626,"modifiedTime":1678209804049,"lastModifiedBy":"xGnwWyEbO2k89UsP"},"ownership":{"default":0,"3jSVOAZZNxArxD7h":3,"xGnwWyEbO2k89UsP":3},"folder":null,"sort":0,"_id":"GtDiGNUn4qpc4abO"}
|
||||
{"name":"Ami des amateurs d’art japonais","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p>Le kappa fréquente des collectionneurs d’estampes japonaises qu’il conseille et renseigne sur la signification de ces images dans la culture japonaise. Il a ainsi 3 contacts gratuits qui sont de riches personnes influentes à Paris et ailleurs en Europe. </p>"},"effects":[],"flags":{"core":{"sourceId":"Compendium.fvtt-les-heritiers.archetypes-fees.oi3X1YErheYnR7qt"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.13","coreVersion":"10.291","createdTime":1678207504322,"modifiedTime":1678209764536,"lastModifiedBy":"xGnwWyEbO2k89UsP"},"ownership":{"default":0,"3jSVOAZZNxArxD7h":3,"xGnwWyEbO2k89UsP":3},"folder":null,"sort":0,"_id":"HTFITTN7TYHGSnsO"}
|
||||
{"name":"Impeccable","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p>La succube a la capacité inexplicable d’être toujours impeccable. Elle n’est jamais couverte de poussière ou de boue, jamais en sueur, jamais écarlate… Elle reste toujours parfaite, quel que soit le traitement qu’on lui a fait subir.</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.6vammHjsOtG7Lwyh"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.5","coreVersion":"10.291","createdTime":1672492409381,"modifiedTime":1672495653285,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"Hb2MZ2vSmB8IIVE8"}
|
||||
{"name":"Domaine rural","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p>L’épouvantail dispose d’une propriété à la campagne discrète mais vaste et comportant plusieurs champs qui lui rapportent un revenu supplémentaire (Fortune + 1).</p>"},"effects":[],"flags":{"core":{"sourceId":"Compendium.fvtt-les-heritiers.archetypes-fees.e56Mfpj4YjV82bb7"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.13","coreVersion":"10.291","createdTime":1678183621879,"modifiedTime":1678209819603,"lastModifiedBy":"xGnwWyEbO2k89UsP"},"ownership":{"default":0,"3jSVOAZZNxArxD7h":3,"xGnwWyEbO2k89UsP":3},"folder":null,"sort":0,"_id":"HigYEf94VNUd1AQN"}
|
||||
{"name":"Autel particulier","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p>La femme-renarde bénéficie d’une sorte de chapelle où des humains lui apportent des offrandes sous forme d’argent, d’objets ou de nourriture volés à d’autres dans l’espoir de bénéficier de sa protection. Ainsi, elle bénéficie de + 1 en Fortune.</p>"},"effects":[],"flags":{"core":{"sourceId":"Compendium.fvtt-les-heritiers.archetypes-fees.lAc2CSCWZNwIMQVl"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.13","coreVersion":"10.291","createdTime":1678168039077,"modifiedTime":1678209791253,"lastModifiedBy":"xGnwWyEbO2k89UsP"},"ownership":{"default":0,"3jSVOAZZNxArxD7h":3,"xGnwWyEbO2k89UsP":3},"folder":null,"sort":0,"_id":"HsXtxVpBGRKFPyiB"}
|
||||
{"name":"Chaudron de pièces d’or","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p>Le farfadet a une réserve de pièces d’or rutilantes qu’il garde dans un petit chaudron (ou équivalent), qui lui octroie + 1 en Fortune.</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.nJEgx9SU7qe97ys2"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.5","coreVersion":"10.291","createdTime":1672488944850,"modifiedTime":1672495595326,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"I5Vwjn903YkTKAgY"}
|
||||
{"name":"Ami d’un(e) ondin(e)","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p>Le korrigan est brillant et aime les gens brillants. Il connaît un(e) ondin(e) qui est pour lui un(e) Allié(e) (5 en Esprit et Prestance, 3 et 2 dans les autres Caractéristiques pour un total de 26 ; Compétences de Gentleman au rang 4 et d’Érudit ainsi que Mouvement au rang 3 ; 2 Compétences futiles au rang 5 le reste au rang 0) et à qui il aime rendre visite.</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.1pXqNqKRKu4UBoYs"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.5","coreVersion":"10.291","createdTime":1672489405984,"modifiedTime":1672495470311,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"I5WSS6c6Ko1p6msd"}
|
||||
{"name":"Empathique","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p>Le sylve sent instinctivement l’état d’esprit des gens. Il bénéficie naturellement d’un bonus de + 1 à ses tests de Sensibilité vis-à-vis des humains ou des fées pour déterminer leurs sentiments.</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.YDfRn8oFLhXnrTEE"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.5","coreVersion":"10.291","createdTime":1672492620709,"modifiedTime":1672495619881,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"IHiLppPJxcru8v3u"}
|
||||
@@ -51,7 +59,9 @@
|
||||
{"name":"Beau parleur","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p>Le korrigan bénéficie d’un bonus de + 1 à toute action visant à briller en société.</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.v5uhHzY9lzgTrjJv"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.5","coreVersion":"10.291","createdTime":1672489436976,"modifiedTime":1672495581583,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"Jb2z0jBykMd3zwwl"}
|
||||
{"name":"Méfiance naturelle","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p>L’ondine ne se laisse pas charmer par les belles paroles des flatteurs et des manipulateurs et bénéficie de ce fait d’un bonus de + 1 à tous ses tests de Fortitude pour résister aux séductions et manipulations et à ses tests de Sensibilité pour détecter le mensonge.</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.h5hXDe4M07KJbMVR"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.5","coreVersion":"10.291","createdTime":1672491490363,"modifiedTime":1672495685273,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"K4nz3BSvDSOlmkk2"}
|
||||
{"name":"Imitateur génial","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p>Le gremelin est capable d’imiter toutes sortes de cris d’animaux à la perfection.</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.ILjbu6I8TeQL2yUP"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.5","coreVersion":"10.291","createdTime":1672494948181,"modifiedTime":1672495652341,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"KcBt0wxIZFDUAkaO"}
|
||||
{"name":"Enfant de la Cinquième saison","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p>En réussissant un test de Sensibilité + PER SD 13, la Créature reconnaîtra un autre Enfant de la Cinquième saison ou sentira si une Cinquième saison se prépare ou a lieu à 500 km à la ronde).</p>"},"effects":[],"flags":{"core":{"sourceId":"Compendium.fvtt-les-heritiers.archetypes-fees.dzljf3lg4x9YIJV6"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.13","coreVersion":"10.291","createdTime":1678206364486,"modifiedTime":1678209824615,"lastModifiedBy":"xGnwWyEbO2k89UsP"},"ownership":{"default":0,"3jSVOAZZNxArxD7h":3,"xGnwWyEbO2k89UsP":3},"folder":null,"sort":0,"_id":"KhqIgOUJeIvpAfit"}
|
||||
{"name":"Fragilité trompeuse","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p>Aussi bien sous forme démasquée que masquée, l’elfe cultive une apparence fragile, ce qui aboutit souvent à ce qu’on ne se méfie pas de lui, alors qu’il peut être très vif quand il s’agit de passer à l’attaque. Il bénéficie d’un bonus de + 1 supplémentaire à ses tests d’Initiative quand il s’attend à attaquer (ce bonus ne fonctionne pas quand l’elfe est surpris ou lui-même attaqué). </p>"},"effects":[],"flags":{"core":{"sourceId":"Item.p737Wmxv9VAuS7bw"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.5","coreVersion":"10.291","createdTime":1672488711202,"modifiedTime":1672495637141,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"KpmDxXWtWqRpbUFL"}
|
||||
{"name":"Terrier (Goupil)","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p>Le goupil possède un terrier dans lequel il peut se réfugier, se cacher ou se reposer sous forme de renard. Il se situe en général en forêt, relativement loin de toute habitation humaine.</p>"},"effects":[],"flags":{"core":{"sourceId":"Compendium.fvtt-les-heritiers.archetypes-fees.FBp8fPsU9DqdcxqY"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.13","coreVersion":"10.291","createdTime":1678205827861,"modifiedTime":1678209848908,"lastModifiedBy":"xGnwWyEbO2k89UsP"},"ownership":{"default":0,"3jSVOAZZNxArxD7h":3,"xGnwWyEbO2k89UsP":3},"folder":null,"sort":0,"_id":"LTucz480larvkHWP"}
|
||||
{"name":"Affinité occulte","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p>Le gnome bénéficie d’une sensibilité particulière avec les esprits et ce qui est secret. Il bénéficie d’un bonus de + 1 à tous ses tests d’Occultisme (en plus de toute Spécialité).</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.U5XHabXqdw10C2le"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.5","coreVersion":"10.291","createdTime":1672489057509,"modifiedTime":1672495456914,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"MoXZGvdYfnVmvGWk"}
|
||||
{"name":"Camarade ogre","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p>Le loup-garou est lié à un ogre qui est son ami (Contact) et qui s’arrange pour faire taire les témoins gênants et faire disparaître les cadavres, lorsque le loup-garou s’est trop laissé aller, en les mangeant. En échange, le loup-garou rend des services à ce camarade en lui fournissant de la nourriture ou autre.</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.Okhb3EM8qoyzCf2I"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.5","coreVersion":"10.291","createdTime":1672489956813,"modifiedTime":1672495588837,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"MyxYOG2tbt8h47d8"}
|
||||
{"name":"Rapière ancestrale","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p>Le phénix possède une rapière de qualité exceptionnelle qui a appartenu à ses lointains ancêtres et porte leurs armoiries. Contrairement aux rapières ordinaires, elle octroie un bonus de + 1 à l’Initiative, occasionne 1 point de dégât supplémentaire par rapport à ce type d’arme et lui confère un certain prestige social (à la discrétion du Docte). La perdre ou la briser ne serait pas bon pour son Sang-froid…</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.SkVBR9ZrVLlcG9Cn"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.5","coreVersion":"10.291","createdTime":1672492072218,"modifiedTime":1672495706289,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"P3tTcUImTXQjhpGy"}
|
||||
@@ -66,7 +76,9 @@
|
||||
{"name":"Domaine naturel","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p>Le sylve, bien qu’il puisse parfaitement habiter en ville, possède un vaste domaine naturel qui lui confère + 1 en Fortune. Ce havre de paix dissimule en général une petite habitation discrète. Ce peut être une colline, un bois, un vallon…</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.ozsGiBNhYMUxSQbb"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.5","coreVersion":"10.291","createdTime":1672492592427,"modifiedTime":1672495614752,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"T8SduUgWGmUHAjCX"}
|
||||
{"name":"Sens de la surprise","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p>Le gremelin a un don pour surprendre les gens. Il bénéficie d’un bonus de + 1 à ses tests pour surprendre quelqu’un (Discrétion pour s’approcher, attaquer, faire sursauter par un cri inattendu, lancer un sujet de conversation déconcertant, etc.). </p>"},"effects":[],"flags":{"core":{"sourceId":"Item.pSJE3dXyHeUfWgKG"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.5","coreVersion":"10.291","createdTime":1672494975907,"modifiedTime":1672495711277,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"TBqeVVeNwG7yUzjq"}
|
||||
{"name":"Empathie avec les chauves-souris","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p>Comme avec le Pouvoir<em> Communication animale</em>, la gargouille est capable de communiquer avec les chauves-souris, et seulement avec elles.</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.fJGSARKFXaUlinKz"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.5","coreVersion":"10.291","createdTime":1672494537858,"modifiedTime":1672495618446,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"Tq1hA1Vq9hGL5Kxf"}
|
||||
{"name":"Analyste comportemental","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p>L’épouvantail est passé maître dans l’art de décrypter les signes corporels d’autrui et bénéficie d’un + 1 à tous ses tests pour ce faire.</p>"},"effects":[],"flags":{"core":{"sourceId":"Compendium.fvtt-les-heritiers.archetypes-fees.mI6G4kQGHg0WODUF"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.13","coreVersion":"10.291","createdTime":1678183553187,"modifiedTime":1678209787569,"lastModifiedBy":"xGnwWyEbO2k89UsP"},"ownership":{"default":0,"3jSVOAZZNxArxD7h":3,"xGnwWyEbO2k89UsP":3},"folder":null,"sort":0,"_id":"U1rMcd3pIoiNKcM0"}
|
||||
{"name":"Malice","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p>Le bastet fait souvent preuve d’Ingéniosité pour se tirer de situations délicates. Il bénéficie d’un bonus de + 1 pour tous ses tests d’Habiletés (<em>Ingéniosité</em>).</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.avZ6An9vHcnd5LvB"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.5","coreVersion":"10.291","createdTime":1672488237046,"modifiedTime":1672495680645,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"U7XD515wnumqYHyq"}
|
||||
{"name":"Produit des perles","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p>Assez régulièrement, le Serpent blanc, au lieu de pondre des oeufs, est capable de pondre des perles, ce qui lui confère un bonus continuel de + 2 en Fortune.</p>"},"effects":[],"flags":{"core":{"sourceId":"Compendium.fvtt-les-heritiers.archetypes-fees.1lg0YmplwKma3fk7"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.13","coreVersion":"10.291","createdTime":1678181916474,"modifiedTime":1678209842890,"lastModifiedBy":"xGnwWyEbO2k89UsP"},"ownership":{"default":0,"3jSVOAZZNxArxD7h":3,"xGnwWyEbO2k89UsP":3},"folder":null,"sort":0,"_id":"UOmuIPKe3ukTfwuI"}
|
||||
{"name":"Spécialités typiques (Ogre)","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p><em>Intimider </em>dans Autorité ; <em>Connaissance de la Pègre</em> dans Monde du Crime.</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.J5PxSwi25t7HoAHG"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.5","coreVersion":"10.291","createdTime":1672491273981,"modifiedTime":1672495748713,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"Ur4a3QtD5vPXVSsd"}
|
||||
{"name":"Ami des chats","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p>Le bastet peut communiquer avec les chats, et seulement avec les chats, comme s’il possédait le Pouvoir Communication animale. S’il prend un peu de temps pour sympathiser avec eux dans un lieu (village, quartier d’une ville), il peut facilement en convaincre un certain nombre de s’organiser pour lui donner des informations à la manière d’un réseau d’espions à l’intellect cependant limité. </p>"},"effects":[],"flags":{"core":{"sourceId":"Item.zSJVW7l5hrG5hjgM"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.5","coreVersion":"10.291","createdTime":1672488121017,"modifiedTime":1672495473660,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"VDmgnMI4SAGJaVzn"}
|
||||
{"name":"Ami gargouille ou gnome","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p>Du fait de leur commune passion pour les vieilles pierres, la gargouille, le gnome et le golem font bon ménage. Le golem a un Contact gargouille ou gnome qui est prêt à lui rendre service, dans la mesure de ses moyens mais pas au point de se battre pour lui.</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.yphuPllxDNMkttpc"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.5","coreVersion":"10.291","createdTime":1672494733069,"modifiedTime":1672495497334,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"WBnD8yq6oSl6EhjX"}
|
||||
@@ -80,12 +92,14 @@
|
||||
{"name":"Enthousiasme des foules","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p>L’ange est un meneur d’homme et peut soulever les foules pour les amener à combattre l’injustice. Lorsqu’il s’exprime en public sur une grande cause et veut convaincre le plus grand nombre, il dispose d’un bonus de + 2 à tous ses tests de Rhétorique.</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.3SGeoVIuzkHBrQKS"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.5","coreVersion":"10.291","createdTime":1672487961062,"modifiedTime":1672495623465,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"YaxuqYnkDKzQmm63"}
|
||||
{"name":"Arme fétiche (Ange)","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p>L’ange, pour punir, possède une arme qu’il a fait améliorer chez un fouinard ou un gnome ou autre armurier talentueux et qu’il a fait orner par un grand joaillier. Cette arme lui procure + 1 point de dégâts et + 1 aux interactions sociales où elle est apparente et à même d’impressionner l’interlocuteur.</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.UnAHDFRuyAaeZLGQ"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.5","coreVersion":"10.291","createdTime":1672487865901,"modifiedTime":1672495578990,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"aDzVxLKJrMrK1SdJ"}
|
||||
{"name":"Ami des comédiens","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p>Pour parfaire son art de la dissimulation et de la comédie, le protys a fréquenté beaucoup de comédiens. Il connaît au moins un comédien dans la plupart des grandes villes d’Europe. Ces Contacts sont laissés à la discrétion du Docte.</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.i09AGQA4YrzU1z38"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.5","coreVersion":"10.291","createdTime":1672495060702,"modifiedTime":1672495474818,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"b3lT92p0x7KQpAIg"}
|
||||
{"name":"Fausse monnaie","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p>Si le Jiangshi voit comme une hérésie le fait de falsifier des livres, il n’a aucun scrupule à fabriquer de la fausse monnaie dont il se sert quand le besoin s’en fait sentir. Il faut réussir un test de Monde du crime Spécialité Faussaire SD 15 pour découvrir la supercherie.</p>"},"effects":[],"flags":{"core":{"sourceId":"Compendium.fvtt-les-heritiers.archetypes-fees.NtnmqoB9MLPONnh0"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.13","coreVersion":"10.291","createdTime":1678182548773,"modifiedTime":1678209830702,"lastModifiedBy":"xGnwWyEbO2k89UsP"},"ownership":{"default":0,"3jSVOAZZNxArxD7h":3,"xGnwWyEbO2k89UsP":3},"folder":null,"sort":0,"_id":"beoemn7tCf339gp2"}
|
||||
{"name":"Ami des druides","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p>Les druides ont un a priori positif envers l’elfe. Ce dernier bénéficie d’un bonus de + 2 dans toutes ses interactions sociales avec eux.</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.0G6SLiQ5ohIuTWhZ"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.5","coreVersion":"10.291","createdTime":1672488312844,"modifiedTime":1672495475892,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"cKptrIvUDI3e5OXG"}
|
||||
{"name":"Ami des médecins juifs (Golem)","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p>Le golem, dans sa quête des origines, a beaucoup fréquenté de médecins juifs et en connaît au moins un dans chaque grande ville d’Europe (à la discrétion du Docte).</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.G2HLXFmQANKSiXJj"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.5","coreVersion":"10.291","createdTime":1672494705023,"modifiedTime":1672495480907,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"d52mcww5W7FEB2Tf"}
|
||||
{"name":"Prince des ivrognes","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p>Quel que soit le débit de boisson visité, le farfadet y trouve toujours un Contact qu’il connaît ou avec lequel il fait rapi\u0002dement connaissance, qui aura des confidences à faire ou pourra être un soutien lors d’une bonne bagarre de bistro. Il bénéficie d’un bonus de + 2 aux tests de Comédie pour faire croire qu’il est ivre et aux tests de Ressort + Constitution pour résister aux effets de l’alcool.</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.KjaqrPbeUgwrHFIp"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.5","coreVersion":"10.291","createdTime":1672488845654,"modifiedTime":1672495695562,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"eYbQodG2XhtzoDQs"}
|
||||
{"name":"Quartier bienveillant","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p>Le sylve passe son temps à soulager les souffrances morales ou physiques de ses voisins, qui le considèrent comme un saint homme (quand il vit quelque part suffisamment longtemps, à la discrétion du Docte). Ils sont bienveillants envers lui et ne refuseront pas de lui rendre service.</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.n7qmAhCDIze0vU32"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.5","coreVersion":"10.291","createdTime":1672492651544,"modifiedTime":1672495705331,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"eYo2oD9g5UFHN1lx"}
|
||||
{"name":"Une conquête dans chaque port","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p>Le léporide a beaucoup voyagé et beaucoup séduit. Il a au moins une conquête (amante ou amant) dans chaque grande ville d’Europe (à la discrétion du Docte) prête à lui rendre service ou à partager des informations avec lui.</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.aMnrHNCtu84ZFbtZ"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.5","coreVersion":"10.291","createdTime":1672489679124,"modifiedTime":1672495773058,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"ftyACBMZMBhVcah1"}
|
||||
{"name":"Amie des mélomanes","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p>L’ondine chante si bien qu’elle s’attire, partout où elle se produit, l’admiration des mélomanes. Elle possède un admirateur dans chaque grande ville d’Europe qui est pour elle un Contact. Son identité est laissée à l’appréciation du Docte.</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.vhAfvdMBPKU3I2im"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.5","coreVersion":"10.291","createdTime":1672491354039,"modifiedTime":1672495507292,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"g9m8KJJUjxq8CjAe"}
|
||||
{"name":"Campagnard","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p>La campagne n’a pas de secret pour l’épouvantail. Il bénéficie d’un bonus de + 1 à ses tests nécessitant de s’y repérer, y trouver des informations ou des ressources.</p>"},"effects":[],"flags":{"core":{"sourceId":"Compendium.fvtt-les-heritiers.archetypes-fees.C9fVTNGNjtO4Dowc"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.13","coreVersion":"10.291","createdTime":1678183587948,"modifiedTime":1678209797938,"lastModifiedBy":"xGnwWyEbO2k89UsP"},"ownership":{"default":0,"3jSVOAZZNxArxD7h":3,"xGnwWyEbO2k89UsP":3},"folder":null,"sort":0,"_id":"gMpG4K1TqjRBAPVZ"}
|
||||
{"name":"Spécialités typiques (Ondine)","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p><em>Appâts </em>dans Séduction et <em>Intuition</em> dans Sensibilité.</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.q4kPkEog4TYG0EgE"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.5","coreVersion":"10.291","createdTime":1672491571016,"modifiedTime":1672495751119,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"gVh6q3jpllu7DHrk"}
|
||||
{"name":"Amie des artistes","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p>Par sa beauté, la fleur de métal fascine les artistes aussi bien féériques qu’humains, c’est une muse pour eux. Elle bénéficie d’un bonus de + 2 pour toute interaction sociale avec les artistes.</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.OivRdTfDc0zjge9p"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.5","coreVersion":"10.291","createdTime":1672493567199,"modifiedTime":1672495503796,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"gyAAgeQvztG6duJw"}
|
||||
{"name":"Féal","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p>Vous êtes le Féal d’une fée noble ayant le titre de Chevalier d’une petite ville. Cette fée vous protège et garantit que vous respectez la Loi du Silence. À vous de déterminer si vous êtes un serviteur fidèle, un ami, un parent de cette fée, ou un mélange de tout cela. </p>"},"effects":[],"flags":{"core":{"sourceId":"Item.l24kHGRhhYxRcNIO"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.5","coreVersion":"10.291","createdTime":1672487644711,"modifiedTime":1672495628350,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"gyBpkbXfE289mcg2"}
|
||||
@@ -93,14 +107,17 @@
|
||||
{"name":"Gardien du trésor","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p>Le korrigan bénéficie d’un bonus de + 2 à toutes ses actions visant à protéger ou récupérer son trésor. </p>"},"effects":[],"flags":{"core":{"sourceId":"Item.ZovSuhpZNXtQW6bf"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.5","coreVersion":"10.291","createdTime":1672489510711,"modifiedTime":1672495640460,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"iEVgSFjqOkBNDT1m"}
|
||||
{"name":"Laboratoire secret (Fouinard)","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p>Le fouinard possède un laboratoire vaste mais discret (cave, grenier…) près de chez lui, dans lequel il travaille à ses inventions les plus folles.</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.cHoBRaPcXH9L1Fot"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.5","coreVersion":"10.291","createdTime":1672494400926,"modifiedTime":1672495677808,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"iNHEH1KxdTzZEOzA"}
|
||||
{"name":"Titre de noblesse","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p>Le phénix fait partie d’une ancienne famille aristocratique. Il est Chevalier sans terre lié à un Baron à déterminer avec lequel il aura un lien remontant à plusieurs générations. Ce titre est cumulable avec un autre titre éventuellement acheté à la création de personnage.</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.t9nFRmA9Me1l3Lgj"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.5","coreVersion":"10.291","createdTime":1672492164589,"modifiedTime":1672495770271,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"jGaluZKMaeopQ1vq"}
|
||||
{"name":"Domaine aquatique","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p>Le kappa a construit une demeure au fond d’un fleuve ou en mer au pied d’une falaise où il peut se cacher. Il a installé tout autour des pièges pour les poissons et les crustacés qu’il peut vendre à des restaurants ou sur les marchés.</p>"},"effects":[],"flags":{"core":{"sourceId":"Compendium.fvtt-les-heritiers.archetypes-fees.w7XhvfNhibpyhTC0"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.13","coreVersion":"10.291","createdTime":1678207580171,"modifiedTime":1678209817329,"lastModifiedBy":"xGnwWyEbO2k89UsP"},"ownership":{"default":0,"3jSVOAZZNxArxD7h":3,"xGnwWyEbO2k89UsP":3},"folder":null,"sort":0,"_id":"lnRUm1sZ31BRg3l3"}
|
||||
{"name":"Ami(e) anarchiste","type":"capacitenaturelle","img":"systems/fvtt-les-heritiers/assets/icons/natural_capacity.webp","system":{"pouvoirtype":"actif","activation":"","cibles":"","effet":"","duree":"","portee":"","resistance":"aucune","resistanceautre":"","isvirulence":false,"virulence":"","description":"<p>Le gobelin a un(e) ami(e) humain(e) anarchiste, qui compte comme un Contact dans ce milieu et lui confectionne des bombes ou grenades d’Allumage facile sans trop poser de questions.</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.ptGao5iFRgCbP3LP"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.5","coreVersion":"10.291","createdTime":1672489335015,"modifiedTime":1672495502913,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"lunIDsjFzDk7dtzy"}
|
||||
{"name":"Ancrage humain fort","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p>Ayant peu voire pas du tout fréquenté la société féérique, vous avez passé la plupart de votre vie parmi les humains. Vous avez une Spécialité gratuite en Entregent pour un type de milieu humain de votre choix (Beau monde, Bourgeoisie, Prolétariat, etc.) ainsi que 3 Points de Personnage supplémentaires pour choisir des Contacts humains dans les tableaux de Profils.</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.dS7bFbjWrSev9FmK"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.5","coreVersion":"10.291","createdTime":1672487759416,"modifiedTime":1672495509656,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"lxquAddcvZEWfTlr"}
|
||||
{"name":"Odeur irrésistible","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p>L’odeur naturelle de la succube est un parfum en lui-même, et un parfum inimi\u0002table. Elle bénéficie d’un bonus de + 1 à toutes ses tentatives de Séduction.</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.H2uIPERbwkmIuoCI"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.5","coreVersion":"10.291","createdTime":1672492447363,"modifiedTime":1672495693692,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"lz9TgxnO0YfWjtZI"}
|
||||
{"name":"Prouesses sexuelles","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p>Le léporide est un amant inoubliable. Toute personne y ayant goûté ne demande qu’à recommencer et est prête à lui rendre service pour ce faire.</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.gXQ4eg3F71kdRw8G"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.5","coreVersion":"10.291","createdTime":1672489650879,"modifiedTime":1672495703706,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"ma0WKyjDNo0UT1GA"}
|
||||
{"name":"Argot gobelin (Orc)","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p>L’orc connaît l’argot gobelin, que seuls les gobelins parlent. Il peut l’enseigner à ses compagnons. Nul ne pourra comprendre leur conversation sans connaître cet argot. Toutefois, c’est une langue particulièrement disgracieuse. Cet atout ne compte pas parmi les langues octroyées par un rang en Culture.</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.iOgyk4iqaTy84hqM"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.5","coreVersion":"10.291","createdTime":1672491680139,"modifiedTime":1672495535540,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"meEVWCsoKjj6cH8M"}
|
||||
{"name":"Amant(e) indéfectible","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p>La succube est l’amante d’une personne humaine, folle d’elle, fortunée (Fortune = 6), connaissant sa véritable nature, et prête à tout pour elle, même à risquer sa vie. On la considère comme un(e) Allié(e). Ses Caractéristiques sont celles d’un Larbin (4 Caractéristiques et Compétences au rang 3, 4 Caractéristiques et Compétences au rang 2). La succube devra toutefois donner de sa personne.</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.Hi47ZCeo2A2yKhuT"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.5","coreVersion":"10.291","createdTime":1672492338399,"modifiedTime":1672495466750,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"mfBc0t24GEEmHFUf"}
|
||||
{"name":"Ami des trouvères","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p>Le goupil possède trois Contacts dans le monde des poètes, musiciens ou comédiens itinérants. Il est conseillé de les créer conjointement avec le Docte, à la création du personnage ou durant un interlude entre deux scénarios.</p>"},"effects":[],"flags":{"core":{"sourceId":"Compendium.fvtt-les-heritiers.archetypes-fees.Buc4K5qFNu2OF1QH"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.13","coreVersion":"10.291","createdTime":1678205773042,"modifiedTime":1678209766253,"lastModifiedBy":"xGnwWyEbO2k89UsP"},"ownership":{"default":0,"3jSVOAZZNxArxD7h":3,"xGnwWyEbO2k89UsP":3},"folder":null,"sort":0,"_id":"mj3erG6B9EaCRquN"}
|
||||
{"name":"Ami des animaux","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p>Le sylve passe son temps à recueillir des animaux et à les soigner. En échange, ils peuvent accepter de lui rendre service. Le sylve a besoin du Pouvoir de <em>Communication animale</em> pour communiquer avec eux. À chaque début de scénario, il peut avoir recueilli trois animaux, dans la limite du vraisemblable (pas d’ours en ville et pas de tigre en Allemagne).</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.mtjDX08FHrSTkzp5"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.5","coreVersion":"10.291","createdTime":1672492542503,"modifiedTime":1672495471497,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"nVcdez2cROEGKRzx"}
|
||||
{"name":"Ami des opprimés","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p>L’ange a déjà aidé plusieurs opprimés dans sa vie. Ces hommes et ces femmes lui sont éternellement reconnaissants. Une fois par scénario, l’ange peut s’inventer parmi ces opprimés un Contact prêt à lui rendre service. Le joueur incarnant l’ange doit préciser les circonstances dans lesquelles il a aidé ce Contact.</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.Tgi4jAQV2f9vE8Jl"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.5","coreVersion":"10.291","createdTime":1672487841462,"modifiedTime":1672495483616,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"nYTwmI3New5Yt8HM"}
|
||||
{"name":"Amie d'un humain","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p>la femme-renarde a jeté son dévolu sur un humain ou une humaine, que leur relation soit amoureuse ou non. Cette personne devient un Allié prêt à lui rendre service. Ses Caractéristiques sont celles d’un Larbin (4 Caractéristiques et Compétences au rang 3, 4 Caractéristiques et Compétences au rang 2).</p>"},"effects":[],"flags":{"core":{"sourceId":"Compendium.fvtt-les-heritiers.archetypes-fees.v84MaQ3eYTTFC0jA"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.13","coreVersion":"10.291","createdTime":1678167998675,"modifiedTime":1678209770522,"lastModifiedBy":"xGnwWyEbO2k89UsP"},"ownership":{"default":0,"3jSVOAZZNxArxD7h":3,"xGnwWyEbO2k89UsP":3},"folder":null,"sort":0,"_id":"oHF8OZ7SIjCkpMFq"}
|
||||
{"name":"Murmure à l’oreille des chevaux","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p>Le farfadet a une affinité spéciale avec les chevaux qui lui permet de communiquer avec eux comme s’il disposait du Pouvoir <em>Communication animale</em>. Il bénéficie en outre d’un bonus de + 1 à tous ses tests de Conduite (<em>Équitation*</em> et <em>Conduite d’attelage*</em>).</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.gLqyE951QrUs8wKd"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.5","coreVersion":"10.291","createdTime":1672488900688,"modifiedTime":1672495689605,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"oKtJTStz8QARm8Ig"}
|
||||
{"name":"Empoisonneur","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p>Le gremelin est habile à repérer et dissimuler l’usage du poison et bénéficie d’un bonus de + 1 à tout test pour ce faire.</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.qNdDaxzuLwyCfjfm"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.5","coreVersion":"10.291","createdTime":1672494916767,"modifiedTime":1672495620771,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"oVN3AIyjg4PjH5G6"}
|
||||
{"name":"Spécialités typiques (Gremelin)","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p><em>Déguisement</em> dans Comédie ; <em>Déplacement silencieux </em>dans Discrétion.</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.c87mbeWbNyebMs5c"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.5","coreVersion":"10.291","createdTime":1672495013409,"modifiedTime":1672495741406,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"oZtDTTejYjzClSjg"}
|
||||
@@ -108,10 +125,12 @@
|
||||
{"name":"Fourrure soyeuse","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p>Le léporide est doté d’une fourrure si douce et agréable qu’il bénéficie, lorsqu’il est démasqué, d’un bonus de + 2 à toute tentative de Séduction.</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.WcSi7zcA4voSzxEQ"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.5","coreVersion":"10.291","createdTime":1672489620558,"modifiedTime":1672495631225,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"pN9x7pDFMNhMh3zl"}
|
||||
{"name":"Ami des scientifiques","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p>Le fouinard a pour Contact un scientifique de haut vol dans chaque capitale d’Europe (à la discrétion du Docte), qui l’aidera volontiers mais pas pour se battre. </p>"},"effects":[],"flags":{"core":{"sourceId":"Item.ShdMQly9QhomPjrm"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.5","coreVersion":"10.291","createdTime":1672494343646,"modifiedTime":1672495490565,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"pZovIGFderf3bEkg"}
|
||||
{"name":"Admirateurs","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p>Partout où elle passe, la succube rassemble toujours autour d’elle un groupe d’admirateurs serviables (à la discrétion du Docte).</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.3124FNGOZQhMmZAt"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.5","coreVersion":"10.291","createdTime":1672492304392,"modifiedTime":1672495455488,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"qE9rzRe1cjkESkOh"}
|
||||
{"name":"Empathie avec les poissons et tortues","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p>Comme avec le Pouvoir Communication animale, le kappa est capable de communiquer avec les poissons et tortues.</p>"},"effects":[],"flags":{"core":{"sourceId":"Compendium.fvtt-les-heritiers.archetypes-fees.s9XjrE6FfB5XgCap"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.13","coreVersion":"10.291","createdTime":1678207547197,"modifiedTime":1678209822624,"lastModifiedBy":"xGnwWyEbO2k89UsP"},"ownership":{"default":0,"3jSVOAZZNxArxD7h":3,"xGnwWyEbO2k89UsP":3},"folder":null,"sort":0,"_id":"qQiTX2fvF37yFSYK"}
|
||||
{"name":"Familier chauve-souris","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p>La gargouille est particulièrement liée avec une chauve-souris qui la suit partout et est prête à lui rendre service, à espionner pour elle (la nuit seulement), etc. En échange, la gargouille doit s’occuper d’elle et bien la traiter. La gargouille doit posséder <em>Empathie avec les chauves-souris</em> pour pouvoir donner efficacement des ordres à son familier.</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.exHDSgSZ7KsphdCh"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.5","coreVersion":"10.291","createdTime":1672494577430,"modifiedTime":1672495626991,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"qb4FDvDHIBjwTPvN"}
|
||||
{"name":"Ami des tueurs à gages","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p>L’ogre a pour Contacts trois tueurs à gages féériques qui font régulièrement appel à lui pour faire disparaître les cadavres. Il peut ainsi se nourrir à l’œil en toute discrétion tout en entretenant un réseau de relations.</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.EP2N2cb73lYK2koo"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.5","coreVersion":"10.291","createdTime":1672491140659,"modifiedTime":1672495495128,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"r7D4lyiO0Av7Oiei"}
|
||||
{"name":"Spécialités typiques (Gnome)","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p><em>Maîtrise de soi</em> dans Fortitude et<em> Explosifs*</em> dans Habiletés.</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.VfvuXMwKV9q8cHGt"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.5","coreVersion":"10.291","createdTime":1672489201169,"modifiedTime":1672495738081,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"rS1houUJyRV4tfhx"}
|
||||
{"name":"Spécialités typiques (Fée Electricité)","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p> <em>Investigation </em>dans Observation ; <em>Esquive</em> dans Mouvement.</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.JQ9NZxjgAyR9JOZD"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.5","coreVersion":"10.291","createdTime":1672493402402,"modifiedTime":1672495730857,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"rWL8AHQNMFc0KJsy"}
|
||||
{"name":"Cerf-volant","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p>Le Jiangshi a la Spécialité Cerf-volant* dans Mouvement avec laquelle il maîtrise un grand cerf-volant lui permettant de flotter dans les airs pour observer les environs et couvrir de petites distances. Pour ce faire, il doit réussir un test de Mouvement (Cerf-volant) + Agilité contre un SD 12 modifié selon la météo.</p>"},"effects":[],"flags":{"core":{"sourceId":"Compendium.fvtt-les-heritiers.archetypes-fees.3OB4E9NBTn11x9lU"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.13","coreVersion":"10.291","createdTime":1678182595972,"modifiedTime":1678209802214,"lastModifiedBy":"xGnwWyEbO2k89UsP"},"ownership":{"default":0,"3jSVOAZZNxArxD7h":3,"xGnwWyEbO2k89UsP":3},"folder":null,"sort":0,"_id":"raZQWoyObz2FrsIv"}
|
||||
{"name":"Aisance souterraine","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p>Le gnome bénéficie d’un bonus de + 2 aux tests de Survie ou de Spéléologie pour s’orienter et se nourrir sous terre.</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.Kae60UbSL3C1C871"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.5","coreVersion":"10.291","createdTime":1672489104784,"modifiedTime":1672495460077,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"s341yqM7IBx9ZswY"}
|
||||
{"name":"Laboratoire secret (Smog)","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p>Le smog possède un vaste laboratoire dans lequel il dispose de produits chimiques divers lui permettant d’utiliser correctement ses talents. Ce laboratoire est un lieu secret et reculé.</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.Hol8T2KF751bxKz5"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.5","coreVersion":"10.291","createdTime":1672495347485,"modifiedTime":1672495678769,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"s7k97nTHI7SHSFYJ"}
|
||||
{"name":"Collection d’armes anciennes","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p>Le golem possède toute une collection d’armes blanches légères et lourdes et d’armes de trait anciennes. On considère qu’il a au moins un exemplaire de chaque arme blanche et arme de trait du tableau des armes et même d’autres plus exotiques issues des quatre coins du monde.</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.rEuDeCusq3fgpzeY"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.5","coreVersion":"10.291","createdTime":1672494790391,"modifiedTime":1672495597601,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"tEu39ZX0ildEAZT9"}
|
||||
@@ -120,10 +139,14 @@
|
||||
{"name":"Domestique dévoué","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p>L’ange a un domestique qu’il traite particulièrement bien par rapport aux canons de la Belle Époque. Ce serviteur ne peut être de nature féérique. C’est un Allié pour l’ange et un Féal, c’est-à-dire un humain au courant de l’existence des fées et respectant scrupuleusement la Loi du Silence. Ses Caractéristiques sont celles d’un Larbin (4 Caractéristiques et Compétences au rang 3, 4 Caractéristiques et Compétences au rang 2).</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.aHhwCPgTtOsCsqkD"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.5","coreVersion":"10.291","createdTime":1672487926484,"modifiedTime":1672495615726,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"uWzqhQV79m8zPsUK"}
|
||||
{"name":"Âme damnée","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p>Le vampyr possède un serviteur féérique (espèce à choisir) qui le sert presque aveuglément, allant jusqu’à mettre sa vie en danger pour lui. Sa fidélité est totale. Ses Caractéristiques sont celles d’un Larbin (4 Caractéristiques et Compétences au rang 3, 4 Caractéristiques et Compétences au rang 2).</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.iHV8Ju4XOIrjUAEX"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.5","coreVersion":"10.291","createdTime":1672492940376,"modifiedTime":1672495469024,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"vXSrx4nFUOP9GWsT"}
|
||||
{"name":"Spécialités typiques (Ange)","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p><em>Premiers soins</em> dans Médecine et <em>Persuader </em>dans Rhétorique.</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.JWTcT8Zo7Rqrea1d"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.5","coreVersion":"10.291","createdTime":1672488080808,"modifiedTime":1672495723439,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"w4z4OXCI4j4RzRbM"}
|
||||
{"name":"Feux d’artifices","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p>Le serpent blanc est capable de fabriquer ses propres feux d’artifices, dessinant les formes qu’il souhaite. Ils ne peuvent servir au combat sauf pour faire diversion ou déstabiliser et permettent d’éclairer, distraire, amuser.</p>"},"effects":[],"flags":{"core":{"sourceId":"Compendium.fvtt-les-heritiers.archetypes-fees.lDOutzJz5NYDVfEM"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.13","coreVersion":"10.291","createdTime":1678182029808,"modifiedTime":1678209833220,"lastModifiedBy":"xGnwWyEbO2k89UsP"},"ownership":{"default":0,"3jSVOAZZNxArxD7h":3,"xGnwWyEbO2k89UsP":3},"folder":null,"sort":0,"_id":"wzlvH9BuMJB81ZVu"}
|
||||
{"name":"Ami des acteurs","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p>Le serpent blanc fréquente ou finance une troupe de comédiens qui sont prêts à jouer pour lui quelques scènes qu’il leur demandera. Cependant, ils refusent de se mettre en danger physiquement. Le nombre de comédiens disponible dépend du niveau de Féérie.</p>"},"effects":[],"flags":{"core":{"sourceId":"Compendium.fvtt-les-heritiers.archetypes-fees.fozYK60HP32s0dYS"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.13","coreVersion":"10.291","createdTime":1678181951711,"modifiedTime":1678209762538,"lastModifiedBy":"xGnwWyEbO2k89UsP"},"ownership":{"default":0,"3jSVOAZZNxArxD7h":3,"xGnwWyEbO2k89UsP":3},"folder":null,"sort":0,"_id":"x6Bkuwg3NEFssfGu"}
|
||||
{"name":"Caverne secrète","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p>Le golem possède un lopin de terre abritant une gigantesque caverne aménagée pour ses besoins en une dizaine de pièces très confortablement meublées. L’existence de cette caverne n’est connue que de lui seul.</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.dCfAYhO9V2Gtyr2S"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.5","coreVersion":"10.291","createdTime":1672494761270,"modifiedTime":1672495592791,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"xl85zd9B6u8hcYKT"}
|
||||
{"name":"Spécialités typiques (Farfadet)","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p><em>Connaissance de la pègre</em> dans Monde du crime ; <em>Mensonge </em>dans Comédie.</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.MZxARAFXMOoNMHSA"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.5","coreVersion":"10.291","createdTime":1672488973144,"modifiedTime":1672495729275,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"xlCJ6ckVMeGBXn6x"}
|
||||
{"name":"Spécialités typiques (Loup-Garou)","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p><em>Course </em>dans Mouvement ; <em>Sciences occultes</em> dans Occultisme.</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.iEeCT8SlDozqiIdE"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.5","coreVersion":"10.291","createdTime":1672490056004,"modifiedTime":1672495747562,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"yV2x8OZjWqiG1t9K"}
|
||||
{"name":"Centre de l’attention","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p>Le kappa est une fée extrêmement rare en dehors du Japon, dont les êtres féeriques sont un mystère pour la plupart des cours féeriques, même en Chine. Tout Kappa sera bien accueilli chez les fées désireuses d’en savoir plus sur le Japon et ses fées si particulières. Le kappa bénéficie d’un avantage similaire à la préférence elfique partout où il passe.</p>"},"effects":[],"flags":{"core":{"sourceId":"Compendium.fvtt-les-heritiers.archetypes-fees.vXsFypvoE9HdLk56"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.13","coreVersion":"10.291","createdTime":1678207446275,"modifiedTime":1678209800057,"lastModifiedBy":"xGnwWyEbO2k89UsP"},"ownership":{"default":0,"3jSVOAZZNxArxD7h":3,"xGnwWyEbO2k89UsP":3},"folder":null,"sort":0,"_id":"yhgb3Do2lyRecpVs"}
|
||||
{"name":"Spécialités typiques (Protys)","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p><em>Persuader </em>dans Rhétorique ; <em>Déguisement </em>dans Comédie.</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.E7yy4vcEI36CJUfN"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.5","coreVersion":"10.291","createdTime":1672495194905,"modifiedTime":1672495757504,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"yn88WoeEoY969EPa"}
|
||||
{"name":"Plus d’un tour dans son sac","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p>Une fois par partie et pour une scène, le goupil peut avoir un score de 2 dans une compétence qu’il ne maîtrise pas.</p>"},"effects":[],"flags":{"core":{"sourceId":"Compendium.fvtt-les-heritiers.archetypes-fees.5KaleLBz3wlFJC0E"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.13","coreVersion":"10.291","createdTime":1678205744023,"modifiedTime":1678209840331,"lastModifiedBy":"xGnwWyEbO2k89UsP"},"ownership":{"default":0,"3jSVOAZZNxArxD7h":3,"xGnwWyEbO2k89UsP":3},"folder":null,"sort":0,"_id":"zACylqTBWMtPrJGv"}
|
||||
{"name":"Grand seigneur","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p>Le loup-garou possède un grand domaine sur lequel se trouve une forêt. Lui et sa meute peuvent ainsi s’ébrouer à leur guise dans ce domaine dont les habitants ne sont pas toujours rassurés mais savent qu’il faut se barricader chez soi les nuits de pleine lune. Ce grand domaine lui procure un bonus de + 1 en Fortune.</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.OQLhKpL6iSRgKYb8"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.5","coreVersion":"10.291","createdTime":1672490019201,"modifiedTime":1672495644408,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"zZGydhQZFhTr9MPO"}
|
||||
{"name":"Spécialités typiques (Orc)","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p>Un type d’armes au choix (<em>Armes blanches légères</em>, <em>Armes à feu lourdes*</em>, etc.) dans Mêlée ou Tir ; <em>Courage </em>dans Ressort.</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.c6YMW21t1ABYFWwd"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.5","coreVersion":"10.291","createdTime":1672491905135,"modifiedTime":1672495753507,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"zaKFtgrnaKI0HDAj"}
|
||||
{"name":"Miroir de Narcisse","type":"atoutfeerique","img":"systems/fvtt-les-heritiers/assets/icons/fairy_atout.webp","system":{"description":"<p>En passant un quart d’heure seul à contempler son reflet et à méditer sous forme démasquée dans un endroit calme, le protys peut regagner un point d’Esprit ou de Sang-froid temporaire ou un point d’usage (voir, sur ce sujet, le chapitre consacré aux Pouvoirs féériques, p. 208). </p>"},"effects":[],"flags":{"core":{"sourceId":"Item.8qOn0BQk5bnebNKR"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.5","coreVersion":"10.291","createdTime":1672495127616,"modifiedTime":1672495687701,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"zvmem5J3nUh5vOMM"}
|
||||
|
||||
BIN
packs/atouts-feeriques/000179.ldb
Normal file
0
packs/atouts-feeriques/000314.log
Normal file
1
packs/atouts-feeriques/CURRENT
Normal file
@@ -0,0 +1 @@
|
||||
MANIFEST-000312
|
||||
0
packs/atouts-feeriques/LOCK
Normal file
8
packs/atouts-feeriques/LOG
Normal file
@@ -0,0 +1,8 @@
|
||||
2026/01/10-22:45:42.628622 7fd462ffd6c0 Recovering log #310
|
||||
2026/01/10-22:45:42.638290 7fd462ffd6c0 Delete type=0 #310
|
||||
2026/01/10-22:45:42.638350 7fd462ffd6c0 Delete type=3 #308
|
||||
2026/01/10-22:49:23.132234 7fd4627fc6c0 Level-0 table #315: started
|
||||
2026/01/10-22:49:23.132271 7fd4627fc6c0 Level-0 table #315: 0 bytes OK
|
||||
2026/01/10-22:49:23.138271 7fd4627fc6c0 Delete type=0 #313
|
||||
2026/01/10-22:49:23.151732 7fd4627fc6c0 Manual compaction at level-0 from '!items!0fPXtA5LkLgG8uDj' @ 72057594037927935 : 1 .. '!items!zvtBlG6KCIn0oCVk' @ 0 : 0; will stop at (end)
|
||||
2026/01/10-22:49:23.151774 7fd4627fc6c0 Manual compaction at level-1 from '!items!0fPXtA5LkLgG8uDj' @ 72057594037927935 : 1 .. '!items!zvtBlG6KCIn0oCVk' @ 0 : 0; will stop at (end)
|
||||
8
packs/atouts-feeriques/LOG.old
Normal file
@@ -0,0 +1,8 @@
|
||||
2026/01/10-17:13:21.469395 7fd4637fe6c0 Recovering log #306
|
||||
2026/01/10-17:13:21.479611 7fd4637fe6c0 Delete type=3 #304
|
||||
2026/01/10-17:13:21.479687 7fd4637fe6c0 Delete type=0 #306
|
||||
2026/01/10-22:35:10.919012 7fd4627fc6c0 Level-0 table #311: started
|
||||
2026/01/10-22:35:10.919040 7fd4627fc6c0 Level-0 table #311: 0 bytes OK
|
||||
2026/01/10-22:35:10.924958 7fd4627fc6c0 Delete type=0 #309
|
||||
2026/01/10-22:35:10.937993 7fd4627fc6c0 Manual compaction at level-0 from '!items!0fPXtA5LkLgG8uDj' @ 72057594037927935 : 1 .. '!items!zvtBlG6KCIn0oCVk' @ 0 : 0; will stop at (end)
|
||||
2026/01/10-22:35:10.938027 7fd4627fc6c0 Manual compaction at level-1 from '!items!0fPXtA5LkLgG8uDj' @ 72057594037927935 : 1 .. '!items!zvtBlG6KCIn0oCVk' @ 0 : 0; will stop at (end)
|
||||
BIN
packs/atouts-feeriques/MANIFEST-000312
Normal file
@@ -1,27 +1,37 @@
|
||||
{"name":"Faux-fuyant","type":"avantage","img":"systems/fvtt-les-heritiers/assets/icons/advantage.webp","system":{"description":"<p>le goupil sait se servir de la nature à son avantage et perdre le regard d’un éventuel poursuivant. Il bénéficie d’un bonus de + 2 à ses tests de Discrétion dès qu’il se trouve dans un paysage naturel. </p>"},"effects":[],"flags":{"core":{"sourceId":"Compendium.fvtt-les-heritiers.archetypes-fees.6R59R2DrELSE2Nyt"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.13","coreVersion":"10.291","createdTime":1678205264693,"modifiedTime":1678209625602,"lastModifiedBy":"xGnwWyEbO2k89UsP"},"ownership":{"default":0,"3jSVOAZZNxArxD7h":3,"xGnwWyEbO2k89UsP":3},"folder":null,"sort":0,"_id":"0EAAt0qSzcD9VRBH"}
|
||||
{"name":"Fée aquatique","type":"avantage","img":"systems/fvtt-les-heritiers/assets/icons/advantage.webp","system":{"description":"<p>Le kappa est parfaitement à l’aise dans l’eau. Il voit sous l’eau comme en plein jour et bénéficie d’un bonus de + 1 à toutes ses actions physiques dans l’eau, qui passe à + 2 lorsqu’il est démasqué.</p>"},"effects":[],"flags":{"core":{"sourceId":"Compendium.fvtt-les-heritiers.archetypes-fees.scZsIGg1SPEXmXWp"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.13","coreVersion":"10.291","createdTime":1678206943357,"modifiedTime":1678209618930,"lastModifiedBy":"xGnwWyEbO2k89UsP"},"ownership":{"default":0,"3jSVOAZZNxArxD7h":3,"xGnwWyEbO2k89UsP":3},"folder":null,"sort":0,"_id":"0OiO4QbQAeQJx3Jg"}
|
||||
{"name":"Insensibilité aux poisons et drogues","type":"avantage","img":"systems/fvtt-les-heritiers/assets/icons/advantage.webp","system":{"description":"<p>Les poisons et les drogues n’ont aucun effet sur le gnome, y compris les poisons et drogues secrétés par les fées (comme la liqueur de berthaniel, ou les griffes ou crocs empoisonnés). Seuls les poisons et drogues magiques, comme les préparations des druides ou des nécromanciens, peuvent l’affecter.</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.sQkDv1PjeI92fbLG"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.1","coreVersion":"10.291","createdTime":1672241254845,"modifiedTime":1672245288333,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"0gMjtKZ7ZQbUKiyp"}
|
||||
{"name":"Insensible","type":"avantage","img":"systems/fvtt-les-heritiers/assets/icons/advantage.webp","system":{"description":"<p>Rien ne peut effrayer un épouvantail, même la perspective de sa mort. En outre, il ne souffre d’aucun malus en cas de blessure et ne sait pas ce qu’est la torture physique.</p>"},"effects":[],"flags":{"core":{"sourceId":"Compendium.fvtt-les-heritiers.archetypes-fees.fyE3E2ZlZ9gbjD6M"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.13","coreVersion":"10.291","createdTime":1678182855112,"modifiedTime":1678209630295,"lastModifiedBy":"xGnwWyEbO2k89UsP"},"ownership":{"default":0,"3jSVOAZZNxArxD7h":3,"xGnwWyEbO2k89UsP":3},"folder":null,"sort":0,"_id":"12WUcY9XS2MllFS7"}
|
||||
{"name":"Sympathique","type":"avantage","img":"systems/fvtt-les-heritiers/assets/icons/advantage.webp","system":{"description":"<p>Le léporide a l’air sympathique. C’est plus fort que lui. Il bénéficie d’un bonus de + 2 à tous ses tests sociaux basés sur la sympathie.</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.uyQFOTbpEyNy4sFX"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.1","coreVersion":"10.291","createdTime":1672241702669,"modifiedTime":1672245336575,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"2OxB42oxUEUby52t"}
|
||||
{"name":"Lien astral","type":"avantage","img":"systems/fvtt-les-heritiers/assets/icons/advantage.webp","system":{"description":"<p>Chaque pleine lune, la gargouille peut, en méditant 3 heures au contact d’une roche ou d’un objet qui est issu du lieu dont elle est gardienne, établir un lien spirituel avec lui (Occultisme + Esprit SD 10). Ce lien astral permet à la gargouille d’éliminer le malus lié au syndrome du chien de garde, jusqu’à ce que la nostalgie la reprenne peu à peu.<br><em><strong>Note : </strong>pour savoir quand a lieu la pleine lune (tous les 30 jours environ) vous pouvez consulter un calendrier si vous connaissez la date ou lancer [[/roll 1D8]], [[/roll 1D10]] et [[/roll 1D12]] au début d’un scénario : le résultat indique le nombre de jours depuis la dernière pleine lune. </em></p>"},"effects":[],"flags":{"core":{"sourceId":"Item.AnwacYlVA7NwWsoX"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.1","coreVersion":"10.291","createdTime":1672244460225,"modifiedTime":1672245302602,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"2kB8IySbO02sye3F"}
|
||||
{"name":"Capital sympathie","type":"avantage","img":"systems/fvtt-les-heritiers/assets/icons/advantage.webp","system":{"description":"<p>Le sylve, quoique peu présent dans les cours féériques, y est pourtant toujours le bienvenu. Il bénéficie d’un bonus de + 1 pour toutes ses interactions sociales en ces lieux.</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.wermb7wwYlvSJsc7"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.1","coreVersion":"10.291","createdTime":1672243090756,"modifiedTime":1672245186371,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"4g1UyJmmo1NgkQAC"}
|
||||
{"name":"Langue de bois","type":"avantage","img":"systems/fvtt-les-heritiers/assets/icons/advantage.webp","system":{"description":"<p>Quel que soit le milieu et les circonstances dans lesquelles il évolue, le protys est capable de soutenir une conversation de dix minutes avec n’importe qui, sur n’importe quel sujet, en ayant l’air à l’aise, au courant et parfaitement à sa place. Au bout de dix minutes, il ne peut plus faire illusion.</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.8zDeJtUNiwDVRN7e"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.1","coreVersion":"10.291","createdTime":1672244885720,"modifiedTime":1672245297033,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"5hIT5iBoS61EjWM5"}
|
||||
{"name":"Système digestif d’acier","type":"avantage","img":"systems/fvtt-les-heritiers/assets/icons/advantage.webp","system":{"description":"<p>L’ogre est capable de manger et digérer beaucoup de matériaux normalement non comestibles (papier, bois, os, argile, terre, etc.), même de l’ogre. Seuls les pierres et les métaux l’arrêtent (marbre, diamant, granit, acier…).</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.ZTSCN5aRH6DfSmqW"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.1","coreVersion":"10.291","createdTime":1672242412073,"modifiedTime":1672245339692,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"7lSkz3BwJCbmNjPT"}
|
||||
{"name":"Aura mystérieuse","type":"avantage","img":"systems/fvtt-les-heritiers/assets/icons/advantage.webp","system":{"description":"<p>Le korrigan dégage quelque chose de fascinant, de mystique ou mystérieux qui peut aider à séduire, à être pris au sérieux et à convaincre. Il bénéficie d’un bonus de + 1 à tout test où une telle aura disposera ses interlocuteurs favorablement.</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.AcWl8hrnJtNGnE46"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.1","coreVersion":"10.291","createdTime":1672241556175,"modifiedTime":1672245178651,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"8n3XdPZ83wROzxG7"}
|
||||
{"name":"Faire le vide :","type":"avantage","img":"systems/fvtt-les-heritiers/assets/icons/advantage.webp","system":{"description":"<p>Le kappa maîtrise un ou plusieurs arts martiaux japonais et se sert de la discipline mentale à tout moment pour se concentrer sur ce qu’il est en train de faire et ne pas se laisser perturber par son environnement.</p>\n<p>Il ajoute + 1 à un test de Sang-froid en cas de situation stressante requérant de la concentration.</p>"},"effects":[],"flags":{"core":{"sourceId":"Compendium.fvtt-les-heritiers.archetypes-fees.4UGuLnmVQKvY9ETC"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.13","coreVersion":"10.291","createdTime":1678206980141,"modifiedTime":1678209614124,"lastModifiedBy":"xGnwWyEbO2k89UsP"},"ownership":{"default":0,"3jSVOAZZNxArxD7h":3,"xGnwWyEbO2k89UsP":3},"folder":null,"sort":0,"_id":"8yQHCHfwHVUG3Tq0"}
|
||||
{"name":"Imitateur génial","type":"avantage","img":"systems/fvtt-les-heritiers/assets/icons/advantage.webp","system":{"description":"<p>Le protys a la capacité de pouvoir imiter à la perfection la voix de n’importe quelle personne à condition qu’il l’ait entendue parler au moins dix minutes. Il peut aussi imiter une langue étrangère et son accent s’il l’a entendue pendant au moins une heure et faire illusion à travers une brève conversation basique.</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.9UrOyoKCT1h9mNBl"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.1","coreVersion":"10.291","createdTime":1672244863243,"modifiedTime":1672245216940,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"9sAJg22CLfNlnqHO"}
|
||||
{"name":"Insensibilité aux flammes","type":"avantage","img":"systems/fvtt-les-heritiers/assets/icons/advantage.webp","system":{"description":"<p>Masqué ou démasqué, le phénix est insensible à tous les dommages dus au feu.</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.x6ll8lmpl7wS7QQS"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.1","coreVersion":"10.291","createdTime":1672242820448,"modifiedTime":1672245285365,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"C9BbP62MOV9jT4wD"}
|
||||
{"name":"Seigneur des oiseaux","type":"avantage","img":"systems/fvtt-les-heritiers/assets/icons/advantage.webp","system":{"description":"<p>Les oiseaux reconnaissent en chaque phénix un noble représentant de leur espèce. Le phénix est capable de communiquer avec eux quand il est sous forme démasquée comme s’il avait le Pouvoir de Communication animale. Il peut leur donner des ordres très simples.</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.aYia6RO0x02psKJt"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.1","coreVersion":"10.291","createdTime":1672242790169,"modifiedTime":1672245333332,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"CBfcWTm2HYlKS00t"}
|
||||
{"name":"Obsession onirique","type":"avantage","img":"systems/fvtt-les-heritiers/assets/icons/advantage.webp","system":{"description":"<p>Un simple regard pourra provoquer un désir conscient ou non chez autrui, qui hantera ses rêves pendant quelques nuits, affaiblissant sa concentration, ce qui se traduit par un malus de - 1 pour toute tâche nécessi\u0002tant une attention soutenue. Toute tentative de séduction pendant que l’obsession onirique (après au moins un rêve) est en cours bénéficie en outre d’un bonus de + 1 en sus des autres bonus potentiels.</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.dlV0QtT4GdmQ9jwo"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.1","coreVersion":"10.291","createdTime":1672242972548,"modifiedTime":1672245311376,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"CkSGGEXVr1cOXRHG"}
|
||||
{"name":"Goût du sang","type":"avantage","img":"systems/fvtt-les-heritiers/assets/icons/advantage.webp","system":{"description":"<p>Le sang a un effet tonifiant et régénérant sur le vampyr. Une fiole ou gourde en contenant quelques rasades permet de lui redonner rapidement 3 points de Vie et efface une partie de sa fatigue. Ce n’est pas aussi efficace que boire le sang frais directement sur une victime avec le Pouvoir Absorption par morsure mais cela permet de se tirer d’affaire rapidement. Il lui faudra du sang frais ou d’autres sources de soin pour regagner davantage de points de Vie.</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.qejYllROtENj9F7C"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.1","coreVersion":"10.291","createdTime":1672243654284,"modifiedTime":1672245210759,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"ELimkkt3iOwqJKch"}
|
||||
{"name":"Zizanie","type":"avantage","img":"systems/fvtt-les-heritiers/assets/icons/advantage.webp","system":{"description":"<p>Lorsqu’elle est témoin d’une dispute, la femme-renarde bénéficie d’un bonus de + 2 pour toutes ses interactions sociales pour attiser la dispute sans forcément prendre parti.</p>"},"effects":[],"flags":{"core":{"sourceId":"Compendium.fvtt-les-heritiers.archetypes-fees.FKjv2nylMHXEhHLq"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.13","coreVersion":"10.291","createdTime":1678167452722,"modifiedTime":1678209648402,"lastModifiedBy":"xGnwWyEbO2k89UsP"},"ownership":{"default":0,"3jSVOAZZNxArxD7h":3,"xGnwWyEbO2k89UsP":3},"folder":null,"sort":0,"_id":"EPhDHH8HQC7IK6Ly"}
|
||||
{"name":"Science du combat","type":"avantage","img":"systems/fvtt-les-heritiers/assets/icons/advantage.webp","system":{"description":"<p>Au premier tour de combat, l’orc sait instinctivement quelles vont être les actions de chaque protagoniste, à condition qu’il ne soit pas surpris. Le Docte doit donc dire au joueur incarnant l’orc, quel que soit son rang d’Initiative, ce que vont faire ses assaillants lors de ce premier tour.</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.344jXo8DVimgJLIw"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.1","coreVersion":"10.291","createdTime":1672242658083,"modifiedTime":1672245329852,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"FTcjQP960oWPrnzC"}
|
||||
{"name":"Mise en scène","type":"avantage","img":"systems/fvtt-les-heritiers/assets/icons/advantage.webp","system":{"description":"<p>Lorsqu’il organise une rencontre sur un terrain qui lui est familier et qu’il peut préparer à l’avance, le serpent blanc y bénéficie d’un bonus de + 2 à toutes ses interactions sociales.</p>"},"effects":[],"flags":{"core":{"sourceId":"Compendium.fvtt-les-heritiers.archetypes-fees.c80OnRfoFK8xInMM"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.13","coreVersion":"10.291","createdTime":1678181199025,"modifiedTime":1678209637368,"lastModifiedBy":"xGnwWyEbO2k89UsP"},"ownership":{"default":0,"3jSVOAZZNxArxD7h":3,"xGnwWyEbO2k89UsP":3},"folder":null,"sort":0,"_id":"FYnoMc4fPG8e4OBA"}
|
||||
{"name":"Langue râpeuse","type":"avantage","img":"systems/fvtt-les-heritiers/assets/icons/advantage.webp","system":{"description":"<p>La langue du gobelin est râpeuse comme une lime. Le gobelin peut s’en servir, certes pour s’alimenter, mais également pour limer à peu près n’importe quoi, du bois à l’acier (notez que cela prend du temps).</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.lHg7R6CCUAnaS3nX"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.1","coreVersion":"10.291","createdTime":1672241450307,"modifiedTime":1672245299478,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"Fw9wwP6vyL3swmOk"}
|
||||
{"name":"Petit producteur","type":"avantage","img":"systems/fvtt-les-heritiers/assets/icons/advantage.webp","system":{"description":"<p>Le farfadet sait produire, en une nuit de travail et à partir de matériaux naturels triviaux, une quantité en litres de liqueur de berthaniel égale à ses rangs de Féérie + Production de liqueur de berthaniel (Compétence futile). Pour les farfadets gris et les farfadets verts, cet avantage leur permet, en une nuit, de fabriquer la même quantité de doses de morphine ou de litres d’absinthe à partir du même type de matériaux. Ils ont des contacts facilités avec des aubergistes ou médecins qu’ils peuvent approvisionner en ces substances.</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.T7BjH5Cm2Lpj9vXf"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.1","coreVersion":"10.291","createdTime":1672241072946,"modifiedTime":1672245316638,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"GFb8i3y6haSlQrgz"}
|
||||
{"name":"Bon goût","type":"avantage","img":"systems/fvtt-les-heritiers/assets/icons/advantage.webp","system":{"description":"<p>L’elfe est l’incarnation du bon goût, puisque ce sont les elfes qui dictent les canons de la société féérique. Il bénéficie d’un bonus de + 2 pour toute action visant à briller en société ou artistiquement ainsi que pour juger de la qualité ou de l’authenticité d’une œuvre d’art.</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.LXDCDEdrD7AeHZQF"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.1","coreVersion":"10.291","createdTime":1672240673136,"modifiedTime":1672245182487,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"GUmVSa94atQCeqhZ"}
|
||||
{"name":"Insomniaque","type":"avantage","img":"systems/fvtt-les-heritiers/assets/icons/advantage.webp","system":{"description":"<p>Le fouinard n’a besoin de dormir que trois heures chaque nuit pour être parfaitement reposé.</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.xkzI6HGtOaRn8rFN"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.1","coreVersion":"10.291","createdTime":1672244275892,"modifiedTime":1672245291640,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"HdEYjkeqnMP4Uihm"}
|
||||
{"name":"Vivacité","type":"avantage","img":"systems/fvtt-les-heritiers/assets/icons/advantage.webp","system":{"description":"<p>La fée électricité est particulièrement vive. Elle bénéficie, en toutes circonstances, d’un bonus de + 1 à son rang d’Initiative.</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.ds2ke1etk96NOCNM"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.1","coreVersion":"10.291","createdTime":1672243955730,"modifiedTime":1672245353775,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"JSeHspIWDdv72eEL"}
|
||||
{"name":"Intelligence contagieuse","type":"avantage","img":"systems/fvtt-les-heritiers/assets/icons/advantage.webp","system":{"description":"<p>Lorsqu’il se trouve dans un groupe, la présence du Jiangshi élève le niveau intellectuel de ses compagnons qui bénéficient d’un bonus de + 1 à tous leurs tests d’Esprit (cela n’augmente pas leur Résistance psychique). Ce bonus n’est pas cumulable quand il y a plusieurs Jiangshi et lui-même n’en bénéficie pas.</p>"},"effects":[],"flags":{"core":{"sourceId":"Compendium.fvtt-les-heritiers.archetypes-fees.Zf8Wu557EFJ6BKSC"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.13","coreVersion":"10.291","createdTime":1678182114653,"modifiedTime":1678209633247,"lastModifiedBy":"xGnwWyEbO2k89UsP"},"ownership":{"default":0,"3jSVOAZZNxArxD7h":3,"xGnwWyEbO2k89UsP":3},"folder":null,"sort":0,"_id":"KoooDRpaO5yLR9Nj"}
|
||||
{"name":"Téméraire","type":"avantage","img":"systems/fvtt-les-heritiers/assets/icons/advantage.webp","system":{"description":"<p>Le troll n’a peur de rien, sauf du feu. Toute situation de stress nécessitant un test de Sang-froid, y compris face à un pouvoir provo\u0002quant la peur, n’a aucun effet lui, même si sa vie est en danger. Cet avantage ne fonctionne pas si la source de l’effroi est le feu.</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.QnQwFutvm6M6Q3Tb"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.1","coreVersion":"10.291","createdTime":1672243514527,"modifiedTime":1672245342482,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"MxQi7DBPoKbovRvf"}
|
||||
{"name":"À la page","type":"avantage","img":"systems/fvtt-les-heritiers/assets/icons/advantage.webp","system":{"description":"<p>Le fouinard passe son temps à se renseigner sur les dernières inventions de la science et de la technique. Au courant de toute découverte majeure dans ces domaines, il saura en faire usage.</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.sWaYiwVMtw88xBWG"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.1","coreVersion":"10.291","createdTime":1672244240669,"modifiedTime":1672245168796,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"NVHokXzT1oiF7lCG"}
|
||||
{"name":"Belle mine","type":"avantage","img":"systems/fvtt-les-heritiers/assets/icons/advantage.webp","system":{"description":"<p>Le bastet est un séducteur-né. Il béné\u0002ficie d’un bonus de + 2 à toutes ses tentatives pour séduire quelqu’un, quel que soit le sexe de la personne ciblée.</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.XmkpaTeiVfdUDSja"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.1","coreVersion":"10.291","createdTime":1672240524125,"modifiedTime":1672245180335,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"OeADXGlO2vGYaBgY"}
|
||||
{"name":"Boussole","type":"avantage","img":"systems/fvtt-les-heritiers/assets/icons/advantage.webp","system":{"description":"<p>La femme-renarde est toujours capable de se repérer dans son environnement qu’elle soit sous terre ou à la surface. Elle bénéficie d’un bonus de + 2 ses tests de Survie (Orientation).</p>"},"effects":[],"flags":{"core":{"sourceId":"Compendium.fvtt-les-heritiers.archetypes-fees.QXHxVr3exELwLYI6"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.13","coreVersion":"10.291","createdTime":1678167412879,"modifiedTime":1678209609121,"lastModifiedBy":"xGnwWyEbO2k89UsP"},"ownership":{"default":0,"3jSVOAZZNxArxD7h":3,"xGnwWyEbO2k89UsP":3},"folder":null,"sort":0,"_id":"PAqSbhrh0vn5fnCz"}
|
||||
{"name":"Apparence statuesque et démoniaque","type":"avantage","img":"systems/fvtt-les-heritiers/assets/icons/advantage.webp","system":{"description":"<p>Sous forme démasquée et en se tenant immobile, une gargouille ressemble à s’y méprendre à une statue inanimée à son effigie. La repérer requiert un test de Perception impliquant l’odorat SD 14, ou bien une <em>Vision thermique</em> ou électrique (mais si la « statue » tranche avec l’environne\u0002ment, on pourra se douter de quelque chose). En revanche, si elle bouge, elle apparaîtra aux yeux des humains comme un démon effrayant et bénéficiera d’un bonus de + 2 à toutes ses tentatives pour faire peur (avec Autorité ou le Pouvoir <br><em>Terreur</em>).</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.ndpVQWAE7sRR3nzX"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.1","coreVersion":"10.291","createdTime":1672244374033,"modifiedTime":1672245175070,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"PmEvJG282up6MGkt"}
|
||||
{"name":"Hurlement","type":"avantage","img":"systems/fvtt-les-heritiers/assets/icons/advantage.webp","system":{"description":"<p>Le loup-garou peut, même sous forme masquée, pousser des hurlements audibles à Constitution kilomètres en environ\u0002nement calme (3 fois moins en environnement bruyant). Ceux-ci permettent de communiquer de manière simple avec d’autres loups(-garous) (requiert l’atout <em>Ami des loups</em>) ou de lancer un signal reconnaissable. Pour autrui, ce hurlement signale qu’un prédateur rôde : un échec sur un test de Ressort ou Fortitude + Sang-froid SD 10 fera fuir ou se cacher une âme sensible.</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.eoCVa9zb3yLIaIc8"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.1","coreVersion":"10.291","createdTime":1672242069422,"modifiedTime":1672245213744,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"QvyEbU5MpgsCiBjz"}
|
||||
{"name":"Poing de la justice","type":"avantage","img":"systems/fvtt-les-heritiers/assets/icons/advantage.webp","system":{"description":"<p>En mêlée, à raison d’une fois par combat, le poing du Jiangshi se transforme en un tourbillon. Si l’attaque porte, il étourdit son adversaire pendant un tour.</p>"},"effects":[],"flags":{"core":{"sourceId":"Compendium.fvtt-les-heritiers.archetypes-fees.DACq7nZ7vpGEpfbu"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.13","coreVersion":"10.291","createdTime":1678182079755,"modifiedTime":1678209643418,"lastModifiedBy":"xGnwWyEbO2k89UsP"},"ownership":{"default":0,"3jSVOAZZNxArxD7h":3,"xGnwWyEbO2k89UsP":3},"folder":null,"sort":0,"_id":"SZ87pm8oyYYgjYK7"}
|
||||
{"name":"Terrier","type":"avantage","img":"systems/fvtt-les-heritiers/assets/icons/advantage.webp","system":{"description":"<p>Grâce à leurs petites griffes, totalement inefficaces en combat, les léporides peuvent creuser des galeries dans un sol meuble à raison de 6 mètres par heure.</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.XodAu1Z6hoxvc5vY"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.1","coreVersion":"10.291","createdTime":1672241727890,"modifiedTime":1672245344677,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"UYFwfF4kNAztOJmG"}
|
||||
{"name":"Artificier né","type":"avantage","img":"systems/fvtt-les-heritiers/assets/icons/advantage.webp","system":{"description":"<p>Lorsqu’il manipule des feux d’artifices, le serpent blanc peut leur donner les formes artistiques de son choix (y compris des idéogrammes), amplifier ou atténuer leur bruit. Il bénéficie aussi d’un bonus de + 2 à tous ses tests liés à la poudre et aux explosifs.</p>"},"effects":[],"flags":{"core":{"sourceId":"Compendium.fvtt-les-heritiers.archetypes-fees.EMXUwytn0rnYbqxb"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.13","coreVersion":"10.291","createdTime":1678181152838,"modifiedTime":1678209607356,"lastModifiedBy":"xGnwWyEbO2k89UsP"},"ownership":{"default":0,"3jSVOAZZNxArxD7h":3,"xGnwWyEbO2k89UsP":3},"folder":null,"sort":0,"_id":"VmxvL3v17XhtLvC6"}
|
||||
{"name":"Naturophile","type":"avantage","img":"systems/fvtt-les-heritiers/assets/icons/advantage.webp","system":{"description":"<p>Lorsque le sylve est dans un espace naturel couvert de végétation, il bénéficie d’un bonus de + 1 à toutes ses actions physiques et de + 2 à ses tests visant à identifier la faune et la flore.</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.QPQZGykP2wPQSS5j"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.1","coreVersion":"10.291","createdTime":1672243115133,"modifiedTime":1672245309187,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"VyRQmuRHQeFDVC5N"}
|
||||
{"name":"Âme de gardienne","type":"avantage","img":"systems/fvtt-les-heritiers/assets/icons/advantage.webp","system":{"description":"<p>La gargouille connaît chaque recoin du lieu qu’elle garde. Elle bénéficie d’un bonus de + 2 à toutes ses actions physiques lorsqu’elle est dans son lieu gardé. En outre, où qu’elle soit sur terre, elle sent si celui-ci est endommagé ou lorsque quelqu’un y pénètre et peut suivre approximativement son parcours. </p>"},"effects":[],"flags":{"core":{"sourceId":"Item.2YBtHtrpzsXzlXZ2"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.1","coreVersion":"10.291","createdTime":1672244428824,"modifiedTime":1672245170501,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"WeyIuHudhRylxPTf"}
|
||||
{"name":"Domaine sous-marin","type":"avantage","img":"systems/fvtt-les-heritiers/assets/icons/advantage.webp","system":{"description":"<p>L’ondine possède un domaine sous-marin aménagé avec goût où elle peut vivre à sa guise et où peu de gens viendront la chercher. </p>"},"effects":[],"flags":{"core":{"sourceId":"Item.BtiDHLQ14cLHuMvR"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.1","coreVersion":"10.291","createdTime":1672242525714,"modifiedTime":1672245196786,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"XHyBbmGqojS9A2Sc"}
|
||||
@@ -45,6 +55,7 @@
|
||||
{"name":"Fée aquatique","type":"avantage","img":"systems/fvtt-les-heritiers/assets/icons/advantage.webp","system":{"description":"<p>Contrairement aux fées terrestres ou aériennes, l’ondine est parfaitement à l’aise dans l’eau. Elle voit sous l’eau comme en plein jour et bénéficie d’un bonus de + 1 à toutes ses actions physiques dans l’eau, qui passe à + 2 lorsqu’elle est sous forme de sirène.</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.aMjwV1nWVPZlk1ZI"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.1","coreVersion":"10.291","createdTime":1672242547584,"modifiedTime":1672245203569,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"oalcolKkymJdbYtn"}
|
||||
{"name":"Lucidité géniale","type":"avantage","img":"systems/fvtt-les-heritiers/assets/icons/advantage.webp","system":{"description":"<p>lorsque le gnome s’attèle à résoudre une énigme ou quelque chose d’assi\u0002milé, il bénéficie d’un bonus de + 2 aux tests lui permettant de progresser dans sa résolution.</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.57aQ8bHxlqoJwCfI"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.1","coreVersion":"10.291","createdTime":1672241285945,"modifiedTime":1672245306116,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"qq8DZSs3QK1UvGyw"}
|
||||
{"name":"Porte-bonheur","type":"avantage","img":"systems/fvtt-les-heritiers/assets/icons/advantage.webp","system":{"description":"<p>Le farfadet a tendance à porter chance aux personnes qui l’entourent. En présence d’un farfadet, un compagnon réussira un test échoué de peu (ME de 1 ou 2), une fois par scénario.</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.ZfKTOv85JHD0rqaK"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.1","coreVersion":"10.291","createdTime":1672241142774,"modifiedTime":1672245319370,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"s9PYnjq48dxpLwLo"}
|
||||
{"name":"Phobophage","type":"avantage","img":"systems/fvtt-les-heritiers/assets/icons/advantage.webp","system":{"description":"<p>L’épouvantail se nourrit de la peur des autres, qui remplace sa nourriture. Il souffrira d’un malus de - 1 par jour où il ne s’est pas repu de peur (jusqu’à - 3). Sous forme masquée, il peut manger et boire, mais cela ne le sustente pas. Toutes ses actions et Pouvoirs liés à la peur bénéficient d’un bonus de + 1 (+ 2 sous forme démasquée).</p>"},"effects":[],"flags":{"core":{"sourceId":"Compendium.fvtt-les-heritiers.archetypes-fees.jwS2zYYstme4CgQ4"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.13","coreVersion":"10.291","createdTime":1678182929327,"modifiedTime":1678209640228,"lastModifiedBy":"xGnwWyEbO2k89UsP"},"ownership":{"default":0,"3jSVOAZZNxArxD7h":3,"xGnwWyEbO2k89UsP":3},"folder":null,"sort":0,"_id":"v4Z4uSwfDjDNQ9Dh"}
|
||||
{"name":"Contorsionniste","type":"avantage","img":"systems/fvtt-les-heritiers/assets/icons/advantage.webp","system":{"description":"<p>Le bastet peut, qu’il soit masqué ou non, se contorsionner et passer à travers n’importe quel orifice ayant au moins la taille de sa tête.</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.m7kcWCA5D33i3Nwk"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.1","coreVersion":"10.291","createdTime":1672240553775,"modifiedTime":1672245194834,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"vsdn0AEq01isdoqn"}
|
||||
{"name":"Orduromancie","type":"avantage","img":"systems/fvtt-les-heritiers/assets/icons/advantage.webp","system":{"description":"<p>Le smog, en inspectant attentivement les ordures de quelqu’un, peut reconstituer son portrait physique et psychologique approximatif : sa nature, son sexe, ses habitudes, ses manies, sa corpulence approximative, son état de santé actuel… Il peut également, d’un coup d’œil, dater les ordures et dégager des strates temporelles. Observer ces ordures permet au smog, s’il réussit un test de Sciences (<em>Faëologie</em>) + Esprit, de déterminer l’espèce à laquelle le propriétaire des déchets appartient.</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.Ji9VojGnKsZbFFVH"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.1","coreVersion":"10.291","createdTime":1672245036773,"modifiedTime":1672245313751,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"vuhUNDSXwKEXFMrI"}
|
||||
{"name":"Douceur apparente","type":"avantage","img":"systems/fvtt-les-heritiers/assets/icons/advantage.webp","system":{"description":"<p>L’ange a l’air si doux qu’il bénéficie d’un bonus de + 2 à toutes ses inte\u0002ractions sociales basées sur la douceur et la confiance. De plus, si un opposant hésite entre plusieurs cibles à attaquer, il ne choisira pas spontanément l’ange en priorité.</p>"},"effects":[],"flags":{"core":{"sourceId":"Item.PRIfcv2OnoQMlCEC"}},"_stats":{"systemId":"fvtt-les-heritiers","systemVersion":"10.0.1","coreVersion":"10.291","createdTime":1672240401605,"modifiedTime":1672245198567,"lastModifiedBy":"P06GBagBYC79kmcP"},"folder":null,"sort":0,"ownership":{"default":0,"P06GBagBYC79kmcP":3},"_id":"w1tchLTjGK9gLJrv"}
|
||||
|
||||
BIN
packs/avantages/000179.ldb
Normal file
0
packs/avantages/000314.log
Normal file
1
packs/avantages/CURRENT
Normal file
@@ -0,0 +1 @@
|
||||
MANIFEST-000312
|
||||
0
packs/avantages/LOCK
Normal file
8
packs/avantages/LOG
Normal file
@@ -0,0 +1,8 @@
|
||||
2026/01/10-22:45:42.589327 7fd4637fe6c0 Recovering log #310
|
||||
2026/01/10-22:45:42.598987 7fd4637fe6c0 Delete type=0 #310
|
||||
2026/01/10-22:45:42.599056 7fd4637fe6c0 Delete type=3 #308
|
||||
2026/01/10-22:49:23.105824 7fd4627fc6c0 Level-0 table #315: started
|
||||
2026/01/10-22:49:23.105875 7fd4627fc6c0 Level-0 table #315: 0 bytes OK
|
||||
2026/01/10-22:49:23.111837 7fd4627fc6c0 Delete type=0 #313
|
||||
2026/01/10-22:49:23.124673 7fd4627fc6c0 Manual compaction at level-0 from '!items!0EAAt0qSzcD9VRBH' @ 72057594037927935 : 1 .. '!items!zfpjROW9LDAlXUkN' @ 0 : 0; will stop at (end)
|
||||
2026/01/10-22:49:23.124705 7fd4627fc6c0 Manual compaction at level-1 from '!items!0EAAt0qSzcD9VRBH' @ 72057594037927935 : 1 .. '!items!zfpjROW9LDAlXUkN' @ 0 : 0; will stop at (end)
|
||||
8
packs/avantages/LOG.old
Normal file
@@ -0,0 +1,8 @@
|
||||
2026/01/10-17:13:21.429229 7fd463fff6c0 Recovering log #306
|
||||
2026/01/10-17:13:21.439355 7fd463fff6c0 Delete type=3 #304
|
||||
2026/01/10-17:13:21.439437 7fd463fff6c0 Delete type=0 #306
|
||||
2026/01/10-22:35:10.925075 7fd4627fc6c0 Level-0 table #311: started
|
||||
2026/01/10-22:35:10.925115 7fd4627fc6c0 Level-0 table #311: 0 bytes OK
|
||||
2026/01/10-22:35:10.931575 7fd4627fc6c0 Delete type=0 #309
|
||||
2026/01/10-22:35:10.938004 7fd4627fc6c0 Manual compaction at level-0 from '!items!0EAAt0qSzcD9VRBH' @ 72057594037927935 : 1 .. '!items!zfpjROW9LDAlXUkN' @ 0 : 0; will stop at (end)
|
||||
2026/01/10-22:35:10.938039 7fd4627fc6c0 Manual compaction at level-1 from '!items!0EAAt0qSzcD9VRBH' @ 72057594037927935 : 1 .. '!items!zfpjROW9LDAlXUkN' @ 0 : 0; will stop at (end)
|
||||