Compare commits
62 Commits
fvtt-mourn
...
13.1.0
| Author | SHA1 | Date | |
|---|---|---|---|
| e7a6c15bf7 | |||
| 1909ff443d | |||
| c72c9d8b02 | |||
| 536812e871 | |||
| 66fe1418f0 | |||
| 901df5b395 | |||
| f5d84832f3 | |||
| 216360e0d8 | |||
| a0502dc467 | |||
| c8b94b74a1 | |||
| c9e4f125b4 | |||
| e840b70ac9 | |||
| 03b8779862 | |||
| 580a2ccaba | |||
| 699dba5511 | |||
| aac552102a | |||
| 4762dc33ac | |||
| 0a030460e4 | |||
| ed2dc58680 | |||
| 9c20f277ea | |||
| 2a8617d781 | |||
| 91ad26730a | |||
| e1816b3dd7 | |||
| c48401a199 | |||
| f487908ecd | |||
| e9dc31ada1 | |||
| e504427dbb | |||
| 6aa63f9a98 | |||
| 861aa19637 | |||
| ddb3f9dee1 | |||
| da074d6ea1 | |||
| 1c0c722bd0 | |||
| fef42b7093 | |||
| a63ec19362 | |||
| a26af23c9c | |||
| 983bc6a2ed | |||
| da6d6584c4 | |||
| f08ec8eaff | |||
| c34bfbf229 | |||
| e7de42cf16 | |||
| 0f2348fec6 | |||
| 98ccd8fde1 | |||
| fcec785f00 | |||
| 734945d68e | |||
| 33916c9ec2 | |||
| dda8fee616 | |||
| 1730a8d390 | |||
| 4a0a57870c | |||
| 8d43ae6b6e | |||
| 3f91a161ab | |||
| 1e72eaec04 | |||
| 09cdd1923a | |||
| fce03107b5 | |||
| 43183d60ea | |||
| 55cb3ca806 | |||
| e7ed5bd02c | |||
| cb74799b42 | |||
| b985da2eca | |||
| f23bdca66d | |||
| d7387ac062 | |||
| fb6463aba5 | |||
| 665feac605 |
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-mournblade/releases/download/latest/system.json
|
||||
download: https://www.uberwald.me/gitea/${{gitea.repository}}/releases/download/${{github.event.release.tag_name}}/fvtt-mournblade.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-mournblade.zip system.json README.md LICENSE assets/ lang/ modules/ packs/ styles/ templates/ template.json
|
||||
|
||||
- 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-mournblade.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-mournblade'
|
||||
version: ${{github.event.release.tag_name}}
|
||||
manifest: 'https://www.uberwald.me/gitea/public/fvtt-mournblade/releases/download/latest/system.json'
|
||||
notes: 'https://www.uberwald.me/gitea/${{gitea.repository}}/releases/download/${{github.event.release.tag_name}}/fvtt-mournblade.zip'
|
||||
compatibility-minimum: '13'
|
||||
compatibility-verified: '13'
|
||||
2
.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
.history/
|
||||
node_modules
|
||||
23
README.md
@@ -1,4 +1,23 @@
|
||||
# fvtt-mournblade
|
||||
# Système Foundry pour Mournblade (French RPG, Titam France/Sombres Projets)
|
||||
|
||||
FoundryVTT system for Mournblade from Sombres Projets
|
||||
## EN
|
||||
|
||||
Unofficial system for Mournblade (French version from Titam France).
|
||||
|
||||
Books are mandatory to play and are available at : http://www.titam-france.fr
|
||||
|
||||
## FR
|
||||
|
||||
Système non-officiel pour le JDR Mournblade (Titam France).
|
||||
|
||||
Ce système a été autorisé par Le Département des Sombres Projets, merci à eux !
|
||||
|
||||
Les livres du jeu sont nécessaires pour jouer, et sont disponibles ici : http://www.titam-france.fr
|
||||
|
||||
# Credits
|
||||
|
||||
Mournblade, le jeu de rôle de Sword & Sorcery, is a property of Titam France/Sombres Projets.
|
||||
|
||||
# Developmement
|
||||
|
||||
LeRatierBretonnien
|
||||
|
||||
BIN
assets/icons/heritage.webp
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
assets/icons/origine.webp
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
assets/icons/profession.webp
Normal file
|
After Width: | Height: | Size: 7.1 KiB |
BIN
assets/tokens/token_chaos.webp
Normal file
|
After Width: | Height: | Size: 57 KiB |
BIN
assets/tokens/token_chaos2.webp
Normal file
|
After Width: | Height: | Size: 55 KiB |
BIN
assets/tokens/token_chaos3.webp
Normal file
|
After Width: | Height: | Size: 53 KiB |
BIN
assets/tokens/token_loi.webp
Normal file
|
After Width: | Height: | Size: 40 KiB |
BIN
assets/tokens/token_loi2.webp
Normal file
|
After Width: | Height: | Size: 44 KiB |
BIN
assets/tokens/token_loi3.webp
Normal file
|
After Width: | Height: | Size: 57 KiB |
BIN
assets/tokens/token_loi4.webp
Normal file
|
After Width: | Height: | Size: 45 KiB |
BIN
assets/ui/fond_mournblade.webp
Normal file
|
After Width: | Height: | Size: 236 KiB |
BIN
assets/ui/landing_page_mournblade.webp
Normal file
|
After Width: | Height: | Size: 380 KiB |
|
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 11 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/mournblade.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;
|
||||
203
lang/en.json
Normal file
@@ -0,0 +1,203 @@
|
||||
{
|
||||
"Adresse": "Agility",
|
||||
"Clairvoyance": "Clarity",
|
||||
"MNBL.abilities": "Gifts/Pacts",
|
||||
"MNBL.activatedrunes": "Activated Runes",
|
||||
"MNBL.addpredilection": "Add a specialization",
|
||||
"MNBL.aimingbonus": "Aiming Bonus",
|
||||
"MNBL.alignement": "Alignment",
|
||||
"MNBL.all": "All",
|
||||
"MNBL.allegiance": "Allegiance",
|
||||
"MNBL.applydamage": "Apply damage/bonus/penalty",
|
||||
"MNBL.aspect": "Aspect",
|
||||
"MNBL.Assaut": "Smite",
|
||||
"MNBL.attack": "Attack",
|
||||
"MNBL.attackcapacity": "Offensive Ability",
|
||||
"MNBL.attackmountbonus": "Mounted attacker vs ground defender (+5)",
|
||||
"MNBL.attacks": "Attacks",
|
||||
"MNBL.attribut": "Attribute",
|
||||
"MNBL.attributes": "Attributes",
|
||||
"MNBL.automalus": "Auto Penalty",
|
||||
"MNBL.base": "Base",
|
||||
"MNBL.beastslords": "Beast Lords",
|
||||
"MNBL.bio": "Bio & Notes",
|
||||
"MNBL.bonus": "Bonus",
|
||||
"MNBL.candoublebonusskill": "Bonuses can be doubled (cf. Profession)",
|
||||
"MNBL.chaos": "Chaos",
|
||||
"MNBL.chaotictraits": "Chaotic Traits",
|
||||
"MNBL.charge": "Charge",
|
||||
"MNBL.consumed": "Consumed",
|
||||
"MNBL.contain": "Contain the opponent",
|
||||
"MNBL.creatureresourcecost": "Resource Cost (creatures)",
|
||||
"MNBL.current": "Current",
|
||||
"MNBL.currentmax": "Current Max",
|
||||
"MNBL.damage": "Damage",
|
||||
"MNBL.damagebonus": "Damage Bonus",
|
||||
"MNBL.defense": "Defense",
|
||||
"MNBL.defensebonus": "Defense Bonus",
|
||||
"MNBL.defensecapacity": "Defensive Ability",
|
||||
"MNBL.dice": "Dice",
|
||||
"MNBL.difficulty": "Difficulty",
|
||||
"MNBL.dirtyattack": "Cheap Shot",
|
||||
"MNBL.disadvantagepositions": "Disadvantageous positions (Max bonus +15)",
|
||||
"MNBL.disarm": "Disarm",
|
||||
"MNBL.doubleD20": "Double d20 (1 Shard Point)",
|
||||
"MNBL.dramaticfailure": "Dramatic Failure",
|
||||
"MNBL.duration": "Duration",
|
||||
"MNBL.easy": "Easy (5)",
|
||||
"MNBL.eclat": "Shard",
|
||||
"MNBL.elementslords": "Elemental Lords",
|
||||
"MNBL.equipmentactions": "Equipment/Actions",
|
||||
"MNBL.equipments": "Equipments",
|
||||
"MNBL.equipped": "Equipped",
|
||||
"MNBL.exp": "Experience",
|
||||
"MNBL.eyes": "Eyes",
|
||||
"MNBL.failure": "Failure",
|
||||
"MNBL.feint": "Feint",
|
||||
"MNBL.flee": "Flee",
|
||||
"MNBL.formula": "Formula",
|
||||
"MNBL.genre": "Gender",
|
||||
"MNBL.gifts": "Gifts",
|
||||
"MNBL.goodadventure": "Good Adventure",
|
||||
"MNBL.hair": "Hair",
|
||||
"MNBL.hard": "Hard (15)",
|
||||
"MNBL.hascover": "Cover",
|
||||
"MNBL.hazardous": "Tricky (20)",
|
||||
"MNBL.health": "Health",
|
||||
"MNBL.healthmalus": "Health Penalty",
|
||||
"MNBL.heavycover": "Almost complete (-10)",
|
||||
"MNBL.heroicsuccess": "Heroic Success",
|
||||
"MNBL.highlanguage": "High Melnibonéan",
|
||||
"MNBL.ignorearmor": "Ignore Armor",
|
||||
"MNBL.ignorehealthmalus": "Ignore Health Penalty",
|
||||
"MNBL.ignoresoulmalus": "Ignore Soul Penalty",
|
||||
"MNBL.immobilize": "Immobilize",
|
||||
"MNBL.insane": "Ridiculous (25)",
|
||||
"MNBL.isdefense": "Defensive",
|
||||
"MNBL.knockout": "Knock Out",
|
||||
"MNBL.law": "Law",
|
||||
"MNBL.legacy": "Legacy",
|
||||
"MNBL.lessthanshort": "Less than short (10)",
|
||||
"MNBL.lethal": "Lethal",
|
||||
"MNBL.level": "Level",
|
||||
"MNBL.lightcover": "Buckler or light (-2)",
|
||||
"MNBL.longmore": "Long and more (25)",
|
||||
"MNBL.longrange": "Long Range",
|
||||
"MNBL.malus": "Penalty",
|
||||
"MNBL.margin": "Margin",
|
||||
"MNBL.medium": "Average (10)",
|
||||
"MNBL.mediumcover": "Pavise or half (-5)",
|
||||
"MNBL.mediummore": "Medium and more (20)",
|
||||
"MNBL.mediumrange": "Medium Range",
|
||||
"MNBL.meleethrowweapon": "Melee and Throwing Weapon",
|
||||
"MNBL.meleeweapon": "Melee Weapon",
|
||||
"MNBL.mode": "Mode",
|
||||
"MNBL.modifier": "Modifiers",
|
||||
"MNBL.modifiertype": "Modifier Type",
|
||||
"MNBL.mounted": "Mounted",
|
||||
"MNBL.nextactionmalus": "Penalty for next action",
|
||||
"MNBL.nextattackbonus": "Bonus for next attack",
|
||||
"MNBL.none": "None",
|
||||
"MNBL.noneunknwon": "None/Unknown",
|
||||
"MNBL.nonlethal": "Non-Lethal",
|
||||
"MNBL.nonlethaldamage": "Non-Lethal Damage",
|
||||
"MNBL.notarget": "No designated target",
|
||||
"MNBL.origin": "Origin",
|
||||
"MNBL.pacts": "Pacts",
|
||||
"MNBL.points": "Points",
|
||||
"MNBL.preciseattack": "Precision Attack",
|
||||
"MNBL.predilections": "Specializations",
|
||||
"MNBL.preferredhand": "Preferred Hand",
|
||||
"MNBL.prerequisites": "Prerequisites",
|
||||
"MNBL.price": "Price",
|
||||
"MNBL.profession": "Profession",
|
||||
"MNBL.pronounced": "Spoken",
|
||||
"MNBL.pronouncedrune": "Spoken Rune",
|
||||
"MNBL.pronouncerune": "Speak the rune",
|
||||
"MNBL.protections": "Protections",
|
||||
"MNBL.puremadness": "Insane (30)",
|
||||
"MNBL.quantity": "Quantity",
|
||||
"MNBL.range": "Range",
|
||||
"MNBL.rarity": "Rarity",
|
||||
"MNBL.registeredmodifiers": "Registered Modifiers",
|
||||
"MNBL.reloadduration": "Reload Time",
|
||||
"MNBL.ressources": "Resources",
|
||||
"MNBL.roll": "Roll",
|
||||
"MNBL.runes": "Runes",
|
||||
"MNBL.runningtarget": "Running target (-5/-10 depending on range)",
|
||||
"MNBL.shootmodifier": "Shooting Modifiers",
|
||||
"MNBL.shootweapon": "Shoot Weapon",
|
||||
"MNBL.shortmore": "Short and more (10)",
|
||||
"MNBL.shortrange": "Short Range",
|
||||
"MNBL.size": "Size",
|
||||
"MNBL.skill": "Skill",
|
||||
"MNBL.skills": "Skills",
|
||||
"MNBL.smallroomtarget": "Target in confined space (+5)",
|
||||
"MNBL.soul": "Soul",
|
||||
"MNBL.soulmalus": "Soul Penalty",
|
||||
"MNBL.soulmultiplier": "Soul Multiplier",
|
||||
"MNBL.soulpoints": "Soul Points",
|
||||
"MNBL.specialactions": "Special Actions",
|
||||
"MNBL.specialweapon": "Special (ability/gift)",
|
||||
"MNBL.speciestrait": "Species Trait",
|
||||
"MNBL.speed": "Speed",
|
||||
"MNBL.success": "Success",
|
||||
"MNBL.target": "Target",
|
||||
"MNBL.targetbelow": "Target below (+5)",
|
||||
"MNBL.targetcantmove": "Target immobilized (+5)",
|
||||
"MNBL.targetdefense": "Opponent's Defense",
|
||||
"MNBL.targetground": "Target on the ground (+5)",
|
||||
"MNBL.targetseeshoot": "Target is aware of the shot",
|
||||
"MNBL.tendancies": "Tendencies",
|
||||
"MNBL.throwweapon": "Throwing Weapon",
|
||||
"MNBL.totalprotection": "Total Protection",
|
||||
"MNBL.traced": "Written",
|
||||
"MNBL.tracedrune": "Written Rune",
|
||||
"MNBL.tracerune": "Write the rune",
|
||||
"MNBL.treasuremoney": "Treasures and Money",
|
||||
"MNBL.twohands": "Two-handed",
|
||||
"MNBL.type": "Type",
|
||||
"MNBL.unarmedtarget": "Unarmed target (+5)",
|
||||
"MNBL.unit": "Unit",
|
||||
"MNBL.use": "Use",
|
||||
"MNBL.usedpredilection": "Used Predilection",
|
||||
"MNBL.value": "Value",
|
||||
"MNBL.weapon": "Weapon",
|
||||
"MNBL.weaponbonusattack": "Handling Bonus (offensive)",
|
||||
"MNBL.weaponbonusdefense": "Handling Bonus (defensive)",
|
||||
"MNBL.weapons": "Weapons",
|
||||
"MNBL.weaponscapacities": "Weapons/Abilities",
|
||||
"MNBL.weapontype": "Weapon Type",
|
||||
"MNBL.weight": "Weight",
|
||||
"MNBL.total": "Total",
|
||||
|
||||
"Présence": "Presence",
|
||||
"Puissance": "Might",
|
||||
"Trempe": "Mettle",
|
||||
"TYPES": {
|
||||
"Actor": {
|
||||
"creature": "Creature",
|
||||
"personnage": "Character"
|
||||
},
|
||||
"Item": {
|
||||
"arme": "Weapon",
|
||||
"bouclier": "Shield",
|
||||
"capacite": "Ability",
|
||||
"competence": "Skill",
|
||||
"don": "Gifts",
|
||||
"equipement": "Equipment",
|
||||
"heritage": "Background",
|
||||
"metier": "Profession",
|
||||
"modifier": "Modifier",
|
||||
"monnaie": "Currency",
|
||||
"origine": "Origin",
|
||||
"pacte": "Pacts",
|
||||
"protection": "Protections",
|
||||
"rune": "Rune",
|
||||
"runeeffect": "Rune Effect",
|
||||
"tendance": "Signs of Chaos",
|
||||
"traitchaotique": "Background",
|
||||
"traitespece": "Species Trait"
|
||||
}
|
||||
}
|
||||
}
|
||||
224
lang/fr.json
Normal file
@@ -0,0 +1,224 @@
|
||||
{
|
||||
"TYPES": {
|
||||
"Actor": {
|
||||
"personnage": "Personnage",
|
||||
"creature": "Créature"
|
||||
},
|
||||
"Item": {
|
||||
"arme": "Arme",
|
||||
"competence": "Compétence",
|
||||
"protection": "Protection",
|
||||
"pacte": "Pacte",
|
||||
"traitchaotique": "Trait Chaotique",
|
||||
"monnaie": "Monnaie",
|
||||
"don": "Don",
|
||||
"tendance": "Tendance",
|
||||
"rune": "Rune",
|
||||
"equipement": "Equipement",
|
||||
"capacite": "Capacité",
|
||||
"origine": "Origine",
|
||||
"heritage": "Héritage",
|
||||
"metier": "Métier",
|
||||
"runeeffect": "Effet de Rune",
|
||||
"bouclier": "Bouclier",
|
||||
"modifier": "Modificateur",
|
||||
"traitespece": "Trait d'Espèce"
|
||||
}
|
||||
},
|
||||
"Adresse": "Adresse",
|
||||
"Puissance": "Puissance",
|
||||
"Clairvoyance": "Clairvoyance",
|
||||
"Présence": "Présence",
|
||||
"Trempe": "Trempe",
|
||||
|
||||
"MNBL.assaut": "Assaut",
|
||||
"MNBL.preciseattack": "Attaque Précise",
|
||||
"MNBL.feint": "Feinte",
|
||||
"MNBL.dirtyattack": "Coup Bas",
|
||||
"MNBL.charge": "Charger",
|
||||
"MNBL.contain": "Contenir l'adversaire",
|
||||
"MNBL.disarm": "Désarmer",
|
||||
|
||||
"MNBL.none": "Aucun",
|
||||
"MNBL.lightcover": "Rondache ou léger (-2)",
|
||||
"MNBL.mediumcover": "Pavois ou à moitié (-5)",
|
||||
"MNBL.heavycover": "Quasi complet (-10)",
|
||||
"MNBL.roll": "Jet",
|
||||
"MNBL.defensecapacity": "Capacité défensive",
|
||||
"MNBL.attackcapacity": "Capacité offensive",
|
||||
|
||||
"MNBL.lessthanshort": "Moins que courte (10)",
|
||||
"MNBL.shortmore": "Courte et + (10)",
|
||||
"MNBL.mediummore": "Moyenne et + (20)",
|
||||
"MNBL.longmore": "Longue et + (25)",
|
||||
|
||||
"MNBL.noneunknwon": "Aucune/Inconnue",
|
||||
"MNBL.easy": "Facile (5)",
|
||||
"MNBL.medium": "Moyenne (10)",
|
||||
"MNBL.hard": "Ardue (15)",
|
||||
"MNBL.hazardous": "Hasardeuse (20)",
|
||||
"MNBL.insane": "Insensée (25)",
|
||||
"MNBL.puremadness": "Pure Folie (30)",
|
||||
|
||||
"MNBL.pronouncerune": "Prononcer la rune",
|
||||
"MNBL.tracerune": "Tracer la rune",
|
||||
"MNBL.pronounced": "Prononcée",
|
||||
"MNBL.traced": "Tracée",
|
||||
|
||||
"MNBL.meleeweapon": "Arme de contact",
|
||||
"MNBL.meleethrowweapon": "Arme de contact et de Jet",
|
||||
"MNBL.throwweapon": "Arme de Lancer",
|
||||
"MNBL.shootweapon": "Arme de Tir",
|
||||
"MNBL.specialweapon": "Spécial (capacité/don)",
|
||||
|
||||
"MNBL.all": "Tous",
|
||||
"MNBL.beastslords": "Seigneurs des Bêtes",
|
||||
"MNBL.elementslords": "Seigneurs Elementaires",
|
||||
|
||||
"MNBL.law": "Loi",
|
||||
"MNBL.chaos": "Chaos",
|
||||
"MNBL.level": "Niveau",
|
||||
"MNBL.points": "Points",
|
||||
"MNBL.aspect": "Aspect",
|
||||
"MNBL.margin": "Marge",
|
||||
"MNBL.goodadventure" : "Bonne Aventure",
|
||||
"MNBL.base": "Base",
|
||||
"MNBL.current": "Actuelle",
|
||||
"MNBL.alignement" : "Alignement",
|
||||
"MNBL.eclat": "Eclat",
|
||||
"MNBL.exp": "Expérience",
|
||||
"MNBL.attributes": "Attributs",
|
||||
"MNBL.skills": "Compétences",
|
||||
"MNBL.abilities": "Dons/Pactes",
|
||||
"MNBL.equipmentactions": "Equipements/Actions",
|
||||
"MNBL.bio": "Bio&Notes",
|
||||
"MNBL.health": "Santé",
|
||||
"MNBL.bonus": "Bonus",
|
||||
"MNBL.malus": "Malus",
|
||||
"MNBL.nonlethal": "Non Létaux",
|
||||
"MNBL.lethal": "Létaux",
|
||||
"MNBL.automalus" : "Malus Auto",
|
||||
"MNBL.soul": "Ame",
|
||||
"MNBL.currentmax": "Max Actuel",
|
||||
"MNBL.consumed": "Consommé",
|
||||
"MNBL.damagebonus": "B. Dégats",
|
||||
"MNBL.speed": "Vitesse",
|
||||
"MNBL.defense": "Défense",
|
||||
"MNBL.totalprotection": "Protection Totale",
|
||||
"MNBL.modifier": "Modificateurs",
|
||||
"MNBL.type": "Type",
|
||||
"MNBL.value": "Valeur",
|
||||
"MNBL.gifts": "Dons",
|
||||
"MNBL.allegiance": "Allégeance",
|
||||
"MNBL.pacts": "Pactes",
|
||||
"MNBL.runes": "Runes",
|
||||
"MNBL.highlanguage": "Haut Parler",
|
||||
"MNBL.difficulty": "Difficulté",
|
||||
"MNBL.tendancies": "Tendances",
|
||||
"MNBL.chaotictraits": "Traits Chaotique",
|
||||
"MNBL.activatedrunes": "Runes actives",
|
||||
"MNBL.mode": "Mode",
|
||||
"MNBL.duration": "Durée",
|
||||
"MNBL.treasuremoney": "Richesses et Argent",
|
||||
"MNBL.quantity": "Quantité",
|
||||
"MNBL.unit": "Unité",
|
||||
"MNBL.specialactions": "Actions spéciales",
|
||||
"MNBL.knockout": "Assomer",
|
||||
"MNBL.flee": "Fuir",
|
||||
"MNBL.immobilize": "Immobiliser",
|
||||
"MNBL.mounted": "Monté",
|
||||
"MNBL.weapons": "Armes",
|
||||
"MNBL.attack": "Attaque",
|
||||
"MNBL.damage": "Dégats",
|
||||
"MNBL.protections": "Protections",
|
||||
"MNBL.equipments": "Equipements",
|
||||
"MNBL.equipment": "Equipement",
|
||||
"MNBL.origin": "Origine",
|
||||
"MNBL.legacy": "Héritage",
|
||||
"MNBL.profession": "Métier",
|
||||
"MNBL.genre": "Genre",
|
||||
"MNBL.size": "Taille",
|
||||
"MNBL.hair": "Cheveux",
|
||||
"MNBL.eyes": "Yeux",
|
||||
"MNBL.preferredhand": "Main Préférée",
|
||||
"MNBL.weight": "Poids",
|
||||
"MNBL.soulmultiplier": "Multiplicateur d'âme",
|
||||
"MNBL.ignorehealthmalus": "Ignore le malus de santé",
|
||||
"MNBL.ignoresoulmalus": "Ignore le malus d'âme",
|
||||
|
||||
"MNBL.weapon": "Arme",
|
||||
"MNBL.nextattackbonus": "Bonus pour prochaine attaque",
|
||||
"MNBL.nextactionmalus": "Malus au défenseur pour prochaine action",
|
||||
"MNBL.applydamage": "Appliquer les dégats/bonus/malus",
|
||||
"MNBL.attribut": "Attribut",
|
||||
"MNBL.skill": "Compétence",
|
||||
"MNBL.target": "Cible",
|
||||
"MNBL.usedpredilection": "Prédilection utilisée",
|
||||
"MNBL.soulpoints": "Points d'âme",
|
||||
"MNBL.formula": "Formule",
|
||||
"MNBL.dice":"Dé",
|
||||
"MNBL.success": "Succés",
|
||||
"MNBL.failure": "Echec",
|
||||
"MNBL.heroicsuccess": "Succés Héroïque",
|
||||
"MNBL.dramaticfailure": "Echec Dramatique",
|
||||
|
||||
"MNBL.attackmountbonus": "Attaquant monté vs def. au sol (+5)",
|
||||
"MNBL.targetdefense": "Défense adversaire",
|
||||
"MNBL.shootmodifier": "Modificateurs de Tir",
|
||||
"MNBL.aimingbonus": "Bonus de visée",
|
||||
"MNBL.targetseeshoot": "La cible est consciente du tir",
|
||||
"MNBL.notarget": "Pas de cible désignée",
|
||||
"MNBL.runningtarget": "La cible court (-5/-10 selon portée)",
|
||||
"MNBL.hascover": "Couvert",
|
||||
"MNBL.range": "Portée",
|
||||
"MNBL.disadvantagepositions": "Positions désavantageuses (Bonus max +15)",
|
||||
"MNBL.targetground": "Cible au sol (+5)",
|
||||
"MNBL.unarmedtarget": "Cible désarmée (+5)",
|
||||
"MNBL.smallroomtarget": "Cible en espace restreint (+5)",
|
||||
"MNBL.targetcantmove": "Cible immobilisée (+5)",
|
||||
"MNBL.targetbelow": "Cible surplombée (+5)",
|
||||
"MNBL.healthmalus": "Malus de santé",
|
||||
"MNBL.soulmalus": "Malus d'âme",
|
||||
"MNBL.registeredmodifiers": "Modificateurs enregistrés",
|
||||
"MNBL.doubleD20": "Doubler le d20 (1 Point d'Eclat)",
|
||||
|
||||
"MNBL.pronouncedrune": "Rune prononcée",
|
||||
"MNBL.tracedrune": "Rune tracée",
|
||||
"MNBL.equipped": "Equipé",
|
||||
"MNBL.rarity": "Rareté",
|
||||
"MNBL.price": "Prix",
|
||||
"MNBL.modifiertype": "Type de modificateur",
|
||||
"MNBL.prerequisites": "Prérequis",
|
||||
"MNBL.predilections": "Prédilections",
|
||||
"MNBL.candoublebonusskill": "Les bonus de Bonne Aventure et d'Eclat peuvent être doublés (cf. Métier)",
|
||||
"MNBL.addpredilection": "Ajouter une prédilection",
|
||||
"MNBL.defensebonus": "Bonus de défense",
|
||||
"MNBL.nonlethaldamage": "Dégâts non létaux",
|
||||
"MNBL.weapontype": "Type d'arme",
|
||||
"MNBL.weaponbonusattack": "Bonus de maniement (offensif)",
|
||||
"MNBL.weaponbonusdefense": "Bonus de maniement (défensif)",
|
||||
"MNBL.isdefense": "Défensive",
|
||||
"MNBL.twohands": "A deux mains",
|
||||
"MNBL.ignorearmor": "Ignore l'armure",
|
||||
"MNBL.creatureresourcecost": "Cout en Ressources (créatures)",
|
||||
"MNBL.shortrange": "Portée courte",
|
||||
"MNBL.mediumrange":"Portée moyenne",
|
||||
"MNBL.longrange":"Portée longue",
|
||||
"MNBL.reloadduration": "Temps de rechargement",
|
||||
"MNBL.attacks": "Attaques",
|
||||
"MNBL.ressources": "Ressources",
|
||||
"MNBL.weaponscapacities": "Armes/Capacités",
|
||||
"MNBL.use": "Utiliser",
|
||||
"MNBL.speciestrait": "Trait d'espèce",
|
||||
|
||||
"MNBL.attribute": "Attribut",
|
||||
"MNBL.Protections": "Protections",
|
||||
"MNBL.rune": "Rune",
|
||||
"MNBL.total": "Total",
|
||||
"MNBL.description": "Description",
|
||||
"MNBL.details": "Détails",
|
||||
"MNBL.sacrifice": "Sacrifice",
|
||||
"MNBL.identity": "Identité",
|
||||
"MNBL.gmtools": "Outils MJ"
|
||||
|
||||
}
|
||||
874
less/actor-styles.less
Normal file
@@ -0,0 +1,874 @@
|
||||
/* ==================== Actor Sheet Styles ==================== */
|
||||
|
||||
// NOTE: Ce fichier surcharge certaines règles de simple-converted.less
|
||||
// Les sélecteurs .fvtt-mournblade.actor sont plus spécifiques et prennent priorité
|
||||
|
||||
.fvtt-mournblade.actor {
|
||||
// Background pour toute la fiche d'acteur
|
||||
background: url("../assets/ui/pc_sheet_bg.webp") repeat;
|
||||
|
||||
// AppV2 - Structure flex pour permettre le scroll
|
||||
.window-content {
|
||||
height: 100%;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
// Main form structure
|
||||
form,
|
||||
.sheet-form-layout {
|
||||
height: 100%;
|
||||
background: url("../assets/ui/pc_sheet_bg.webp") repeat-y;
|
||||
color: black;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
overflow: hidden;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
|
||||
// La section racine du template (if nested inside form, or simple direct children handling)
|
||||
> section {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
// SURCHARGE: simple-converted.less définit flex: 0 0 210px
|
||||
.sheet-header {
|
||||
background: url("../assets/ui/pc_sheet_bg.webp") repeat;
|
||||
padding: 0.5rem;
|
||||
margin: 0;
|
||||
flex: 0 0 auto !important; // Override simple-converted
|
||||
overflow: visible !important; // Override simple-converted
|
||||
|
||||
.background-sheet-header {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.header-main-content {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.header-stats-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 2fr 1fr 1fr;
|
||||
gap: 0.75rem;
|
||||
padding: 0.5rem;
|
||||
background: rgba(0, 0, 0, 0.15);
|
||||
border: 2px solid rgba(139, 69, 19, 0.5);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.stat-group {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.3rem;
|
||||
padding: 0.35rem 0.6rem;
|
||||
background: rgba(0, 0, 0, 0.2);
|
||||
border: 1px solid rgba(139, 69, 19, 0.4);
|
||||
border-radius: 3px;
|
||||
|
||||
&.stat-group-health {
|
||||
border-left: 3px solid rgba(200, 0, 0, 0.6);
|
||||
background: rgba(40, 0, 0, 0.15);
|
||||
}
|
||||
}
|
||||
|
||||
.stat-title {
|
||||
font-size: 0.75rem;
|
||||
font-weight: bold;
|
||||
color: #f5e6d3;
|
||||
margin: 0;
|
||||
padding: 0 0 0.3rem 0;
|
||||
border-bottom: 1px solid rgba(139, 69, 19, 0.5);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.5px;
|
||||
font-family: "CentaurMT", serif;
|
||||
text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.8);
|
||||
}
|
||||
|
||||
.stat-values {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
gap: 0.5rem;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.stat-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.2rem;
|
||||
align-items: center;
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.stat-label {
|
||||
font-size: 0.7rem;
|
||||
color: #d4c5b0;
|
||||
margin: 0;
|
||||
font-weight: 600;
|
||||
text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.7);
|
||||
}
|
||||
|
||||
.stat-value {
|
||||
font-size: 0.85rem;
|
||||
font-weight: bold;
|
||||
color: #fff;
|
||||
padding: 0.25rem 0.5rem;
|
||||
background: rgba(0, 0, 0, 0.4);
|
||||
border: 1px solid rgba(139, 69, 19, 0.6);
|
||||
border-radius: 3px;
|
||||
min-width: 2.5rem;
|
||||
text-align: center;
|
||||
text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.9);
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.stat-input {
|
||||
font-size: 0.8rem;
|
||||
font-weight: 600;
|
||||
padding: 0.25rem 0.4rem;
|
||||
background: rgba(40, 30, 20, 0.7);
|
||||
border: 1px solid rgba(139, 69, 19, 0.7);
|
||||
color: #fff;
|
||||
border-radius: 3px;
|
||||
text-align: center;
|
||||
min-width: 2.5rem;
|
||||
max-width: 100%;
|
||||
width: 100%;
|
||||
text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.9);
|
||||
box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.3);
|
||||
|
||||
&.stat-input-single {
|
||||
min-width: 3.5rem;
|
||||
}
|
||||
|
||||
&.stat-input-damage {
|
||||
border-color: rgba(200, 0, 0, 0.8);
|
||||
background: rgba(80, 0, 0, 0.5);
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: rgba(60, 45, 30, 0.8);
|
||||
border-color: rgba(255, 102, 0, 0.6);
|
||||
}
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
border-color: rgba(255, 102, 0, 1);
|
||||
box-shadow: 0 0 6px rgba(255, 102, 0, 0.5), inset 0 1px 3px rgba(0, 0, 0, 0.3);
|
||||
background: rgba(70, 50, 35, 0.9);
|
||||
}
|
||||
}
|
||||
|
||||
.header-fields {
|
||||
h4.item-name-label.competence-name {
|
||||
font-size: 0.75rem;
|
||||
padding-top: 3px;
|
||||
}
|
||||
|
||||
.item-name-label.competence-name {
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
|
||||
label.item-name-label.competence-name {
|
||||
font-size: 0.7rem;
|
||||
}
|
||||
|
||||
.item-field-label-short {
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
.status-small-label {
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sheet navigation tabs
|
||||
// SURCHARGE: simple-converted.less définit flex: 0
|
||||
.sheet-tabs {
|
||||
margin: 0;
|
||||
padding: 0 0.5rem;
|
||||
flex: 0 0 auto !important; // Override simple-converted
|
||||
}
|
||||
|
||||
// Sheet body - section scrollable
|
||||
// SURCHARGE CRITIQUE: simple-converted.less définit height: auto sur .sheet-body et .tab
|
||||
// Ces surcharges permettent le scroll vertical
|
||||
.sheet-body {
|
||||
margin: 0;
|
||||
padding: 0.5rem;
|
||||
flex: 1 !important; // Override simple-converted
|
||||
min-height: 0 !important; // Critique pour le scroll
|
||||
overflow-y: auto !important; // Override simple-converted
|
||||
|
||||
.tab {
|
||||
padding: 0;
|
||||
height: auto !important; // Override simple-converted qui met height: auto
|
||||
|
||||
&:not(.active) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
// Assurer que les grilles peuvent scroller
|
||||
.grid, .grid-2col {
|
||||
height: auto;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.sheet-box {
|
||||
height: auto;
|
||||
}
|
||||
}
|
||||
|
||||
// Listes compactes dans les sections
|
||||
.compact-list {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
|
||||
li.item {
|
||||
padding: 0.2rem 0.4rem;
|
||||
margin-bottom: 0.15rem;
|
||||
background: rgba(0, 0, 0, 0.1);
|
||||
border: 1px solid rgba(139, 69, 19, 0.3);
|
||||
border-radius: 3px;
|
||||
|
||||
&:hover {
|
||||
background: rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
&.items-title-bg {
|
||||
background: rgba(0, 0, 0, 0.3);
|
||||
border-color: rgba(139, 69, 19, 0.5);
|
||||
font-weight: 600;
|
||||
margin-bottom: 0.3rem;
|
||||
|
||||
.item-name-label-header {
|
||||
color: #f5e6d3;
|
||||
text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.7);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Contrôles d'items (edit, delete, equip, etc.)
|
||||
.item-controls {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.3rem;
|
||||
justify-content: flex-end;
|
||||
|
||||
.item-control {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
color: #5a3a1a;
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
border-radius: 3px;
|
||||
transition: all 0.2s;
|
||||
|
||||
&:hover {
|
||||
color: #2a1a0a;
|
||||
background: rgba(139, 69, 19, 0.2);
|
||||
transform: scale(1.1);
|
||||
}
|
||||
|
||||
i {
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
|
||||
&.item-edit {
|
||||
color: #4a7c59;
|
||||
|
||||
&:hover {
|
||||
color: #2d5a3a;
|
||||
background: rgba(74, 124, 89, 0.2);
|
||||
}
|
||||
}
|
||||
|
||||
&.item-delete {
|
||||
color: #a04040;
|
||||
|
||||
&:hover {
|
||||
color: #802020;
|
||||
background: rgba(160, 64, 64, 0.2);
|
||||
}
|
||||
}
|
||||
|
||||
&.item-equip {
|
||||
color: #6b5b3a;
|
||||
|
||||
&:hover {
|
||||
color: #4a3a1a;
|
||||
background: rgba(107, 91, 58, 0.2);
|
||||
}
|
||||
|
||||
i.fa-circle {
|
||||
color: #4a7c59;
|
||||
}
|
||||
|
||||
i.fa-genderless {
|
||||
color: #8a6a4a;
|
||||
}
|
||||
}
|
||||
|
||||
&.item-add {
|
||||
color: #4a7c59;
|
||||
|
||||
&:hover {
|
||||
color: #2d5a3a;
|
||||
background: rgba(74, 124, 89, 0.2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.item-controls-fixed {
|
||||
min-width: 3.2rem;
|
||||
max-width: 3.2rem;
|
||||
}
|
||||
|
||||
// Couleurs pour les labels et textes dans les onglets
|
||||
h4, h3, label, span.item-name-label, span.competence-name,
|
||||
.label-name, .generic-label, .item-field-label-short,
|
||||
.item-field-label-medium, .item-field-label-long,
|
||||
.short-label, .items-title-text {
|
||||
color: #3a2a1a !important;
|
||||
text-shadow: 0px 0px 1px rgba(255, 255, 255, 0.3);
|
||||
}
|
||||
|
||||
// Inputs dans le corps
|
||||
input[type="text"], input[type="number"], select {
|
||||
color: #2a1a0a;
|
||||
background: rgba(255, 250, 240, 0.8);
|
||||
border: 1px solid rgba(139, 69, 19, 0.5);
|
||||
height: 24px;
|
||||
padding: 0.15rem 0.3rem;
|
||||
line-height: 1.2;
|
||||
|
||||
&:focus {
|
||||
background: rgba(255, 255, 245, 0.95);
|
||||
border-color: rgba(139, 69, 19, 0.8);
|
||||
}
|
||||
}
|
||||
|
||||
// Titres de sections
|
||||
h3, h4 {
|
||||
font-weight: bold;
|
||||
color: #2a1a0a !important;
|
||||
}
|
||||
|
||||
// Titres de sections Santé, Âme, Combat
|
||||
h4.item-name-label.competence-name {
|
||||
font-size: 0.85rem;
|
||||
margin-top: 0.2rem;
|
||||
margin-bottom: 0.3rem;
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
// Section grids pour Santé, Âme, Combat
|
||||
.section-grid {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.2rem;
|
||||
padding: 0.3rem 0.4rem;
|
||||
margin-bottom: 0.3rem;
|
||||
background: rgba(0, 0, 0, 0.15);
|
||||
border: 2px solid rgba(139, 69, 19, 0.5);
|
||||
border-radius: 4px;
|
||||
|
||||
.section-title {
|
||||
font-size: 0.85rem;
|
||||
font-weight: bold;
|
||||
color: #f5e6d3;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.5px;
|
||||
margin: 0 0 0.2rem 0;
|
||||
padding: 0.2rem 0.4rem;
|
||||
background: rgba(0, 0, 0, 0.3);
|
||||
border-left: 3px solid rgba(139, 69, 19, 0.8);
|
||||
border-radius: 2px;
|
||||
text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.9);
|
||||
}
|
||||
|
||||
.grid-row {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
align-items: center;
|
||||
gap: 0.4rem;
|
||||
padding: 0.25rem 0.4rem;
|
||||
background: rgba(0, 0, 0, 0.2);
|
||||
border: 1px solid rgba(139, 69, 19, 0.4);
|
||||
border-radius: 3px;
|
||||
|
||||
input {
|
||||
width: 60px;
|
||||
min-width: 60px;
|
||||
}
|
||||
|
||||
&.attr-row {
|
||||
grid-template-columns: 40px 1fr auto;
|
||||
gap: 0.5rem;
|
||||
|
||||
.item-name-img {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border-radius: 3px;
|
||||
border: 1px solid rgba(139, 69, 19, 0.5);
|
||||
}
|
||||
|
||||
.label-name {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
a {
|
||||
color: #f5e6d3;
|
||||
text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.7);
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
color: #fff;
|
||||
text-shadow: 0 0 4px rgba(255, 200, 100, 0.8);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
select {
|
||||
width: 80px;
|
||||
}
|
||||
}
|
||||
|
||||
.label-name {
|
||||
font-weight: 600;
|
||||
font-size: 0.9rem;
|
||||
color: #d4c5b0;
|
||||
text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.7);
|
||||
}
|
||||
|
||||
.stat-label {
|
||||
font-weight: 600;
|
||||
font-size: 0.9rem;
|
||||
color: #d4c5b0;
|
||||
text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.7);
|
||||
}
|
||||
|
||||
.value-display {
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
font-size: 1rem;
|
||||
color: #fff;
|
||||
background: rgba(0, 0, 0, 0.4);
|
||||
padding: 0.2rem 0.4rem;
|
||||
border-radius: 3px;
|
||||
border: 1px solid rgba(139, 69, 19, 0.6);
|
||||
text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.9);
|
||||
}
|
||||
|
||||
.malus-value {
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
font-size: 1rem;
|
||||
color: #ff9999;
|
||||
background: rgba(0, 0, 0, 0.4);
|
||||
padding: 0.2rem 0.4rem;
|
||||
border-radius: 3px;
|
||||
border: 1px solid rgba(200, 50, 50, 0.6);
|
||||
text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.9);
|
||||
}
|
||||
|
||||
&.damage-row {
|
||||
grid-template-columns: 120px 1fr;
|
||||
|
||||
.damage-label {
|
||||
font-size: 0.95rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.damage-controls {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 0.4rem;
|
||||
|
||||
input {
|
||||
width: 60px;
|
||||
min-width: 60px;
|
||||
flex-shrink: 0;
|
||||
text-align: center;
|
||||
font-size: 1.1rem;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.plus-minus-button {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 1.2rem;
|
||||
font-weight: bold;
|
||||
border-radius: 4px;
|
||||
border: 2px solid rgba(139, 69, 19, 0.5);
|
||||
background: linear-gradient(to bottom, rgba(210, 180, 140, 0.9), rgba(180, 150, 110, 0.9));
|
||||
color: #2a1a0a;
|
||||
cursor: pointer;
|
||||
transition: all 0.15s;
|
||||
|
||||
&:hover {
|
||||
background: linear-gradient(to bottom, rgba(230, 200, 160, 0.95), rgba(200, 170, 130, 0.95));
|
||||
border-color: rgba(139, 69, 19, 0.8);
|
||||
transform: scale(1.08);
|
||||
}
|
||||
|
||||
&:active {
|
||||
transform: scale(0.95);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.soul-consumed-row {
|
||||
grid-template-columns: 120px 1fr;
|
||||
}
|
||||
|
||||
&.soul-malus-row {
|
||||
grid-template-columns: 90px 1fr;
|
||||
gap: 0.4rem;
|
||||
|
||||
.label-name {
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
|
||||
.malus-value {
|
||||
font-size: 0.9rem;
|
||||
padding: 0.2rem 0.3rem;
|
||||
}
|
||||
}
|
||||
|
||||
&.malus-row {
|
||||
grid-template-columns: 55px 60px 75px 50px;
|
||||
gap: 0.3rem;
|
||||
|
||||
.label-name {
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
|
||||
input {
|
||||
width: 100%;
|
||||
min-width: unset;
|
||||
}
|
||||
|
||||
.malus-value {
|
||||
font-size: 0.9rem;
|
||||
padding: 0.2rem 0.3rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.combat-grid {
|
||||
.grid-row.combat-stat {
|
||||
grid-template-columns: 85px 50px 60px 55px;
|
||||
gap: 0.4rem;
|
||||
|
||||
.stat-label {
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
|
||||
.stat-base {
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
font-size: 0.85rem;
|
||||
color: #fff;
|
||||
background: rgba(0, 0, 0, 0.4);
|
||||
padding: 0.2rem 0.3rem;
|
||||
border-radius: 3px;
|
||||
border: 1px solid rgba(139, 69, 19, 0.6);
|
||||
text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.9);
|
||||
}
|
||||
|
||||
input {
|
||||
width: 50px;
|
||||
min-width: 50px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.stat-total {
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
font-size: 0.85rem;
|
||||
color: #fff;
|
||||
background: rgba(0, 0, 0, 0.4);
|
||||
padding: 0.2rem 0.3rem;
|
||||
border-radius: 3px;
|
||||
border: 1px solid rgba(139, 69, 19, 0.6);
|
||||
text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.9);
|
||||
}
|
||||
}
|
||||
|
||||
.grid-row.protection-row {
|
||||
grid-template-columns: 1fr 1fr;
|
||||
|
||||
.protection-value {
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
font-size: 1.2rem;
|
||||
color: #fff;
|
||||
background: rgba(0, 0, 0, 0.4);
|
||||
padding: 0.25rem 0.4rem;
|
||||
border-radius: 3px;
|
||||
border: 1px solid rgba(139, 69, 19, 0.6);
|
||||
text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.9);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Boutons d'actions spéciales
|
||||
.action-buttons {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.3rem;
|
||||
padding: 0.3rem 0;
|
||||
|
||||
button {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.action-buttons-row {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
padding: 0.3rem 0;
|
||||
|
||||
button {
|
||||
margin: 0;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.mounted-checkbox {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.4rem;
|
||||
padding: 0.3rem 0.6rem;
|
||||
white-space: nowrap;
|
||||
|
||||
label {
|
||||
margin: 0;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
input[type="checkbox"] {
|
||||
margin: 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================== Creature Sheet Specific Styles ==================== */
|
||||
.fvtt-mournblade.actor.creature-sheet {
|
||||
|
||||
// Variant background pour creatures - teinte légèrement différente
|
||||
.background-sheet-header-creature {
|
||||
background: linear-gradient(135deg, rgba(0, 60, 0, 0.15) 0%, rgba(20, 80, 20, 0.1) 100%);
|
||||
border: 2px solid rgba(34, 139, 34, 0.5);
|
||||
border-radius: 4px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
// Légère teinte verte pour les sections
|
||||
.sheet-box {
|
||||
&.color-bg-archetype {
|
||||
background: linear-gradient(135deg, rgba(0, 40, 0, 0.08) 0%, rgba(20, 60, 20, 0.05) 100%);
|
||||
}
|
||||
}
|
||||
|
||||
// Header simplifié pour creatures
|
||||
.sheet-header {
|
||||
flex: 0 0 auto !important;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.profile-img {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
border-radius: 8px;
|
||||
border: 2px solid rgba(34, 139, 34, 0.6);
|
||||
object-fit: cover;
|
||||
cursor: pointer;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
// Tabs avec teinte verte
|
||||
nav.tabs {
|
||||
.item.active {
|
||||
border-bottom-color: rgba(34, 139, 34, 0.8);
|
||||
color: #228b22;
|
||||
}
|
||||
}
|
||||
|
||||
// Section titles avec teinte verte
|
||||
.section-title {
|
||||
color: #1a5a1a;
|
||||
border-bottom-color: rgba(34, 139, 34, 0.3);
|
||||
}
|
||||
|
||||
// Items headers
|
||||
.items-title-bg {
|
||||
background: linear-gradient(135deg, rgba(0, 60, 0, 0.15) 0%, rgba(20, 80, 20, 0.1) 100%);
|
||||
border-bottom: 1px solid rgba(34, 139, 34, 0.3);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// PNJ Sheet - Orange/Copper theme for visual distinction
|
||||
.fvtt-mournblade.actor.pnj-sheet {
|
||||
|
||||
// Variant background pour PNJs - teinte orange/cuivre
|
||||
.background-sheet-header-creature {
|
||||
background: linear-gradient(135deg, rgba(80, 40, 0, 0.15) 0%, rgba(100, 50, 0, 0.1) 100%);
|
||||
border: 2px solid rgba(205, 127, 50, 0.5);
|
||||
border-radius: 4px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
// Légère teinte orange/cuivre pour les sections
|
||||
.sheet-box {
|
||||
&.color-bg-archetype {
|
||||
background: linear-gradient(135deg, rgba(60, 30, 0, 0.08) 0%, rgba(80, 40, 0, 0.05) 100%);
|
||||
}
|
||||
}
|
||||
|
||||
// Header simplifié pour PNJs
|
||||
.sheet-header {
|
||||
flex: 0 0 auto !important;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.profile-img {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
border-radius: 8px;
|
||||
border: 2px solid rgba(205, 127, 50, 0.6);
|
||||
object-fit: cover;
|
||||
cursor: pointer;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
// Tabs avec teinte orange/cuivre
|
||||
nav.tabs {
|
||||
.item.active {
|
||||
border-bottom-color: rgba(205, 127, 50, 0.8);
|
||||
color: #cd7f32;
|
||||
}
|
||||
}
|
||||
|
||||
// Section titles avec teinte orange/cuivre
|
||||
.section-title {
|
||||
color: #b8734d;
|
||||
border-bottom-color: rgba(205, 127, 50, 0.3);
|
||||
}
|
||||
|
||||
// Items headers
|
||||
.items-title-bg {
|
||||
background: linear-gradient(135deg, rgba(80, 40, 0, 0.15) 0%, rgba(100, 50, 0, 0.1) 100%);
|
||||
border-bottom: 1px solid rgba(205, 127, 50, 0.3);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// GM Tools section - labels plus larges
|
||||
.gm-tools-section {
|
||||
.grid {
|
||||
.item-list .flexrow.item {
|
||||
.label-name {
|
||||
flex: 1;
|
||||
min-width: 12rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Alignment group in header
|
||||
.stat-group-alignment {
|
||||
.stat-values.alignment-values {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.3rem;
|
||||
}
|
||||
|
||||
.alignment-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.3rem;
|
||||
|
||||
.alignment-label {
|
||||
font-weight: bold;
|
||||
min-width: 4rem;
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
|
||||
.alignment-inputs {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.2rem;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.stat-label-mini {
|
||||
font-size: 0.7rem;
|
||||
min-width: 2.5rem;
|
||||
}
|
||||
|
||||
.stat-input-mini {
|
||||
width: 2.5rem;
|
||||
height: 1.5rem;
|
||||
padding: 0.1rem 0.2rem;
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
select.stat-input-mini {
|
||||
width: 3rem;
|
||||
}
|
||||
}
|
||||
|
||||
.alignment-info {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
margin-top: 0.2rem;
|
||||
padding-top: 0.2rem;
|
||||
border-top: 1px solid rgba(139, 69, 19, 0.3);
|
||||
|
||||
.info-label {
|
||||
font-size: 0.75rem;
|
||||
color: #f5e6d3;
|
||||
|
||||
strong {
|
||||
color: #ffd700;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
299
less/item-styles.less
Normal file
@@ -0,0 +1,299 @@
|
||||
/* ==================== Item Sheet Styles ==================== */
|
||||
|
||||
/* Item header with image and name */
|
||||
.fvtt-mournblade.item {
|
||||
/* Background pour toute la fiche d'item */
|
||||
background: url("../assets/ui/pc_sheet_bg.webp") repeat;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
|
||||
/* AppV2 - Remove window content padding */
|
||||
.window-content {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* AppV2 - Main section structure */
|
||||
section {
|
||||
background: url("../assets/ui/pc_sheet_bg.webp") repeat-y;
|
||||
color: black;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* AppV2 Item Sheets - Disabled inputs readability */
|
||||
input:disabled,
|
||||
select:disabled {
|
||||
color: #000000;
|
||||
opacity: 0.8;
|
||||
background-color: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
|
||||
/* Inputs and selects styling */
|
||||
input[type="text"],
|
||||
input[type="number"],
|
||||
select {
|
||||
color: #000000;
|
||||
background-color: rgba(255, 255, 255, 0.7);
|
||||
border: 1px solid #999999;
|
||||
margin: 0;
|
||||
padding: 2px 4px;
|
||||
font-family: "CentaurMT", serif;
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
|
||||
textarea {
|
||||
margin: 0;
|
||||
padding: 2px 4px;
|
||||
}
|
||||
|
||||
input[type="checkbox"] {
|
||||
width: auto;
|
||||
height: auto;
|
||||
margin: 0 4px;
|
||||
align-self: center;
|
||||
}
|
||||
|
||||
.header {
|
||||
flex: 0 0 auto;
|
||||
border-bottom: 1px solid #999;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.sheet-header {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
padding: 0.5rem;
|
||||
background: url("../assets/ui/pc_sheet_bg.webp") repeat;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
.item-sheet-img {
|
||||
flex: 0 0 64px;
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
object-fit: cover;
|
||||
border: 1px solid #999;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
box-shadow: 0 0 8px rgba(255, 102, 0, 0.8);
|
||||
}
|
||||
}
|
||||
|
||||
.header-fields {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.25rem;
|
||||
}
|
||||
|
||||
.header-actions {
|
||||
flex: 0 0 auto;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
|
||||
button {
|
||||
background: rgba(0, 0, 0, 0.1);
|
||||
border: 1px solid #999;
|
||||
padding: 0.25rem 0.5rem;
|
||||
cursor: pointer;
|
||||
font-family: "CentaurMT", serif;
|
||||
|
||||
&:hover {
|
||||
background: rgba(255, 102, 0, 0.2);
|
||||
box-shadow: 0 0 5px rgba(255, 102, 0, 0.5);
|
||||
}
|
||||
}
|
||||
|
||||
.chat-card-button {
|
||||
background: linear-gradient(to bottom, #21374afc 5%, #152833ab 100%);
|
||||
border: 2px ridge #846109;
|
||||
color: #d4b5a8;
|
||||
padding: 0.3rem 0.5rem;
|
||||
transition: all 0.2s ease;
|
||||
|
||||
i {
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: linear-gradient(to bottom, #800000 5%, #3e0101 100%);
|
||||
color: #ffffff;
|
||||
box-shadow: 0 0 8px rgba(128, 0, 0, 0.6);
|
||||
}
|
||||
|
||||
&:active {
|
||||
position: relative;
|
||||
top: 1px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.sheet-header h1.charname {
|
||||
height: 50px;
|
||||
padding: 0;
|
||||
margin: 5px 0;
|
||||
border-bottom: 0;
|
||||
font-weight: bold;
|
||||
font-size: 2rem;
|
||||
font-family: "CentaurMT";
|
||||
}
|
||||
|
||||
.sheet-header h1.charname input {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
font-weight: bold;
|
||||
font-family: "CentaurMT";
|
||||
font-size: 2rem;
|
||||
text-align: left;
|
||||
border: 0 none;
|
||||
|
||||
&:focus {
|
||||
outline: 1px solid #ff6600;
|
||||
}
|
||||
}
|
||||
|
||||
/* Tabs - Modern style matching actor sheets */
|
||||
nav.tabs {
|
||||
display: flex;
|
||||
border-bottom: 1px solid #7a7971;
|
||||
margin: 0;
|
||||
padding: 4px;
|
||||
background-color: #1c1c1c;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
nav.tabs a.item {
|
||||
padding: 6px 12px;
|
||||
color: #d4af37;
|
||||
text-decoration: none;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 4px 4px 0 0;
|
||||
margin-right: 4px;
|
||||
transition: all 0.2s;
|
||||
|
||||
i {
|
||||
display: none; // Hide icons to match actor sheets
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(212, 175, 55, 0.1);
|
||||
}
|
||||
|
||||
&.active {
|
||||
background-color: #2a2a2a;
|
||||
border-bottom-color: #d4af37;
|
||||
color: #f5f5f5;
|
||||
}
|
||||
}
|
||||
|
||||
/* Tab content */
|
||||
.tab {
|
||||
display: none;
|
||||
padding: 4px 8px;
|
||||
overflow-y: auto;
|
||||
flex: 1 1 auto;
|
||||
|
||||
&.active {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
/* Item list in details tab */
|
||||
.item-list {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
|
||||
li.item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 2px;
|
||||
padding: 2px 4px;
|
||||
min-height: 24px;
|
||||
border-bottom: none;
|
||||
|
||||
&.flexrow {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Labels */
|
||||
.generic-label {
|
||||
display: inline-block;
|
||||
white-space: nowrap;
|
||||
font-weight: 700;
|
||||
color: #464331c4;
|
||||
font-size: 0.9rem;
|
||||
font-family: "CentaurMT", serif;
|
||||
margin: 0;
|
||||
padding: 0 4px 0 0;
|
||||
}
|
||||
|
||||
/* Field labels */
|
||||
.item-field-label-short {
|
||||
flex: 0 0 60px;
|
||||
max-width: 60px;
|
||||
}
|
||||
|
||||
.item-field-label-medium {
|
||||
flex: 0 0 100px;
|
||||
max-width: 100px;
|
||||
}
|
||||
|
||||
.item-field-label-long {
|
||||
flex: 1;
|
||||
min-width: 150px;
|
||||
}
|
||||
|
||||
.item-field-label-long1 {
|
||||
flex: 1;
|
||||
min-width: 200px;
|
||||
}
|
||||
|
||||
.item-field-label-long2 {
|
||||
flex: 1;
|
||||
min-width: 250px;
|
||||
max-width: 250px;
|
||||
}
|
||||
.item-field-label-long3 {
|
||||
flex: 1;
|
||||
min-width: 350px;
|
||||
max-width: 350px;
|
||||
}
|
||||
|
||||
.numeric-input {
|
||||
text-align: center;
|
||||
width: 60px;
|
||||
}
|
||||
|
||||
/* Editor fields */
|
||||
.editor {
|
||||
height: 300px;
|
||||
border: 1px solid #999;
|
||||
background: rgba(255, 255, 255, 0.9);
|
||||
|
||||
.editor-content {
|
||||
height: 100%;
|
||||
padding: 0.5rem;
|
||||
color: #000;
|
||||
}
|
||||
}
|
||||
}
|
||||
6
less/mournblade.less
Normal file
@@ -0,0 +1,6 @@
|
||||
// Main LESS file for Mournblade system
|
||||
// Importing base styles and component-specific styles
|
||||
|
||||
@import "simple-converted";
|
||||
@import "item-styles";
|
||||
@import "actor-styles";
|
||||
2476
less/simple-converted.less
Normal file
@@ -1,18 +1,18 @@
|
||||
/**
|
||||
* Extend the basic ActorSheet with some very simple modifications
|
||||
* @extends {ActorSheet}
|
||||
* @extends {ActorSheetV2}
|
||||
*/
|
||||
|
||||
import { MournbladeUtility } from "./mournblade-utility.js";
|
||||
import { MournbladeRollDialog } from "./mournblade-roll-dialog.js";
|
||||
|
||||
/* -------------------------------------------- */
|
||||
export class MournbladeActorSheet extends ActorSheet {
|
||||
export class MournbladeActorSheet extends foundry.applications.sheets.ActorSheetV2 {
|
||||
|
||||
/** @override */
|
||||
static get defaultOptions() {
|
||||
|
||||
return mergeObject(super.defaultOptions, {
|
||||
return foundry.utils.mergeObject(super.defaultOptions, {
|
||||
classes: ["fvtt-mournblade", "sheet", "actor"],
|
||||
template: "systems/fvtt-mournblade/templates/actor-sheet.html",
|
||||
width: 640,
|
||||
@@ -25,9 +25,8 @@ export class MournbladeActorSheet extends ActorSheet {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async getData() {
|
||||
const objectData = MournbladeUtility.data(this.object);
|
||||
|
||||
let actorData = duplicate(MournbladeUtility.templateData(this.object))
|
||||
const objectData = foundry.utils.duplicate(this.object)
|
||||
let actorData = objectData
|
||||
|
||||
let formData = {
|
||||
title: this.title,
|
||||
@@ -37,14 +36,34 @@ export class MournbladeActorSheet extends ActorSheet {
|
||||
name: objectData.name,
|
||||
editable: this.isEditable,
|
||||
cssClass: this.isEditable ? "editable" : "locked",
|
||||
data: actorData,
|
||||
data: actorData.system,
|
||||
effects: this.object.effects.map(e => foundry.utils.deepClone(e.data)),
|
||||
limited: this.object.limited,
|
||||
skills: duplicate(this.actor.getSkills()),
|
||||
weapons: duplicate(this.actor.getWeapons()),
|
||||
armors: duplicate(this.actor.getArmors()),
|
||||
skills: this.actor.getSkills(),
|
||||
armes: foundry.utils.duplicate(this.actor.getWeapons()),
|
||||
protections: foundry.utils.duplicate(this.actor.getArmors()),
|
||||
dons: foundry.utils.duplicate(this.actor.getDons()),
|
||||
pactes: foundry.utils.duplicate(this.actor.getPactes()),
|
||||
alignement: this.actor.getAlignement(),
|
||||
//equipments: duplicate(this.actor.getEquipments()),
|
||||
aspect: this.actor.getAspect(),
|
||||
marge: this.actor.getMarge(),
|
||||
tendances:foundry.utils.duplicate(this.actor.getTendances()),
|
||||
runes:foundry.utils.duplicate(this.actor.getRunes()),
|
||||
traitsChaotiques:foundry.utils.duplicate(this.actor.getTraitsChaotiques()),
|
||||
traitsEspeces: foundry.utils.duplicate(this.actor.getTraitsEspeces()),
|
||||
origine: foundry.utils.duplicate(this.actor.getOrigine() || {}),
|
||||
heritage: foundry.utils.duplicate(this.actor.getHeritage() || {}),
|
||||
metier: foundry.utils.duplicate(this.actor.getMetier() || {}),
|
||||
combat: this.actor.getCombatValues(),
|
||||
equipements: foundry.utils.duplicate(this.actor.getEquipments()),
|
||||
modifiers: foundry.utils.duplicate(this.actor.getModifiers()),
|
||||
monnaies: foundry.utils.duplicate(this.actor.getMonnaies()),
|
||||
runeEffects: foundry.utils.duplicate(this.actor.getRuneEffects()),
|
||||
config: game.system.mournblade.config,
|
||||
protectionTotal: this.actor.getProtectionTotal(),
|
||||
santeMalus: this.actor.getStatusMalus(),
|
||||
ameMalus: this.actor.getAmeMalus(),
|
||||
description: await foundry.applications.ux.TextEditor.implementation.enrichHTML(this.object.system.biodata.description, {async: true}),
|
||||
options: this.options,
|
||||
owner: this.document.isOwner,
|
||||
editScore: this.options.editScore,
|
||||
@@ -56,7 +75,7 @@ export class MournbladeActorSheet extends ActorSheet {
|
||||
return formData;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/** @override */
|
||||
activateListeners(html) {
|
||||
@@ -64,14 +83,14 @@ export class MournbladeActorSheet extends ActorSheet {
|
||||
|
||||
// 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");
|
||||
@@ -86,7 +105,7 @@ export class MournbladeActorSheet extends ActorSheet {
|
||||
let value = ev.currentTarget.value
|
||||
this.actor.editItemField(itemId, itemType, itemField, dataType, value)
|
||||
})
|
||||
|
||||
|
||||
html.find('.quantity-minus').click(event => {
|
||||
const li = $(event.currentTarget).parents(".item");
|
||||
this.actor.incDecQuantity( li.data("item-id"), -1 );
|
||||
@@ -107,41 +126,68 @@ export class MournbladeActorSheet extends ActorSheet {
|
||||
let compId = li.data("item-id")
|
||||
this.actor.rollCompetence(attrKey, compId)
|
||||
})
|
||||
|
||||
html.find('.roll-spec').click((event) => {
|
||||
const li = $(event.currentTarget).parents(".item");
|
||||
const specId = li.data("item-id");
|
||||
this.actor.rollSpec(specId);
|
||||
});
|
||||
html.find('.weapon-roll').click((event) => {
|
||||
const li = $(event.currentTarget).parents(".item");
|
||||
const weaponId = li.data("item-id");
|
||||
this.actor.rollWeapon(weaponId);
|
||||
});
|
||||
html.find('.armor-roll').click((event) => {
|
||||
const li = $(event.currentTarget).parents(".item");
|
||||
const armorId = li.data("item-id");
|
||||
this.actor.rollArmor(armorId);
|
||||
});
|
||||
|
||||
html.find('.weapon-damage-roll').click((event) => {
|
||||
const li = $(event.currentTarget).parents(".item");
|
||||
const weaponId = li.data("item-id");
|
||||
this.actor.rollWeapon(weaponId, true);
|
||||
});
|
||||
|
||||
html.find('.roll-rune').click((event) => {
|
||||
const li = $(event.currentTarget).parents(".item")
|
||||
let runeId = li.data("item-id")
|
||||
this.actor.rollRune(runeId)
|
||||
})
|
||||
html.find('.roll-arme-offensif').click((event) => {
|
||||
const li = $(event.currentTarget).parents(".item")
|
||||
let armeId = li.data("item-id")
|
||||
this.actor.rollArmeOffensif(armeId)
|
||||
})
|
||||
html.find('.roll-assomer').click((event) => {
|
||||
this.actor.rollAssomer()
|
||||
})
|
||||
html.find('.roll-fuir').click((event) => {
|
||||
this.actor.rollFuir()
|
||||
})
|
||||
html.find('.roll-immobiliser').click((event) => {
|
||||
this.actor.rollImmobiliser()
|
||||
})
|
||||
html.find('.roll-arme-special').click((event) => {
|
||||
const li = $(event.currentTarget).parents(".item")
|
||||
let armeId = li.data("item-id")
|
||||
this.actor.rollArmeSpecial(armeId)
|
||||
})
|
||||
|
||||
html.find('.roll-arme-degats').click((event) => {
|
||||
const li = $(event.currentTarget).parents(".item")
|
||||
let armeId = li.data("item-id")
|
||||
this.actor.rollArmeDegats(armeId)
|
||||
})
|
||||
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('.item-add').click((event) => {
|
||||
const itemType = $(event.currentTarget).data("type")
|
||||
this.actor.createEmbeddedDocuments('Item', [{ name: `Nouveau ${itemType}`, type: itemType }], { renderSheet: true })
|
||||
})
|
||||
html.find('.sante-modify').click((event) => {
|
||||
const santeType = $(event.currentTarget).data("type")
|
||||
const value = $(event.currentTarget).data("value")
|
||||
this.actor.incDecSante(santeType, value, false)
|
||||
})
|
||||
html.find('.ame-modify').click((event) => {
|
||||
const value = $(event.currentTarget).data("value")
|
||||
this.actor.incDecAme(value)
|
||||
})
|
||||
|
||||
|
||||
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);
|
||||
this.render(true);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/** @override */
|
||||
setPosition(options = {}) {
|
||||
@@ -153,11 +199,11 @@ export class MournbladeActorSheet extends ActorSheet {
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async _onDropItem(event, dragData) {
|
||||
/*async _onDropItem(event, dragData) {
|
||||
let item = await MournbladeUtility.searchItem( dragData)
|
||||
this.actor.preprocessItem( event, item, true )
|
||||
super._onDropItem(event, dragData)
|
||||
}
|
||||
}*/
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/** @override */
|
||||
25
modules/_deprecated/mournblade-creature-sheet.js
Normal file
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
* Extend the basic ActorSheet with some very simple modifications
|
||||
* @extends {ActorSheet}
|
||||
*/
|
||||
|
||||
import { MournbladeActorSheet } from "./mournblade-actor-sheet.js";
|
||||
import { MournbladeUtility } from "./mournblade-utility.js";
|
||||
|
||||
/* -------------------------------------------- */
|
||||
export class MournbladeCreatureSheet extends MournbladeActorSheet {
|
||||
|
||||
/** @override */
|
||||
static get defaultOptions() {
|
||||
|
||||
return foundry.utils.mergeObject(super.defaultOptions, {
|
||||
classes: ["fvtt-mournblade", "sheet", "actor"],
|
||||
template: "systems/fvtt-mournblade/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
|
||||
})
|
||||
}
|
||||
}
|
||||
158
modules/applications/mournblade-roll-dialog.mjs
Normal file
@@ -0,0 +1,158 @@
|
||||
import { MournbladeUtility } from "../mournblade-utility.js"
|
||||
|
||||
/**
|
||||
* Dialogue de jet de dé pour Mournblade - Version DialogV2
|
||||
*/
|
||||
export class MournbladeRollDialog {
|
||||
|
||||
/**
|
||||
* Create and display the roll dialog
|
||||
* @param {MournbladeActor} actor - The actor making the roll
|
||||
* @param {Object} rollData - Data for the roll
|
||||
* @returns {Promise<MournbladeRollDialog>}
|
||||
*/
|
||||
static async create(actor, rollData) {
|
||||
// Préparer le contexte pour le template
|
||||
const context = {
|
||||
...rollData,
|
||||
difficulte: String(rollData.difficulte || 0),
|
||||
img: actor.img,
|
||||
name: actor.name,
|
||||
config: game.system.mournblade.config,
|
||||
}
|
||||
|
||||
// Si attrKey est "tochoose", préparer la liste des attributs sélectionnables
|
||||
if (rollData.attrKey === "tochoose") {
|
||||
context.selectableAttributes = actor.system.attributs
|
||||
}
|
||||
|
||||
// Rendre le template en HTML
|
||||
const content = await foundry.applications.handlebars.renderTemplate(
|
||||
"systems/fvtt-mournblade/templates/roll-dialog-v2.hbs",
|
||||
context
|
||||
)
|
||||
|
||||
// Utiliser DialogV2.wait avec le HTML rendu
|
||||
return foundry.applications.api.DialogV2.wait({
|
||||
window: { title: "Test de Capacité", icon: "fa-solid fa-dice-d20" },
|
||||
classes: ["mournblade-roll-dialog"],
|
||||
position: { width: 500 },
|
||||
modal: false,
|
||||
content,
|
||||
buttons: [
|
||||
{
|
||||
action: "rolld10",
|
||||
label: "Lancer 1d10",
|
||||
icon: "fa-solid fa-dice-d10",
|
||||
default: true,
|
||||
callback: (event, button, dialog) => {
|
||||
this._updateRollDataFromForm(rollData, button.form.elements, actor)
|
||||
rollData.mainDice = "1d10"
|
||||
MournbladeUtility.rollMournblade(rollData)
|
||||
}
|
||||
},
|
||||
{
|
||||
action: "rolld20",
|
||||
label: "Lancer 1d20",
|
||||
icon: "fa-solid fa-dice-d20",
|
||||
callback: (event, button, dialog) => {
|
||||
this._updateRollDataFromForm(rollData, button.form.elements, actor)
|
||||
rollData.mainDice = "1d20"
|
||||
MournbladeUtility.rollMournblade(rollData)
|
||||
}
|
||||
},
|
||||
],
|
||||
rejectClose: false,
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Mettre à jour rollData avec les valeurs du formulaire
|
||||
* @param {Object} rollData - L'objet rollData à mettre à jour
|
||||
* @param {HTMLFormControlsCollection} formElements - Les éléments du formulaire
|
||||
* @param {MournbladeActor} actor - L'acteur pour récupérer les attributs
|
||||
* @private
|
||||
*/
|
||||
static _updateRollDataFromForm(rollData, formElements, actor) {
|
||||
// Attributs
|
||||
if (formElements.attrKey) {
|
||||
rollData.attrKey = formElements.attrKey.value
|
||||
if (rollData.attrKey !== "tochoose" && actor) {
|
||||
rollData.attr = foundry.utils.duplicate(actor.system.attributs[rollData.attrKey])
|
||||
rollData.actionImg = "systems/fvtt-mournblade/assets/icons/" + actor.system.attributs[rollData.attrKey].labelnorm + ".webp"
|
||||
}
|
||||
}
|
||||
|
||||
// Modificateurs de base
|
||||
if (formElements.difficulte) {
|
||||
rollData.difficulte = Number(formElements.difficulte.value)
|
||||
}
|
||||
if (formElements.modificateur) {
|
||||
rollData.modificateur = Number(formElements.modificateur.value)
|
||||
}
|
||||
|
||||
// Runes
|
||||
if (formElements.runemode) {
|
||||
rollData.runemode = String(formElements.runemode.value)
|
||||
}
|
||||
if (formElements.runeame) {
|
||||
rollData.runeame = Number(formElements.runeame.value)
|
||||
}
|
||||
|
||||
// Combat mêlée
|
||||
if (formElements.typeAttaque) {
|
||||
rollData.typeAttaque = String(formElements.typeAttaque.value)
|
||||
}
|
||||
if (formElements.isMonte !== undefined) {
|
||||
rollData.isMonte = formElements.isMonte.checked
|
||||
}
|
||||
|
||||
// Combat distance
|
||||
if (formElements.visee !== undefined) {
|
||||
rollData.visee = formElements.visee.checked
|
||||
}
|
||||
if (formElements.cibleconsciente !== undefined) {
|
||||
rollData.cibleconsciente = formElements.cibleconsciente.checked
|
||||
}
|
||||
if (formElements.ciblecourt !== undefined) {
|
||||
rollData.ciblecourt = formElements.ciblecourt.checked
|
||||
}
|
||||
if (formElements.typeCouvert) {
|
||||
rollData.typeCouvert = String(formElements.typeCouvert.value)
|
||||
}
|
||||
|
||||
// Désavantages
|
||||
if (!rollData.desavantages) rollData.desavantages = {}
|
||||
|
||||
if (formElements.cibleausol !== undefined) {
|
||||
rollData.desavantages.cibleausol = formElements.cibleausol.checked
|
||||
}
|
||||
if (formElements.cibledesarmee !== undefined) {
|
||||
rollData.desavantages.cibledesarmee = formElements.cibledesarmee.checked
|
||||
}
|
||||
if (formElements.ciblerestreint !== undefined) {
|
||||
rollData.desavantages.ciblerestreint = formElements.ciblerestreint.checked
|
||||
}
|
||||
if (formElements.cibleimmobilisée !== undefined) {
|
||||
rollData.desavantages.cibleimmobilisée = formElements.cibleimmobilisée.checked
|
||||
}
|
||||
if (formElements.ciblesurplomb !== undefined) {
|
||||
rollData.desavantages.ciblesurplomb = formElements.ciblesurplomb.checked
|
||||
}
|
||||
|
||||
// Double D20
|
||||
if (formElements.doubleD20 !== undefined) {
|
||||
rollData.doubleD20 = formElements.doubleD20.checked
|
||||
}
|
||||
|
||||
// Modifiers
|
||||
if (rollData.modifiers) {
|
||||
rollData.modifiers.forEach((modifier, idx) => {
|
||||
const checkbox = formElements[`apply-modifier-${idx}`]
|
||||
if (checkbox) {
|
||||
modifier.system.apply = checkbox.checked
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
29
modules/applications/sheets/_module.mjs
Normal file
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* Index des applications AppV2 pour Mournblade
|
||||
* Ce fichier centralise tous les exports des applications
|
||||
*/
|
||||
|
||||
// Applications de feuilles d'acteurs
|
||||
export { default as MournbladePersonnageSheet } from './mournblade-personnage-sheet.mjs';
|
||||
export { default as MournbladeCreatureSheet } from './mournblade-creature-sheet.mjs';
|
||||
export { default as MournbladePnjSheet } from './mournblade-pnj-sheet.mjs';
|
||||
|
||||
// Applications de feuilles d'items
|
||||
export { default as MournbladeArmeSheet } from './mournblade-arme-sheet.mjs';
|
||||
export { default as MournbladeBouclierSheet } from './mournblade-bouclier-sheet.mjs';
|
||||
export { default as MournbladeCapaciteSheet } from './mournblade-capacite-sheet.mjs';
|
||||
export { default as MournbladeCompetenceSheet } from './mournblade-competence-sheet.mjs';
|
||||
export { default as MournbladeDonSheet } from './mournblade-don-sheet.mjs';
|
||||
export { default as MournbladeEquipementSheet } from './mournblade-equipement-sheet.mjs';
|
||||
export { default as MournbladeHeritageSheet } from './mournblade-heritage-sheet.mjs';
|
||||
export { default as MournbladeMetierSheet } from './mournblade-metier-sheet.mjs';
|
||||
export { default as MournbladeModifierSheet } from './mournblade-modifier-sheet.mjs';
|
||||
export { default as MournbladeMonnaieSheet } from './mournblade-monnaie-sheet.mjs';
|
||||
export { default as MournbladeOrigineSheet } from './mournblade-origine-sheet.mjs';
|
||||
export { default as MournbladePacteSheet } from './mournblade-pacte-sheet.mjs';
|
||||
export { default as MournbladeProtectionSheet } from './mournblade-protection-sheet.mjs';
|
||||
export { default as MournbladeRuneSheet } from './mournblade-rune-sheet.mjs';
|
||||
export { default as MournbladeRuneEffectSheet } from './mournblade-runeeffect-sheet.mjs';
|
||||
export { default as MournbladeTendanceSheet } from './mournblade-tendance-sheet.mjs';
|
||||
export { default as MournbladeTraitChaotiqueSheet } from './mournblade-traitchaotique-sheet.mjs';
|
||||
export { default as MournbladeTraitEspeceSheet } from './mournblade-traitespece-sheet.mjs';
|
||||
406
modules/applications/sheets/base-actor-sheet.mjs
Normal file
@@ -0,0 +1,406 @@
|
||||
const { HandlebarsApplicationMixin } = foundry.applications.api
|
||||
|
||||
import { MournbladeUtility } from "../../mournblade-utility.js"
|
||||
|
||||
export default class MournbladeActorSheet 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 // Commencer en mode visualisation
|
||||
}
|
||||
|
||||
#dragDrop
|
||||
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ["fvtt-mournblade", "sheet", "actor"],
|
||||
position: {
|
||||
width: 650,
|
||||
height: 720,
|
||||
},
|
||||
form: {
|
||||
submitOnChange: true,
|
||||
closeOnSubmit: false,
|
||||
},
|
||||
window: {
|
||||
resizable: true,
|
||||
},
|
||||
tabs: [
|
||||
{
|
||||
navSelector: 'nav[data-group="primary"]',
|
||||
contentSelector: "section.sheet-body",
|
||||
initial: "stats",
|
||||
},
|
||||
],
|
||||
dragDrop: [{ dragSelector: ".item-list .item", dropSelector: null }],
|
||||
actions: {
|
||||
editImage: MournbladeActorSheet.#onEditImage,
|
||||
toggleSheet: MournbladeActorSheet.#onToggleSheet,
|
||||
editItem: MournbladeActorSheet.#onEditItem,
|
||||
deleteItem: MournbladeActorSheet.#onDeleteItem,
|
||||
createItem: MournbladeActorSheet.#onCreateItem,
|
||||
equipItem: MournbladeActorSheet.#onEquipItem,
|
||||
modifyQuantity: MournbladeActorSheet.#onModifyQuantity,
|
||||
modifySante: MournbladeActorSheet.#onModifySante,
|
||||
modifyAme: MournbladeActorSheet.#onModifyAme,
|
||||
rollAttribut: MournbladeActorSheet.#onRollAttribut,
|
||||
rollCompetence: MournbladeActorSheet.#onRollCompetence,
|
||||
rollRune: MournbladeActorSheet.#onRollRune,
|
||||
rollArmeOffensif: MournbladeActorSheet.#onRollArmeOffensif,
|
||||
rollArmeSpecial: MournbladeActorSheet.#onRollArmeSpecial,
|
||||
rollArmeDegats: MournbladeActorSheet.#onRollArmeDegats,
|
||||
rollAssommer: MournbladeActorSheet.#onRollAssommer,
|
||||
rollImmobiliser: MournbladeActorSheet.#onRollImmobiliser,
|
||||
rollFuir: MournbladeActorSheet.#onRollFuir,
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* 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: "stats" }
|
||||
|
||||
/** @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: game.system.mournblade.config,
|
||||
enrichedDescription: await foundry.applications.ux.TextEditor.implementation.enrichHTML(actor.system.biodata?.description || "", { async: true }),
|
||||
}
|
||||
return context
|
||||
}
|
||||
|
||||
/** @override */
|
||||
_onRender(context, options) {
|
||||
super._onRender(context, options)
|
||||
this.#dragDrop.forEach((d) => d.bind(this.element))
|
||||
|
||||
// Handle edit-item-data changes
|
||||
this.element.querySelectorAll('.edit-item-data').forEach(element => {
|
||||
element.addEventListener('change', async (event) => {
|
||||
const target = event.currentTarget
|
||||
const itemElement = target.closest('[data-item-id]')
|
||||
if (!itemElement) return
|
||||
|
||||
const itemId = itemElement.dataset.itemId
|
||||
const itemType = itemElement.dataset.itemType
|
||||
const itemField = target.dataset.itemField
|
||||
const dataType = target.dataset.dtype
|
||||
const value = target.value
|
||||
|
||||
await this.document.editItemField(itemId, itemType, itemField, dataType, value)
|
||||
})
|
||||
})
|
||||
|
||||
// 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] || "stats"
|
||||
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
|
||||
*/
|
||||
#createDragDropHandlers() {
|
||||
return []
|
||||
}
|
||||
|
||||
// #region Actions
|
||||
/** @override */
|
||||
static ACTIONS = {
|
||||
editImage: MournbladeActorSheet.#onEditImage,
|
||||
toggleSheet: MournbladeActorSheet.#onToggleSheet,
|
||||
editItem: MournbladeActorSheet.#onEditItem,
|
||||
deleteItem: MournbladeActorSheet.#onDeleteItem,
|
||||
createItem: MournbladeActorSheet.#onCreateItem,
|
||||
equipItem: MournbladeActorSheet.#onEquipItem,
|
||||
modifyQuantity: MournbladeActorSheet.#onModifyQuantity,
|
||||
rollAttribut: MournbladeActorSheet.#onRollAttribut,
|
||||
rollCompetence: MournbladeActorSheet.#onRollCompetence,
|
||||
rollArmeOffensif: MournbladeActorSheet.#onRollArmeOffensif,
|
||||
rollArmeDegats: MournbladeActorSheet.#onRollArmeDegats,
|
||||
rollAssommer: MournbladeActorSheet.#onRollAssommer,
|
||||
rollImmobiliser: MournbladeActorSheet.#onRollImmobiliser,
|
||||
rollFuir: MournbladeActorSheet.#onRollFuir,
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle editing the actor image
|
||||
* @param {Event} event - The triggering event
|
||||
*/
|
||||
static async #onEditImage(event) {
|
||||
event.preventDefault()
|
||||
const sheet = this
|
||||
const filePicker = new FilePicker({
|
||||
type: "image",
|
||||
current: sheet.document.img,
|
||||
callback: (path) => {
|
||||
sheet.document.update({ img: path })
|
||||
},
|
||||
})
|
||||
filePicker.browse()
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle toggling the sheet mode
|
||||
* @param {Event} event - The triggering event
|
||||
*/
|
||||
static async #onToggleSheet(event) {
|
||||
event.preventDefault()
|
||||
const sheet = this
|
||||
sheet._sheetMode = sheet._sheetMode === sheet.constructor.SHEET_MODES.PLAY ? sheet.constructor.SHEET_MODES.EDIT : sheet.constructor.SHEET_MODES.PLAY
|
||||
sheet.render()
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle editing an item
|
||||
* @param {Event} event - The triggering event
|
||||
* @param {HTMLElement} target - The target element
|
||||
*/
|
||||
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)
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle deleting an item
|
||||
* @param {Event} event - The triggering event
|
||||
* @param {HTMLElement} target - The target element
|
||||
*/
|
||||
static async #onDeleteItem(event, target) {
|
||||
const li = target.closest(".item")
|
||||
await MournbladeUtility.confirmDelete(this, li)
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle creating an item
|
||||
* @param {Event} event - The triggering event
|
||||
* @param {HTMLElement} target - The target element
|
||||
*/
|
||||
static async #onCreateItem(event, target) {
|
||||
const itemType = target.dataset.type
|
||||
await this.actor.createEmbeddedDocuments("Item", [{ name: `Nouveau ${itemType}`, type: itemType }], { renderSheet: true })
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle equipping an item
|
||||
* @param {Event} event - The triggering event
|
||||
* @param {HTMLElement} target - The target element
|
||||
*/
|
||||
static async #onEquipItem(event, target) {
|
||||
const li = target.closest(".item")
|
||||
const itemId = li?.dataset.itemId
|
||||
if (!itemId) return
|
||||
const item = this.actor.items.get(itemId)
|
||||
if (item) {
|
||||
await item.update({ "system.equipped": !item.system.equipped })
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle modifying the quantity of an item
|
||||
* @param {Event} event - The triggering event
|
||||
* @param {HTMLElement} target - The target element
|
||||
*/
|
||||
static async #onModifyQuantity(event, target) {
|
||||
const li = target.closest('[data-item-id]')
|
||||
const itemId = li?.dataset.itemId
|
||||
const value = Number.parseInt(target.dataset.quantiteValue)
|
||||
const item = this.document.items.get(itemId)
|
||||
if (item) {
|
||||
const newQuantity = Math.max(0, (item.system.quantite || 0) + value)
|
||||
await item.update({ "system.quantite": newQuantity })
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle modifying santé (health) values
|
||||
* @param {Event} event - The triggering event
|
||||
* @param {HTMLElement} target - The target element
|
||||
*/
|
||||
static async #onModifySante(event, target) {
|
||||
const type = target.dataset.type
|
||||
const value = Number.parseInt(target.dataset.value)
|
||||
const actor = this.document
|
||||
const currentValue = actor.system.sante[type] || 0
|
||||
const newValue = Math.max(0, currentValue + value)
|
||||
await actor.update({ [`system.sante.${type}`]: newValue })
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle modifying âme (soul) value
|
||||
* @param {Event} event - The triggering event
|
||||
* @param {HTMLElement} target - The target element
|
||||
*/
|
||||
static async #onModifyAme(event, target) {
|
||||
const value = Number.parseInt(target.dataset.value)
|
||||
const actor = this.document
|
||||
const currentValue = actor.system.ame.value || 0
|
||||
const newValue = Math.max(0, currentValue + value)
|
||||
await actor.update({ "system.ame.value": newValue })
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle rolling an attribut
|
||||
* @param {Event} event - The triggering event
|
||||
*/
|
||||
static async #onRollAttribut(event, target) {
|
||||
event.preventDefault()
|
||||
const sheet = this
|
||||
const attrKey = target.dataset.attrKey
|
||||
const actor = sheet.document
|
||||
await actor.rollAttribut(attrKey)
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle rolling a competence
|
||||
* @param {Event} event - The triggering event
|
||||
*/
|
||||
static async #onRollCompetence(event, target) {
|
||||
event.preventDefault()
|
||||
const sheet = this
|
||||
const attrKey = target.dataset.attrKey
|
||||
const li = target.closest('[data-item-id]')
|
||||
const compId = li?.dataset.itemId
|
||||
const actor = sheet.document
|
||||
await actor.rollCompetence(attrKey, compId)
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle rolling a rune
|
||||
* @param {Event} event - The triggering event
|
||||
*/
|
||||
static async #onRollRune(event, target) {
|
||||
event.preventDefault()
|
||||
const sheet = this
|
||||
const li = target.closest('[data-item-id]')
|
||||
const runeId = li?.dataset.itemId
|
||||
const actor = sheet.document
|
||||
await actor.rollRune(runeId)
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle rolling an arme offensif
|
||||
* @param {Event} event - The triggering event
|
||||
*/
|
||||
static async #onRollArmeOffensif(event, target) {
|
||||
event.preventDefault()
|
||||
const sheet = this
|
||||
const armeId = target.dataset.armeId
|
||||
const actor = sheet.document
|
||||
await actor.rollArmeOffensif(armeId)
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle rolling an arme degats
|
||||
* @param {Event} event - The triggering event
|
||||
*/
|
||||
static async #onRollArmeDegats(event, target) {
|
||||
event.preventDefault()
|
||||
const sheet = this
|
||||
const armeId = target.dataset.armeId
|
||||
const actor = sheet.document
|
||||
await actor.rollArmeDegats(armeId)
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle rolling an arme special
|
||||
* @param {Event} event - The triggering event
|
||||
*/
|
||||
static async #onRollArmeSpecial(event, target) {
|
||||
event.preventDefault()
|
||||
const sheet = this
|
||||
const armeId = target.dataset.armeId
|
||||
const actor = sheet.document
|
||||
await actor.rollArmeSpecial(armeId)
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle rolling an assommer
|
||||
* @param {Event} event - The triggering event
|
||||
*/
|
||||
static async #onRollAssommer(event, target) {
|
||||
event.preventDefault()
|
||||
const sheet = this
|
||||
const actor = sheet.document
|
||||
await actor.rollAssomer()
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle rolling an immobiliser
|
||||
* @param {Event} event - The triggering event
|
||||
*/
|
||||
static async #onRollImmobiliser(event, target) {
|
||||
event.preventDefault()
|
||||
const sheet = this
|
||||
const actor = sheet.document
|
||||
await actor.rollImmobiliser()
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle rolling a fuir
|
||||
* @param {Event} event - The triggering event
|
||||
*/
|
||||
static async #onRollFuir(event, target) {
|
||||
event.preventDefault()
|
||||
const sheet = this
|
||||
const actor = sheet.document
|
||||
await actor.rollFuir()
|
||||
}
|
||||
}
|
||||
142
modules/applications/sheets/base-item-sheet.mjs
Normal file
@@ -0,0 +1,142 @@
|
||||
const { HandlebarsApplicationMixin } = foundry.applications.api
|
||||
|
||||
export default class MournbladeItemSheet extends HandlebarsApplicationMixin(foundry.applications.sheets.ItemSheetV2) {
|
||||
constructor(options = {}) {
|
||||
super(options)
|
||||
this.#dragDrop = this.#createDragDropHandlers()
|
||||
}
|
||||
|
||||
#dragDrop
|
||||
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ["fvtt-mournblade", "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: MournbladeItemSheet.#onEditImage,
|
||||
postItem: MournbladeItemSheet.#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: game.system.mournblade.config,
|
||||
}
|
||||
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
|
||||
*/
|
||||
#createDragDropHandlers() {
|
||||
return []
|
||||
}
|
||||
|
||||
// #region Actions
|
||||
|
||||
/**
|
||||
* Handle editing the item image
|
||||
* @param {Event} event - The triggering event
|
||||
*/
|
||||
static async #onEditImage(event) {
|
||||
event.preventDefault()
|
||||
const filePicker = new FilePicker({
|
||||
type: "image",
|
||||
current: this.document.img,
|
||||
callback: (path) => {
|
||||
this.document.update({ img: path })
|
||||
},
|
||||
})
|
||||
filePicker.browse()
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle posting the item to chat
|
||||
* @param {Event} event - The triggering event
|
||||
*/
|
||||
static async #onPostItem(event) {
|
||||
event.preventDefault()
|
||||
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 = null
|
||||
}
|
||||
// JSON object for easy creation
|
||||
chatData.jsondata = JSON.stringify({
|
||||
compendium: "postedItem",
|
||||
payload: chatData,
|
||||
})
|
||||
|
||||
const html = await renderTemplate('systems/fvtt-mournblade/templates/post-item.hbs', chatData)
|
||||
const chatOptions = {
|
||||
user: game.user.id,
|
||||
content: html,
|
||||
}
|
||||
ChatMessage.create(chatOptions)
|
||||
}
|
||||
}
|
||||
49
modules/applications/sheets/mournblade-arme-sheet.mjs
Normal file
@@ -0,0 +1,49 @@
|
||||
import MournbladeItemSheet from "./base-item-sheet.mjs"
|
||||
|
||||
export default class MournbladeArmeSheet extends MournbladeItemSheet {
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ["arme"],
|
||||
position: {
|
||||
width: 620,
|
||||
},
|
||||
window: {
|
||||
contentClasses: ["arme-content"],
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
main: {
|
||||
template: "systems/fvtt-mournblade/templates/item-arme-sheet.hbs",
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
tabGroups = {
|
||||
primary: "description",
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare an array of form header tabs.
|
||||
* @returns {Record<string, Partial<ApplicationTab>>}
|
||||
*/
|
||||
#getTabs() {
|
||||
const tabs = {
|
||||
details: { id: "details", group: "primary", label: "Détails" },
|
||||
description: { id: "description", group: "primary", label: "Description" }
|
||||
}
|
||||
for (const v of Object.values(tabs)) {
|
||||
v.active = this.tabGroups[v.group] === v.id
|
||||
v.cssClass = v.active ? "active" : ""
|
||||
}
|
||||
return tabs
|
||||
}
|
||||
|
||||
/** @override */
|
||||
async _prepareContext() {
|
||||
const context = await super._prepareContext()
|
||||
context.tabs = this.#getTabs()
|
||||
return context
|
||||
}
|
||||
}
|
||||
49
modules/applications/sheets/mournblade-bouclier-sheet.mjs
Normal file
@@ -0,0 +1,49 @@
|
||||
import MournbladeItemSheet from "./base-item-sheet.mjs"
|
||||
|
||||
export default class MournbladeBouclierSheet extends MournbladeItemSheet {
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ["bouclier"],
|
||||
position: {
|
||||
width: 620,
|
||||
},
|
||||
window: {
|
||||
contentClasses: ["bouclier-content"],
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
main: {
|
||||
template: "systems/fvtt-mournblade/templates/item-bouclier-sheet.hbs",
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
tabGroups = {
|
||||
primary: "description",
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare an array of form header tabs.
|
||||
* @returns {Record<string, Partial<ApplicationTab>>}
|
||||
*/
|
||||
#getTabs() {
|
||||
const tabs = {
|
||||
details: { id: "details", group: "primary", label: "Détails" },
|
||||
description: { id: "description", group: "primary", label: "Description" }
|
||||
}
|
||||
for (const v of Object.values(tabs)) {
|
||||
v.active = this.tabGroups[v.group] === v.id
|
||||
v.cssClass = v.active ? "active" : ""
|
||||
}
|
||||
return tabs
|
||||
}
|
||||
|
||||
/** @override */
|
||||
async _prepareContext() {
|
||||
const context = await super._prepareContext()
|
||||
context.tabs = this.#getTabs()
|
||||
return context
|
||||
}
|
||||
}
|
||||
49
modules/applications/sheets/mournblade-capacite-sheet.mjs
Normal file
@@ -0,0 +1,49 @@
|
||||
import MournbladeItemSheet from "./base-item-sheet.mjs"
|
||||
|
||||
export default class MournbladeCapaciteSheet extends MournbladeItemSheet {
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ["capacite"],
|
||||
position: {
|
||||
width: 620,
|
||||
},
|
||||
window: {
|
||||
contentClasses: ["capacite-content"],
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
main: {
|
||||
template: "systems/fvtt-mournblade/templates/item-capacite-sheet.hbs",
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
tabGroups = {
|
||||
primary: "description",
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare an array of form header tabs.
|
||||
* @returns {Record<string, Partial<ApplicationTab>>}
|
||||
*/
|
||||
#getTabs() {
|
||||
const tabs = {
|
||||
details: { id: "details", group: "primary", label: "Détails" },
|
||||
description: { id: "description", group: "primary", label: "Description" }
|
||||
}
|
||||
for (const v of Object.values(tabs)) {
|
||||
v.active = this.tabGroups[v.group] === v.id
|
||||
v.cssClass = v.active ? "active" : ""
|
||||
}
|
||||
return tabs
|
||||
}
|
||||
|
||||
/** @override */
|
||||
async _prepareContext() {
|
||||
const context = await super._prepareContext()
|
||||
context.tabs = this.#getTabs()
|
||||
return context
|
||||
}
|
||||
}
|
||||
49
modules/applications/sheets/mournblade-competence-sheet.mjs
Normal file
@@ -0,0 +1,49 @@
|
||||
import MournbladeItemSheet from "./base-item-sheet.mjs"
|
||||
|
||||
export default class MournbladeCompetenceSheet extends MournbladeItemSheet {
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ["competence"],
|
||||
position: {
|
||||
width: 620,
|
||||
},
|
||||
window: {
|
||||
contentClasses: ["competence-content"],
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
main: {
|
||||
template: "systems/fvtt-mournblade/templates/item-competence-sheet.hbs",
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
tabGroups = {
|
||||
primary: "description",
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare an array of form header tabs.
|
||||
* @returns {Record<string, Partial<ApplicationTab>>}
|
||||
*/
|
||||
#getTabs() {
|
||||
const tabs = {
|
||||
details: { id: "details", group: "primary", label: "Détails" },
|
||||
description: { id: "description", group: "primary", label: "Description" }
|
||||
}
|
||||
for (const v of Object.values(tabs)) {
|
||||
v.active = this.tabGroups[v.group] === v.id
|
||||
v.cssClass = v.active ? "active" : ""
|
||||
}
|
||||
return tabs
|
||||
}
|
||||
|
||||
/** @override */
|
||||
async _prepareContext() {
|
||||
const context = await super._prepareContext()
|
||||
context.tabs = this.#getTabs()
|
||||
return context
|
||||
}
|
||||
}
|
||||
43
modules/applications/sheets/mournblade-creature-sheet.mjs
Normal file
@@ -0,0 +1,43 @@
|
||||
import MournbladeActorSheet from "./base-actor-sheet.mjs"
|
||||
|
||||
export default class MournbladeCreatureSheet extends MournbladeActorSheet {
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
...super.DEFAULT_OPTIONS,
|
||||
classes: [...super.DEFAULT_OPTIONS.classes],
|
||||
window: {
|
||||
...super.DEFAULT_OPTIONS.window,
|
||||
title: "SHEETS.Actor.creature",
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
sheet: {
|
||||
template: "systems/fvtt-mournblade/templates/creature-sheet.hbs",
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
tabGroups = {
|
||||
primary: "stats",
|
||||
}
|
||||
|
||||
/** @override */
|
||||
async _prepareContext() {
|
||||
const context = await super._prepareContext()
|
||||
const actor = this.document
|
||||
|
||||
// Add creature-specific data
|
||||
context.skills = actor.getSkills()
|
||||
context.armes = foundry.utils.duplicate(actor.getWeapons())
|
||||
context.protections = foundry.utils.duplicate(actor.getArmors())
|
||||
context.runes = foundry.utils.duplicate(actor.getRunes())
|
||||
context.combat = actor.getCombatValues()
|
||||
context.equipements = foundry.utils.duplicate(actor.getEquipments())
|
||||
context.protectionTotal = actor.getProtectionTotal()
|
||||
context.santeMalus = actor.getStatusMalus()
|
||||
context.ameMalus = actor.getAmeMalus()
|
||||
return context
|
||||
}
|
||||
}
|
||||
50
modules/applications/sheets/mournblade-don-sheet.mjs
Normal file
@@ -0,0 +1,50 @@
|
||||
import MournbladeItemSheet from "./base-item-sheet.mjs"
|
||||
|
||||
export default class MournbladeDonSheet extends MournbladeItemSheet {
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ["don"],
|
||||
position: {
|
||||
width: 620,
|
||||
},
|
||||
window: {
|
||||
contentClasses: ["don-content"],
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
main: {
|
||||
template: "systems/fvtt-mournblade/templates/item-don-sheet.hbs",
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
tabGroups = {
|
||||
primary: "description",
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare an array of form header tabs.
|
||||
* @returns {Record<string, Partial<ApplicationTab>>}
|
||||
*/
|
||||
#getTabs() {
|
||||
const tabs = {
|
||||
details: { id: "details", group: "primary", label: "Détails" },
|
||||
description: { id: "description", group: "primary", label: "Description" }
|
||||
}
|
||||
for (const v of Object.values(tabs)) {
|
||||
v.active = this.tabGroups[v.group] === v.id
|
||||
v.cssClass = v.active ? "active" : ""
|
||||
}
|
||||
return tabs
|
||||
}
|
||||
|
||||
/** @override */
|
||||
async _prepareContext() {
|
||||
const context = await super._prepareContext()
|
||||
context.tabs = this.#getTabs()
|
||||
context.enrichedSacrifice = await foundry.applications.ux.TextEditor.implementation.enrichHTML(this.document.system.sacrifice, { async: true })
|
||||
return context
|
||||
}
|
||||
}
|
||||
49
modules/applications/sheets/mournblade-equipement-sheet.mjs
Normal file
@@ -0,0 +1,49 @@
|
||||
import MournbladeItemSheet from "./base-item-sheet.mjs"
|
||||
|
||||
export default class MournbladeEquipementSheet extends MournbladeItemSheet {
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ["equipement"],
|
||||
position: {
|
||||
width: 620,
|
||||
},
|
||||
window: {
|
||||
contentClasses: ["equipement-content"],
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
main: {
|
||||
template: "systems/fvtt-mournblade/templates/item-equipement-sheet.hbs",
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
tabGroups = {
|
||||
primary: "description",
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare an array of form header tabs.
|
||||
* @returns {Record<string, Partial<ApplicationTab>>}
|
||||
*/
|
||||
#getTabs() {
|
||||
const tabs = {
|
||||
details: { id: "details", group: "primary", label: "Détails" },
|
||||
description: { id: "description", group: "primary", label: "Description" }
|
||||
}
|
||||
for (const v of Object.values(tabs)) {
|
||||
v.active = this.tabGroups[v.group] === v.id
|
||||
v.cssClass = v.active ? "active" : ""
|
||||
}
|
||||
return tabs
|
||||
}
|
||||
|
||||
/** @override */
|
||||
async _prepareContext() {
|
||||
const context = await super._prepareContext()
|
||||
context.tabs = this.#getTabs()
|
||||
return context
|
||||
}
|
||||
}
|
||||
49
modules/applications/sheets/mournblade-heritage-sheet.mjs
Normal file
@@ -0,0 +1,49 @@
|
||||
import MournbladeItemSheet from "./base-item-sheet.mjs"
|
||||
|
||||
export default class MournbladeHeritageSheet extends MournbladeItemSheet {
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ["heritage"],
|
||||
position: {
|
||||
width: 620,
|
||||
},
|
||||
window: {
|
||||
contentClasses: ["heritage-content"],
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
main: {
|
||||
template: "systems/fvtt-mournblade/templates/item-heritage-sheet.hbs",
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
tabGroups = {
|
||||
primary: "description",
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare an array of form header tabs.
|
||||
* @returns {Record<string, Partial<ApplicationTab>>}
|
||||
*/
|
||||
#getTabs() {
|
||||
const tabs = {
|
||||
details: { id: "details", group: "primary", label: "Détails" },
|
||||
description: { id: "description", group: "primary", label: "Description" }
|
||||
}
|
||||
for (const v of Object.values(tabs)) {
|
||||
v.active = this.tabGroups[v.group] === v.id
|
||||
v.cssClass = v.active ? "active" : ""
|
||||
}
|
||||
return tabs
|
||||
}
|
||||
|
||||
/** @override */
|
||||
async _prepareContext() {
|
||||
const context = await super._prepareContext()
|
||||
context.tabs = this.#getTabs()
|
||||
return context
|
||||
}
|
||||
}
|
||||
49
modules/applications/sheets/mournblade-metier-sheet.mjs
Normal file
@@ -0,0 +1,49 @@
|
||||
import MournbladeItemSheet from "./base-item-sheet.mjs"
|
||||
|
||||
export default class MournbladeMetierSheet extends MournbladeItemSheet {
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ["metier"],
|
||||
position: {
|
||||
width: 620,
|
||||
},
|
||||
window: {
|
||||
contentClasses: ["metier-content"],
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
main: {
|
||||
template: "systems/fvtt-mournblade/templates/item-metier-sheet.hbs",
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
tabGroups = {
|
||||
primary: "description",
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare an array of form header tabs.
|
||||
* @returns {Record<string, Partial<ApplicationTab>>}
|
||||
*/
|
||||
#getTabs() {
|
||||
const tabs = {
|
||||
details: { id: "details", group: "primary", label: "Détails" },
|
||||
description: { id: "description", group: "primary", label: "Description" }
|
||||
}
|
||||
for (const v of Object.values(tabs)) {
|
||||
v.active = this.tabGroups[v.group] === v.id
|
||||
v.cssClass = v.active ? "active" : ""
|
||||
}
|
||||
return tabs
|
||||
}
|
||||
|
||||
/** @override */
|
||||
async _prepareContext() {
|
||||
const context = await super._prepareContext()
|
||||
context.tabs = this.#getTabs()
|
||||
return context
|
||||
}
|
||||
}
|
||||
49
modules/applications/sheets/mournblade-modifier-sheet.mjs
Normal file
@@ -0,0 +1,49 @@
|
||||
import MournbladeItemSheet from "./base-item-sheet.mjs"
|
||||
|
||||
export default class MournbladeModifierSheet extends MournbladeItemSheet {
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ["modifier"],
|
||||
position: {
|
||||
width: 620,
|
||||
},
|
||||
window: {
|
||||
contentClasses: ["modifier-content"],
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
main: {
|
||||
template: "systems/fvtt-mournblade/templates/item-modifier-sheet.hbs",
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
tabGroups = {
|
||||
primary: "description",
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare an array of form header tabs.
|
||||
* @returns {Record<string, Partial<ApplicationTab>>}
|
||||
*/
|
||||
#getTabs() {
|
||||
const tabs = {
|
||||
details: { id: "details", group: "primary", label: "Détails" },
|
||||
description: { id: "description", group: "primary", label: "Description" }
|
||||
}
|
||||
for (const v of Object.values(tabs)) {
|
||||
v.active = this.tabGroups[v.group] === v.id
|
||||
v.cssClass = v.active ? "active" : ""
|
||||
}
|
||||
return tabs
|
||||
}
|
||||
|
||||
/** @override */
|
||||
async _prepareContext() {
|
||||
const context = await super._prepareContext()
|
||||
context.tabs = this.#getTabs()
|
||||
return context
|
||||
}
|
||||
}
|
||||
49
modules/applications/sheets/mournblade-monnaie-sheet.mjs
Normal file
@@ -0,0 +1,49 @@
|
||||
import MournbladeItemSheet from "./base-item-sheet.mjs"
|
||||
|
||||
export default class MournbladeMonnaieSheet extends MournbladeItemSheet {
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ["monnaie"],
|
||||
position: {
|
||||
width: 620,
|
||||
},
|
||||
window: {
|
||||
contentClasses: ["monnaie-content"],
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
main: {
|
||||
template: "systems/fvtt-mournblade/templates/item-monnaie-sheet.hbs",
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
tabGroups = {
|
||||
primary: "description",
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare an array of form header tabs.
|
||||
* @returns {Record<string, Partial<ApplicationTab>>}
|
||||
*/
|
||||
#getTabs() {
|
||||
const tabs = {
|
||||
details: { id: "details", group: "primary", label: "Détails" },
|
||||
description: { id: "description", group: "primary", label: "Description" }
|
||||
}
|
||||
for (const v of Object.values(tabs)) {
|
||||
v.active = this.tabGroups[v.group] === v.id
|
||||
v.cssClass = v.active ? "active" : ""
|
||||
}
|
||||
return tabs
|
||||
}
|
||||
|
||||
/** @override */
|
||||
async _prepareContext() {
|
||||
const context = await super._prepareContext()
|
||||
context.tabs = this.#getTabs()
|
||||
return context
|
||||
}
|
||||
}
|
||||
49
modules/applications/sheets/mournblade-origine-sheet.mjs
Normal file
@@ -0,0 +1,49 @@
|
||||
import MournbladeItemSheet from "./base-item-sheet.mjs"
|
||||
|
||||
export default class MournbladeOrigineSheet extends MournbladeItemSheet {
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ["origine"],
|
||||
position: {
|
||||
width: 620,
|
||||
},
|
||||
window: {
|
||||
contentClasses: ["origine-content"],
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
main: {
|
||||
template: "systems/fvtt-mournblade/templates/item-origine-sheet.hbs",
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
tabGroups = {
|
||||
primary: "description",
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare an array of form header tabs.
|
||||
* @returns {Record<string, Partial<ApplicationTab>>}
|
||||
*/
|
||||
#getTabs() {
|
||||
const tabs = {
|
||||
details: { id: "details", group: "primary", label: "Détails" },
|
||||
description: { id: "description", group: "primary", label: "Description" }
|
||||
}
|
||||
for (const v of Object.values(tabs)) {
|
||||
v.active = this.tabGroups[v.group] === v.id
|
||||
v.cssClass = v.active ? "active" : ""
|
||||
}
|
||||
return tabs
|
||||
}
|
||||
|
||||
/** @override */
|
||||
async _prepareContext() {
|
||||
const context = await super._prepareContext()
|
||||
context.tabs = this.#getTabs()
|
||||
return context
|
||||
}
|
||||
}
|
||||
49
modules/applications/sheets/mournblade-pacte-sheet.mjs
Normal file
@@ -0,0 +1,49 @@
|
||||
import MournbladeItemSheet from "./base-item-sheet.mjs"
|
||||
|
||||
export default class MournbladePacteSheet extends MournbladeItemSheet {
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ["pacte"],
|
||||
position: {
|
||||
width: 620,
|
||||
},
|
||||
window: {
|
||||
contentClasses: ["pacte-content"],
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
main: {
|
||||
template: "systems/fvtt-mournblade/templates/item-pacte-sheet.hbs",
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
tabGroups = {
|
||||
primary: "description",
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare an array of form header tabs.
|
||||
* @returns {Record<string, Partial<ApplicationTab>>}
|
||||
*/
|
||||
#getTabs() {
|
||||
const tabs = {
|
||||
details: { id: "details", group: "primary", label: "Détails" },
|
||||
description: { id: "description", group: "primary", label: "Description" }
|
||||
}
|
||||
for (const v of Object.values(tabs)) {
|
||||
v.active = this.tabGroups[v.group] === v.id
|
||||
v.cssClass = v.active ? "active" : ""
|
||||
}
|
||||
return tabs
|
||||
}
|
||||
|
||||
/** @override */
|
||||
async _prepareContext() {
|
||||
const context = await super._prepareContext()
|
||||
context.tabs = this.#getTabs()
|
||||
return context
|
||||
}
|
||||
}
|
||||
57
modules/applications/sheets/mournblade-personnage-sheet.mjs
Normal file
@@ -0,0 +1,57 @@
|
||||
import MournbladeActorSheet from "./base-actor-sheet.mjs"
|
||||
|
||||
export default class MournbladePersonnageSheet extends MournbladeActorSheet {
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
...super.DEFAULT_OPTIONS,
|
||||
classes: [...super.DEFAULT_OPTIONS.classes],
|
||||
window: {
|
||||
...super.DEFAULT_OPTIONS.window,
|
||||
title: "SHEETS.Actor.personnage",
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
sheet: {
|
||||
template: "systems/fvtt-mournblade/templates/actor-sheet.hbs",
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
tabGroups = {
|
||||
primary: "principal",
|
||||
}
|
||||
|
||||
/** @override */
|
||||
async _prepareContext() {
|
||||
const context = await super._prepareContext()
|
||||
const actor = this.document
|
||||
|
||||
// Add personnage-specific data
|
||||
context.skills = actor.getSkills()
|
||||
context.armes = foundry.utils.duplicate(actor.getWeapons())
|
||||
context.protections = foundry.utils.duplicate(actor.getArmors())
|
||||
context.dons = foundry.utils.duplicate(actor.getDons())
|
||||
context.pactes = foundry.utils.duplicate(actor.getPactes())
|
||||
context.alignement = actor.getAlignement()
|
||||
context.aspect = actor.getAspect()
|
||||
context.marge = actor.getMarge()
|
||||
context.tendances = foundry.utils.duplicate(actor.getTendances())
|
||||
context.runes = foundry.utils.duplicate(actor.getRunes())
|
||||
context.traitsChaotiques = foundry.utils.duplicate(actor.getTraitsChaotiques())
|
||||
context.traitsEspeces = foundry.utils.duplicate(actor.getTraitsEspeces())
|
||||
context.origine = foundry.utils.duplicate(actor.getOrigine() || {})
|
||||
context.heritage = foundry.utils.duplicate(actor.getHeritage() || {})
|
||||
context.metier = foundry.utils.duplicate(actor.getMetier() || {})
|
||||
context.combat = actor.getCombatValues()
|
||||
context.equipements = foundry.utils.duplicate(actor.getEquipments())
|
||||
context.modifiers = foundry.utils.duplicate(actor.getModifiers())
|
||||
context.monnaies = foundry.utils.duplicate(actor.getMonnaies())
|
||||
context.runeEffects = foundry.utils.duplicate(actor.getRuneEffects())
|
||||
context.protectionTotal = actor.getProtectionTotal()
|
||||
context.santeMalus = actor.getStatusMalus()
|
||||
context.ameMalus = actor.getAmeMalus()
|
||||
return context
|
||||
}
|
||||
}
|
||||
47
modules/applications/sheets/mournblade-pnj-sheet.mjs
Normal file
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
* Application de feuille de PNJ pour Mournblade
|
||||
*/
|
||||
import MournbladeActorSheet from "./base-actor-sheet.mjs"
|
||||
|
||||
export default class MournbladePnjSheet extends MournbladeActorSheet {
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
...super.DEFAULT_OPTIONS,
|
||||
classes: [...super.DEFAULT_OPTIONS.classes],
|
||||
window: {
|
||||
...super.DEFAULT_OPTIONS.window,
|
||||
title: "SHEETS.Actor.pnj",
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
sheet: {
|
||||
template: "systems/fvtt-mournblade/templates/actor-sheet.hbs",
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
tabGroups = {
|
||||
primary: "principal",
|
||||
}
|
||||
|
||||
/** @override */
|
||||
async _prepareContext() {
|
||||
const context = await super._prepareContext()
|
||||
const actor = this.document
|
||||
|
||||
// Add pnj-specific data
|
||||
context.skills = actor.getSkills()
|
||||
context.armes = foundry.utils.duplicate(actor.getWeapons())
|
||||
context.protections = foundry.utils.duplicate(actor.getArmors())
|
||||
context.dons = foundry.utils.duplicate(actor.getDons())
|
||||
context.pactes = foundry.utils.duplicate(actor.getPactes())
|
||||
context.combat = actor.getCombatValues()
|
||||
context.equipements = foundry.utils.duplicate(actor.getEquipments())
|
||||
context.protectionTotal = actor.getProtectionTotal()
|
||||
context.santeMalus = actor.getStatusMalus()
|
||||
context.ameMalus = actor.getAmeMalus()
|
||||
return context
|
||||
}
|
||||
}
|
||||
49
modules/applications/sheets/mournblade-protection-sheet.mjs
Normal file
@@ -0,0 +1,49 @@
|
||||
import MournbladeItemSheet from "./base-item-sheet.mjs"
|
||||
|
||||
export default class MournbladeProtectionSheet extends MournbladeItemSheet {
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ["protection"],
|
||||
position: {
|
||||
width: 620,
|
||||
},
|
||||
window: {
|
||||
contentClasses: ["protection-content"],
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
main: {
|
||||
template: "systems/fvtt-mournblade/templates/item-protection-sheet.hbs",
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
tabGroups = {
|
||||
primary: "description",
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare an array of form header tabs.
|
||||
* @returns {Record<string, Partial<ApplicationTab>>}
|
||||
*/
|
||||
#getTabs() {
|
||||
const tabs = {
|
||||
details: { id: "details", group: "primary", label: "Détails" },
|
||||
description: { id: "description", group: "primary", label: "Description" }
|
||||
}
|
||||
for (const v of Object.values(tabs)) {
|
||||
v.active = this.tabGroups[v.group] === v.id
|
||||
v.cssClass = v.active ? "active" : ""
|
||||
}
|
||||
return tabs
|
||||
}
|
||||
|
||||
/** @override */
|
||||
async _prepareContext() {
|
||||
const context = await super._prepareContext()
|
||||
context.tabs = this.#getTabs()
|
||||
return context
|
||||
}
|
||||
}
|
||||
49
modules/applications/sheets/mournblade-rune-sheet.mjs
Normal file
@@ -0,0 +1,49 @@
|
||||
import MournbladeItemSheet from "./base-item-sheet.mjs"
|
||||
|
||||
export default class MournbladeRuneSheet extends MournbladeItemSheet {
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ["rune"],
|
||||
position: {
|
||||
width: 620,
|
||||
},
|
||||
window: {
|
||||
contentClasses: ["rune-content"],
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
main: {
|
||||
template: "systems/fvtt-mournblade/templates/item-rune-sheet.hbs",
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
tabGroups = {
|
||||
primary: "description",
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare an array of form header tabs.
|
||||
* @returns {Record<string, Partial<ApplicationTab>>}
|
||||
*/
|
||||
#getTabs() {
|
||||
const tabs = {
|
||||
details: { id: "details", group: "primary", label: "Détails" },
|
||||
description: { id: "description", group: "primary", label: "Description" }
|
||||
}
|
||||
for (const v of Object.values(tabs)) {
|
||||
v.active = this.tabGroups[v.group] === v.id
|
||||
v.cssClass = v.active ? "active" : ""
|
||||
}
|
||||
return tabs
|
||||
}
|
||||
|
||||
/** @override */
|
||||
async _prepareContext() {
|
||||
const context = await super._prepareContext()
|
||||
context.tabs = this.#getTabs()
|
||||
return context
|
||||
}
|
||||
}
|
||||
49
modules/applications/sheets/mournblade-runeeffect-sheet.mjs
Normal file
@@ -0,0 +1,49 @@
|
||||
import MournbladeItemSheet from "./base-item-sheet.mjs"
|
||||
|
||||
export default class MournbladeRuneEffectSheet extends MournbladeItemSheet {
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ["runeeffect"],
|
||||
position: {
|
||||
width: 620,
|
||||
},
|
||||
window: {
|
||||
contentClasses: ["runeeffect-content"],
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
main: {
|
||||
template: "systems/fvtt-mournblade/templates/item-runeeffect-sheet.hbs",
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
tabGroups = {
|
||||
primary: "description",
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare an array of form header tabs.
|
||||
* @returns {Record<string, Partial<ApplicationTab>>}
|
||||
*/
|
||||
#getTabs() {
|
||||
const tabs = {
|
||||
details: { id: "details", group: "primary", label: "Détails" },
|
||||
description: { id: "description", group: "primary", label: "Description" }
|
||||
}
|
||||
for (const v of Object.values(tabs)) {
|
||||
v.active = this.tabGroups[v.group] === v.id
|
||||
v.cssClass = v.active ? "active" : ""
|
||||
}
|
||||
return tabs
|
||||
}
|
||||
|
||||
/** @override */
|
||||
async _prepareContext() {
|
||||
const context = await super._prepareContext()
|
||||
context.tabs = this.#getTabs()
|
||||
return context
|
||||
}
|
||||
}
|
||||
49
modules/applications/sheets/mournblade-tendance-sheet.mjs
Normal file
@@ -0,0 +1,49 @@
|
||||
import MournbladeItemSheet from "./base-item-sheet.mjs"
|
||||
|
||||
export default class MournbladeTendanceSheet extends MournbladeItemSheet {
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ["tendance"],
|
||||
position: {
|
||||
width: 620,
|
||||
},
|
||||
window: {
|
||||
contentClasses: ["tendance-content"],
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
main: {
|
||||
template: "systems/fvtt-mournblade/templates/item-tendance-sheet.hbs",
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
tabGroups = {
|
||||
primary: "description",
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare an array of form header tabs.
|
||||
* @returns {Record<string, Partial<ApplicationTab>>}
|
||||
*/
|
||||
#getTabs() {
|
||||
const tabs = {
|
||||
details: { id: "details", group: "primary", label: "Détails" },
|
||||
description: { id: "description", group: "primary", label: "Description" }
|
||||
}
|
||||
for (const v of Object.values(tabs)) {
|
||||
v.active = this.tabGroups[v.group] === v.id
|
||||
v.cssClass = v.active ? "active" : ""
|
||||
}
|
||||
return tabs
|
||||
}
|
||||
|
||||
/** @override */
|
||||
async _prepareContext() {
|
||||
const context = await super._prepareContext()
|
||||
context.tabs = this.#getTabs()
|
||||
return context
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
import MournbladeItemSheet from "./base-item-sheet.mjs"
|
||||
|
||||
export default class MournbladeTraitChaotiqueSheet extends MournbladeItemSheet {
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ["traitchaotique"],
|
||||
position: {
|
||||
width: 620,
|
||||
},
|
||||
window: {
|
||||
contentClasses: ["traitchaotique-content"],
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
main: {
|
||||
template: "systems/fvtt-mournblade/templates/item-traitchaotique-sheet.hbs",
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
tabGroups = {
|
||||
primary: "description",
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare an array of form header tabs.
|
||||
* @returns {Record<string, Partial<ApplicationTab>>}
|
||||
*/
|
||||
#getTabs() {
|
||||
const tabs = {
|
||||
details: { id: "details", group: "primary", label: "Détails" },
|
||||
description: { id: "description", group: "primary", label: "Description" }
|
||||
}
|
||||
for (const v of Object.values(tabs)) {
|
||||
v.active = this.tabGroups[v.group] === v.id
|
||||
v.cssClass = v.active ? "active" : ""
|
||||
}
|
||||
return tabs
|
||||
}
|
||||
|
||||
/** @override */
|
||||
async _prepareContext() {
|
||||
const context = await super._prepareContext()
|
||||
context.tabs = this.#getTabs()
|
||||
return context
|
||||
}
|
||||
}
|
||||
49
modules/applications/sheets/mournblade-traitespece-sheet.mjs
Normal file
@@ -0,0 +1,49 @@
|
||||
import MournbladeItemSheet from "./base-item-sheet.mjs"
|
||||
|
||||
export default class MournbladeTraitEspeceSheet extends MournbladeItemSheet {
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ["traitespece"],
|
||||
position: {
|
||||
width: 620,
|
||||
},
|
||||
window: {
|
||||
contentClasses: ["traitespece-content"],
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
main: {
|
||||
template: "systems/fvtt-mournblade/templates/item-traitespece-sheet.hbs",
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
tabGroups = {
|
||||
primary: "description",
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare an array of form header tabs.
|
||||
* @returns {Record<string, Partial<ApplicationTab>>}
|
||||
*/
|
||||
#getTabs() {
|
||||
const tabs = {
|
||||
details: { id: "details", group: "primary", label: "Détails" },
|
||||
description: { id: "description", group: "primary", label: "Description" }
|
||||
}
|
||||
for (const v of Object.values(tabs)) {
|
||||
v.active = this.tabGroups[v.group] === v.id
|
||||
v.cssClass = v.active ? "active" : ""
|
||||
}
|
||||
return tabs
|
||||
}
|
||||
|
||||
/** @override */
|
||||
async _prepareContext() {
|
||||
const context = await super._prepareContext()
|
||||
context.tabs = this.#getTabs()
|
||||
return context
|
||||
}
|
||||
}
|
||||
27
modules/models/arme.mjs
Normal file
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* 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: "" }),
|
||||
typearme: new fields.StringField({ initial: "" }),
|
||||
isdefense: new fields.BooleanField({ initial: false }),
|
||||
bonusmaniementoff: new fields.NumberField({ initial: 0, integer: true }),
|
||||
bonusmaniementdef: new fields.NumberField({ initial: 0, integer: true }),
|
||||
ignorearmure: new fields.BooleanField({ initial: false }),
|
||||
nbressources: new fields.NumberField({ initial: 0, integer: true }),
|
||||
degats: new fields.StringField({ initial: "" }),
|
||||
nonletaux: new fields.BooleanField({ initial: false }),
|
||||
deuxmains: new fields.BooleanField({ initial: false }),
|
||||
courte: new fields.NumberField({ initial: 0, integer: true }),
|
||||
moyenne: new fields.NumberField({ initial: 0, integer: true }),
|
||||
longue: new fields.NumberField({ initial: 0, integer: true }),
|
||||
tr: new fields.NumberField({ initial: 0, integer: true }),
|
||||
rarete: new fields.NumberField({ initial: 0, integer: true }),
|
||||
prix: new fields.NumberField({ initial: 0, integer: true }),
|
||||
equipped: new fields.BooleanField({ initial: false })
|
||||
};
|
||||
}
|
||||
}
|
||||
11
modules/models/base-item.mjs
Normal file
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* Data model de base pour les items Mournblade
|
||||
*/
|
||||
export default class BaseItemDataModel extends foundry.abstract.TypeDataModel {
|
||||
static defineSchema() {
|
||||
const fields = foundry.data.fields;
|
||||
return {
|
||||
description: new fields.HTMLField({ initial: "" })
|
||||
};
|
||||
}
|
||||
}
|
||||
17
modules/models/bouclier.mjs
Normal file
@@ -0,0 +1,17 @@
|
||||
/**
|
||||
* Data model pour les boucliers
|
||||
*/
|
||||
export default class BouclierDataModel extends foundry.abstract.TypeDataModel {
|
||||
static defineSchema() {
|
||||
const fields = foundry.data.fields;
|
||||
return {
|
||||
description: new fields.HTMLField({ initial: "" }),
|
||||
bonusdefense: new fields.NumberField({ initial: 0, integer: true }),
|
||||
degats: new fields.StringField({ initial: "" }),
|
||||
nonletaux: new fields.BooleanField({ initial: false }),
|
||||
rarete: new fields.NumberField({ initial: 0, integer: true }),
|
||||
prix: new fields.NumberField({ initial: 0, integer: true }),
|
||||
equipped: new fields.BooleanField({ initial: false })
|
||||
};
|
||||
}
|
||||
}
|
||||
11
modules/models/capacite.mjs
Normal file
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* Data model pour les capacités
|
||||
*/
|
||||
export default class CapaciteDataModel extends foundry.abstract.TypeDataModel {
|
||||
static defineSchema() {
|
||||
const fields = foundry.data.fields;
|
||||
return {
|
||||
description: new fields.HTMLField({ initial: "" })
|
||||
};
|
||||
}
|
||||
}
|
||||
17
modules/models/competence.mjs
Normal file
@@ -0,0 +1,17 @@
|
||||
/**
|
||||
* Data model pour les compétences
|
||||
*/
|
||||
export default class CompetenceDataModel extends foundry.abstract.TypeDataModel {
|
||||
static defineSchema() {
|
||||
const fields = foundry.data.fields;
|
||||
return {
|
||||
description: new fields.HTMLField({ initial: "" }),
|
||||
niveau: new fields.NumberField({ initial: 0, integer: true }),
|
||||
attribut1: new fields.StringField({ initial: "" }),
|
||||
attribut2: new fields.StringField({ initial: "" }),
|
||||
attribut3: new fields.StringField({ initial: "" }),
|
||||
doublebonus: new fields.BooleanField({ initial: false }),
|
||||
predilections: new fields.ArrayField(new fields.StringField(), { initial: [] })
|
||||
};
|
||||
}
|
||||
}
|
||||
103
modules/models/creature.mjs
Normal file
@@ -0,0 +1,103 @@
|
||||
/**
|
||||
* Data model pour les créatures
|
||||
*/
|
||||
export default class CreatureDataModel extends foundry.abstract.TypeDataModel {
|
||||
static defineSchema() {
|
||||
const fields = foundry.data.fields;
|
||||
return {
|
||||
// Template biodata
|
||||
biodata: new fields.SchemaField({
|
||||
name: new fields.StringField({ initial: "" }),
|
||||
age: new fields.NumberField({ initial: 0, integer: true }),
|
||||
alignement: new fields.StringField({ initial: "" }),
|
||||
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: "" }),
|
||||
amemultiplier: new fields.NumberField({ initial: 2, integer: true }),
|
||||
ignoreamemalus: new fields.BooleanField({ initial: false }),
|
||||
ignoresantemalus: new fields.BooleanField({ initial: false }),
|
||||
notes: new fields.HTMLField({ initial: "" }),
|
||||
gmnotes: new fields.HTMLField({ initial: "" })
|
||||
}),
|
||||
// Template core
|
||||
subactors: new fields.ArrayField(new fields.StringField(), { initial: [] }),
|
||||
attributs: new fields.SchemaField({
|
||||
adr: new fields.SchemaField({
|
||||
label: new fields.StringField({ initial: "Adresse" }),
|
||||
labelnorm: new fields.StringField({ initial: "adresse" }),
|
||||
abbrev: new fields.StringField({ initial: "adr" }),
|
||||
value: new fields.NumberField({ initial: 1, integer: true })
|
||||
}),
|
||||
pui: new fields.SchemaField({
|
||||
label: new fields.StringField({ initial: "Puissance" }),
|
||||
labelnorm: new fields.StringField({ initial: "puissance" }),
|
||||
abbrev: new fields.StringField({ initial: "pui" }),
|
||||
value: new fields.NumberField({ initial: 1, integer: true })
|
||||
}),
|
||||
cla: new fields.SchemaField({
|
||||
label: new fields.StringField({ initial: "Clairvoyance" }),
|
||||
labelnorm: new fields.StringField({ initial: "clairvoyance" }),
|
||||
abbrev: new fields.StringField({ initial: "cla" }),
|
||||
value: new fields.NumberField({ initial: 1, integer: true })
|
||||
}),
|
||||
pre: new fields.SchemaField({
|
||||
label: new fields.StringField({ initial: "Présence" }),
|
||||
labelnorm: new fields.StringField({ initial: "presence" }),
|
||||
abbrev: new fields.StringField({ initial: "pre" }),
|
||||
value: new fields.NumberField({ initial: 0, integer: true })
|
||||
}),
|
||||
tre: new fields.SchemaField({
|
||||
label: new fields.StringField({ initial: "Trempe" }),
|
||||
labelnorm: new fields.StringField({ initial: "trempe" }),
|
||||
abbrev: new fields.StringField({ initial: "tre" }),
|
||||
value: new fields.NumberField({ initial: 0, integer: true })
|
||||
})
|
||||
}),
|
||||
bonneaventure: new fields.SchemaField({
|
||||
base: new fields.NumberField({ initial: 0, integer: true }),
|
||||
actuelle: new fields.NumberField({ initial: 0, integer: true })
|
||||
}),
|
||||
experience: new fields.SchemaField({
|
||||
value: new fields.NumberField({ initial: 0, integer: true })
|
||||
}),
|
||||
eclat: new fields.SchemaField({
|
||||
value: new fields.NumberField({ initial: 0, integer: true })
|
||||
}),
|
||||
sante: new fields.SchemaField({
|
||||
base: new fields.NumberField({ initial: 0, integer: true }),
|
||||
bonus: new fields.NumberField({ initial: 0, integer: true }),
|
||||
nonletaux: new fields.NumberField({ initial: 0, integer: true }),
|
||||
letaux: new fields.NumberField({ initial: 0, integer: true }),
|
||||
malusmanuel: new fields.NumberField({ initial: 0, integer: true }),
|
||||
sequelles: new fields.StringField({ initial: "" })
|
||||
}),
|
||||
ame: new fields.SchemaField({
|
||||
fullmax: new fields.NumberField({ initial: 0, integer: true }),
|
||||
currentmax: new fields.NumberField({ initial: 0, integer: true }),
|
||||
value: new fields.NumberField({ initial: 0, integer: true }),
|
||||
traumatismes: new fields.StringField({ initial: "" })
|
||||
}),
|
||||
combat: new fields.SchemaField({
|
||||
initbonus: new fields.NumberField({ initial: 0, integer: true }),
|
||||
vitessebonus: new fields.NumberField({ initial: 0, integer: true }),
|
||||
bonusdegats: new fields.NumberField({ initial: 0, integer: true }),
|
||||
defensebonus: new fields.NumberField({ initial: 0, integer: true }),
|
||||
monte: new fields.BooleanField({ initial: false })
|
||||
}),
|
||||
balance: new fields.SchemaField({
|
||||
loi: new fields.NumberField({ initial: 0, integer: true }),
|
||||
chaos: new fields.NumberField({ initial: 0, integer: true }),
|
||||
aspect: new fields.NumberField({ initial: 0, integer: true }),
|
||||
marge: new fields.NumberField({ initial: 0, integer: true }),
|
||||
pointschaos: new fields.NumberField({ initial: 0, integer: true }),
|
||||
pointsloi: new fields.NumberField({ initial: 0, integer: true })
|
||||
}),
|
||||
ressources: new fields.SchemaField({
|
||||
value: new fields.NumberField({ initial: 0, integer: true })
|
||||
})
|
||||
};
|
||||
}
|
||||
}
|
||||
14
modules/models/don.mjs
Normal file
@@ -0,0 +1,14 @@
|
||||
/**
|
||||
* Data model pour les dons
|
||||
*/
|
||||
export default class DonDataModel extends foundry.abstract.TypeDataModel {
|
||||
static defineSchema() {
|
||||
const fields = foundry.data.fields;
|
||||
return {
|
||||
description: new fields.HTMLField({ initial: "" }),
|
||||
allegeance: new fields.StringField({ initial: "" }),
|
||||
prerequis: new fields.StringField({ initial: "" }),
|
||||
sacrifice: new fields.HTMLField({ initial: "" })
|
||||
};
|
||||
}
|
||||
}
|
||||
13
modules/models/equipement.mjs
Normal file
@@ -0,0 +1,13 @@
|
||||
/**
|
||||
* 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 }),
|
||||
prix: new fields.NumberField({ initial: 0, integer: true })
|
||||
};
|
||||
}
|
||||
}
|
||||
11
modules/models/heritage.mjs
Normal file
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* Data model pour les héritages
|
||||
*/
|
||||
export default class HeritageDataModel extends foundry.abstract.TypeDataModel {
|
||||
static defineSchema() {
|
||||
const fields = foundry.data.fields;
|
||||
return {
|
||||
description: new fields.HTMLField({ initial: "" })
|
||||
};
|
||||
}
|
||||
}
|
||||
28
modules/models/index.mjs
Normal file
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* Index des DataModels pour Mournblade
|
||||
* Ce fichier centralise tous les exports des modèles de données
|
||||
*/
|
||||
|
||||
// Modèles d'items
|
||||
export { default as ArmeDataModel } from './arme.mjs';
|
||||
export { default as BouclierDataModel } from './bouclier.mjs';
|
||||
export { default as CapaciteDataModel } from './capacite.mjs';
|
||||
export { default as CompetenceDataModel } from './competence.mjs';
|
||||
export { default as DonDataModel } from './don.mjs';
|
||||
export { default as EquipementDataModel } from './equipement.mjs';
|
||||
export { default as HeritageDataModel } from './heritage.mjs';
|
||||
export { default as MetierDataModel } from './metier.mjs';
|
||||
export { default as ModifierDataModel } from './modifier.mjs';
|
||||
export { default as MonnaieDataModel } from './monnaie.mjs';
|
||||
export { default as OrigineDataModel } from './origine.mjs';
|
||||
export { default as PacteDataModel } from './pacte.mjs';
|
||||
export { default as ProtectionDataModel } from './protection.mjs';
|
||||
export { default as RuneDataModel } from './rune.mjs';
|
||||
export { default as RuneEffectDataModel } from './runeeffect.mjs';
|
||||
export { default as TendanceDataModel } from './tendance.mjs';
|
||||
export { default as TraitChaotiqueDataModel } from './traitchaotique.mjs';
|
||||
export { default as TraitEspeceDataModel } from './traitespece.mjs';
|
||||
|
||||
// Modèles d'acteurs
|
||||
export { default as PersonnageDataModel } from './personnage.mjs';
|
||||
export { default as CreatureDataModel } from './creature.mjs';
|
||||
11
modules/models/metier.mjs
Normal file
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* Data model pour les métiers
|
||||
*/
|
||||
export default class MetierDataModel extends foundry.abstract.TypeDataModel {
|
||||
static defineSchema() {
|
||||
const fields = foundry.data.fields;
|
||||
return {
|
||||
description: new fields.HTMLField({ initial: "" })
|
||||
};
|
||||
}
|
||||
}
|
||||
18
modules/models/modifier.mjs
Normal file
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
* Data model pour les modificateurs
|
||||
*/
|
||||
export default class ModifierDataModel extends foundry.abstract.TypeDataModel {
|
||||
static defineSchema() {
|
||||
const fields = foundry.data.fields;
|
||||
return {
|
||||
description: new fields.HTMLField({ initial: "" }),
|
||||
modifiertype: new fields.StringField({ initial: "roll" }),
|
||||
value: new fields.NumberField({ initial: 0, integer: true }),
|
||||
attribut: new fields.StringField({ initial: "aucun" }),
|
||||
competence: new fields.StringField({ initial: "aucun" }),
|
||||
permanent: new fields.BooleanField({ initial: true }),
|
||||
once: new fields.BooleanField({ initial: false }),
|
||||
duree: new fields.StringField({ initial: "" })
|
||||
};
|
||||
}
|
||||
}
|
||||
13
modules/models/monnaie.mjs
Normal file
@@ -0,0 +1,13 @@
|
||||
/**
|
||||
* Data model pour les monnaies
|
||||
*/
|
||||
export default class MonnaieDataModel extends foundry.abstract.TypeDataModel {
|
||||
static defineSchema() {
|
||||
const fields = foundry.data.fields;
|
||||
return {
|
||||
description: new fields.HTMLField({ initial: "" }),
|
||||
quantite: new fields.NumberField({ initial: 0, integer: true }),
|
||||
unite: new fields.StringField({ initial: "" })
|
||||
};
|
||||
}
|
||||
}
|
||||
11
modules/models/origine.mjs
Normal file
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* Data model pour les origines
|
||||
*/
|
||||
export default class OrigineDataModel extends foundry.abstract.TypeDataModel {
|
||||
static defineSchema() {
|
||||
const fields = foundry.data.fields;
|
||||
return {
|
||||
description: new fields.HTMLField({ initial: "" })
|
||||
};
|
||||
}
|
||||
}
|
||||
12
modules/models/pacte.mjs
Normal file
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* Data model pour les pactes
|
||||
*/
|
||||
export default class PacteDataModel extends foundry.abstract.TypeDataModel {
|
||||
static defineSchema() {
|
||||
const fields = foundry.data.fields;
|
||||
return {
|
||||
description: new fields.HTMLField({ initial: "" }),
|
||||
allegeance: new fields.StringField({ initial: "" })
|
||||
};
|
||||
}
|
||||
}
|
||||
100
modules/models/personnage.mjs
Normal file
@@ -0,0 +1,100 @@
|
||||
/**
|
||||
* 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: "" }),
|
||||
age: new fields.NumberField({ initial: 0, integer: true }),
|
||||
alignement: new fields.StringField({ initial: "" }),
|
||||
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: "" }),
|
||||
amemultiplier: new fields.NumberField({ initial: 2, integer: true }),
|
||||
ignoreamemalus: new fields.BooleanField({ initial: false }),
|
||||
ignoresantemalus: new fields.BooleanField({ initial: false }),
|
||||
notes: new fields.HTMLField({ initial: "" }),
|
||||
gmnotes: new fields.HTMLField({ initial: "" })
|
||||
}),
|
||||
// Template core
|
||||
subactors: new fields.ArrayField(new fields.StringField(), { initial: [] }),
|
||||
attributs: new fields.SchemaField({
|
||||
adr: new fields.SchemaField({
|
||||
label: new fields.StringField({ initial: "Adresse" }),
|
||||
labelnorm: new fields.StringField({ initial: "adresse" }),
|
||||
abbrev: new fields.StringField({ initial: "adr" }),
|
||||
value: new fields.NumberField({ initial: 1, integer: true })
|
||||
}),
|
||||
pui: new fields.SchemaField({
|
||||
label: new fields.StringField({ initial: "Puissance" }),
|
||||
labelnorm: new fields.StringField({ initial: "puissance" }),
|
||||
abbrev: new fields.StringField({ initial: "pui" }),
|
||||
value: new fields.NumberField({ initial: 1, integer: true })
|
||||
}),
|
||||
cla: new fields.SchemaField({
|
||||
label: new fields.StringField({ initial: "Clairvoyance" }),
|
||||
labelnorm: new fields.StringField({ initial: "clairvoyance" }),
|
||||
abbrev: new fields.StringField({ initial: "cla" }),
|
||||
value: new fields.NumberField({ initial: 1, integer: true })
|
||||
}),
|
||||
pre: new fields.SchemaField({
|
||||
label: new fields.StringField({ initial: "Présence" }),
|
||||
labelnorm: new fields.StringField({ initial: "presence" }),
|
||||
abbrev: new fields.StringField({ initial: "pre" }),
|
||||
value: new fields.NumberField({ initial: 0, integer: true })
|
||||
}),
|
||||
tre: new fields.SchemaField({
|
||||
label: new fields.StringField({ initial: "Trempe" }),
|
||||
labelnorm: new fields.StringField({ initial: "trempe" }),
|
||||
abbrev: new fields.StringField({ initial: "tre" }),
|
||||
value: new fields.NumberField({ initial: 0, integer: true })
|
||||
})
|
||||
}),
|
||||
bonneaventure: new fields.SchemaField({
|
||||
base: new fields.NumberField({ initial: 0, integer: true }),
|
||||
actuelle: new fields.NumberField({ initial: 0, integer: true })
|
||||
}),
|
||||
experience: new fields.SchemaField({
|
||||
value: new fields.NumberField({ initial: 0, integer: true })
|
||||
}),
|
||||
eclat: new fields.SchemaField({
|
||||
value: new fields.NumberField({ initial: 0, integer: true })
|
||||
}),
|
||||
sante: new fields.SchemaField({
|
||||
base: new fields.NumberField({ initial: 0, integer: true }),
|
||||
bonus: new fields.NumberField({ initial: 0, integer: true }),
|
||||
nonletaux: new fields.NumberField({ initial: 0, integer: true }),
|
||||
letaux: new fields.NumberField({ initial: 0, integer: true }),
|
||||
malusmanuel: new fields.NumberField({ initial: 0, integer: true }),
|
||||
sequelles: new fields.StringField({ initial: "" })
|
||||
}),
|
||||
ame: new fields.SchemaField({
|
||||
fullmax: new fields.NumberField({ initial: 0, integer: true }),
|
||||
currentmax: new fields.NumberField({ initial: 0, integer: true }),
|
||||
value: new fields.NumberField({ initial: 0, integer: true }),
|
||||
traumatismes: new fields.StringField({ initial: "" })
|
||||
}),
|
||||
combat: new fields.SchemaField({
|
||||
initbonus: new fields.NumberField({ initial: 0, integer: true }),
|
||||
vitessebonus: new fields.NumberField({ initial: 0, integer: true }),
|
||||
bonusdegats: new fields.NumberField({ initial: 0, integer: true }),
|
||||
defensebonus: new fields.NumberField({ initial: 0, integer: true }),
|
||||
monte: new fields.BooleanField({ initial: false })
|
||||
}),
|
||||
balance: new fields.SchemaField({
|
||||
loi: new fields.NumberField({ initial: 0, integer: true }),
|
||||
chaos: new fields.NumberField({ initial: 0, integer: true }),
|
||||
aspect: new fields.NumberField({ initial: 0, integer: true }),
|
||||
marge: new fields.NumberField({ initial: 0, integer: true }),
|
||||
pointschaos: new fields.NumberField({ initial: 0, integer: true }),
|
||||
pointsloi: new fields.NumberField({ initial: 0, integer: true })
|
||||
})
|
||||
};
|
||||
}
|
||||
}
|
||||
17
modules/models/protection.mjs
Normal file
@@ -0,0 +1,17 @@
|
||||
/**
|
||||
* 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: "" }),
|
||||
typeprotection: new fields.StringField({ initial: "" }),
|
||||
protection: new fields.NumberField({ initial: 0, integer: true }),
|
||||
degats: new fields.StringField({ initial: "" }),
|
||||
rarete: new fields.NumberField({ initial: 0, integer: true }),
|
||||
prix: new fields.NumberField({ initial: 0, integer: true }),
|
||||
equipped: new fields.BooleanField({ initial: false })
|
||||
};
|
||||
}
|
||||
}
|
||||
15
modules/models/rune.mjs
Normal file
@@ -0,0 +1,15 @@
|
||||
/**
|
||||
* Data model pour les runes
|
||||
*/
|
||||
export default class RuneDataModel extends foundry.abstract.TypeDataModel {
|
||||
static defineSchema() {
|
||||
const fields = foundry.data.fields;
|
||||
return {
|
||||
description: new fields.HTMLField({ initial: "" }),
|
||||
formule: new fields.StringField({ initial: "" }),
|
||||
seuil: new fields.NumberField({ initial: 0, integer: true }),
|
||||
prononcee: new fields.StringField({ initial: "" }),
|
||||
tracee: new fields.StringField({ initial: "" })
|
||||
};
|
||||
}
|
||||
}
|
||||
15
modules/models/runeeffect.mjs
Normal file
@@ -0,0 +1,15 @@
|
||||
/**
|
||||
* Data model pour les effets de runes
|
||||
*/
|
||||
export default class RuneEffectDataModel extends foundry.abstract.TypeDataModel {
|
||||
static defineSchema() {
|
||||
const fields = foundry.data.fields;
|
||||
return {
|
||||
description: new fields.HTMLField({ initial: "" }),
|
||||
rune: new fields.StringField({ initial: "" }),
|
||||
mode: new fields.StringField({ initial: "" }),
|
||||
duree: new fields.StringField({ initial: "" }),
|
||||
pointame: new fields.NumberField({ initial: 0, integer: true })
|
||||
};
|
||||
}
|
||||
}
|
||||
12
modules/models/tendance.mjs
Normal file
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* Data model pour les tendances
|
||||
*/
|
||||
export default class TendanceDataModel extends foundry.abstract.TypeDataModel {
|
||||
static defineSchema() {
|
||||
const fields = foundry.data.fields;
|
||||
return {
|
||||
description: new fields.HTMLField({ initial: "" }),
|
||||
allegeance: new fields.StringField({ initial: "" })
|
||||
};
|
||||
}
|
||||
}
|
||||
11
modules/models/traitchaotique.mjs
Normal file
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* Data model pour les traits chaotiques
|
||||
*/
|
||||
export default class TraitChaotiqueDataModel extends foundry.abstract.TypeDataModel {
|
||||
static defineSchema() {
|
||||
const fields = foundry.data.fields;
|
||||
return {
|
||||
description: new fields.HTMLField({ initial: "" })
|
||||
};
|
||||
}
|
||||
}
|
||||
11
modules/models/traitespece.mjs
Normal file
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* Data model pour les traits d'espèce
|
||||
*/
|
||||
export default class TraitEspeceDataModel extends foundry.abstract.TypeDataModel {
|
||||
static defineSchema() {
|
||||
const fields = foundry.data.fields;
|
||||
return {
|
||||
description: new fields.HTMLField({ initial: "" })
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,21 +1,46 @@
|
||||
/* -------------------------------------------- */
|
||||
import { MournbladeUtility } from "./mournblade-utility.js";
|
||||
import { MournbladeRollDialog } from "./mournblade-roll-dialog.js";
|
||||
import { MournbladeRollDialog } from "./applications/mournblade-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]
|
||||
const __vitesseBonus = [-2, -2, -1, -1, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8]
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/**
|
||||
* Extend the base Actor entity by defining a custom roll data structure which is ideal for the Simple system.
|
||||
* @extends {Actor}
|
||||
*/
|
||||
export class MournbladeActor extends Actor {
|
||||
prepareData() {
|
||||
super.prepareData();
|
||||
|
||||
// Calculate derived attributes
|
||||
const data = this.system;
|
||||
|
||||
// Calculate total health
|
||||
data.sante.total = data.sante.base + data.sante.bonus;
|
||||
|
||||
// Calculate current health
|
||||
data.sante.current = data.sante.total - data.sante.nonletaux - data.sante.letaux;
|
||||
|
||||
// Calculate total ame
|
||||
data.ame.total = data.ame.fullmax;
|
||||
|
||||
// Calculate balance
|
||||
data.balance.total = data.balance.loi + data.balance.chaos;
|
||||
}
|
||||
|
||||
prepareDerivedData() {
|
||||
this.prepareData();
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/**
|
||||
* 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.
|
||||
@@ -28,7 +53,7 @@ export class MournbladeActor extends Actor {
|
||||
if (data instanceof Array) {
|
||||
return super.create(data, options);
|
||||
}
|
||||
// If the created actor has items (only applicable to duplicated actors) bypass the new actor creation logic
|
||||
// If the created actor has items (only applicable to foundry.utils.duplicated actors) bypass the new actor creation logic
|
||||
if (data.items) {
|
||||
let actor = super.create(data, options);
|
||||
return actor;
|
||||
@@ -36,66 +61,261 @@ export class MournbladeActor extends Actor {
|
||||
|
||||
if (data.type == 'personnage') {
|
||||
const skills = await MournbladeUtility.loadCompendium("fvtt-mournblade.skills")
|
||||
data.items = skills.map(i => i.toObject());
|
||||
data.items = skills.map(i => i.toObject())
|
||||
}
|
||||
if (data.type == 'pnj') {
|
||||
if (data.type == 'creature') {
|
||||
const skills = await MournbladeUtility.loadCompendium("fvtt-mournblade.skills-creatures")
|
||||
data.items = skills.map(i => i.toObject())
|
||||
data.items.push({ name: "Arme naturelle 1", type: 'arme', img: "systems/fvtt-mournblade/assets/icons/arme.webp", system: { typearme: "contact", bonusmaniementoff: 0, seuildefense: 0, degats: "0" } })
|
||||
data.items.push({ name: "Arme naturelle 2", type: 'arme', img: "systems/fvtt-mournblade/assets/icons/arme.webp", system: { typearme: "contact", bonusmaniementoff: 0, seuildefense: 0, degats: "0" } })
|
||||
}
|
||||
|
||||
|
||||
return super.create(data, options);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
getWeapons() {
|
||||
return this.data.items.filter(item => item.type == "arme")
|
||||
setModifier(name, type, value) {
|
||||
this.createEmbeddedDocuments("Item", [{ type: "modifier", name: name, system: { modifiertype: type, value: value } }])
|
||||
ui.notifications.info("Le modificateur " + name + " a été ajouté à " + this.name + ".")
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
prepareArme(arme) {
|
||||
arme = foundry.utils.duplicate(arme)
|
||||
let combat = this.getCombatValues()
|
||||
if (arme.system.typearme == "contact" || arme.system.typearme == "contactjet") {
|
||||
arme.system.isMelee = true
|
||||
let competence = this.items.find(item => item.type == "competence" && item.name.toLowerCase() == "mêlée")
|
||||
if (competence) {
|
||||
arme.system.competence = foundry.utils.duplicate(competence)
|
||||
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 + combat.attaqueModifier
|
||||
if (arme.system.isdefense) {
|
||||
arme.system.totalDefensif = combat.defenseTotal + arme.system.competence.system.niveau + arme.system.bonusmaniementdef
|
||||
}
|
||||
} else {
|
||||
arme.system.competence = null
|
||||
arme.system.totalOffensif = 0
|
||||
arme.system.totalDegats = arme.system.degats
|
||||
arme.system.totalDefensif = 0
|
||||
}
|
||||
}
|
||||
if (arme.system.typearme == "jet" || arme.system.typearme == "tir") {
|
||||
arme.system.isDistance = true
|
||||
let competence = this.items.find(item => item.type == "competence" && item.name.toLowerCase() == "armes à distance")
|
||||
if (competence) {
|
||||
arme.system.competence = foundry.utils.duplicate(competence)
|
||||
arme.system.attrKey = "adr"
|
||||
arme.system.totalOffensif = this.system.attributs.adr.value + arme.system.competence.system.niveau + arme.system.bonusmaniementoff + combat.attaqueModifier
|
||||
arme.system.totalDegats = arme.system.degats
|
||||
if (arme.system.isdefense) {
|
||||
arme.system.totalDefensif = combat.defenseTotal + arme.system.competence.system.niveau + arme.system.bonusmaniementdef
|
||||
}
|
||||
} else {
|
||||
arme.system.competence = null
|
||||
arme.system.totalOffensif = 0
|
||||
arme.system.totalDegats = arme.system.degats
|
||||
arme.system.totalDefensif = 0
|
||||
}
|
||||
}
|
||||
return arme
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
prepareBouclier(bouclier) {
|
||||
bouclier = foundry.utils.duplicate(bouclier)
|
||||
let combat = this.getCombatValues()
|
||||
let competence = this.items.find(item => item.type == "competence" && item.name.toLowerCase() == "mêlée")
|
||||
if (competence) {
|
||||
bouclier.system.competence = foundry.utils.duplicate(competence)
|
||||
bouclier.system.attrKey = "pui"
|
||||
bouclier.system.totalDegats = bouclier.system.degats + "+" + combat.bonusDegatsTotal
|
||||
bouclier.system.totalOffensif = this.system.attributs.pui.value + bouclier.system.competence.system.niveau
|
||||
bouclier.system.isdefense = true
|
||||
bouclier.system.bonusmaniementoff = 0
|
||||
bouclier.system.totalDefensif = combat.defenseTotal + bouclier.system.competence.system.niveau + bouclier.system.bonusdefense
|
||||
} else {
|
||||
bouclier.system.competence = null
|
||||
bouclier.system.totalOffensif = 0
|
||||
bouclier.system.totalDegats = bouclier.system.degats
|
||||
bouclier.system.totalDefensif = 0
|
||||
}
|
||||
return bouclier
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
getWeapons() {
|
||||
let armes = []
|
||||
for (let arme of this.items) {
|
||||
if (arme.type == "arme") {
|
||||
armes.push(this.prepareArme(arme))
|
||||
}
|
||||
if (arme.type == "bouclier") {
|
||||
armes.push(this.prepareBouclier(arme))
|
||||
}
|
||||
}
|
||||
MournbladeUtility.sortArrayObjectsByName(armes)
|
||||
return armes
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
getModifiersForRoll() {
|
||||
let modifiers = []
|
||||
for (let mod of this.items) {
|
||||
if (mod.type == "modifier" && mod.system.modifiertype == "roll") {
|
||||
let modObj = mod.toObject()
|
||||
modObj.system.apply = true
|
||||
modifiers.push(modObj)
|
||||
}
|
||||
}
|
||||
MournbladeUtility.sortArrayObjectsByName(modifiers)
|
||||
return modifiers
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
getItemSorted(types) {
|
||||
let items = this.items.filter(item => types.includes(item.type)) || []
|
||||
MournbladeUtility.sortArrayObjectsByName(items)
|
||||
return items
|
||||
}
|
||||
getDons() {
|
||||
return this.getItemSorted(["don"])
|
||||
}
|
||||
getPactes() {
|
||||
return this.getItemSorted(["pacte"])
|
||||
}
|
||||
getTendances() {
|
||||
return this.getItemSorted(["tendance"])
|
||||
}
|
||||
getRunes() {
|
||||
return this.getItemSorted(["rune"])
|
||||
}
|
||||
getEquipments() {
|
||||
return this.getItemSorted(["equipement"])
|
||||
}
|
||||
getModifiers() {
|
||||
return this.getItemSorted(["modifier"])
|
||||
}
|
||||
getTraitsChaotiques() {
|
||||
return this.getItemSorted(["traitchaotique"])
|
||||
}
|
||||
getTraitsEspeces() {
|
||||
return this.getItemSorted(["traitespece"])
|
||||
}
|
||||
getMonnaies() {
|
||||
return this.getItemSorted(["monnaie"])
|
||||
}
|
||||
getArmors() {
|
||||
return this.data.items.filter(item => item.type == "protection")
|
||||
return this.getItemSorted(["protection"])
|
||||
}
|
||||
getRuneEffects() {
|
||||
return this.getItemSorted(["runeeffect"])
|
||||
}
|
||||
getOrigine() {
|
||||
return this.items.find(item => item.type == "origine")
|
||||
}
|
||||
getMetier() {
|
||||
return this.items.find(item => item.type == "metier")
|
||||
}
|
||||
getHeritage() {
|
||||
return this.items.find(item => item.type == "heritage")
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
getSkills() {
|
||||
let comp = []
|
||||
for (let item of this.data.items) {
|
||||
item = duplicate(item)
|
||||
for (let item of this.items) {
|
||||
item = foundry.utils.duplicate(item)
|
||||
if (item.type == "competence") {
|
||||
item.data.attribut1total = item.data.niveau + (this.data.data.attributs[item.data.attribut1]?.value || 0)
|
||||
item.data.attribut2total = item.data.niveau + (this.data.data.attributs[item.data.attribut2]?.value || 0)
|
||||
item.data.attribut3total = item.data.niveau + (this.data.data.attributs[item.data.attribut3]?.value || 0)
|
||||
if (item.data.niveau == 0) {
|
||||
item.data.attribut1total -= 3
|
||||
item.data.attribut2total -= 3
|
||||
item.data.attribut3total -= 3
|
||||
item.system.attribut1total = item.system.niveau + (this.system.attributs[item.system.attribut1]?.value || 0)
|
||||
item.system.attribut2total = item.system.niveau + (this.system.attributs[item.system.attribut2]?.value || 0)
|
||||
item.system.attribut3total = item.system.niveau + (this.system.attributs[item.system.attribut3]?.value || 0)
|
||||
if (item.system.niveau == 0) {
|
||||
item.system.attribut1total -= 3
|
||||
item.system.attribut2total -= 3
|
||||
item.system.attribut3total -= 3
|
||||
}
|
||||
item.data.attribut1label = this.data.data.attributs[item.data.attribut1]?.label || ""
|
||||
item.data.attribut2label = this.data.data.attributs[item.data.attribut2]?.label || ""
|
||||
item.data.attribut3label = this.data.data.attributs[item.data.attribut3]?.label || ""
|
||||
item.system.attribut1label = this.system.attributs[item.system.attribut1]?.label || ""
|
||||
item.system.attribut2label = this.system.attributs[item.system.attribut2]?.label || ""
|
||||
item.system.attribut3label = this.system.attributs[item.system.attribut3]?.label || ""
|
||||
comp.push(item)
|
||||
}
|
||||
}
|
||||
MournbladeUtility.sortArrayObjectsByName(comp)
|
||||
return comp
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
getProtectionTotal() {
|
||||
let protection = 0
|
||||
for (let item of this.items) {
|
||||
if (item.type == "protection" && item.system.equipped) {
|
||||
protection += item.system.protection
|
||||
}
|
||||
}
|
||||
return protection
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
getAspect() {
|
||||
return (this.system.balance.loi > this.system.balance.chaos) ? this.system.balance.loi : this.system.balance.chaos
|
||||
}
|
||||
getMarge() {
|
||||
return Math.abs(this.system.balance.loi - this.system.balance.chaos)
|
||||
}
|
||||
getAlignement() {
|
||||
return (this.data.data.balance.loi > this.data.data.balance.chaos) ? "loyal" : "chaotique"
|
||||
return (this.system.balance.loi > this.system.balance.chaos) ? "loyal" : "chaotique"
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
prepareBaseData() {
|
||||
getDefenseBase() {
|
||||
return this.system.attributs.tre.value + 5
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async prepareData() {
|
||||
super.prepareData();
|
||||
getVitesseBase() {
|
||||
return 5 + __vitesseBonus[this.system.attributs.adr.value]
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
getCombatValues() {
|
||||
let defenserModifier = 0
|
||||
this.items.filter(item => item.type == "modifier" && item.system.modifiertype == "defense").map(e => defenserModifier += e.system.value)
|
||||
let attaqueModifier = 0
|
||||
this.items.filter(item => item.type == "modifier" && item.system.modifiertype == "attaque").map(e => attaqueModifier += e.system.value)
|
||||
|
||||
let combat = {
|
||||
defenserModifier,
|
||||
attaqueModifier,
|
||||
initBase: this.system.attributs.adr.value,
|
||||
initTotal: this.system.attributs.adr.value + this.system.combat.initbonus,
|
||||
bonusDegats: this.getBonusDegats(),
|
||||
bonusDegatsTotal: this.getBonusDegats() + this.system.combat.bonusdegats,
|
||||
vitesseBase: this.getVitesseBase(),
|
||||
vitesseTotal: this.getVitesseBase() + this.system.combat.vitessebonus,
|
||||
defenseBase: this.getDefenseBase(),
|
||||
defenseTotal: this.getDefenseBase() + this.system.combat.defensebonus + defenserModifier
|
||||
}
|
||||
return combat
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
prepareDerivedData() {
|
||||
|
||||
if (this.type == 'character') {
|
||||
if (this.type == 'personnage') {
|
||||
let newSante = this.system.sante.bonus + (this.system.attributs.pui.value + this.system.attributs.tre.value) * 2 + 5
|
||||
if (this.system.sante.base != newSante && this._id) {
|
||||
// Only update if the actor already exists (has an _id)
|
||||
this.update({ 'system.sante.base': newSante })
|
||||
}
|
||||
let newAme = (this.system.attributs.cla.value + this.system.attributs.tre.value) * this.system.biodata.amemultiplier + 5
|
||||
if (this.system.ame.fullmax != newAme && this._id) {
|
||||
// Only update if the actor already exists (has an _id)
|
||||
this.update({ 'system.ame.fullmax': newAme })
|
||||
}
|
||||
}
|
||||
|
||||
super.prepareDerivedData();
|
||||
super.prepareDerivedData()
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
@@ -106,25 +326,62 @@ export class MournbladeActor extends Actor {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
getItemById(id) {
|
||||
let item = this.data.items.find(item => item.id == id);
|
||||
let item = this.items.find(item => item.id == id);
|
||||
if (item) {
|
||||
item = duplicate(item)
|
||||
item = foundry.utils.duplicate(item)
|
||||
}
|
||||
return item;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async equipItem(itemId) {
|
||||
let item = this.data.items.find(item => item.id == itemId);
|
||||
if (item && item.data.data) {
|
||||
let update = { _id: item.id, "data.equipped": !item.data.data.equipped };
|
||||
let item = this.items.find(item => item.id == itemId)
|
||||
if (item?.system) {
|
||||
let update = { _id: item.id, "system.equipped": !item.system.equipped }
|
||||
await this.updateEmbeddedDocuments('Item', [update]); // Updates one EmbeddedEntity
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
getStatusMalus() {
|
||||
if (this.system.biodata.ignoresantemalus) {
|
||||
return 0
|
||||
}
|
||||
|
||||
let malusL = 0
|
||||
let malusNL = 0
|
||||
if (this.system.sante.base - this.system.sante.letaux < 10) {
|
||||
malusL = -2
|
||||
}
|
||||
if (this.system.sante.base - this.system.sante.letaux < 5) {
|
||||
malusL = -5
|
||||
}
|
||||
if (this.system.sante.base - this.system.sante.nonletaux < 10) {
|
||||
malusNL = -2
|
||||
}
|
||||
if (this.system.sante.base - this.system.sante.nonletaux < 5) {
|
||||
malusNL = -5
|
||||
}
|
||||
return Math.min(malusL, malusNL)
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
getAmeMalus() {
|
||||
if (this.system.biodata.ignoreamemalus) {
|
||||
return 0
|
||||
}
|
||||
let malusA = 0
|
||||
if (this.system.ame.currentmax - this.system.ame.value < 10) {
|
||||
malusA = -2
|
||||
}
|
||||
if (this.system.ame.currentmax - this.system.ame.value < 5) {
|
||||
malusA = -5
|
||||
}
|
||||
return malusA
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
editItemField(itemId, itemType, itemField, dataType, value) {
|
||||
let item = this.data.items.find(item => item.id == itemId)
|
||||
let item = this.items.find(item => item.id == itemId)
|
||||
if (item) {
|
||||
console.log("Item ", item, itemField, dataType, value)
|
||||
if (dataType.toLowerCase() == "number") {
|
||||
@@ -132,38 +389,86 @@ export class MournbladeActor extends Actor {
|
||||
} else {
|
||||
value = String(value)
|
||||
}
|
||||
let update = { _id: item.id, [`data.${itemField}`]: value };
|
||||
let update = { _id: item.id, [`system.${itemField}`]: value };
|
||||
this.updateEmbeddedDocuments("Item", [update])
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
incDecSante(type, value, applyArmure = true) {
|
||||
value = Number(value)
|
||||
if (value && applyArmure) {
|
||||
let protection = this.getProtectionTotal()
|
||||
value -= protection
|
||||
value = Math.max(0, Number(value))
|
||||
}
|
||||
if (value) {
|
||||
let newSante = foundry.utils.duplicate(this.system.sante)
|
||||
newSante[type] += Number(value)
|
||||
newSante[type] = Math.max(0, newSante[type])
|
||||
if (newSante[type] > this.system.sante.base) {
|
||||
value -= this.system.sante.base - newSante[type]
|
||||
newSante[type] = this.system.sante.base
|
||||
} else {
|
||||
value = 0
|
||||
}
|
||||
newSante[type] = Math.min(newSante[type], newSante.base)
|
||||
if (value && type == "nonletaux") {
|
||||
newSante["letaux"] += value
|
||||
}
|
||||
this.update({ 'system.sante': newSante })
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
incDecAme(value) {
|
||||
value = Number(value)
|
||||
if (value) {
|
||||
let newAme = foundry.utils.duplicate(this.system.ame)
|
||||
newAme.value += Number(value)
|
||||
newAme.value = Math.max(0, newAme.value)
|
||||
newAme.value = Math.min(newAme.value, newAme.currentmax)
|
||||
this.update({ 'system.ame': newAme })
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
getBonneAventure() {
|
||||
return this.data.data.bonneaventure.actuelle
|
||||
return this.system.bonneaventure.actuelle
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
changeBonneAventure(value) {
|
||||
let newBA = this.data.data.bonneaventure.actuelle
|
||||
let newBA = this.system.bonneaventure.actuelle
|
||||
newBA += value
|
||||
this.update({ 'data.bonneaventure.actuelle': newBA })
|
||||
this.update({ 'system.bonneaventure.actuelle': newBA })
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
getEclat() {
|
||||
return this.data.data.eclat.value
|
||||
return this.system.eclat.value
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
changeEclat(value) {
|
||||
let newE = this.data.data.eclat.value
|
||||
let newE = this.system.eclat.value
|
||||
newE += value
|
||||
this.update({ 'data.eclat.value': newE })
|
||||
this.update({ 'system.eclat.value': newE })
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
canEclatDoubleD20() {
|
||||
return (this.getAlignement() == "loyal" && this.data.data.eclat.value > 0)
|
||||
return (this.getAlignement() == "loyal" && this.system.eclat.value > 0)
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
subPointsAme(runeMode, value) {
|
||||
let ame = foundry.utils.duplicate(this.system.ame)
|
||||
if (runeMode == "prononcer") {
|
||||
ame.value += value
|
||||
} else {
|
||||
ame.currentmax -= value
|
||||
}
|
||||
this.update({ 'system.ame': ame })
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
@@ -179,14 +484,22 @@ export class MournbladeActor extends Actor {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
getAttribute(attrKey) {
|
||||
return this.data.data.attributes[attrKey]
|
||||
return this.system.attributes[attrKey]
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
getBonusDegats() {
|
||||
if (this.type == "creature") {
|
||||
return 0
|
||||
}
|
||||
return __degatsBonus[this.system.attributs.pui.value]
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async equipGear(equipmentId) {
|
||||
let item = this.data.items.find(item => item.id == equipmentId);
|
||||
if (item && item.data.data) {
|
||||
let update = { _id: item.id, "data.equipped": !item.data.data.equipped };
|
||||
let item = this.items.find(item => item.id == equipmentId);
|
||||
if (item && item.system.data) {
|
||||
let update = { _id: item.id, "system.equipped": !item.system.equipped };
|
||||
await this.updateEmbeddedDocuments('Item', [update]); // Updates one EmbeddedEntity
|
||||
}
|
||||
}
|
||||
@@ -194,58 +507,129 @@ export class MournbladeActor extends Actor {
|
||||
/* -------------------------------------------- */
|
||||
getSubActors() {
|
||||
let subActors = [];
|
||||
for (let id of this.data.data.subactors) {
|
||||
subActors.push(duplicate(game.actors.get(id)));
|
||||
for (let id of this.system.subactors) {
|
||||
subActors.push(foundry.utils.duplicate(game.actors.get(id)));
|
||||
}
|
||||
return subActors;
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
async addSubActor(subActorId) {
|
||||
let subActors = duplicate(this.data.data.subactors);
|
||||
let subActors = foundry.utils.duplicate(this.system.subactors);
|
||||
subActors.push(subActorId);
|
||||
await this.update({ 'data.subactors': subActors });
|
||||
await this.update({ 'system.subactors': subActors });
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
async delSubActor(subActorId) {
|
||||
let newArray = [];
|
||||
for (let id of this.data.data.subactors) {
|
||||
for (let id of this.system.subactors) {
|
||||
if (id != subActorId) {
|
||||
newArray.push(id);
|
||||
}
|
||||
}
|
||||
await this.update({ 'data.subactors': newArray });
|
||||
await this.update({ 'system.subactors': newArray });
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async incDecQuantity(objetId, incDec = 0) {
|
||||
let objetQ = this.data.items.get(objetId)
|
||||
let objetQ = this.items.get(objetId)
|
||||
if (objetQ) {
|
||||
let newQ = objetQ.data.data.quantity + incDec;
|
||||
const updated = await this.updateEmbeddedDocuments('Item', [{ _id: objetQ.id, 'data.quantity': newQ }]); // pdates one EmbeddedEntity
|
||||
let newQ = objetQ.system.quantite + incDec;
|
||||
const updated = await this.updateEmbeddedDocuments('Item', [{ _id: objetQ.id, 'system.quantite': newQ }]); // pdates one EmbeddedEntity
|
||||
}
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
getCompetence(compId) {
|
||||
return this.items.get(compId)
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async setPredilectionUsed(compId, predIdx) {
|
||||
let comp = this.items.get(compId)
|
||||
let pred = foundry.utils.duplicate(comp.system.predilections)
|
||||
pred[predIdx].used = true
|
||||
await this.updateEmbeddedDocuments('Item', [{ _id: compId, 'system.predilections': pred }])
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
getInitiativeScore() {
|
||||
return Number(this.system.attributs.adr.value) + Number(this.system.combat.initbonus)
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
getBestDefenseValue() {
|
||||
let defenseList = this.items.filter(item => (item.type == "arme" || item.type == "bouclier") && item.system.equipped)
|
||||
let maxDef = 0
|
||||
let bestArme
|
||||
for (let arme of defenseList) {
|
||||
if (arme.type == "arme" && arme.system.isdefense) {
|
||||
arme = this.prepareArme(arme)
|
||||
}
|
||||
if (arme.type == "bouclier") {
|
||||
arme = this.prepareBouclier(arme)
|
||||
}
|
||||
if (arme.system.totalDefensif > maxDef) {
|
||||
maxDef = arme.system.totalDefensif
|
||||
bestArme = foundry.utils.duplicate(arme)
|
||||
}
|
||||
}
|
||||
return bestArme
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
depenseRessources(arme) {
|
||||
if (arme.system.nbressources && Number(arme.system.nbressources) > 0) {
|
||||
if (this.type == "creature") {
|
||||
let ressources = foundry.utils.duplicate(this.system.ressources)
|
||||
if (Number(ressources.value) >= Number(arme.system.nbressources)) {
|
||||
ressources.value -= arme.system.nbressources
|
||||
this.update({ 'system.ressources': ressources })
|
||||
ChatMessage.create({
|
||||
content: "L'utilisation de la capacité/arme a dépensé " + arme.system.nbressources + " ressources.",
|
||||
whisper: game.user._id,
|
||||
user: game.user._id
|
||||
});
|
||||
} else {
|
||||
ui.notifications.warn("Points de ressources insuffisants.")
|
||||
}
|
||||
} else {
|
||||
ui.notifications.warn("Les ressources ne sont pas disponibles pour les personnages.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
getCommonRollData(attrKey = undefined, compId = undefined) {
|
||||
getCommonRollData(attrKey = undefined, compId = undefined, compName = undefined) {
|
||||
let rollData = MournbladeUtility.getBasicRollData()
|
||||
rollData.alias = this.name
|
||||
rollData.actorImg = this.img
|
||||
rollData.actorId = this.id
|
||||
rollData.tokenId = this.token?.id
|
||||
rollData.img = this.img
|
||||
rollData.canEclatDoubleD20 = this.canEclatDoubleD20()
|
||||
rollData.doubleD20 = false
|
||||
rollData.attributs = MournbladeUtility.getAttributs()
|
||||
rollData.selectDifficulte = true
|
||||
rollData.malusSante = this.getStatusMalus() + this.system.sante.malusmanuel
|
||||
rollData.malusAme = this.getAmeMalus()
|
||||
rollData.modifiers = this.getModifiersForRoll()
|
||||
rollData.desavantages = {}
|
||||
rollData.isMonte = this.system.combat.monte
|
||||
if (rollData.isMonte) {
|
||||
rollData.config.attaques["chargecavalerie"] = "Charge de cavalerie"
|
||||
}
|
||||
|
||||
if (attrKey) {
|
||||
rollData.attrKey = attrKey
|
||||
if (attrKey != "tochoose") {
|
||||
rollData.actionImg = "systems/fvtt-mournblade/assets/icons/" + this.data.data.attributs[attrKey].labelnorm + ".webp"
|
||||
rollData.attr = duplicate(this.data.data.attributs[attrKey])
|
||||
rollData.actionImg = "systems/fvtt-mournblade/assets/icons/" + this.system.attributs[attrKey].labelnorm + ".webp"
|
||||
rollData.attr = foundry.utils.duplicate(this.system.attributs[attrKey])
|
||||
}
|
||||
}
|
||||
if (compId) {
|
||||
rollData.competence = duplicate(this.data.items.get(compId) || {})
|
||||
rollData.actionImg = rollData.competence.img
|
||||
rollData.competence = foundry.utils.duplicate(this.items.get(compId) || {})
|
||||
rollData.actionImg = rollData.competence?.img
|
||||
}
|
||||
if (compName) {
|
||||
rollData.competence = foundry.utils.duplicate(this.items.find(item => item.name.toLowerCase() == compName.toLowerCase()) || {})
|
||||
rollData.actionImg = rollData.competence?.img
|
||||
}
|
||||
return rollData
|
||||
}
|
||||
@@ -253,17 +637,134 @@ export class MournbladeActor extends Actor {
|
||||
/* -------------------------------------------- */
|
||||
async rollAttribut(attrKey) {
|
||||
let rollData = this.getCommonRollData(attrKey)
|
||||
console.log("RollDatra", rollData)
|
||||
let rollDialog = await MournbladeRollDialog.create(this, rollData)
|
||||
rollDialog.render(true)
|
||||
await MournbladeRollDialog.create(this, rollData)
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async rollCompetence(attrKey, compId) {
|
||||
let rollData = this.getCommonRollData(attrKey, compId)
|
||||
console.log("RollDatra", rollData)
|
||||
let rollDialog = await MournbladeRollDialog.create(this, rollData)
|
||||
rollDialog.render(true)
|
||||
await MournbladeRollDialog.create(this, rollData)
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async rollRune(runeId) {
|
||||
let comp = this.items.find(comp => comp.type == "competence" && comp.name.toLowerCase() == "savoir : runes")
|
||||
if (!comp) {
|
||||
ui.notifications.warn("La compétence Savoirs : Runes n'a pas été trouvée, abandon.")
|
||||
return
|
||||
}
|
||||
let rollData = this.getCommonRollData("cla", undefined, "Savoir : Runes")
|
||||
rollData.rune = foundry.utils.duplicate(this.items.get(runeId) || {})
|
||||
rollData.difficulte = rollData.rune?.system?.seuil || 0
|
||||
rollData.runemode = "prononcer"
|
||||
rollData.runeame = 1
|
||||
console.log("runeData", rollData)
|
||||
await MournbladeRollDialog.create(this, rollData)
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async rollArmeOffensif(armeId) {
|
||||
let arme = this.items.get(armeId)
|
||||
if (arme.type == "arme") {
|
||||
arme = this.prepareArme(arme)
|
||||
}
|
||||
if (arme.type == "bouclier") {
|
||||
arme = this.prepareBouclier(arme)
|
||||
}
|
||||
let rollData = this.getCommonRollData(arme.system.attrKey, arme.system.competence._id)
|
||||
rollData.arme = arme
|
||||
rollData.typeAttaque = "assaut"
|
||||
rollData.typeCouvert = "aucun"
|
||||
rollData.hasDesavantageBonus = true
|
||||
rollData.visee = false
|
||||
rollData.ciblecourt = false
|
||||
rollData.cibleconsciente = false
|
||||
// Do not display difficulte if defense weapon or distance
|
||||
if (rollData.armeDefense || rollData.arme.system.isDistance) {
|
||||
rollData.selectDifficulte = false
|
||||
rollData.difficulte = (rollData.arme.system.isDistance) ? 0 : rollData.difficulte
|
||||
}
|
||||
console.log("ARME!", rollData)
|
||||
this.depenseRessources(arme)
|
||||
await MournbladeRollDialog.create(this, rollData)
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async rollAssomer() {
|
||||
let rollData = this.getCommonRollData("adr", undefined, "Filouterie")
|
||||
rollData.typeAttaque = "assomer"
|
||||
rollData.typeCouvert = "aucun"
|
||||
rollData.hasDesavantageBonus = true
|
||||
if (rollData.defender) {
|
||||
rollData.selectDifficulte = false
|
||||
rollData.difficulte = rollData.defender.system.attributs.tre.value * 2
|
||||
}
|
||||
console.log("Assomer!", rollData)
|
||||
await MournbladeRollDialog.create(this, rollData)
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
async rollFuir() {
|
||||
let rollData = this.getCommonRollData("adr", undefined, "Mouvements")
|
||||
rollData.typeAttaque = "fuir"
|
||||
rollData.typeCouvert = "aucun"
|
||||
rollData.hasDesavantageBonus = true
|
||||
if (rollData.defender) {
|
||||
rollData.selectDifficulte = false
|
||||
let comp = rollData.defender.items.find(it => it.type == "competence" && it.name.toLowerCase() == "mouvements")
|
||||
rollData.difficulte = rollData.defender.system.attributs.adr.value + ((comp) ? comp.system.niveau : rollData.defender.system.attributs.adr.value)
|
||||
}
|
||||
console.log("Fuir!", rollData)
|
||||
await MournbladeRollDialog.create(this, rollData)
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
async rollImmobiliser() {
|
||||
let rollData = this.getCommonRollData("pui", undefined, "Mêlée")
|
||||
rollData.typeAttaque = "immobiliser"
|
||||
rollData.typeCouvert = "aucun"
|
||||
rollData.hasDesavantageBonus = true
|
||||
if (rollData.defender) {
|
||||
rollData.selectDifficulte = false
|
||||
rollData.difficulte = rollData.defenderCombatValues.defenseTotal
|
||||
}
|
||||
console.log("Immobiliser!", rollData)
|
||||
await MournbladeRollDialog.create(this, rollData)
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
async rollArmeSpecial(armeId) {
|
||||
let arme = this.items.get(armeId)
|
||||
if (arme) {
|
||||
MournbladeUtility.createChatWithRollMode("GM", {
|
||||
content: await renderTemplate(`systems/fvtt-mournblade/templates/chat-display-description.hbs`, arme)
|
||||
}, arme)
|
||||
this.depenseRessources(arme)
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async rollArmeDegats(armeId) {
|
||||
let arme = this.items.get(armeId)
|
||||
if (arme.type == "arme") {
|
||||
arme = this.prepareArme(arme)
|
||||
}
|
||||
if (arme.type == "bouclier") {
|
||||
arme = this.prepareBouclier(arme)
|
||||
}
|
||||
//Unused rollData.degatsFormula = arme.system.totalDegats
|
||||
let roll = await new Roll(arme.system.totalDegats).roll()
|
||||
await MournbladeUtility.showDiceSoNice(roll, game.settings.get("core", "rollMode"));
|
||||
let rollData = {
|
||||
degatsFormula:arme.system.totalDegats,
|
||||
arme: arme,
|
||||
finalResult: roll.total,
|
||||
alias: this.name,
|
||||
actorImg: this.img,
|
||||
actorId: this.id,
|
||||
actionImg: arme.img,
|
||||
}
|
||||
MournbladeUtility.createChatWithRollMode(rollData.alias, {
|
||||
content: await foundry.applications.handlebars.renderTemplate(`systems/fvtt-mournblade/templates/chat-degats-result-v2.hbs`, rollData)
|
||||
})
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,8 +9,11 @@ export class MournbladeCombat extends Combat {
|
||||
for (let cId = 0; cId < ids.length; cId++) {
|
||||
const c = this.combatants.get(ids[cId]);
|
||||
let id = c._id || c.id;
|
||||
let initBonus = c.actor ? c.actor.getInitiativeScore( this.id, id ) : -1;
|
||||
await this.updateEmbeddedDocuments("Combatant", [ { _id: id, initiative: initBonus } ]);
|
||||
let initBonus = c.actor ? c.actor.getInitiativeScore() : 0
|
||||
let roll = new Roll("1d10 + "+initBonus).roll({ async: false})
|
||||
await MournbladeUtility.showDiceSoNice(roll, game.settings.get("core", "rollMode"))
|
||||
//console.log("Init bonus", initBonus, roll.total)
|
||||
await this.updateEmbeddedDocuments("Combatant", [ { _id: id, initiative: roll.total } ]);
|
||||
}
|
||||
|
||||
return this;
|
||||
|
||||
@@ -116,8 +116,7 @@ export class MournbladeCommands {
|
||||
rollData.mode = "generic"
|
||||
rollData.title = `Dice Pool Roll`;
|
||||
|
||||
let rollDialog = await MournbladeRollDialog.create( this, rollData);
|
||||
rollDialog.render( true );
|
||||
await MournbladeRollDialog.create( this, rollData);
|
||||
}
|
||||
|
||||
}
|
||||
81
modules/mournblade-config.js
Normal file
@@ -0,0 +1,81 @@
|
||||
|
||||
export class MournbladeConfig {
|
||||
|
||||
static getConfig() {
|
||||
let MOURNBLADE_CONFIG = {
|
||||
|
||||
attaques: {
|
||||
assaut: game.i18n.localize("MNBL.assaut"),
|
||||
precise: game.i18n.localize("MNBL.preciseattack"),
|
||||
feinte: game.i18n.localize("MNBL.feint"),
|
||||
coupbas: game.i18n.localize("MNBL.dirtyattack"),
|
||||
charger: game.i18n.localize("MNBL.charge"),
|
||||
contenir: game.i18n.localize("MNBL.contain"),
|
||||
desarmer: game.i18n.localize("MNBL.disarm")
|
||||
},
|
||||
couverts: {
|
||||
aucun: { name: game.i18n.localize("MNBL.none"), value: 0 },
|
||||
rondache: { name: game.i18n.localize("MNBL.lightcover"), value: -2 },
|
||||
pavois: { name: game.i18n.localize("MNBL.mediumcover"), value: -5 },
|
||||
complet: { name: game.i18n.localize("MNBL.heavycover"), value: -10 },
|
||||
},
|
||||
modifierTypes: {
|
||||
aucun: { name: game.i18n.localize("MNBL.none"), value: 0 },
|
||||
roll: { name: game.i18n.localize("MNBL.roll"), value: 0 },
|
||||
degats: { name: game.i18n.localize("MNBL.damage"), value: 0 },
|
||||
defense: { name: game.i18n.localize("MNBL.defensecapacity"), value: 0 },
|
||||
attaque: { name: game.i18n.localize("MNBL.attackcapacity"), value: 0 },
|
||||
},
|
||||
listeNiveau: {
|
||||
},
|
||||
listeNiveauCreature: {
|
||||
},
|
||||
listePortees: {
|
||||
"10": game.i18n.localize("MNBL.lessthanshort"),
|
||||
"15": game.i18n.localize("MNBL.shortmore"),
|
||||
"20": game.i18n.localize("MNBL.mediummore"),
|
||||
"25": game.i18n.localize("MNBL.longmore")
|
||||
},
|
||||
modificateurOptions: {},
|
||||
pointsAmeOptions: {},
|
||||
difficulteOptions: {
|
||||
"0": game.i18n.localize("MNBL.noneunknwon"),
|
||||
"5": game.i18n.localize("MNBL.easy"),
|
||||
"10": game.i18n.localize("MNBL.medium"),
|
||||
"15": game.i18n.localize("MNBL.hard"),
|
||||
"20": game.i18n.localize("MNBL.hazardous"),
|
||||
"25": game.i18n.localize("MNBL.insane"),
|
||||
"30": game.i18n.localize("MNBL.puremadness")
|
||||
},
|
||||
attributs: {
|
||||
adr: game.i18n.localize("Adresse"), pui: game.i18n.localize("Puissance"),
|
||||
cla: game.i18n.localize("Clairvoyance"), pre: game.i18n.localize("Présence"), tre: game.i18n.localize("Trempe")
|
||||
},
|
||||
lancementRuneOptions: {
|
||||
prononcer: game.i18n.localize("MNBL.pronouncerune"),
|
||||
inscrire: game.i18n.localize("MNBL.tracerune")
|
||||
},
|
||||
effetRuneOptions: {
|
||||
prononcee: game.i18n.localize("MNBL.pronounced"),
|
||||
inscrite: game.i18n.localize("MNBL.traced")
|
||||
},
|
||||
typeArmeOptions: {
|
||||
contact: game.i18n.localize("MNBL.meleeweapon"),
|
||||
contactjet: game.i18n.localize("MNBL.meleethrowweapon"),
|
||||
jet: game.i18n.localize("MNBL.throwweapon"),
|
||||
tir: game.i18n.localize("MNBL.shootweapon"),
|
||||
special: game.i18n.localize("MNBL.specialweapon")
|
||||
},
|
||||
allegeanceOptions: {
|
||||
tous: game.i18n.localize("MNBL.all"),
|
||||
chaos: game.i18n.localize("MNBL.chaos"),
|
||||
loi: game.i18n.localize("MNBL.law"),
|
||||
betes: game.i18n.localize("MNBL.beastslords"),
|
||||
elementaires: game.i18n.localize("MNBL.elementslords")
|
||||
}
|
||||
}
|
||||
|
||||
return MOURNBLADE_CONFIG;
|
||||
}
|
||||
|
||||
};
|
||||
@@ -4,14 +4,14 @@ import { MournbladeUtility } from "./mournblade-utility.js";
|
||||
* Extend the basic ItemSheet with some very simple modifications
|
||||
* @extends {ItemSheet}
|
||||
*/
|
||||
export class MournbladeItemSheet extends ItemSheet {
|
||||
export class MournbladeItemSheet extends foundry.appv1.sheets.ItemSheet {
|
||||
|
||||
/** @override */
|
||||
static get defaultOptions() {
|
||||
|
||||
return mergeObject(super.defaultOptions, {
|
||||
return foundry.utils.mergeObject(super.defaultOptions, {
|
||||
classes: ["fvtt-mournblade", "sheet", "item"],
|
||||
template: "systems/fvtt-mournblade/templates/item-sheet.html",
|
||||
template: "systems/fvtt-mournblade/templates/item-sheet.hbs",
|
||||
dragDrop: [{ dragSelector: null, dropSelector: null }],
|
||||
width: 620,
|
||||
height: 550
|
||||
@@ -48,9 +48,8 @@ export class MournbladeItemSheet extends ItemSheet {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async getData() {
|
||||
const objectData = MournbladeUtility.data(this.object);
|
||||
|
||||
let itemData = foundry.utils.deepClone(MournbladeUtility.templateData(this.object));
|
||||
const objectData = foundry.utils.duplicate(this.object)
|
||||
let itemData = objectData
|
||||
let formData = {
|
||||
title: this.title,
|
||||
id: this.id,
|
||||
@@ -60,15 +59,20 @@ export class MournbladeItemSheet extends ItemSheet {
|
||||
editable: this.isEditable,
|
||||
cssClass: this.isEditable ? "editable" : "locked",
|
||||
attributs: MournbladeUtility.getAttributs(),
|
||||
data: itemData,
|
||||
data: itemData.system,
|
||||
limited: this.object.limited,
|
||||
options: this.options,
|
||||
owner: this.document.isOwner,
|
||||
description: await foundry.applications.ux.TextEditor.implementation.enrichHTML(this.object.system.description, {async: true}),
|
||||
config: game.system.mournblade.config,
|
||||
mr: (this.object.type == 'specialisation'),
|
||||
isGM: game.user.isGM
|
||||
}
|
||||
|
||||
this.options.editable = !(this.object.data.origin == "embeddedItem");
|
||||
if ( objectData.type == "don") {
|
||||
formData.sacrifice = await foundry.applications.ux.TextEditor.implementation.enrichHTML(this.object.system.sacrifice, {async: true})
|
||||
}
|
||||
//this.options.editable = !(this.object.origin == "embeddedItem");
|
||||
console.log("ITEM DATA", formData, this);
|
||||
return formData;
|
||||
}
|
||||
@@ -87,7 +91,7 @@ export class MournbladeItemSheet extends ItemSheet {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
postItem() {
|
||||
let chatData = duplicate(MournbladeUtility.data(this.item));
|
||||
let chatData = foundry.utils.duplicate(MournbladeUtility.data(this.item));
|
||||
if (this.actor) {
|
||||
chatData.actor = { id: this.actor.id };
|
||||
}
|
||||
@@ -102,7 +106,7 @@ export class MournbladeItemSheet extends ItemSheet {
|
||||
payload: chatData,
|
||||
});
|
||||
|
||||
renderTemplate('systems/fvtt-Mournblade-rpg/templates/post-item.html', chatData).then(html => {
|
||||
renderTemplate('systems/fvtt-mournblade/templates/post-item.hbs', chatData).then(html => {
|
||||
let chatOptions = MournbladeUtility.chatDataSetup(html);
|
||||
ChatMessage.create(chatOptions)
|
||||
});
|
||||
@@ -119,15 +123,40 @@ export class MournbladeItemSheet extends ItemSheet {
|
||||
|
||||
// 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"));
|
||||
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('.edit-prediction').change(ev => {
|
||||
const li = $(ev.currentTarget).parents(".prediction-item")
|
||||
let index = li.data("prediction-index")
|
||||
let pred = foundry.utils.duplicate(this.object.system.predilections)
|
||||
pred[index].name = ev.currentTarget.value
|
||||
this.object.update( { 'system.predilections': pred })
|
||||
})
|
||||
html.find('.delete-prediction').click(ev => {
|
||||
const li = $(ev.currentTarget).parents(".prediction-item")
|
||||
let index = li.data("prediction-index")
|
||||
let pred = foundry.utils.duplicate(this.object.system.predilections)
|
||||
pred.splice(index,1)
|
||||
this.object.update( { 'system.predilections': pred })
|
||||
})
|
||||
html.find('.use-prediction').change(ev => {
|
||||
const li = $(ev.currentTarget).parents(".prediction-item")
|
||||
let index = li.data("prediction-index")
|
||||
let pred = foundry.utils.duplicate(this.object.system.predilections)
|
||||
pred[index].used = ev.currentTarget.checked
|
||||
this.object.update( { 'system.predilections': pred })
|
||||
})
|
||||
html.find('#add-predilection').click(ev => {
|
||||
let pred = foundry.utils.duplicate(this.object.system.predilections)
|
||||
pred.push( { name: "Nouvelle prédilection", id: randomID(), used: false })
|
||||
this.object.update( { 'system.predilections': pred })
|
||||
})
|
||||
// Update Inventory Item
|
||||
html.find('.item-delete').click(ev => {
|
||||
const li = $(ev.currentTarget).parents(".item");
|
||||
@@ -135,20 +164,12 @@ export class MournbladeItemSheet extends ItemSheet {
|
||||
let itemType = li.data("item-type");
|
||||
});
|
||||
|
||||
html.find('.view-subitem').click(ev => {
|
||||
this.viewSubitem(ev);
|
||||
});
|
||||
|
||||
html.find('.view-spec').click(ev => {
|
||||
this.manageSpec();
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
get template() {
|
||||
let type = this.item.type;
|
||||
return `systems/fvtt-mournblade/templates/item-${type}-sheet.html`;
|
||||
return `systems/fvtt-mournblade/templates/item-${type}-sheet.hbs`;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
@@ -11,8 +11,10 @@ export const defaultItemImg = {
|
||||
predilection: "systems/fvtt-mournblade/assets/icons/predilection.webp",
|
||||
protection: "systems/fvtt-mournblade/assets/icons/protection.webp",
|
||||
rune: "systems/fvtt-mournblade/assets/icons/rune.webp",
|
||||
runeeffect: "systems/fvtt-mournblade/assets/icons/rune.webp",
|
||||
tendance: "systems/fvtt-mournblade/assets/icons/tendance.webp",
|
||||
traitchaotique: "systems/fvtt-mournblade/assets/icons/traitchaotique.webp",
|
||||
traitespece: "systems/fvtt-mournblade/assets/icons/capacite.webp"
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -10,11 +10,19 @@
|
||||
// Import Modules
|
||||
import { MournbladeActor } from "./mournblade-actor.js";
|
||||
import { MournbladeItemSheet } from "./mournblade-item-sheet.js";
|
||||
import { MournbladeActorSheet } from "./mournblade-actor-sheet.js";
|
||||
//import { MournbladeNPCSheet } from "./mournblade-npc-sheet.js";
|
||||
// import { MournbladeActorSheet } from "./mournblade-actor-sheet.js";
|
||||
// import { MournbladeCreatureSheet } from "./mournblade-creature-sheet.js";
|
||||
import { MournbladeUtility } from "./mournblade-utility.js";
|
||||
import { MournbladeCombat } from "./mournblade-combat.js";
|
||||
import { MournbladeItem } from "./mournblade-item.js";
|
||||
import { MournbladeConfig } from "./mournblade-config.js";
|
||||
|
||||
// Import DataModels
|
||||
import * as models from "./models/index.mjs";
|
||||
|
||||
// Import AppV2 Item Sheets
|
||||
import * as sheets from "./applications/sheets/_module.mjs";
|
||||
import { MournbladeRollDialog } from "./mournblade-roll-dialog.js";
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/* Foundry VTT Initialization */
|
||||
@@ -29,7 +37,7 @@ Hooks.once("init", async function () {
|
||||
MournbladeUtility.preloadHandlebarsTemplates();
|
||||
|
||||
/* -------------------------------------------- */
|
||||
// Set an initiative formula for the system
|
||||
// Set an initiative formula for the system
|
||||
CONFIG.Combat.initiative = {
|
||||
formula: "1d6",
|
||||
decimals: 1
|
||||
@@ -44,30 +52,91 @@ Hooks.once("init", async function () {
|
||||
// Define custom Entity classes
|
||||
CONFIG.Combat.documentClass = MournbladeCombat
|
||||
CONFIG.Actor.documentClass = MournbladeActor
|
||||
CONFIG.Actor.dataModels = {
|
||||
personnage: models.PersonnageDataModel,
|
||||
creature: models.CreatureDataModel,
|
||||
}
|
||||
|
||||
CONFIG.Item.documentClass = MournbladeItem
|
||||
game.system.mournblade = { }
|
||||
CONFIG.Item.dataModels = {
|
||||
arme: models.ArmeDataModel,
|
||||
bouclier: models.BouclierDataModel,
|
||||
capacite: models.CapaciteDataModel,
|
||||
competence: models.CompetenceDataModel,
|
||||
don: models.DonDataModel,
|
||||
equipement: models.EquipementDataModel,
|
||||
heritage: models.HeritageDataModel,
|
||||
metier: models.MetierDataModel,
|
||||
modifier: models.ModifierDataModel,
|
||||
monnaie: models.MonnaieDataModel,
|
||||
origine: models.OrigineDataModel,
|
||||
pacte: models.PacteDataModel,
|
||||
protection: models.ProtectionDataModel,
|
||||
rune: models.RuneDataModel,
|
||||
runeeffect: models.RuneEffectDataModel,
|
||||
tendance: models.TendanceDataModel,
|
||||
traitchaotique: models.TraitChaotiqueDataModel,
|
||||
traitespece: models.TraitEspeceDataModel
|
||||
}
|
||||
|
||||
game.system.mournblade = {
|
||||
config : MournbladeConfig.getConfig(),
|
||||
models,
|
||||
sheets,
|
||||
MournbladeRollDialog
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
// Register sheet application classes
|
||||
Actors.unregisterSheet("core", ActorSheet);
|
||||
Actors.registerSheet("fvtt-mournblade", MournbladeActorSheet, { types: ["personnage"], makeDefault: true })
|
||||
//Actors.registerSheet("fvtt-mournblade", MournbladeNPCSheet, { types: ["npc"], makeDefault: false });
|
||||
foundry.documents.collections.Actors.unregisterSheet("core", foundry.appv1.sheets.ActorSheet);
|
||||
foundry.documents.collections.Actors.registerSheet("fvtt-mournblade", sheets.MournbladePersonnageSheet, { types: ["personnage"], makeDefault: true });
|
||||
foundry.documents.collections.Actors.registerSheet("fvtt-mournblade", sheets.MournbladeCreatureSheet, { types: ["creature"], makeDefault: true });
|
||||
|
||||
Items.unregisterSheet("core", ItemSheet);
|
||||
Items.registerSheet("fvtt-mournblade", MournbladeItemSheet, { makeDefault: true })
|
||||
foundry.documents.collections.Items.unregisterSheet("core", foundry.appv1.sheets.ItemSheet);
|
||||
foundry.documents.collections.Items.registerSheet("fvtt-mournblade", sheets.MournbladeArmeSheet, { types: ["arme"], makeDefault: true });
|
||||
foundry.documents.collections.Items.registerSheet("fvtt-mournblade", sheets.MournbladeBouclierSheet, { types: ["bouclier"], makeDefault: true });
|
||||
foundry.documents.collections.Items.registerSheet("fvtt-mournblade", sheets.MournbladeCapaciteSheet, { types: ["capacite"], makeDefault: true });
|
||||
foundry.documents.collections.Items.registerSheet("fvtt-mournblade", sheets.MournbladeCompetenceSheet, { types: ["competence"], makeDefault: true });
|
||||
foundry.documents.collections.Items.registerSheet("fvtt-mournblade", sheets.MournbladeDonSheet, { types: ["don"], makeDefault: true });
|
||||
foundry.documents.collections.Items.registerSheet("fvtt-mournblade", sheets.MournbladeEquipementSheet, { types: ["equipement"], makeDefault: true });
|
||||
foundry.documents.collections.Items.registerSheet("fvtt-mournblade", sheets.MournbladeHeritageSheet, { types: ["heritage"], makeDefault: true });
|
||||
foundry.documents.collections.Items.registerSheet("fvtt-mournblade", sheets.MournbladeMetierSheet, { types: ["metier"], makeDefault: true });
|
||||
foundry.documents.collections.Items.registerSheet("fvtt-mournblade", sheets.MournbladeModifierSheet, { types: ["modifier"], makeDefault: true });
|
||||
foundry.documents.collections.Items.registerSheet("fvtt-mournblade", sheets.MournbladeMonnaieSheet, { types: ["monnaie"], makeDefault: true });
|
||||
foundry.documents.collections.Items.registerSheet("fvtt-mournblade", sheets.MournbladeOrigineSheet, { types: ["origine"], makeDefault: true });
|
||||
foundry.documents.collections.Items.registerSheet("fvtt-mournblade", sheets.MournbladePacteSheet, { types: ["pacte"], makeDefault: true });
|
||||
foundry.documents.collections.Items.registerSheet("fvtt-mournblade", sheets.MournbladeProtectionSheet, { types: ["protection"], makeDefault: true });
|
||||
foundry.documents.collections.Items.registerSheet("fvtt-mournblade", sheets.MournbladeRuneSheet, { types: ["rune"], makeDefault: true });
|
||||
foundry.documents.collections.Items.registerSheet("fvtt-mournblade", sheets.MournbladeRuneEffectSheet, { types: ["runeeffect"], makeDefault: true });
|
||||
foundry.documents.collections.Items.registerSheet("fvtt-mournblade", sheets.MournbladeTendanceSheet, { types: ["tendance"], makeDefault: true });
|
||||
foundry.documents.collections.Items.registerSheet("fvtt-mournblade", sheets.MournbladeTraitChaotiqueSheet, { types: ["traitchaotique"], makeDefault: true });
|
||||
foundry.documents.collections.Items.registerSheet("fvtt-mournblade", sheets.MournbladeTraitEspeceSheet, { types: ["traitespece"], makeDefault: true });
|
||||
|
||||
MournbladeUtility.init();
|
||||
|
||||
|
||||
});
|
||||
|
||||
/* -------------------------------------------- */
|
||||
function welcomeMessage() {
|
||||
async function welcomeMessage() {
|
||||
const templateData = {};
|
||||
const html = await renderTemplate("systems/fvtt-mournblade/templates/chat-welcome-message.hbs", templateData);
|
||||
|
||||
ChatMessage.create({
|
||||
user: game.user.id,
|
||||
whisper: [game.user.id],
|
||||
content: `<div id="welcome-message-Mournblade"><span class="rdd-roll-part">
|
||||
<strong>Bienvenue dans les Jeunes Royaumes de Mournblade !</strong>
|
||||
` });
|
||||
content: html
|
||||
});
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async function importDefaultScene() {
|
||||
let exists = game.scenes.find(j => j.name == "Accueil");
|
||||
if (!exists) {
|
||||
const scenes = await MournbladeUtility.loadCompendium("fvtt-mournblade.scenes")
|
||||
let newDocuments = scenes.filter(i => i.name == "Accueil");
|
||||
await game.scenes.documentClass.create(newDocuments);
|
||||
game.scenes.find(i => i.name == "Accueil").activate();
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
@@ -75,6 +144,10 @@ function welcomeMessage() {
|
||||
/* -------------------------------------------- */
|
||||
Hooks.once("ready", function () {
|
||||
|
||||
game.system.mournblade = {
|
||||
config : MournbladeConfig.getConfig(),
|
||||
}
|
||||
|
||||
MournbladeUtility.ready();
|
||||
// User warning
|
||||
if (!game.user.isGM && game.user.character == undefined) {
|
||||
@@ -84,13 +157,22 @@ Hooks.once("ready", function () {
|
||||
user: game.user._id
|
||||
});
|
||||
}
|
||||
|
||||
// CSS patch for v9
|
||||
if (game.version) {
|
||||
let sidebar = document.getElementById("sidebar");
|
||||
sidebar.style.width = "min-content";
|
||||
if (!game.user.isGM && game.user.character && !game.user.character.prototypeToken.actorLink) {
|
||||
ui.notifications.info("Le token de du joueur n'est pas connecté à l'acteur !");
|
||||
ChatMessage.create({
|
||||
content: "<b>ATTENTION</b> Le token du joueur " + game.user.name + " n'est pas connecté à l'acteur !",
|
||||
user: game.user._id
|
||||
});
|
||||
}
|
||||
|
||||
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.")
|
||||
)
|
||||
|
||||
importDefaultScene();
|
||||
welcomeMessage();
|
||||
});
|
||||
|
||||
@@ -107,4 +189,3 @@ Hooks.on("chatMessage", (html, content, msg) => {
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
|
||||
@@ -1,73 +1,120 @@
|
||||
import { MournbladeUtility } from "./mournblade-utility.js";
|
||||
|
||||
export class MournbladeRollDialog extends Dialog {
|
||||
export class MournbladeRollDialog extends Application {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async create(actor, rollData ) {
|
||||
|
||||
let options = { classes: ["MournbladeDialog"], width: 620, height: 380, 'z-index': 99999 };
|
||||
let html = await renderTemplate('systems/fvtt-mournblade/templates/roll-dialog-generic.html', rollData);
|
||||
|
||||
return new MournbladeRollDialog(actor, rollData, html, options );
|
||||
return new MournbladeRollDialog(actor, rollData);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
constructor(actor, rollData, html, options, close = undefined) {
|
||||
let conf = {
|
||||
title: "Test de Capacité",
|
||||
content: html,
|
||||
buttons: {
|
||||
rolld10: {
|
||||
icon: '<i class="fas fa-check"></i>',
|
||||
label: "Lancer 1d10",
|
||||
callback: () => { this.roll("1d10") }
|
||||
},
|
||||
rolld20: {
|
||||
icon: '<i class="fas fa-check"></i>',
|
||||
label: "Lancer 1d20",
|
||||
callback: () => { this.roll("1d20") }
|
||||
},
|
||||
cancel: {
|
||||
icon: '<i class="fas fa-times"></i>',
|
||||
label: "Annuler",
|
||||
callback: () => { this.close() }
|
||||
} },
|
||||
close: close
|
||||
constructor(actor, rollData, options = {}) {
|
||||
super(options);
|
||||
this.actor = actor;
|
||||
this.rollData = rollData;
|
||||
}
|
||||
|
||||
static get defaultOptions() {
|
||||
return foundry.utils.mergeObject(super.defaultOptions, {
|
||||
classes: ["fvtt-mournblade", "sheet", "item"],
|
||||
template: "systems/fvtt-mournblade/templates/roll-dialog-generic.hbs",
|
||||
width: 400,
|
||||
height: "auto",
|
||||
title: "Test de Capacité"
|
||||
});
|
||||
}
|
||||
|
||||
getData() {
|
||||
const data = foundry.utils.duplicate(this.rollData);
|
||||
if (!data.config) {
|
||||
data.config = game.system.mournblade.config;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
super(conf, options);
|
||||
|
||||
this.actor = actor
|
||||
this.rollData = rollData
|
||||
_onCancel() {
|
||||
this.close();
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
roll ( dice) {
|
||||
this.rollData.mainDice = dice
|
||||
MournbladeUtility.rollMournblade( this.rollData )
|
||||
_onRoll(dice) {
|
||||
this.rollData.mainDice = dice;
|
||||
MournbladeUtility.rollMournblade(this.rollData);
|
||||
this.close();
|
||||
}
|
||||
|
||||
|
||||
/* -------------------------------------------- */
|
||||
activateListeners(html) {
|
||||
super.activateListeners(html);
|
||||
|
||||
// Roll buttons
|
||||
html.find(".rolld10").click(this._onRoll.bind(this, "1d10"));
|
||||
html.find(".rolld20").click(this._onRoll.bind(this, "1d20"));
|
||||
html.find(".cancel").click(this._onCancel.bind(this));
|
||||
|
||||
var dialog = this;
|
||||
function onLoad() {
|
||||
}
|
||||
$(function () { onLoad(); });
|
||||
|
||||
|
||||
html.find('.apply-modifier').change(async (event) => {
|
||||
let modifierIdx = $(event.currentTarget).data("modifier-idx")
|
||||
let modifier = this.rollData.modifiers[modifierIdx]
|
||||
modifier.system.apply = event.currentTarget.checked
|
||||
})
|
||||
|
||||
html.find('#modificateur').change(async (event) => {
|
||||
this.rollData.modificateur = Number(event.currentTarget.value)
|
||||
})
|
||||
html.find('#typeAttaque').change(async (event) => {
|
||||
this.rollData.typeAttaque = String(event.currentTarget.value)
|
||||
})
|
||||
html.find('#difficulte').change(async (event) => {
|
||||
this.rollData.difficulte = Number(event.currentTarget.value)
|
||||
})
|
||||
html.find('#attrKey').change(async (event) => {
|
||||
this.rollData.attrKey = String(event.currentTarget.value)
|
||||
})
|
||||
})
|
||||
html.find('#runemode').change(async (event) => {
|
||||
this.rollData.runemode = String(event.currentTarget.value)
|
||||
})
|
||||
html.find('#runeame').change(async (event) => {
|
||||
this.rollData.runeame = Number(event.currentTarget.value)
|
||||
})
|
||||
html.find('#isMonte').change(async (event) => {
|
||||
this.rollData.desavantages.isMonte = event.currentTarget.checked
|
||||
})
|
||||
|
||||
html.find('#cibleausol').change(async (event) => {
|
||||
this.rollData.desavantages.cibleausol = event.currentTarget.checked
|
||||
})
|
||||
html.find('#cibledesarmee').change(async (event) => {
|
||||
this.rollData.desavantages.cibledesarmee = event.currentTarget.checked
|
||||
})
|
||||
html.find('#ciblerestreint').change(async (event) => {
|
||||
this.rollData.desavantages.ciblerestreint = event.currentTarget.checked
|
||||
})
|
||||
html.find('#cibleimmobilisée').change(async (event) => {
|
||||
this.rollData.desavantages.cibleimmobilisée = event.currentTarget.checked
|
||||
})
|
||||
html.find('#ciblesurplomb').change(async (event) => {
|
||||
this.rollData.desavantages.ciblesurplomb = event.currentTarget.checked
|
||||
})
|
||||
|
||||
html.find('#doubleD20').change(async (event) => {
|
||||
this.rollData.doubleD20 = event.currentTarget.checked
|
||||
})
|
||||
})
|
||||
html.find('#visee').change(async (event) => {
|
||||
this.rollData.visee = event.currentTarget.checked
|
||||
})
|
||||
html.find('#cibleconsciente').change(async (event) => {
|
||||
this.rollData.cibleconsciente = event.currentTarget.checked
|
||||
})
|
||||
html.find('#ciblecourt').change(async (event) => {
|
||||
this.rollData.ciblecourt = event.currentTarget.checked
|
||||
})
|
||||
html.find('#typeCouvert').change(async (event) => {
|
||||
this.rollData.typeCouvert = String(event.currentTarget.value)
|
||||
})
|
||||
|
||||
}
|
||||
}
|
||||
@@ -8,15 +8,13 @@ export class MournbladeUtility {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async init() {
|
||||
Hooks.on('renderChatLog', (log, html, data) => MournbladeUtility.chatListeners(html))
|
||||
Hooks.on("getChatLogEntryContext", (html, options) => MournbladeUtility.chatRollMenu(html, options))
|
||||
Hooks.on('renderChatMessageHTML', (log, html, data) => MournbladeUtility.chatListeners(html))
|
||||
Hooks.on("getChatMessageContextOptions", (html, options) => MournbladeUtility.chatRollMenu(html, options))
|
||||
Hooks.on('renderChatMessageHTML', (message, html, data) => MournbladeUtility.chatMessageHandler(message, html, data))
|
||||
|
||||
Hooks.on("getCombatTrackerEntryContext", (html, options) => {
|
||||
MournbladeUtility.pushInitiativeOptions(html, options);
|
||||
})
|
||||
Hooks.on("dropCanvasData", (canvas, data) => {
|
||||
MournbladeUtility.dropItemOnToken(canvas, data)
|
||||
});
|
||||
|
||||
this.rollDataStore = {}
|
||||
this.defenderStore = {}
|
||||
@@ -46,19 +44,28 @@ export class MournbladeUtility {
|
||||
})
|
||||
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
static getActorFromRollData(rollData) {
|
||||
let actor = game.actors.get(rollData.actorId)
|
||||
if (rollData.tokenId) {
|
||||
let token = canvas.tokens.placeables.find(t => t.id == rollData.tokenId)
|
||||
if (token) {
|
||||
actor = token.actor
|
||||
}
|
||||
}
|
||||
return actor
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static getModificateurOptions() {
|
||||
let opt = []
|
||||
for (let i = -15; i <= 15; i++) {
|
||||
opt.push(`<option value="${i}">${i}</option>`)
|
||||
}
|
||||
return opt.concat("\n")
|
||||
static sortArrayObjectsByName(myArray) {
|
||||
myArray.sort((a, b) => {
|
||||
return a.name.localeCompare(b.name);
|
||||
})
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static getAttributs() {
|
||||
return { adr: "Adresse", pui: "Puissance", cla: "Clairvoyance", pre: "Présence", tre: "Trempe" }
|
||||
return game.system.mournblade.config.attributs
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
static pushInitiativeOptions(html, options) {
|
||||
@@ -73,6 +80,11 @@ export class MournbladeUtility {
|
||||
static async ready() {
|
||||
const skills = await MournbladeUtility.loadCompendium("fvtt-mournblade.skills")
|
||||
this.skills = skills.map(i => i.toObject())
|
||||
|
||||
game.system.mournblade.config.listeNiveauSkill = MournbladeUtility.createDirectOptionList(0, 10)
|
||||
game.system.mournblade.config.listeNiveauCreature = MournbladeUtility.createDirectOptionList(0, 35)
|
||||
game.system.mournblade.config.modificateurOptions = MournbladeUtility.createArrayOptionList(-15, 15)
|
||||
game.system.mournblade.config.pointsAmeOptions = MournbladeUtility.createDirectOptionList(0, 20)
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
@@ -91,23 +103,72 @@ export class MournbladeUtility {
|
||||
static getOptionsStatusList() {
|
||||
return this.optionsStatusList;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static getPredilection(comp, predIdx) {
|
||||
let pred = foundry.utils.duplicate(comp.system.predilections)
|
||||
return foundry.utils.duplicate(pred[predIdx] || { name: "Error!" })
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async chatMessageHandler(message, html, data) {
|
||||
const chatCard = $(html).find('.action-section')
|
||||
if (chatCard.length > 0) {
|
||||
// If the user is the message author or the actor owner, proceed
|
||||
const actor = game.actors.get(data.message.speaker.actor)
|
||||
// DEBUG : console.log("FOUND 1!!! ", actor, data.message)
|
||||
if (actor?.isOwner || game.user.isGM) {
|
||||
return
|
||||
}
|
||||
chatCard.hide()
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async chatListeners(html) {
|
||||
|
||||
html.on("click", '.view-item-from-chat', event => {
|
||||
game.system.Mournblade.creator.openItemView(event)
|
||||
});
|
||||
$(html).on("click", '.predilection-reroll', async event => {
|
||||
let predIdx = $(event.currentTarget).data("predilection-index")
|
||||
let messageId = MournbladeUtility.findChatMessageId(event.currentTarget)
|
||||
let message = game.messages.get(messageId)
|
||||
let rollData = message.getFlag("world", "mournblade-roll")
|
||||
let actor = MournbladeUtility.getActorFromRollData(rollData)
|
||||
await actor.setPredilectionUsed(rollData.competence._id, predIdx)
|
||||
rollData.competence = foundry.utils.duplicate(actor.getCompetence(rollData.competence._id))
|
||||
rollData.predilectionUsed = MournbladeUtility.getPredilection(rollData.competence, predIdx)
|
||||
await MournbladeUtility.rollMournblade(rollData)
|
||||
})
|
||||
|
||||
$(html).on("click", '.arme-roll-degats', async event => {
|
||||
let messageId = MournbladeUtility.findChatMessageId(event.currentTarget)
|
||||
let message = game.messages.get(messageId)
|
||||
let rollData = message.getFlag("world", "mournblade-roll")
|
||||
MournbladeUtility.rollDegatsFromAttaque(rollData)
|
||||
|
||||
})
|
||||
|
||||
$(html).on("click", '.arme-apply-degats', async event => {
|
||||
let messageId = MournbladeUtility.findChatMessageId(event.currentTarget)
|
||||
let message = game.messages.get(messageId)
|
||||
let rollData = message.getFlag("world", "mournblade-roll")
|
||||
if (game.user.isGM) {
|
||||
MournbladeUtility.applyDegatsFromAttaque(rollData)
|
||||
} else {
|
||||
game.socket.emit("system.fvtt-mournblade", { name: "msg_apply_damage", data: { rolLData: rollData } })
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async preloadHandlebarsTemplates() {
|
||||
|
||||
const templatePaths = [
|
||||
'systems/fvtt-mournblade/templates/editor-notes-gm.html',
|
||||
'systems/fvtt-mournblade/templates/partial-item-description.html',
|
||||
'systems/fvtt-mournblade/templates/partial-list-niveau.html'
|
||||
'systems/fvtt-mournblade/templates/editor-notes-gm.hbs',
|
||||
'systems/fvtt-mournblade/templates/partial-item-description.hbs',
|
||||
'systems/fvtt-mournblade/templates/partial-item-header.hbs',
|
||||
'systems/fvtt-mournblade/templates/partial-item-nav.hbs'
|
||||
]
|
||||
return loadTemplates(templatePaths);
|
||||
return foundry.applications.handlebars.loadTemplates(templatePaths);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
@@ -126,7 +187,7 @@ export class MournbladeUtility {
|
||||
}
|
||||
|
||||
static findChatMessage(current) {
|
||||
return MournbladeUtility.findNodeMatching(current, it => it.classList.contains('chat-message') && it.attributes.getNamedItem('data-message-id'));
|
||||
return MournbladeUtility.findNodeMatching(current, it => it.classList.contains('chat-message') && it.attributes.getNamedItem('data-message-id'))
|
||||
}
|
||||
|
||||
static findNodeMatching(current, predicate) {
|
||||
@@ -139,19 +200,6 @@ export class MournbladeUtility {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static templateData(it) {
|
||||
return MournbladeUtility.data(it)?.data ?? {}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static data(it) {
|
||||
if (it instanceof Actor || it instanceof Item || it instanceof Combatant) {
|
||||
return it.data;
|
||||
}
|
||||
return it;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static createDirectOptionList(min, max) {
|
||||
let options = {};
|
||||
@@ -160,12 +208,10 @@ export class MournbladeUtility {
|
||||
}
|
||||
return options;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static buildListOptions(min, max) {
|
||||
let options = ""
|
||||
static createArrayOptionList(min, max) {
|
||||
let options = [];
|
||||
for (let i = min; i <= max; i++) {
|
||||
options += `<option value="${i}">${i}</option>`
|
||||
options.push({ key: `${i}`, label: `${i}` });
|
||||
}
|
||||
return options;
|
||||
}
|
||||
@@ -180,27 +226,6 @@ export class MournbladeUtility {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static getDefenseState(actorId) {
|
||||
return this.defenderStore[actorId];
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static updateRollData(rollData) {
|
||||
|
||||
let id = rollData.rollId;
|
||||
let oldRollData = this.rollDataStore[id] || {};
|
||||
let newRollData = mergeObject(oldRollData, rollData);
|
||||
this.rollDataStore[id] = newRollData;
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
static saveRollData(rollData) {
|
||||
game.socket.emit("system.fvtt-mournblade", {
|
||||
name: "msg_update_roll", data: rollData
|
||||
}); // Notify all other clients of the roll
|
||||
this.updateRollData(rollData);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static getRollData(id) {
|
||||
return this.rollDataStore[id];
|
||||
@@ -208,12 +233,10 @@ export class MournbladeUtility {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
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);
|
||||
}
|
||||
if (msg.name == "msg_update_roll") {
|
||||
this.updateRollData(msg.data);
|
||||
if (msg.name == "msg_apply_damage") {
|
||||
if (game.user.isGM) {
|
||||
this.applyDegatsFromAttaque(msg.data.rollData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -277,77 +300,293 @@ export class MournbladeUtility {
|
||||
}
|
||||
}
|
||||
}
|
||||
this.computeQualityResult(rollData)
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static computeQualityResult(rollData) {
|
||||
//console.log("Result : ", rollData)
|
||||
if (rollData.difficulte > 0 && !rollData.isDramatique) {
|
||||
rollData.isSuccess = (rollData.roll.finalResult >= rollData.difficulte)
|
||||
rollData.isHeroique = ((rollData.roll.finalResult - rollData.difficulte) >= 10)
|
||||
rollData.isDramatique = ((rollData.roll.finalResult - rollData.difficulte) <= -10)
|
||||
rollData.isSuccess = (rollData.finalResult >= rollData.difficulte)
|
||||
rollData.isHeroique = ((rollData.finalResult - rollData.difficulte) >= 10)
|
||||
rollData.isDramatique = ((rollData.finalResult - rollData.difficulte) <= -10)
|
||||
rollData.isPureSuccess = (rollData.isSuccess && !rollData.isHeroique)
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async rollMournblade(rollData) {
|
||||
|
||||
let actor = game.actors.get(rollData.actorId)
|
||||
let actor = MournbladeUtility.getActorFromRollData(rollData)
|
||||
if (rollData.attrKey == "tochoose") { // No attr selected, force address
|
||||
rollData.attrKey = "adr"
|
||||
}
|
||||
if ( !rollData.attr) {
|
||||
console.log("ATTR!!!", rollData.attrKey)
|
||||
rollData.actionImg = "systems/fvtt-mournblade/assets/icons/" + actor.data.data.attributs[rollData.attrKey].labelnorm + ".webp"
|
||||
rollData.attr = duplicate(actor.data.data.attributs[rollData.attrKey])
|
||||
if (!rollData.attr) {
|
||||
rollData.actionImg = "systems/fvtt-mournblade/assets/icons/" + actor.system.attributs[rollData.attrKey].labelnorm + ".webp"
|
||||
rollData.attr = foundry.utils.duplicate(actor.system.attributs[rollData.attrKey])
|
||||
}
|
||||
|
||||
rollData.diceFormula = rollData.mainDice
|
||||
if ( rollData.doubleD20) { // Multiply result !
|
||||
if (rollData.doubleD20) { // Multiply result !
|
||||
rollData.diceFormula += "*2"
|
||||
if (!rollData.isReroll) {
|
||||
actor.changeEclat(-1)
|
||||
}
|
||||
}
|
||||
//console.log("BEFORE COMP", rollData)
|
||||
if (rollData.competence) {
|
||||
let compmod = (rollData.competence.data.niveau == 0) ? -3 : 0
|
||||
rollData.diceFormula += `+${rollData.attr.value}+${rollData.competence.data.niveau}+${rollData.modificateur}+${compmod}`
|
||||
rollData.predilections = foundry.utils.duplicate(rollData.competence.system.predilections)
|
||||
let compmod = (rollData.competence.system.niveau == 0) ? -3 : 0
|
||||
rollData.diceFormula += `+${rollData.attr.value}+${rollData.competence.system.niveau}+${rollData.modificateur}+${compmod}`
|
||||
} else {
|
||||
rollData.diceFormula += `+${rollData.attr.value}*2+${rollData.modificateur}`
|
||||
}
|
||||
rollData.diceFormula += `+${rollData.malusSante}+${rollData.malusAme}`
|
||||
|
||||
let myRoll = new Roll(rollData.diceFormula).roll({ async: false })
|
||||
await this.showDiceSoNice(myRoll, game.settings.get("core", "rollMode"));
|
||||
rollData.roll = myRoll
|
||||
if (rollData.arme?.type == "arme") {
|
||||
rollData.diceFormula += `+${rollData.arme.system.bonusmaniementoff}`
|
||||
}
|
||||
|
||||
// Apply modifiers
|
||||
for (let modifier of rollData.modifiers) {
|
||||
if (modifier.system.modifiertype == "roll" && modifier.system.apply) {
|
||||
rollData.diceFormula += `+${modifier.system.value}`
|
||||
}
|
||||
}
|
||||
// Apply desavantages
|
||||
let desavantagesBonus = 0
|
||||
for (let desavantage in rollData.desavantages) {
|
||||
if (rollData.desavantages[desavantage]) {
|
||||
desavantagesBonus += 5
|
||||
}
|
||||
}
|
||||
desavantagesBonus = Math.min(15, desavantagesBonus)
|
||||
rollData.diceFormula += `+${desavantagesBonus}`
|
||||
|
||||
// Monté ?
|
||||
if (rollData.isMonte) {
|
||||
rollData.diceFormula += "+5"
|
||||
}
|
||||
|
||||
// Specific modifier for distance
|
||||
if (rollData.arme?.system?.isDistance) {
|
||||
if (rollData.visee) {
|
||||
rollData.diceFormula += "+5"
|
||||
}
|
||||
if (rollData.cibleconsciente && rollData.defender) {
|
||||
rollData.diceFormula += `-${rollData.defender.system.attributs.adr.value}`
|
||||
}
|
||||
if (rollData.ciblecourt) {
|
||||
if (rollData.difficulte <= 15) { // Portée courte ou moins
|
||||
rollData.diceFormula += `-5`
|
||||
} else {
|
||||
rollData.diceFormula += `-10`
|
||||
}
|
||||
}
|
||||
if (rollData.typeCouvert && rollData.typeCouvert != "aucun" && rollData.config.couverts[rollData.typeCouvert]) {
|
||||
rollData.diceFormula += `+${rollData.config.couverts[rollData.typeCouvert].value}`
|
||||
}
|
||||
}
|
||||
|
||||
if (rollData.rune) {
|
||||
rollData.runeduree = Math.ceil((rollData.runeame + 3) / 3)
|
||||
if (rollData.runemode == "inscrire") {
|
||||
rollData.runeduree *= 2
|
||||
}
|
||||
if (rollData.runemode == "prononcer") {
|
||||
rollData.runeduree = 1
|
||||
}
|
||||
}
|
||||
|
||||
let myRoll = await new Roll(rollData.diceFormula).evaluate();
|
||||
await this.showDiceSoNice(myRoll, game.settings.get("core", "rollMode"))
|
||||
rollData.roll = foundry.utils.duplicate(myRoll)
|
||||
rollData.diceResult = myRoll.terms[0].results[0].result
|
||||
console.log(">>>> ", myRoll)
|
||||
|
||||
rollData.finalResult = myRoll.total
|
||||
this.computeResult( rollData)
|
||||
this.computeResult(rollData)
|
||||
|
||||
// Application immédiate selon type de jet
|
||||
if (rollData.rune) {
|
||||
let subAme = rollData.runeame
|
||||
if (rollData.isEchec && !rollData.isDramatique) {
|
||||
subAme = Math.ceil((subAme + 1) / 2)
|
||||
}
|
||||
actor.subPointsAme(rollData.runemode, subAme)
|
||||
}
|
||||
if (rollData.typeAttaque == "assomer" && rollData.defenderTokenId && rollData.isPureSuccess) {
|
||||
let defender = game.canvas.tokens.get(rollData?.defenderTokenId)?.actor
|
||||
defender.setModifier("Assomer : Prochaine action", "roll", -5)
|
||||
}
|
||||
if (rollData.typeAttaque == "fuir" && rollData.difficulte > 0 && !rollData.isSuccess) {
|
||||
actor.setModifier("Fuite échouée : -5 en défense ce round et suivant", "defense", -5)
|
||||
}
|
||||
if (rollData.typeAttaque == "immobiliser" && rollData.difficulte > 0 && rollData.isPureSuccess) {
|
||||
actor.setModifier("Immobilisation en cours : -5 pour prochaine action", "roll", -5)
|
||||
}
|
||||
if (rollData.typeAttaque == "chargecavalerie") {
|
||||
actor.setModifier("Charge de Cavalerie : -5 défense pour le tour", "defense", -5)
|
||||
}
|
||||
this.createChatWithRollMode(rollData.alias, {
|
||||
content: await renderTemplate(`systems/fvtt-mournblade/templates/chat-generic-result.html`, rollData)
|
||||
content: await foundry.applications.handlebars.renderTemplate(`systems/fvtt-mournblade/templates/chat-generic-result-v2.hbs`, rollData)
|
||||
}, rollData)
|
||||
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async bonusRollMournblade(rollData) {
|
||||
rollData.bonusFormula = rollData.addedBonus
|
||||
|
||||
let bonusRoll = new Roll(rollData.bonusFormula).roll({async: false})
|
||||
await this.showDiceSoNice(bonusRoll, game.settings.get("core", "rollMode"));
|
||||
rollData.bonusRoll = bonusRoll
|
||||
|
||||
rollData.finalResult += rollData.bonusRoll.total
|
||||
static async rollDegatsFromAttaque(rollData) {
|
||||
let maximize = false
|
||||
let degatsMessage = "Degats normaux"
|
||||
|
||||
this.computeResult( rollData)
|
||||
if (rollData.arme?.system?.isMelee) {
|
||||
rollData.degatsFormula = rollData.arme.system.totalDegats
|
||||
if (rollData.isHeroique) { // Deux fois les dés de dégats
|
||||
degatsMessage = "Dégats doublés"
|
||||
}
|
||||
|
||||
if (rollData.typeAttaque == "assomer") {
|
||||
rollData.degatsFormula = false
|
||||
}
|
||||
|
||||
if (rollData.typeAttaque == "charger") {
|
||||
rollData.degatsFormula += "+2"
|
||||
}
|
||||
if (rollData.typeAttaque == "chargecavalerie") {
|
||||
rollData.degatsFormula += "+5"
|
||||
}
|
||||
|
||||
if (rollData.typeAttaque == "precise") {
|
||||
degatsMessage = "Degats normaux"
|
||||
if (rollData.isHeroique) { // Degats max
|
||||
maximize = true
|
||||
degatsMessage = "Dégats maximaux, ignore l'armure du défenseur";
|
||||
rollData.ignoreDefenseArmor = true
|
||||
}
|
||||
}
|
||||
if (rollData.typeAttaque == "feinte") {
|
||||
degatsMessage = "Pas de dégats, mais bonus pour prochaine attaque"
|
||||
rollData.degatsFormula = false
|
||||
rollData.nextBonus = 5
|
||||
if (rollData.isHeroique) { // Bonus pour prochaine action
|
||||
rollData.nextBonus = 10
|
||||
rollData.nextBonusDegats = 10
|
||||
}
|
||||
}
|
||||
if (rollData.typeAttaque == "coupbas") {
|
||||
degatsMessage = "Pas de dégats, mais malus pour prochaine action complexe du défenseur"
|
||||
rollData.degatsFormula = false
|
||||
rollData.nextMalus = 5
|
||||
if (rollData.isHeroique) { // Malus pour prochaine action
|
||||
rollData.nextMalus = 15
|
||||
}
|
||||
}
|
||||
if (rollData.typeAttaque == "contenir") {
|
||||
degatsMessage = "Pas de dégats, mais l'adversaire ne peut pas vous attaquer pour le reste du tour"
|
||||
rollData.degatsFormula = false
|
||||
if (rollData.isHeroique) { // Malus pour prochaine action
|
||||
degatsMessage = "Pas de dégats, mais tout les adversaires avec une défense inférieure ou égale à " + rollData.finalResult - 10 +
|
||||
" ne peuvent pas vous attaquer pour le reste du tour"
|
||||
}
|
||||
}
|
||||
if (rollData.typeAttaque == "desarmer") {
|
||||
degatsMessage = "Pas de dégats, mais l'adversaire reçoit un malus de -5 pour sa prochaine action"
|
||||
rollData.degatsFormula = false
|
||||
if (rollData.isHeroique) { // Malus pour prochaine action
|
||||
rollData.defenderDesarme = true
|
||||
degatsMessage = "Pas de dégats, mais l'arme de votre adversaire est arrachée de ses mains"
|
||||
}
|
||||
}
|
||||
} else { // Armes à distance
|
||||
rollData.degatsFormula = rollData.arme.system.totalDegats
|
||||
}
|
||||
|
||||
// Perform the roll, show the dice
|
||||
rollData.finalResult = 0
|
||||
rollData.degatsMessage = degatsMessage
|
||||
if (rollData.degatsFormula) {
|
||||
console.log("Degats formula", rollData.degatsFormula)
|
||||
// Twice!maximize
|
||||
if (rollData.isHeroique && !maximize) {
|
||||
rollData.degatsFormula += "+" + rollData.degatsFormula
|
||||
}
|
||||
// Latest modifiers
|
||||
for (let mod of rollData.modifiers) {
|
||||
if (mod.system.modifiertype == "degats") {
|
||||
rollData.degatsFormula += `+${mod.system.value}`
|
||||
}
|
||||
}
|
||||
let degatsRoll = await new Roll(rollData.degatsFormula).evaluate({ maximize: maximize })
|
||||
await this.showDiceSoNice(degatsRoll, game.settings.get("core", "rollMode"))
|
||||
rollData.degatsRoll = foundry.utils.duplicate(degatsRoll)
|
||||
rollData.finalResult = degatsRoll.total
|
||||
}
|
||||
|
||||
this.createChatWithRollMode(rollData.alias, {
|
||||
content: await renderTemplate(`systems/fvtt-mournblade/templates/chat-generic-result.html`, rollData)
|
||||
content: await foundry.applications.handlebars.renderTemplate(`systems/fvtt-mournblade/templates/chat-degats-result-v2.hbs`, rollData)
|
||||
}, rollData)
|
||||
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static applyDegatsFromAttaque(rollData) {
|
||||
let defender = game.canvas.tokens.get(rollData?.defenderTokenId)?.actor
|
||||
if (defender && rollData.arme) {
|
||||
let actor = MournbladeUtility.getActorFromRollData(rollData)
|
||||
if (rollData.typeAttaque == "desarmer" && !rollData.isHeroique) {
|
||||
defender.setModifier("Malus suite à désarmement", "roll", -5)
|
||||
}
|
||||
if (rollData.typeAttaque == "charger") {
|
||||
actor.setModifier("Défense suite à charge", "roll", -5)
|
||||
}
|
||||
if (rollData.nextBonus) {
|
||||
actor.setModifier("Prochaine attaque", "roll", rollData.nextBonus)
|
||||
if (rollData.nextDegatsBonus) {
|
||||
actor.setModifier("Prochaine attaque", "degats", rollData.nextDegatsBonus)
|
||||
}
|
||||
}
|
||||
if (rollData.nextMalus) {
|
||||
defender.setModifier("Prochaine action complexe", "roll", -rollData.nextMalus)
|
||||
}
|
||||
if (rollData.defenderDesarme) {
|
||||
ui.notifications.info("L'arme de " + defender.name + " est arrachée de ses mains (à gérer manuellement)")
|
||||
}
|
||||
let degats = rollData.finalResult
|
||||
|
||||
let type = (rollData.arme.system.nonletaux) ? "nonletaux" : "letaux"
|
||||
if (rollData.arme.system.ignorearmure) {
|
||||
rollData.ignoreDefenseArmor = true
|
||||
}
|
||||
defender.incDecSante(type, +degats, rollData.ignoreDefenseArmor)
|
||||
ui.notifications.info(defender.name + "a subi " + degats + " points de santé " + type + ".")
|
||||
} else {
|
||||
ui.notifications.warn("Pas de cible sélectionnée ou pas d'arme de défense équipée.")
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async bonusRollMournblade(rollData) {
|
||||
rollData.bonusFormula = rollData.addedBonus
|
||||
|
||||
let bonusRoll = await new Roll(rollData.bonusFormula).evaluate()
|
||||
await this.showDiceSoNice(bonusRoll, game.settings.get("core", "rollMode"));
|
||||
rollData.bonusRoll = foundry.utils.duplicate(bonusRoll)
|
||||
|
||||
rollData.finalResult += rollData.bonusRoll.total
|
||||
|
||||
this.computeQualityResult(rollData)
|
||||
|
||||
this.createChatWithRollMode(rollData.alias, {
|
||||
content: await foundry.applications.handlebars.renderTemplate(`systems/fvtt-mournblade/templates/chat-generic-result-v2.hbs`, rollData)
|
||||
}, rollData)
|
||||
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static getUsers(filter) {
|
||||
return game.users.filter(filter).map(user => user.data._id);
|
||||
return game.users.filter(filter).map(user => user._id);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static getWhisperRecipients(rollMode, name) {
|
||||
switch (rollMode) {
|
||||
@@ -365,7 +604,7 @@ export class MournbladeUtility {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
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);
|
||||
@@ -418,7 +657,8 @@ export class MournbladeUtility {
|
||||
chatOptions.whisper = this.getWhisperRecipients(rollMode, name);
|
||||
break;
|
||||
}
|
||||
chatOptions.alias = chatOptions.alias || name
|
||||
chatOptions.alias = chatOptions.alias || name;
|
||||
chatOptions.speaker = ChatMessage.getSpeaker();
|
||||
let msg = await ChatMessage.create(chatOptions)
|
||||
console.log("=======>", rollData)
|
||||
msg.setFlag("world", "mournblade-roll", rollData)
|
||||
@@ -427,11 +667,11 @@ export class MournbladeUtility {
|
||||
/* -------------------------------------------- */
|
||||
static getBasicRollData() {
|
||||
let rollData = {
|
||||
rollId: randomID(16),
|
||||
rollId: foundry.utils.randomID(16),
|
||||
rollMode: game.settings.get("core", "rollMode"),
|
||||
modificateursOptions: this.getModificateurOptions(),
|
||||
difficulte: 0,
|
||||
modificateur: 0,
|
||||
config: foundry.utils.duplicate(game.system.mournblade.config),
|
||||
}
|
||||
MournbladeUtility.updateWithTarget(rollData)
|
||||
return rollData
|
||||
@@ -439,15 +679,19 @@ export class MournbladeUtility {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static updateWithTarget(rollData) {
|
||||
let objectDefender
|
||||
let target = MournbladeUtility.getTarget();
|
||||
let target = MournbladeUtility.getTarget()
|
||||
if (target) {
|
||||
let defenderActor = game.actors.get(target.data.actorId)
|
||||
objectDefender = MournbladeUtility.data(defenderActor)
|
||||
objectDefender = mergeObject(objectDefender, target.data.actorData)
|
||||
rollData.defender = objectDefender
|
||||
rollData.attackerId = this.id
|
||||
rollData.defenderId = objectDefender._id
|
||||
rollData.defenderTokenId = target.id
|
||||
let defender = game.canvas.tokens.get(rollData.defenderTokenId).actor
|
||||
rollData.defenderCombatValues = defender.getCombatValues()
|
||||
rollData.defender = defender.toObject() // Simpler
|
||||
rollData.defenderDefense = defender.getBestDefenseValue()
|
||||
rollData.armeDefense = defender.getBestDefenseValue()
|
||||
if (rollData.armeDefense) {
|
||||
rollData.difficulte = rollData.armeDefense.system.totalDefensif
|
||||
} else {
|
||||
ui.notifications.warn("Aucune arme de défense équipée, difficulté manuelle à positionner.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -458,72 +702,90 @@ export class MournbladeUtility {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static applyBonneAventureRoll(li, changed, addedBonus) {
|
||||
let msgId = li.data("message-id")
|
||||
let msgId = $(li).data("message-id")
|
||||
let msg = game.messages.get(msgId)
|
||||
if (msg) {
|
||||
let rollData = msg.getFlag("world", "mournblade-roll")
|
||||
let actor = game.actors.get(rollData.actorId)
|
||||
actor.changeBonneAventure( changed )
|
||||
rollData.isReroll = true
|
||||
let actor = MournbladeUtility.getActorFromRollData(rollData)
|
||||
actor.changeBonneAventure(changed)
|
||||
rollData.isReroll = true
|
||||
rollData.textBonus = "Bonus de Points d'Aventure"
|
||||
if (addedBonus == "reroll") {
|
||||
MournbladeUtility.rollMournblade(rollData)
|
||||
} else {
|
||||
MournbladeUtility.rollMournblade(rollData)
|
||||
} else {
|
||||
rollData.addedBonus = addedBonus
|
||||
MournbladeUtility.bonusRollMournblade(rollData)
|
||||
MournbladeUtility.bonusRollMournblade(rollData)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static applyEclatRoll(li, changed, addedBonus) {
|
||||
let msgId = li.data("message-id")
|
||||
let msg = game.messages.get(msgId)
|
||||
if (msg) {
|
||||
let rollData = msg.getFlag("world", "mournblade-roll")
|
||||
let actor = game.actors.get(rollData.actorId)
|
||||
actor.changeEclat( changed )
|
||||
rollData.isReroll = true
|
||||
rollData.textBonus = "Bonus d'Eclat"
|
||||
rollData.addedBonus = addedBonus
|
||||
MournbladeUtility.bonusRollMournblade(rollData)
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
static applyEclatRoll(li, changed, addedBonus) {
|
||||
let msgId = $(li).data("message-id")
|
||||
let msg = game.messages.get(msgId)
|
||||
if (msg) {
|
||||
let rollData = msg.getFlag("world", "mournblade-roll")
|
||||
let actor = MournbladeUtility.getActorFromRollData(rollData)
|
||||
actor.changeEclat(changed)
|
||||
rollData.isReroll = true
|
||||
rollData.textBonus = "Bonus d'Eclat"
|
||||
rollData.addedBonus = addedBonus
|
||||
MournbladeUtility.bonusRollMournblade(rollData)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static chatRollMenu(html, options) {
|
||||
let canApply = li => canvas.tokens.controlled.length && li.find(".mournblade-roll").length
|
||||
let canApplyBALoyal = 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", "mournblade-roll")
|
||||
let actor = game.actors.get(rollData.actorId)
|
||||
return ( !rollData.isReroll && actor.getBonneAventure() > 0 && actor.getAlignement() == "loyal")
|
||||
let actor = MournbladeUtility.getActorFromRollData(rollData)
|
||||
return (!rollData.isReroll && actor.getBonneAventure() > 0 && actor.getAlignement() == "loyal")
|
||||
}
|
||||
let canApplyPELoyal = 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", "mournblade-roll")
|
||||
let actor = game.actors.get(rollData.actorId)
|
||||
return ( !rollData.isReroll && actor.getEclat() > 0 && actor.getAlignement() == "loyal")
|
||||
let actor = MournbladeUtility.getActorFromRollData(rollData)
|
||||
return (!rollData.isReroll && actor.getEclat() > 0 && actor.getAlignement() == "loyal")
|
||||
}
|
||||
let canApplyBAChaotique = 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", "mournblade-roll")
|
||||
let actor = game.actors.get(rollData.actorId)
|
||||
return ( !rollData.isReroll && actor.getBonneAventure() > 0 && actor.getAlignement() == "chaotique")
|
||||
let actor = MournbladeUtility.getActorFromRollData(rollData)
|
||||
return (!rollData.isReroll && actor.getBonneAventure() > 0 && actor.getAlignement() == "chaotique")
|
||||
}
|
||||
let canApplyBAChaotique3 = 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", "mournblade-roll")
|
||||
let actor = game.actors.get(rollData.actorId)
|
||||
return ( !rollData.isReroll && actor.getBonneAventure() > 2 && actor.getAlignement() == "chaotique")
|
||||
let actor = MournbladeUtility.getActorFromRollData(rollData)
|
||||
return (!rollData.isReroll && actor.getBonneAventure() > 2 && actor.getAlignement() == "chaotique")
|
||||
}
|
||||
let canApplyPEChaotique = 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", "mournblade-roll")
|
||||
let actor = game.actors.get(rollData.actorId)
|
||||
return ( !rollData.isReroll && actor.getEclat() > 0 && actor.getAlignement() == "chaotique")
|
||||
let actor = MournbladeUtility.getActorFromRollData(rollData)
|
||||
return (!rollData.isReroll && actor.getEclat() > 0 && actor.getAlignement() == "chaotique")
|
||||
}
|
||||
let hasPredilection = function (li) {
|
||||
let message = game.messages.get($(li).attr("data-message-id"))
|
||||
let rollData = message.getFlag("world", "mournblade-roll")
|
||||
let actor = MournbladeUtility.getActorFromRollData(rollData)
|
||||
if (rollData.competence) {
|
||||
let nbPred = rollData.competence.system.predilections.filter(pred => !pred.used).length
|
||||
return (!rollData.isReroll && rollData.competence && nbPred > 0)
|
||||
}
|
||||
return false
|
||||
}
|
||||
let canCompetenceDouble = function (li) {
|
||||
let message = game.messages.get($(li).attr("data-message-id"))
|
||||
let rollData = message.getFlag("world", "mournblade-roll")
|
||||
let actor = MournbladeUtility.getActorFromRollData(rollData)
|
||||
if (rollData.competence) {
|
||||
return rollData.competence.system.doublebonus
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
options.push(
|
||||
{
|
||||
name: "Ajouer +3 (1 point de Bonne Aventure)",
|
||||
@@ -532,6 +794,14 @@ export class MournbladeUtility {
|
||||
callback: li => MournbladeUtility.applyBonneAventureRoll(li, -1, "+3")
|
||||
}
|
||||
)
|
||||
options.push(
|
||||
{
|
||||
name: "Ajouer +6 (1 point de Bonne Aventure)",
|
||||
icon: "<i class='fas fa-user-plus'></i>",
|
||||
condition: canApply && canApplyBALoyal && canCompetenceDouble,
|
||||
callback: li => MournbladeUtility.applyBonneAventureRoll(li, -1, "+6")
|
||||
}
|
||||
)
|
||||
options.push(
|
||||
{
|
||||
name: "Ajouer +1d6 (1 point de Bonne Aventure)",
|
||||
@@ -540,6 +810,14 @@ export class MournbladeUtility {
|
||||
callback: li => MournbladeUtility.applyBonneAventureRoll(li, -1, "+1d6")
|
||||
}
|
||||
)
|
||||
options.push(
|
||||
{
|
||||
name: "Ajouer +2d6 (1 point de Bonne Aventure)",
|
||||
icon: "<i class='fas fa-user-plus'></i>",
|
||||
condition: canApply && canApplyBAChaotique && canCompetenceDouble,
|
||||
callback: li => MournbladeUtility.applyBonneAventureRoll(li, -1, "+2d6")
|
||||
}
|
||||
)
|
||||
options.push(
|
||||
{
|
||||
name: "Relancer le dé (3 points de Bonne Aventure)",
|
||||
@@ -558,10 +836,10 @@ export class MournbladeUtility {
|
||||
)
|
||||
options.push(
|
||||
{
|
||||
name: "Ajouter +1d20(1 Point d'Eclat)",
|
||||
name: "Ajouter +20 (1 Point d'Eclat)",
|
||||
icon: "<i class='fas fa-user-plus'></i>",
|
||||
condition: canApply && canApplyPEChaotique,
|
||||
callback: li => MournbladeUtility.applyEclatRoll(li, -1, "+1d20")
|
||||
condition: canApply && canApplyPELoyal && canCompetenceDouble,
|
||||
callback: li => MournbladeUtility.applyEclatRoll(li, -1, "+20")
|
||||
}
|
||||
)
|
||||
return options
|
||||
@@ -569,25 +847,25 @@ export class MournbladeUtility {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async confirmDelete(actorSheet, li) {
|
||||
let itemId = li.data("item-id");
|
||||
let msgTxt = "<p>Are you sure to remove this Item ?";
|
||||
let itemId = li.dataset?.itemId || li.data("item-id");
|
||||
let msgTxt = "<p>Voulez vous 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));
|
||||
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"
|
||||
|
||||
4968
package-lock.json
generated
Normal file
16
package.json
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"name": "fvtt-mournblade",
|
||||
"version": "1.0.0",
|
||||
"description": "Mournblade 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"
|
||||
}
|
||||
}
|
||||
@@ -1,42 +1,46 @@
|
||||
{"name":"Fouet","type":"arme","img":"systems/fvtt-mournblade/assets/icons/arme.webp","data":{"description":"","typearme":"contactjet","bonusmaniementoff":0,"bonusmaniementdef":0,"degats":"1d4 + 1","deuxmains":false,"courte":3,"moyenne":0,"longue":0,"tr":0,"rarete":4,"prix":40},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"RiMAsQHaUMojde7N":3},"flags":{"core":{"sourceId":"Item.Qb1h25U88mTM4h72"}},"_id":"0swiE8k5zfUIqmXu"}
|
||||
{"name":"Hache des mers","type":"arme","img":"systems/fvtt-mournblade/assets/icons/arme.webp","data":{"description":"","typearme":"contact","bonusmaniementoff":2,"bonusmaniementdef":0,"degats":"2d6","deuxmains":true,"courte":0,"moyenne":0,"longue":0,"tr":0,"rarete":7,"prix":150},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"RiMAsQHaUMojde7N":3},"flags":{"core":{"sourceId":"Item.mGYFgteaWBDo10Xb"}},"_id":"2BSVJXr0FGZZJ9fh"}
|
||||
{"name":"Fléau d’armes","type":"arme","img":"systems/fvtt-mournblade/assets/icons/arme.webp","data":{"description":"","typearme":"contact","bonusmaniementoff":0,"bonusmaniementdef":0,"degats":"1D10+1","deuxmains":false,"courte":0,"moyenne":0,"longue":0,"tr":0,"rarete":7,"prix":70},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"RiMAsQHaUMojde7N":3},"flags":{"core":{"sourceId":"Item.PHQabMgfk1GNOjKo"}},"_id":"2qezkR1BdC0DcRIl"}
|
||||
{"name":"Arbalète","type":"arme","img":"systems/fvtt-mournblade/assets/icons/arme.webp","data":{"description":"","typearme":"tir","bonusmaniementoff":1,"bonusmaniementdef":0,"degats":"2d6","deuxmains":false,"courte":25,"moyenne":50,"longue":75,"tr":3,"rarete":10,"prix":500},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"RiMAsQHaUMojde7N":3},"flags":{"core":{"sourceId":"Item.WYp8ojQN8HYJwUJc"}},"_id":"2zIdrBK88iuMbOF0"}
|
||||
{"name":"Cimeterre","type":"arme","img":"systems/fvtt-mournblade/assets/icons/arme.webp","data":{"description":"","typearme":"contact","bonusmaniementoff":1,"bonusmaniementdef":1,"degats":"1d10","deuxmains":false,"courte":0,"moyenne":0,"longue":0,"tr":0,"rarete":8,"prix":100},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"RiMAsQHaUMojde7N":3},"flags":{"core":{"sourceId":"Item.RYxEg0gJfAlIZ4mw"}},"_id":"3Iv1oLpZcPEJVaI4"}
|
||||
{"name":"Fronde","type":"arme","img":"systems/fvtt-mournblade/assets/icons/arme.webp","data":{"description":"","typearme":"tir","bonusmaniementoff":0,"bonusmaniementdef":0,"degats":"1D4","deuxmains":false,"courte":10,"moyenne":25,"longue":50,"tr":1,"rarete":2,"prix":1},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"RiMAsQHaUMojde7N":3},"flags":{"core":{"sourceId":"Item.TgVuNnytO9k2K0Xe"}},"_id":"4To8rLxv4efsoZK0"}
|
||||
{"name":"Pierre","type":"arme","img":"systems/fvtt-mournblade/assets/icons/arme.webp","data":{"description":"","typearme":"contactjet","bonusmaniementoff":0,"bonusmaniementdef":0,"degats":"1D4","deuxmains":false,"courte":3,"moyenne":6,"longue":15,"tr":1,"rarete":0,"prix":0},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"RiMAsQHaUMojde7N":3},"flags":{"core":{"sourceId":"Item.3YS9IfQddECnoagK"}},"_id":"4yKlK8MeSj5Zk8lM"}
|
||||
{"name":"Grand marteau","type":"arme","img":"systems/fvtt-mournblade/assets/icons/arme.webp","data":{"description":"","typearme":"contact","bonusmaniementoff":1,"bonusmaniementdef":0,"degats":"2D6+2","deuxmains":true,"courte":0,"moyenne":0,"longue":0,"tr":0,"rarete":7,"prix":120},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"RiMAsQHaUMojde7N":3},"flags":{"core":{"sourceId":"Item.vjic4cPkJ0iMCIt5"}},"_id":"6e1JHoD1Jrz020R7"}
|
||||
{"name":"Arc de cavalerie","type":"arme","img":"systems/fvtt-mournblade/assets/icons/arme.webp","data":{"description":"","typearme":"tir","bonusmaniementoff":1,"bonusmaniementdef":0,"degats":"1d6","deuxmains":false,"courte":25,"moyenne":50,"longue":75,"tr":1,"rarete":7,"prix":100},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"RiMAsQHaUMojde7N":3},"flags":{"core":{"sourceId":"Item.5EWrgNQjJMx1t2v1"}},"_id":"88UuW1bdpFuCmkqb"}
|
||||
{"name":"Épée de maître","type":"arme","img":"systems/fvtt-mournblade/assets/icons/arme.webp","data":{"description":"","typearme":"contact","bonusmaniementoff":2,"bonusmaniementdef":1,"degats":"1d8+ 2","deuxmains":false,"courte":0,"moyenne":0,"longue":0,"tr":0,"rarete":7,"prix":120},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"RiMAsQHaUMojde7N":3},"flags":{"core":{"sourceId":"Item.kX3MbDFu9uYZVNf2"}},"_id":"9Eo9mRbPPZHN98Cr"}
|
||||
{"name":"Lance ilmioréenne","type":"arme","img":"systems/fvtt-mournblade/assets/icons/arme.webp","data":{"description":"<p>La lance ilmioréenne est un solide bâton de combat surmonté d’une pointe sur lequel est fi xé quasi perpendiculairement un fer de hache plat et étroit. Un contrepoids fi xé à l’autre extrémité sert à équilibrer l’arme qui peut être maniée à la fois comme une lance et comme une hache à deux mains, ce qui permet de maintenir ses ennemis à distance ou de leur porter des coups dévastateurs. Ces lances furent inventées à l’époque de la tribu d’Ilm, quand les lances et épées étaient déclarées illégales par les gouverneurs melnibonéens de la région. Certaines écoles militaires ilmioréennes enseignent toujours le Style Imar, qui mêle en une seule et même technique le combat à deux mains à la lance et le combat au bâton.</p>","typearme":"contact","bonusmaniementoff":0,"bonusmaniementdef":2,"degats":"1d8 + 2","deuxmains":true,"courte":0,"moyenne":0,"longue":0,"tr":0,"rarete":8,"prix":100},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"RiMAsQHaUMojde7N":3},"flags":{"core":{"sourceId":"Item.8ApbiVgkx79OHVp2"}},"_id":"9xPd4ITtyk3nmMoN"}
|
||||
{"name":"Masse lourde","type":"arme","img":"systems/fvtt-mournblade/assets/icons/arme.webp","data":{"description":"","typearme":"contact","bonusmaniementoff":2,"bonusmaniementdef":0,"degats":"1d10 + 1","deuxmains":true,"courte":0,"moyenne":0,"longue":0,"tr":0,"rarete":5,"prix":80},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"RiMAsQHaUMojde7N":3},"flags":{"core":{"sourceId":"Item.DPfXgFj3gpjJ3nbR"}},"_id":"CeC5lAKs7NdPF05l"}
|
||||
{"name":"Gourdin","type":"arme","img":"systems/fvtt-mournblade/assets/icons/arme.webp","data":{"description":"","typearme":"contact","bonusmaniementoff":2,"bonusmaniementdef":0,"degats":"1D6","deuxmains":false,"courte":0,"moyenne":0,"longue":0,"tr":0,"rarete":0,"prix":5},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"RiMAsQHaUMojde7N":3},"flags":{"core":{"sourceId":"Item.CBIfq9eRd2RmoI4H"}},"_id":"CqP80SQFQOefpGgd"}
|
||||
{"name":"Rapière","type":"arme","img":"systems/fvtt-mournblade/assets/icons/arme.webp","data":{"description":"","typearme":"contact","bonusmaniementoff":3,"bonusmaniementdef":1,"degats":"1d8+ 1","deuxmains":false,"courte":0,"moyenne":0,"longue":0,"tr":0,"rarete":8,"prix":150},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"RiMAsQHaUMojde7N":3},"flags":{"core":{"sourceId":"Item.XIStcClTnmLoSwyR"}},"_id":"CupT9m8L909l4Fo5"}
|
||||
{"name":"Hachette / Hache de lancer","type":"arme","img":"systems/fvtt-mournblade/assets/icons/arme.webp","data":{"description":"","typearme":"contactjet","bonusmaniementoff":2,"bonusmaniementdef":0,"degats":"1d4 + 1","deuxmains":false,"courte":5,"moyenne":10,"longue":15,"tr":1,"rarete":5,"prix":50},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"RiMAsQHaUMojde7N":3},"flags":{"core":{"sourceId":"Item.5NHbRanxXA5vUE3B"}},"_id":"DzkeP7jbruqW4nQH"}
|
||||
{"name":"Lance légère","type":"arme","img":"systems/fvtt-mournblade/assets/icons/arme.webp","data":{"description":"","typearme":"contact","bonusmaniementoff":2,"bonusmaniementdef":0,"degats":"1d8","deuxmains":false,"courte":10,"moyenne":25,"longue":50,"tr":1,"rarete":5,"prix":5},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"RiMAsQHaUMojde7N":3},"flags":{"core":{"sourceId":"Item.LIVeq22E9EanRS9L"}},"_id":"FDeRBkxXwoZIuL9B"}
|
||||
{"name":"Arc de chasse","type":"arme","img":"systems/fvtt-mournblade/assets/icons/arme.webp","data":{"description":"","typearme":"tir","bonusmaniementoff":2,"bonusmaniementdef":0,"degats":"1d6 - 1","deuxmains":false,"courte":25,"moyenne":50,"longue":75,"tr":1,"rarete":8,"prix":250},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"RiMAsQHaUMojde7N":3},"flags":{"core":{"sourceId":"Item.TrYZ9BxYukS1mbBX"}},"_id":"Hrm08cpgAMMV6Jpq"}
|
||||
{"name":"Coup de pied / poing / tête","type":"arme","img":"systems/fvtt-mournblade/assets/icons/arme.webp","data":{"description":"","typearme":"contact","bonusmaniementoff":3,"bonusmaniementdef":0,"degats":"1d4","deuxmains":false,"courte":0,"moyenne":0,"longue":0,"tr":0,"rarete":0,"prix":0},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"RiMAsQHaUMojde7N":3},"flags":{"core":{"sourceId":"Item.nBPKHsYIM0HgMcBy"}},"_id":"Iw3j4oC6H8HJ9MFQ"}
|
||||
{"name":"Lance lourde","type":"arme","img":"systems/fvtt-mournblade/assets/icons/arme.webp","data":{"description":"","typearme":"contact","bonusmaniementoff":1,"bonusmaniementdef":2,"degats":"1d10","deuxmains":true,"courte":0,"moyenne":0,"longue":0,"tr":0,"rarete":5,"prix":50},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"RiMAsQHaUMojde7N":3},"flags":{"core":{"sourceId":"Item.Kcl07bs7TOcne37W"}},"_id":"KY22L6Lx5WxgvyGD"}
|
||||
{"name":"Arc du Désert des Larmes","type":"arme","img":"systems/fvtt-mournblade/assets/icons/arme.webp","data":{"description":"<p>Cet arc composite fait de bois, d’andouillers de cerf et/ou d’os est un arc court et très recourbé utilisé par les barbares du Désert des Larmes pour la chasse. On peut également trouver ce type d’arcs à Pikarayd et au Dorel.</p>","typearme":"tir","bonusmaniementoff":2,"bonusmaniementdef":0,"degats":"1d6 + 1","deuxmains":false,"courte":25,"moyenne":50,"longue":75,"tr":1,"rarete":8,"prix":250},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"RiMAsQHaUMojde7N":3},"flags":{"core":{"sourceId":"Item.QmYjdRCAk3MnxKJg"}},"_id":"MDpFpqmXpIX5VV80"}
|
||||
{"name":"Hache de bataille dite lormyrienne","type":"arme","img":"systems/fvtt-mournblade/assets/icons/arme.webp","data":{"description":"<p>Cette double hache parfaitement équilibrée et proportionnée est l’arme favorite des chevaliers lormyriens. Il s’agit de l’arme idéale pour trancher, découper les lances ennemies et fendre les crânes.</p>","typearme":"contact","bonusmaniementoff":2,"bonusmaniementdef":0,"degats":"2d6 + 2","deuxmains":true,"courte":0,"moyenne":0,"longue":0,"tr":0,"rarete":8,"prix":250},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"RiMAsQHaUMojde7N":3},"flags":{"core":{"sourceId":"Item.Lpa6kesbzgKVtogn"}},"_id":"MP49mYF7FVuW9ALB"}
|
||||
{"name":"Couteau / Dague","type":"arme","img":"systems/fvtt-mournblade/assets/icons/arme.webp","data":{"description":"","typearme":"contactjet","bonusmaniementoff":3,"bonusmaniementdef":0,"degats":"1d4","deuxmains":false,"courte":3,"moyenne":6,"longue":15,"tr":1,"rarete":1,"prix":10},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"RiMAsQHaUMojde7N":3},"flags":{"core":{"sourceId":"Item.5a9GKIvNgbbXBq3s"}},"_id":"N5BbO2lGwzQnpvH0"}
|
||||
{"name":"Pique filkharienne","type":"arme","img":"systems/fvtt-mournblade/assets/icons/arme.webp","data":{"description":"<p>Cette longue pique à grande lame de près de trois mètres de long est l’arme de prédilection des piquiers de l’armée de Filkhar. Très effi cace pour lutter contre des cavaliers ou des ennemis en train de charger, elle l’est beaucoup moins en combat rapproché.</p>","typearme":"contact","bonusmaniementoff":2,"bonusmaniementdef":0,"degats":"1d8 + 2","deuxmains":true,"courte":0,"moyenne":0,"longue":0,"tr":0,"rarete":8,"prix":150},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"RiMAsQHaUMojde7N":3},"flags":{"core":{"sourceId":"Item.dF9LxfA1crZBmT92"}},"_id":"QwrZbFeJUQv2OBqI"}
|
||||
{"name":"Masse légère","type":"arme","img":"systems/fvtt-mournblade/assets/icons/arme.webp","data":{"description":"","typearme":"contact","bonusmaniementoff":2,"bonusmaniementdef":0,"degats":"1d6 + 2","deuxmains":false,"courte":0,"moyenne":0,"longue":0,"tr":0,"rarete":5,"prix":5},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"RiMAsQHaUMojde7N":3},"flags":{"core":{"sourceId":"Item.xrWRNZBrEzkUQzRG"}},"_id":"SzgkzHvzma8NiMd5"}
|
||||
{"name":"Sabre d’abordage","type":"arme","img":"systems/fvtt-mournblade/assets/icons/arme.webp","data":{"description":"","typearme":"contact","bonusmaniementoff":1,"bonusmaniementdef":0,"degats":"1d8","deuxmains":false,"courte":0,"moyenne":0,"longue":0,"tr":0,"rarete":5,"prix":50},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"RiMAsQHaUMojde7N":3},"flags":{"core":{"sourceId":"Item.aNUqO9OZT0GBszvv"}},"_id":"U8CoqFhGuT3ZHeq1"}
|
||||
{"name":"Javelot","type":"arme","img":"systems/fvtt-mournblade/assets/icons/arme.webp","data":{"description":"","typearme":"jet","bonusmaniementoff":1,"bonusmaniementdef":0,"degats":"1d6","deuxmains":false,"courte":25,"moyenne":50,"longue":75,"tr":1,"rarete":5,"prix":30},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"RiMAsQHaUMojde7N":3},"flags":{"core":{"sourceId":"Item.Zwiz9E3TbeUP8qHH"}},"_id":"aELvOR7A9DIJKgBk"}
|
||||
{"name":"Fourche / Faux de paysan","type":"arme","img":"systems/fvtt-mournblade/assets/icons/arme.webp","data":{"description":"","typearme":"contact","bonusmaniementoff":0,"bonusmaniementdef":0,"degats":"1D6","deuxmains":true,"courte":0,"moyenne":0,"longue":0,"tr":0,"rarete":1,"prix":10},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"RiMAsQHaUMojde7N":3},"flags":{"core":{"sourceId":"Item.K5Ayim6mPKZoCSCc"}},"_id":"aJBVfqQ3JQNyVL7c"}
|
||||
{"name":"Arme improvisée","type":"arme","img":"systems/fvtt-mournblade/assets/icons/arme.webp","data":{"description":"","typearme":"contact","bonusmaniementoff":0,"bonusmaniementdef":0,"degats":"1d6","deuxmains":false,"courte":0,"moyenne":0,"longue":0,"tr":0,"rarete":0,"prix":0},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"RiMAsQHaUMojde7N":3},"flags":{"core":{"sourceId":"Item.E7gcmnNQK2t5OQjv"}},"_id":"c6l49ZmEBjUxfI3W"}
|
||||
{"name":"Arc de guerre","type":"arme","img":"systems/fvtt-mournblade/assets/icons/arme.webp","data":{"description":"","typearme":"tir","bonusmaniementoff":0,"bonusmaniementdef":0,"degats":"1d10 + 1","deuxmains":false,"courte":30,"moyenne":50,"longue":100,"tr":1,"rarete":6,"prix":70},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"RiMAsQHaUMojde7N":3},"flags":{"core":{"sourceId":"Item.Tq6lUFPTkBN5cBwn"}},"_id":"cKf5z3fajUnxJh0r"}
|
||||
{"name":"Main gauche","type":"arme","img":"systems/fvtt-mournblade/assets/icons/arme.webp","data":{"description":"","typearme":"contact","bonusmaniementoff":0,"bonusmaniementdef":3,"degats":"1d4 + 1","deuxmains":false,"courte":0,"moyenne":0,"longue":0,"tr":0,"rarete":8,"prix":10},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"RiMAsQHaUMojde7N":3},"flags":{"core":{"sourceId":"Item.BBii0qi1unvSRNO4"}},"_id":"fLHX6ut131CQI630"}
|
||||
{"name":"Marteau de guerre","type":"arme","img":"systems/fvtt-mournblade/assets/icons/arme.webp","data":{"description":"","typearme":"contact","bonusmaniementoff":0,"bonusmaniementdef":0,"degats":"1d8 + 2","deuxmains":false,"courte":0,"moyenne":0,"longue":0,"tr":0,"rarete":6,"prix":70},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"RiMAsQHaUMojde7N":3},"flags":{"core":{"sourceId":"Item.6n2uSdYfRAsSqQnA"}},"_id":"freCCeiYGfWmUAQU"}
|
||||
{"name":"Sabre de Pan Tang","type":"arme","img":"systems/fvtt-mournblade/assets/icons/arme.webp","data":{"description":"<p>Ce long sabre effi lé sert aux Cavaliers démoniaques de Pan Tang pour couper les têtes depuis le dos de leurs monstrueuses montures reptiliennes à six pattes.</p>","typearme":"contact","bonusmaniementoff":2,"bonusmaniementdef":0,"degats":"1d10 + 2","deuxmains":false,"courte":0,"moyenne":0,"longue":0,"tr":0,"rarete":8,"prix":120},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"RiMAsQHaUMojde7N":3},"flags":{"core":{"sourceId":"Item.l3ffzso7GyHMKguD"}},"_id":"j5659PJlrHz56V1k"}
|
||||
{"name":"Hallebarde","type":"arme","img":"systems/fvtt-mournblade/assets/icons/arme.webp","data":{"description":"","typearme":"contact","bonusmaniementoff":0,"bonusmaniementdef":2,"degats":"2d6","deuxmains":true,"courte":0,"moyenne":0,"longue":0,"tr":0,"rarete":7,"prix":150},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"RiMAsQHaUMojde7N":3},"flags":{"core":{"sourceId":"Item.ZTdyIoMzE9kqm4e6"}},"_id":"lYtm5MwP96numskx"}
|
||||
{"name":"Lance melnibonéenne","type":"arme","img":"systems/fvtt-mournblade/assets/icons/arme.webp","data":{"description":"<p>La lance melnibonéenne, faite pour le combat à cheval ou à dos de dragon, ressemble à une lance ordinaire. Son fer est cependant plus fi n et plus étroit. Avant la chute d’Imrryr, il est quasi impossible de se procurer de telles armes sur les marchés des Jeunes Royaumes. Elles peuvent être maniées à une main comme lors des joutes à cheval ou à deux mains au cœur des mêlées.</p>","typearme":"contact","bonusmaniementoff":1,"bonusmaniementdef":2,"degats":"2d6+ 4","deuxmains":true,"courte":0,"moyenne":0,"longue":0,"tr":0,"rarete":10,"prix":70},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"RiMAsQHaUMojde7N":3},"flags":{"core":{"sourceId":"Item.KAl5qXHeYDoYRU6G"}},"_id":"mQGT0vmDjoTZCW5u"}
|
||||
{"name":"Arc en os","type":"arme","img":"systems/fvtt-mournblade/assets/icons/arme.webp","data":{"description":"<p>Arc composite recourbé fait de bois, d’os et d’acier, l’arc en os melnibonéen est une arme extraordinairement puissante entre les mains d’un guerrier melnibonéen ou d’un archer esclave du Glorieux Empire. On peut se le procurer dans les Jeunes Royaumes après la chute d’Imrryr.</p>","typearme":"tir","bonusmaniementoff":3,"bonusmaniementdef":0,"degats":"1d8 + 1","deuxmains":false,"courte":30,"moyenne":60,"longue":125,"tr":2,"rarete":10,"prix":500},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"RiMAsQHaUMojde7N":3},"flags":{"core":{"sourceId":"Item.Dy9dzVhXbNAVm3zn"}},"_id":"nzve5qucVN6FC5wn"}
|
||||
{"name":"Bâton ferré ou lesté","type":"arme","img":"systems/fvtt-mournblade/assets/icons/arme.webp","data":{"description":"","typearme":"contact","bonusmaniementoff":1,"bonusmaniementdef":2,"degats":"1D8","deuxmains":true,"courte":0,"moyenne":0,"longue":0,"tr":0,"rarete":0,"prix":1},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"RiMAsQHaUMojde7N":3},"flags":{"core":{"sourceId":"Item.zoBHSbvJPnjbtPh6"}},"_id":"sHj90bPcMaDlOw51"}
|
||||
{"name":"Épée courte / Glaive","type":"arme","img":"systems/fvtt-mournblade/assets/icons/arme.webp","data":{"description":"","typearme":"contact","bonusmaniementoff":2,"bonusmaniementdef":1,"degats":"1D6+1","deuxmains":false,"courte":0,"moyenne":0,"longue":0,"tr":0,"rarete":4,"prix":40},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"RiMAsQHaUMojde7N":3},"flags":{"core":{"sourceId":"Item.Mxv5gMHRvRrsuhPA"}},"_id":"sju2r73hUHyGbHYg"}
|
||||
{"name":"Faucheur","type":"arme","img":"systems/fvtt-mournblade/assets/icons/arme.webp","data":{"description":"","typearme":"contact","bonusmaniementoff":2,"bonusmaniementdef":1,"degats":"1d4 + 1","deuxmains":false,"courte":0,"moyenne":0,"longue":0,"tr":0,"rarete":7,"prix":100},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"RiMAsQHaUMojde7N":3},"flags":{"core":{"sourceId":"Item.OlmzE29fh9DFd8TF"}},"_id":"t2uQcWe7kirUOp3D"}
|
||||
{"name":"Fléau lourd","type":"arme","img":"systems/fvtt-mournblade/assets/icons/arme.webp","data":{"description":"","typearme":"contact","bonusmaniementoff":1,"bonusmaniementdef":0,"degats":"1d10+ 3","deuxmains":true,"courte":0,"moyenne":0,"longue":0,"tr":0,"rarete":7,"prix":150},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"RiMAsQHaUMojde7N":3},"flags":{"core":{"sourceId":"Item.vDDw0qqM1Kg7Pu6T"}},"_id":"uatjBTFCE5ZCqhAd"}
|
||||
{"name":"Hache","type":"arme","img":"systems/fvtt-mournblade/assets/icons/arme.webp","data":{"description":"","typearme":"contact","bonusmaniementoff":2,"bonusmaniementdef":0,"degats":"1d6 + 2","deuxmains":false,"courte":0,"moyenne":0,"longue":0,"tr":0,"rarete":2,"prix":30},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"RiMAsQHaUMojde7N":3},"flags":{"core":{"sourceId":"Item.2MwgptY2kE4tgYBe"}},"_id":"v7ymzlEALvsk0poA"}
|
||||
{"name":"Épée large","type":"arme","img":"systems/fvtt-mournblade/assets/icons/arme.webp","data":{"description":"","typearme":"contact","bonusmaniementoff":2,"bonusmaniementdef":1,"degats":"1d6+ 2","deuxmains":false,"courte":0,"moyenne":0,"longue":0,"tr":0,"rarete":5,"prix":70},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"RiMAsQHaUMojde7N":3},"flags":{"core":{"sourceId":"Item.iuAizxCvnUxmsjrn"}},"_id":"wWk0Wfer06Ttmouv"}
|
||||
{"name":"Épée longue","type":"arme","img":"systems/fvtt-mournblade/assets/icons/arme.webp","data":{"description":"","typearme":"contact","bonusmaniementoff":2,"bonusmaniementdef":0,"degats":"2d6 + 1","deuxmains":true,"courte":0,"moyenne":0,"longue":0,"tr":0,"rarete":8,"prix":250},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"RiMAsQHaUMojde7N":3},"flags":{"core":{"sourceId":"Item.yiYtZ0sCUpMihvzz"}},"_id":"wv5EiePmPTpqFutt"}
|
||||
{"name":"Fouet","type":"arme","img":"systems/fvtt-mournblade/assets/icons/arme.webp","effects":[],"folder":null,"sort":0,"flags":{"core":{"sourceId":"Item.Qb1h25U88mTM4h72"}},"_id":"0swiE8k5zfUIqmXu","system":{"description":"","typearme":"contactjet","isdefense":false,"bonusmaniementoff":0,"bonusmaniementdef":0,"degats":"1d4 + 1","nonletaux":true,"deuxmains":false,"courte":3,"moyenne":0,"longue":0,"tr":0,"rarete":4,"prix":40,"equipped":false},"ownership":{"default":0,"RiMAsQHaUMojde7N":3},"_stats":{"systemId":"fvtt-mournblade","systemVersion":"10.0.9","coreVersion":"10.286","createdTime":1664572964292,"modifiedTime":1664573659387,"lastModifiedBy":"1Hr6ON03ooIXzvIm"}}
|
||||
{"_id":"2BSVJXr0FGZZJ9fh","name":"Hache des mers","type":"arme","img":"systems/fvtt-mournblade/assets/icons/arme.webp","effects":[],"folder":null,"sort":0,"flags":{"core":{"sourceId":"Item.mGYFgteaWBDo10Xb"}},"system":{"description":"","typearme":"contact","isdefense":true,"bonusmaniementoff":2,"bonusmaniementdef":0,"degats":"2d6","nonletaux":false,"deuxmains":true,"courte":0,"moyenne":0,"longue":0,"tr":0,"rarete":7,"prix":150,"equipped":false},"ownership":{"default":0,"RiMAsQHaUMojde7N":3},"_stats":{"systemId":"fvtt-mournblade","systemVersion":"10.0.9","coreVersion":"10.286","createdTime":1664572964293,"modifiedTime":1664573659388,"lastModifiedBy":"1Hr6ON03ooIXzvIm"}}
|
||||
{"name":"Ecu d'acier","type":"bouclier","img":"systems/fvtt-mournblade/assets/icons/protection.webp","system":{"description":"","bonusdefense":3,"degats":"1d8","nonletaux":"false","rarete":9,"prix":10,"equipped":false,"isdefense":null},"effects":[],"ownership":{"default":0,"1Hr6ON03ooIXzvIm":3},"flags":{"core":{"sourceId":"Item.Gn52Vfp6Vg4cnpd0"}},"_stats":{"systemId":"fvtt-mournblade","systemVersion":"10.0.9","coreVersion":"10.286","createdTime":1664572521380,"modifiedTime":1664573706183,"lastModifiedBy":"1Hr6ON03ooIXzvIm"},"folder":null,"sort":0,"_id":"2PmIgKP4wZLHGp0s"}
|
||||
{"_id":"2qezkR1BdC0DcRIl","name":"Fléau d’armes","type":"arme","img":"systems/fvtt-mournblade/assets/icons/arme.webp","effects":[],"folder":null,"sort":0,"flags":{"core":{"sourceId":"Item.PHQabMgfk1GNOjKo"}},"system":{"description":"","typearme":"contact","isdefense":true,"bonusmaniementoff":0,"bonusmaniementdef":0,"degats":"1D10+1","nonletaux":false,"deuxmains":false,"courte":0,"moyenne":0,"longue":0,"tr":0,"rarete":7,"prix":70,"equipped":false},"ownership":{"default":0,"RiMAsQHaUMojde7N":3},"_stats":{"systemId":"fvtt-mournblade","systemVersion":"10.0.9","coreVersion":"10.286","createdTime":1664572964293,"modifiedTime":1664573659387,"lastModifiedBy":"1Hr6ON03ooIXzvIm"}}
|
||||
{"name":"Arbalète","type":"arme","img":"systems/fvtt-mournblade/assets/icons/arme.webp","effects":[],"folder":null,"sort":0,"flags":{"core":{"sourceId":"Item.WYp8ojQN8HYJwUJc"}},"_id":"2zIdrBK88iuMbOF0","system":{"description":"","typearme":"tir","isdefense":null,"bonusmaniementoff":1,"bonusmaniementdef":0,"degats":"2d6","nonletaux":null,"deuxmains":"","courte":25,"moyenne":50,"longue":75,"tr":3,"rarete":10,"prix":500,"equipped":false},"ownership":{"default":0,"RiMAsQHaUMojde7N":3},"_stats":{"systemId":"fvtt-mournblade","systemVersion":"10.0.9","coreVersion":"10.286","createdTime":1664572964293,"modifiedTime":1664573659385,"lastModifiedBy":"1Hr6ON03ooIXzvIm"}}
|
||||
{"_id":"3Iv1oLpZcPEJVaI4","name":"Cimeterre","type":"arme","img":"systems/fvtt-mournblade/assets/icons/arme.webp","effects":[],"folder":null,"sort":0,"flags":{"core":{"sourceId":"Item.RYxEg0gJfAlIZ4mw"}},"system":{"description":"","typearme":"contact","isdefense":true,"bonusmaniementoff":1,"bonusmaniementdef":1,"degats":"1d10","nonletaux":false,"deuxmains":false,"courte":0,"moyenne":0,"longue":0,"tr":0,"rarete":8,"prix":100,"equipped":false},"ownership":{"default":0,"RiMAsQHaUMojde7N":3},"_stats":{"systemId":"fvtt-mournblade","systemVersion":"10.0.9","coreVersion":"10.286","createdTime":1664572964294,"modifiedTime":1664573659386,"lastModifiedBy":"1Hr6ON03ooIXzvIm"}}
|
||||
{"name":"Fronde","type":"arme","img":"systems/fvtt-mournblade/assets/icons/arme.webp","effects":[],"folder":null,"sort":0,"flags":{"core":{"sourceId":"Item.TgVuNnytO9k2K0Xe"}},"_id":"4To8rLxv4efsoZK0","system":{"description":"","typearme":"tir","isdefense":false,"bonusmaniementoff":0,"bonusmaniementdef":0,"degats":"1D4","nonletaux":false,"deuxmains":false,"courte":10,"moyenne":25,"longue":50,"tr":1,"rarete":2,"prix":1,"equipped":false},"ownership":{"default":0,"RiMAsQHaUMojde7N":3},"_stats":{"systemId":"fvtt-mournblade","systemVersion":"10.0.9","coreVersion":"10.286","createdTime":1664572964294,"modifiedTime":1664573659388,"lastModifiedBy":"1Hr6ON03ooIXzvIm"}}
|
||||
{"name":"Pierre","type":"arme","img":"systems/fvtt-mournblade/assets/icons/arme.webp","effects":[],"folder":null,"sort":0,"flags":{"core":{"sourceId":"Item.3YS9IfQddECnoagK"}},"_id":"4yKlK8MeSj5Zk8lM","system":{"description":"","typearme":"contactjet","isdefense":false,"bonusmaniementoff":0,"bonusmaniementdef":0,"degats":"1D4","nonletaux":true,"deuxmains":false,"courte":3,"moyenne":6,"longue":15,"tr":1,"rarete":0,"prix":0,"equipped":false},"ownership":{"default":0,"RiMAsQHaUMojde7N":3},"_stats":{"systemId":"fvtt-mournblade","systemVersion":"10.0.9","coreVersion":"10.286","createdTime":1664572964294,"modifiedTime":1664573659390,"lastModifiedBy":"1Hr6ON03ooIXzvIm"}}
|
||||
{"_id":"6e1JHoD1Jrz020R7","name":"Grand marteau","type":"arme","img":"systems/fvtt-mournblade/assets/icons/arme.webp","effects":[],"folder":null,"sort":0,"flags":{"core":{"sourceId":"Item.vjic4cPkJ0iMCIt5"}},"system":{"description":"","typearme":"contact","isdefense":true,"bonusmaniementoff":1,"bonusmaniementdef":0,"degats":"2D6+2","nonletaux":false,"deuxmains":true,"courte":0,"moyenne":0,"longue":0,"tr":0,"rarete":7,"prix":120,"equipped":false},"ownership":{"default":0,"RiMAsQHaUMojde7N":3},"_stats":{"systemId":"fvtt-mournblade","systemVersion":"10.0.9","coreVersion":"10.286","createdTime":1664572964294,"modifiedTime":1664573659388,"lastModifiedBy":"1Hr6ON03ooIXzvIm"}}
|
||||
{"name":"Arc de cavalerie","type":"arme","img":"systems/fvtt-mournblade/assets/icons/arme.webp","effects":[],"folder":null,"sort":0,"flags":{"core":{"sourceId":"Item.5EWrgNQjJMx1t2v1"}},"_id":"88UuW1bdpFuCmkqb","system":{"description":"","typearme":"tir","isdefense":null,"bonusmaniementoff":1,"bonusmaniementdef":0,"degats":"1d6","nonletaux":null,"deuxmains":null,"courte":25,"moyenne":50,"longue":75,"tr":1,"rarete":7,"prix":100,"equipped":false},"ownership":{"default":0,"RiMAsQHaUMojde7N":3},"_stats":{"systemId":"fvtt-mournblade","systemVersion":"10.0.9","coreVersion":"10.286","createdTime":1664572964294,"modifiedTime":1664573659385,"lastModifiedBy":"1Hr6ON03ooIXzvIm"}}
|
||||
{"_id":"9Eo9mRbPPZHN98Cr","name":"Épée de maître","type":"arme","img":"systems/fvtt-mournblade/assets/icons/arme.webp","effects":[],"folder":null,"sort":0,"flags":{"core":{"sourceId":"Item.kX3MbDFu9uYZVNf2"}},"system":{"description":"","typearme":"contact","isdefense":true,"bonusmaniementoff":2,"bonusmaniementdef":1,"degats":"1d8+ 2","nonletaux":false,"deuxmains":false,"courte":0,"moyenne":0,"longue":0,"tr":0,"rarete":7,"prix":120,"equipped":false},"ownership":{"default":0,"RiMAsQHaUMojde7N":3},"_stats":{"systemId":"fvtt-mournblade","systemVersion":"10.0.9","coreVersion":"10.286","createdTime":1664572964294,"modifiedTime":1664573659386,"lastModifiedBy":"1Hr6ON03ooIXzvIm"}}
|
||||
{"_id":"9xPd4ITtyk3nmMoN","name":"Lance ilmioréenne","type":"arme","img":"systems/fvtt-mournblade/assets/icons/arme.webp","effects":[],"folder":null,"sort":0,"flags":{"core":{"sourceId":"Item.8ApbiVgkx79OHVp2"}},"system":{"description":"<p>La lance ilmioréenne est un solide bâton de combat surmonté d’une pointe sur lequel est fi xé quasi perpendiculairement un fer de hache plat et étroit. Un contrepoids fi xé à l’autre extrémité sert à équilibrer l’arme qui peut être maniée à la fois comme une lance et comme une hache à deux mains, ce qui permet de maintenir ses ennemis à distance ou de leur porter des coups dévastateurs. Ces lances furent inventées à l’époque de la tribu d’Ilm, quand les lances et épées étaient déclarées illégales par les gouverneurs melnibonéens de la région. Certaines écoles militaires ilmioréennes enseignent toujours le Style Imar, qui mêle en une seule et même technique le combat à deux mains à la lance et le combat au bâton.</p>","typearme":"contact","isdefense":true,"bonusmaniementoff":0,"bonusmaniementdef":2,"degats":"1d8 + 2","nonletaux":false,"deuxmains":true,"courte":0,"moyenne":0,"longue":0,"tr":0,"rarete":8,"prix":100,"equipped":false},"ownership":{"default":0,"RiMAsQHaUMojde7N":3},"_stats":{"systemId":"fvtt-mournblade","systemVersion":"10.0.9","coreVersion":"10.286","createdTime":1664572964294,"modifiedTime":1664573659389,"lastModifiedBy":"1Hr6ON03ooIXzvIm"}}
|
||||
{"_id":"CeC5lAKs7NdPF05l","name":"Masse lourde","type":"arme","img":"systems/fvtt-mournblade/assets/icons/arme.webp","effects":[],"folder":null,"sort":0,"flags":{"core":{"sourceId":"Item.DPfXgFj3gpjJ3nbR"}},"system":{"description":"","typearme":"contact","isdefense":true,"bonusmaniementoff":2,"bonusmaniementdef":0,"degats":"1d10 + 1","nonletaux":false,"deuxmains":true,"courte":0,"moyenne":0,"longue":0,"tr":0,"rarete":5,"prix":80,"equipped":false},"ownership":{"default":0,"RiMAsQHaUMojde7N":3},"_stats":{"systemId":"fvtt-mournblade","systemVersion":"10.0.9","coreVersion":"10.286","createdTime":1664572964294,"modifiedTime":1664573659389,"lastModifiedBy":"1Hr6ON03ooIXzvIm"}}
|
||||
{"_id":"CqP80SQFQOefpGgd","name":"Gourdin","type":"arme","img":"systems/fvtt-mournblade/assets/icons/arme.webp","effects":[],"folder":null,"sort":0,"flags":{"core":{"sourceId":"Item.CBIfq9eRd2RmoI4H"}},"system":{"description":"","typearme":"contact","isdefense":true,"bonusmaniementoff":2,"bonusmaniementdef":0,"degats":"1D6","nonletaux":true,"deuxmains":false,"courte":0,"moyenne":0,"longue":0,"tr":0,"rarete":0,"prix":5,"equipped":false},"ownership":{"default":0,"RiMAsQHaUMojde7N":3},"_stats":{"systemId":"fvtt-mournblade","systemVersion":"10.0.9","coreVersion":"10.286","createdTime":1664572964294,"modifiedTime":1664573659388,"lastModifiedBy":"1Hr6ON03ooIXzvIm"}}
|
||||
{"_id":"CupT9m8L909l4Fo5","name":"Rapière","type":"arme","img":"systems/fvtt-mournblade/assets/icons/arme.webp","effects":[],"folder":null,"sort":0,"flags":{"core":{"sourceId":"Item.XIStcClTnmLoSwyR"}},"system":{"description":"","typearme":"contact","isdefense":true,"bonusmaniementoff":3,"bonusmaniementdef":1,"degats":"1d8+ 1","nonletaux":false,"deuxmains":false,"courte":0,"moyenne":0,"longue":0,"tr":0,"rarete":8,"prix":150,"equipped":false},"ownership":{"default":0,"RiMAsQHaUMojde7N":3},"_stats":{"systemId":"fvtt-mournblade","systemVersion":"10.0.9","coreVersion":"10.286","createdTime":1664572964295,"modifiedTime":1664573659390,"lastModifiedBy":"1Hr6ON03ooIXzvIm"}}
|
||||
{"name":"Hachette / Hache de lancer","type":"arme","img":"systems/fvtt-mournblade/assets/icons/arme.webp","effects":[],"folder":null,"sort":0,"flags":{"core":{"sourceId":"Item.5NHbRanxXA5vUE3B"}},"_id":"DzkeP7jbruqW4nQH","system":{"description":"","typearme":"contactjet","isdefense":false,"bonusmaniementoff":2,"bonusmaniementdef":0,"degats":"1d4 + 1","nonletaux":false,"deuxmains":false,"courte":5,"moyenne":10,"longue":15,"tr":1,"rarete":5,"prix":50,"equipped":false},"ownership":{"default":0,"RiMAsQHaUMojde7N":3},"_stats":{"systemId":"fvtt-mournblade","systemVersion":"10.0.9","coreVersion":"10.286","createdTime":1664572964295,"modifiedTime":1664573659388,"lastModifiedBy":"1Hr6ON03ooIXzvIm"}}
|
||||
{"_id":"FDeRBkxXwoZIuL9B","name":"Lance légère","type":"arme","img":"systems/fvtt-mournblade/assets/icons/arme.webp","effects":[],"folder":null,"sort":0,"flags":{"core":{"sourceId":"Item.LIVeq22E9EanRS9L"}},"system":{"description":"","typearme":"contact","isdefense":true,"bonusmaniementoff":2,"bonusmaniementdef":0,"degats":"1d8","nonletaux":false,"deuxmains":false,"courte":10,"moyenne":25,"longue":50,"tr":1,"rarete":5,"prix":5,"equipped":false},"ownership":{"default":0,"RiMAsQHaUMojde7N":3},"_stats":{"systemId":"fvtt-mournblade","systemVersion":"10.0.9","coreVersion":"10.286","createdTime":1664572964295,"modifiedTime":1664573659389,"lastModifiedBy":"1Hr6ON03ooIXzvIm"}}
|
||||
{"name":"Arc de chasse","type":"arme","img":"systems/fvtt-mournblade/assets/icons/arme.webp","effects":[],"folder":null,"sort":0,"flags":{"core":{"sourceId":"Item.TrYZ9BxYukS1mbBX"}},"_id":"Hrm08cpgAMMV6Jpq","system":{"description":"","typearme":"tir","isdefense":false,"bonusmaniementoff":2,"bonusmaniementdef":0,"degats":"1d6 - 1","nonletaux":false,"deuxmains":false,"courte":25,"moyenne":50,"longue":75,"tr":1,"rarete":8,"prix":250,"equipped":false},"ownership":{"default":0,"RiMAsQHaUMojde7N":3},"_stats":{"systemId":"fvtt-mournblade","systemVersion":"10.0.9","coreVersion":"10.286","createdTime":1664572964295,"modifiedTime":1664573659385,"lastModifiedBy":"1Hr6ON03ooIXzvIm"}}
|
||||
{"_id":"Iw3j4oC6H8HJ9MFQ","name":"Coup de pied / poing / tête","type":"arme","img":"systems/fvtt-mournblade/assets/icons/arme.webp","effects":[],"folder":null,"sort":0,"flags":{"core":{"sourceId":"Item.nBPKHsYIM0HgMcBy"}},"system":{"description":"","typearme":"contact","isdefense":true,"bonusmaniementoff":3,"bonusmaniementdef":0,"degats":"1d4","nonletaux":true,"deuxmains":false,"courte":0,"moyenne":0,"longue":0,"tr":0,"rarete":0,"prix":0,"equipped":false},"ownership":{"default":0,"RiMAsQHaUMojde7N":3},"_stats":{"systemId":"fvtt-mournblade","systemVersion":"10.0.9","coreVersion":"10.286","createdTime":1664572964295,"modifiedTime":1664573659386,"lastModifiedBy":"1Hr6ON03ooIXzvIm"}}
|
||||
{"_id":"KY22L6Lx5WxgvyGD","name":"Lance lourde","type":"arme","img":"systems/fvtt-mournblade/assets/icons/arme.webp","effects":[],"folder":null,"sort":0,"flags":{"core":{"sourceId":"Item.Kcl07bs7TOcne37W"}},"system":{"description":"","typearme":"contact","isdefense":true,"bonusmaniementoff":1,"bonusmaniementdef":2,"degats":"1d10","nonletaux":false,"deuxmains":true,"courte":0,"moyenne":0,"longue":0,"tr":0,"rarete":5,"prix":50,"equipped":false},"ownership":{"default":0,"RiMAsQHaUMojde7N":3},"_stats":{"systemId":"fvtt-mournblade","systemVersion":"10.0.9","coreVersion":"10.286","createdTime":1664572964295,"modifiedTime":1664573659389,"lastModifiedBy":"1Hr6ON03ooIXzvIm"}}
|
||||
{"name":"Arc du Désert des Larmes","type":"arme","img":"systems/fvtt-mournblade/assets/icons/arme.webp","effects":[],"folder":null,"sort":0,"flags":{"core":{"sourceId":"Item.QmYjdRCAk3MnxKJg"}},"_id":"MDpFpqmXpIX5VV80","system":{"description":"<p>Cet arc composite fait de bois, d’andouillers de cerf et/ou d’os est un arc court et très recourbé utilisé par les barbares du Désert des Larmes pour la chasse. On peut également trouver ce type d’arcs à Pikarayd et au Dorel.</p>","typearme":"tir","isdefense":null,"bonusmaniementoff":2,"bonusmaniementdef":0,"degats":"1d6 + 1","nonletaux":null,"deuxmains":null,"courte":25,"moyenne":50,"longue":75,"tr":1,"rarete":8,"prix":250,"equipped":false},"ownership":{"default":0,"RiMAsQHaUMojde7N":3},"_stats":{"systemId":"fvtt-mournblade","systemVersion":"10.0.9","coreVersion":"10.286","createdTime":1664572964296,"modifiedTime":1664573659385,"lastModifiedBy":"1Hr6ON03ooIXzvIm"}}
|
||||
{"_id":"MP49mYF7FVuW9ALB","name":"Hache de bataille dite lormyrienne","type":"arme","img":"systems/fvtt-mournblade/assets/icons/arme.webp","effects":[],"folder":null,"sort":0,"flags":{"core":{"sourceId":"Item.Lpa6kesbzgKVtogn"}},"system":{"description":"<p>Cette double hache parfaitement équilibrée et proportionnée est l’arme favorite des chevaliers lormyriens. Il s’agit de l’arme idéale pour trancher, découper les lances ennemies et fendre les crânes.</p>","typearme":"contact","isdefense":true,"bonusmaniementoff":2,"bonusmaniementdef":0,"degats":"2d6 + 2","nonletaux":false,"deuxmains":true,"courte":0,"moyenne":0,"longue":0,"tr":0,"rarete":8,"prix":250,"equipped":false},"ownership":{"default":0,"RiMAsQHaUMojde7N":3},"_stats":{"systemId":"fvtt-mournblade","systemVersion":"10.0.9","coreVersion":"10.286","createdTime":1664572964296,"modifiedTime":1664573659388,"lastModifiedBy":"1Hr6ON03ooIXzvIm"}}
|
||||
{"_id":"N5BbO2lGwzQnpvH0","name":"Couteau / Dague","type":"arme","img":"systems/fvtt-mournblade/assets/icons/arme.webp","effects":[],"folder":null,"sort":0,"flags":{"core":{"sourceId":"Item.5a9GKIvNgbbXBq3s"}},"system":{"description":"","typearme":"contactjet","isdefense":true,"bonusmaniementoff":3,"bonusmaniementdef":0,"degats":"1d4","nonletaux":false,"deuxmains":false,"courte":3,"moyenne":6,"longue":15,"tr":1,"rarete":1,"prix":10,"equipped":false},"ownership":{"default":0,"RiMAsQHaUMojde7N":3},"_stats":{"systemId":"fvtt-mournblade","systemVersion":"10.0.9","coreVersion":"10.286","createdTime":1664572964297,"modifiedTime":1664573659386,"lastModifiedBy":"1Hr6ON03ooIXzvIm"}}
|
||||
{"_id":"QwrZbFeJUQv2OBqI","name":"Pique filkharienne","type":"arme","img":"systems/fvtt-mournblade/assets/icons/arme.webp","effects":[],"folder":null,"sort":0,"flags":{"core":{"sourceId":"Item.dF9LxfA1crZBmT92"}},"system":{"description":"<p>Cette longue pique à grande lame de près de trois mètres de long est l’arme de prédilection des piquiers de l’armée de Filkhar. Très effi cace pour lutter contre des cavaliers ou des ennemis en train de charger, elle l’est beaucoup moins en combat rapproché.</p>","typearme":"contact","isdefense":true,"bonusmaniementoff":2,"bonusmaniementdef":0,"degats":"1d8 + 2","nonletaux":false,"deuxmains":true,"courte":0,"moyenne":0,"longue":0,"tr":0,"rarete":8,"prix":150,"equipped":false},"ownership":{"default":0,"RiMAsQHaUMojde7N":3},"_stats":{"systemId":"fvtt-mournblade","systemVersion":"10.0.9","coreVersion":"10.286","createdTime":1664572964297,"modifiedTime":1664573659390,"lastModifiedBy":"1Hr6ON03ooIXzvIm"}}
|
||||
{"_id":"SzgkzHvzma8NiMd5","name":"Masse légère","type":"arme","img":"systems/fvtt-mournblade/assets/icons/arme.webp","effects":[],"folder":null,"sort":0,"flags":{"core":{"sourceId":"Item.xrWRNZBrEzkUQzRG"}},"system":{"description":"","typearme":"contact","isdefense":true,"bonusmaniementoff":2,"bonusmaniementdef":0,"degats":"1d6 + 2","nonletaux":false,"deuxmains":false,"courte":0,"moyenne":0,"longue":0,"tr":0,"rarete":5,"prix":5,"equipped":false},"ownership":{"default":0,"RiMAsQHaUMojde7N":3},"_stats":{"systemId":"fvtt-mournblade","systemVersion":"10.0.9","coreVersion":"10.286","createdTime":1664572964297,"modifiedTime":1664573659389,"lastModifiedBy":"1Hr6ON03ooIXzvIm"}}
|
||||
{"_id":"U8CoqFhGuT3ZHeq1","name":"Sabre d’abordage","type":"arme","img":"systems/fvtt-mournblade/assets/icons/arme.webp","effects":[],"folder":null,"sort":0,"flags":{"core":{"sourceId":"Item.aNUqO9OZT0GBszvv"}},"system":{"description":"","typearme":"contact","isdefense":true,"bonusmaniementoff":1,"bonusmaniementdef":0,"degats":"1d8","nonletaux":false,"deuxmains":false,"courte":0,"moyenne":0,"longue":0,"tr":0,"rarete":5,"prix":50,"equipped":false},"ownership":{"default":0,"RiMAsQHaUMojde7N":3},"_stats":{"systemId":"fvtt-mournblade","systemVersion":"10.0.9","coreVersion":"10.286","createdTime":1664572964297,"modifiedTime":1664573659390,"lastModifiedBy":"1Hr6ON03ooIXzvIm"}}
|
||||
{"name":"Javelot","type":"arme","img":"systems/fvtt-mournblade/assets/icons/arme.webp","effects":[],"folder":null,"sort":0,"flags":{"core":{"sourceId":"Item.Zwiz9E3TbeUP8qHH"}},"_id":"aELvOR7A9DIJKgBk","system":{"description":"","typearme":"jet","isdefense":false,"bonusmaniementoff":1,"bonusmaniementdef":0,"degats":"1d6","nonletaux":false,"deuxmains":false,"courte":25,"moyenne":50,"longue":75,"tr":1,"rarete":5,"prix":30,"equipped":false},"ownership":{"default":0,"RiMAsQHaUMojde7N":3},"_stats":{"systemId":"fvtt-mournblade","systemVersion":"10.0.9","coreVersion":"10.286","createdTime":1664572964297,"modifiedTime":1664573659389,"lastModifiedBy":"1Hr6ON03ooIXzvIm"}}
|
||||
{"_id":"aJBVfqQ3JQNyVL7c","name":"Fourche / Faux de paysan","type":"arme","img":"systems/fvtt-mournblade/assets/icons/arme.webp","effects":[],"folder":null,"sort":0,"flags":{"core":{"sourceId":"Item.K5Ayim6mPKZoCSCc"}},"system":{"description":"","typearme":"contact","isdefense":true,"bonusmaniementoff":0,"bonusmaniementdef":0,"degats":"1D6","nonletaux":false,"deuxmains":true,"courte":0,"moyenne":0,"longue":0,"tr":0,"rarete":1,"prix":10,"equipped":false},"ownership":{"default":0,"RiMAsQHaUMojde7N":3},"_stats":{"systemId":"fvtt-mournblade","systemVersion":"10.0.9","coreVersion":"10.286","createdTime":1664572964298,"modifiedTime":1664573659387,"lastModifiedBy":"1Hr6ON03ooIXzvIm"}}
|
||||
{"name":"Pavois","type":"bouclier","img":"systems/fvtt-mournblade/assets/icons/protection.webp","system":{"description":"<p>Le Pavois se plante dans le sol au début du combat et ne peut plus être déplacé jusqu'à son issue.</p>","bonusdefense":3,"degats":"0","nonletaux":"false","rarete":7,"prix":5,"equipped":false,"isdefense":"false"},"effects":[],"ownership":{"default":0,"1Hr6ON03ooIXzvIm":3},"flags":{"core":{"sourceId":"Item.E3A8EnGzQctvYndd"}},"_stats":{"systemId":"fvtt-mournblade","systemVersion":"10.0.9","coreVersion":"10.286","createdTime":1664572521380,"modifiedTime":1664573708981,"lastModifiedBy":"1Hr6ON03ooIXzvIm"},"folder":null,"sort":0,"_id":"b2VNhFBgbvlzaMw8"}
|
||||
{"name":"Bouclier d'Infanterie","type":"bouclier","img":"systems/fvtt-mournblade/assets/icons/protection.webp","system":{"description":"","bonusdefense":2,"degats":"1d6","nonletaux":"false","rarete":5,"prix":2,"equipped":false},"effects":[],"ownership":{"default":0,"1Hr6ON03ooIXzvIm":3},"flags":{"core":{"sourceId":"Item.jeMLhLTJhTU6TJ58"}},"_stats":{"systemId":"fvtt-mournblade","systemVersion":"10.0.9","coreVersion":"10.286","createdTime":1664572521380,"modifiedTime":1664573703190,"lastModifiedBy":"1Hr6ON03ooIXzvIm"},"folder":null,"sort":0,"_id":"bqDEyPj9OlGnEJsr"}
|
||||
{"_id":"c6l49ZmEBjUxfI3W","name":"Arme improvisée","type":"arme","img":"systems/fvtt-mournblade/assets/icons/arme.webp","effects":[],"folder":null,"sort":0,"flags":{"core":{"sourceId":"Item.E7gcmnNQK2t5OQjv"}},"system":{"description":"","typearme":"contact","isdefense":true,"bonusmaniementoff":0,"bonusmaniementdef":0,"degats":"1d6","nonletaux":true,"deuxmains":false,"courte":0,"moyenne":0,"longue":0,"tr":0,"rarete":0,"prix":0,"equipped":false},"ownership":{"default":0,"RiMAsQHaUMojde7N":3},"_stats":{"systemId":"fvtt-mournblade","systemVersion":"10.0.9","coreVersion":"10.286","createdTime":1664572964298,"modifiedTime":1664573659386,"lastModifiedBy":"1Hr6ON03ooIXzvIm"}}
|
||||
{"name":"Arc de guerre","type":"arme","img":"systems/fvtt-mournblade/assets/icons/arme.webp","effects":[],"folder":null,"sort":0,"flags":{"core":{"sourceId":"Item.Tq6lUFPTkBN5cBwn"}},"_id":"cKf5z3fajUnxJh0r","system":{"description":"","typearme":"tir","isdefense":false,"bonusmaniementoff":0,"bonusmaniementdef":0,"degats":"1d10 + 1","nonletaux":false,"deuxmains":false,"courte":30,"moyenne":50,"longue":100,"tr":1,"rarete":6,"prix":70,"equipped":false},"ownership":{"default":0,"RiMAsQHaUMojde7N":3},"_stats":{"systemId":"fvtt-mournblade","systemVersion":"10.0.9","coreVersion":"10.286","createdTime":1664572964298,"modifiedTime":1664573659385,"lastModifiedBy":"1Hr6ON03ooIXzvIm"}}
|
||||
{"name":"Targe","type":"bouclier","img":"systems/fvtt-mournblade/assets/icons/protection.webp","system":{"description":"","bonusdefense":1,"degats":"1d4","nonletaux":"false","rarete":4,"prix":2,"equipped":false},"effects":[],"ownership":{"default":0,"1Hr6ON03ooIXzvIm":3},"flags":{"core":{"sourceId":"Item.9rJkBsRltxH08QT8"}},"_stats":{"systemId":"fvtt-mournblade","systemVersion":"10.0.9","coreVersion":"10.286","createdTime":1664572521380,"modifiedTime":1664573712553,"lastModifiedBy":"1Hr6ON03ooIXzvIm"},"folder":null,"sort":0,"_id":"cZorS8WAKNS0dN0T"}
|
||||
{"_id":"fLHX6ut131CQI630","name":"Main gauche","type":"arme","img":"systems/fvtt-mournblade/assets/icons/arme.webp","effects":[],"folder":null,"sort":0,"flags":{"core":{"sourceId":"Item.BBii0qi1unvSRNO4"}},"system":{"description":"","typearme":"contact","isdefense":true,"bonusmaniementoff":0,"bonusmaniementdef":3,"degats":"1d4 + 1","nonletaux":false,"deuxmains":false,"courte":0,"moyenne":0,"longue":0,"tr":0,"rarete":8,"prix":10,"equipped":false},"ownership":{"default":0,"RiMAsQHaUMojde7N":3},"_stats":{"systemId":"fvtt-mournblade","systemVersion":"10.0.9","coreVersion":"10.286","createdTime":1664572964298,"modifiedTime":1664573659389,"lastModifiedBy":"1Hr6ON03ooIXzvIm"}}
|
||||
{"_id":"freCCeiYGfWmUAQU","name":"Marteau de guerre","type":"arme","img":"systems/fvtt-mournblade/assets/icons/arme.webp","effects":[],"folder":null,"sort":0,"flags":{"core":{"sourceId":"Item.6n2uSdYfRAsSqQnA"}},"system":{"description":"","typearme":"contact","isdefense":true,"bonusmaniementoff":0,"bonusmaniementdef":0,"degats":"1d8 + 2","nonletaux":false,"deuxmains":false,"courte":0,"moyenne":0,"longue":0,"tr":0,"rarete":6,"prix":70,"equipped":false},"ownership":{"default":0,"RiMAsQHaUMojde7N":3},"_stats":{"systemId":"fvtt-mournblade","systemVersion":"10.0.9","coreVersion":"10.286","createdTime":1664572964298,"modifiedTime":1664573659389,"lastModifiedBy":"1Hr6ON03ooIXzvIm"}}
|
||||
{"_id":"j5659PJlrHz56V1k","name":"Sabre de Pan Tang","type":"arme","img":"systems/fvtt-mournblade/assets/icons/arme.webp","effects":[],"folder":null,"sort":0,"flags":{"core":{"sourceId":"Item.l3ffzso7GyHMKguD"}},"system":{"description":"<p>Ce long sabre effi lé sert aux Cavaliers démoniaques de Pan Tang pour couper les têtes depuis le dos de leurs monstrueuses montures reptiliennes à six pattes.</p>","typearme":"contact","isdefense":true,"bonusmaniementoff":2,"bonusmaniementdef":0,"degats":"1d10 + 2","nonletaux":false,"deuxmains":false,"courte":0,"moyenne":0,"longue":0,"tr":0,"rarete":8,"prix":120,"equipped":false},"ownership":{"default":0,"RiMAsQHaUMojde7N":3},"_stats":{"systemId":"fvtt-mournblade","systemVersion":"10.0.9","coreVersion":"10.286","createdTime":1664572964299,"modifiedTime":1664573659390,"lastModifiedBy":"1Hr6ON03ooIXzvIm"}}
|
||||
{"_id":"lYtm5MwP96numskx","name":"Hallebarde","type":"arme","img":"systems/fvtt-mournblade/assets/icons/arme.webp","effects":[],"folder":null,"sort":0,"flags":{"core":{"sourceId":"Item.ZTdyIoMzE9kqm4e6"}},"system":{"description":"","typearme":"contact","isdefense":true,"bonusmaniementoff":0,"bonusmaniementdef":2,"degats":"2d6","nonletaux":false,"deuxmains":true,"courte":0,"moyenne":0,"longue":0,"tr":0,"rarete":7,"prix":150,"equipped":false},"ownership":{"default":0,"RiMAsQHaUMojde7N":3},"_stats":{"systemId":"fvtt-mournblade","systemVersion":"10.0.9","coreVersion":"10.286","createdTime":1664572964299,"modifiedTime":1664573659389,"lastModifiedBy":"1Hr6ON03ooIXzvIm"}}
|
||||
{"_id":"mQGT0vmDjoTZCW5u","name":"Lance melnibonéenne","type":"arme","img":"systems/fvtt-mournblade/assets/icons/arme.webp","effects":[],"folder":null,"sort":0,"flags":{"core":{"sourceId":"Item.KAl5qXHeYDoYRU6G"}},"system":{"description":"<p>La lance melnibonéenne, faite pour le combat à cheval ou à dos de dragon, ressemble à une lance ordinaire. Son fer est cependant plus fi n et plus étroit. Avant la chute d’Imrryr, il est quasi impossible de se procurer de telles armes sur les marchés des Jeunes Royaumes. Elles peuvent être maniées à une main comme lors des joutes à cheval ou à deux mains au cœur des mêlées.</p>","typearme":"contact","isdefense":true,"bonusmaniementoff":1,"bonusmaniementdef":2,"degats":"2d6+ 4","nonletaux":false,"deuxmains":true,"courte":0,"moyenne":0,"longue":0,"tr":0,"rarete":10,"prix":70,"equipped":false},"ownership":{"default":0,"RiMAsQHaUMojde7N":3},"_stats":{"systemId":"fvtt-mournblade","systemVersion":"10.0.9","coreVersion":"10.286","createdTime":1664572964299,"modifiedTime":1664573659389,"lastModifiedBy":"1Hr6ON03ooIXzvIm"}}
|
||||
{"name":"Arc en os","type":"arme","img":"systems/fvtt-mournblade/assets/icons/arme.webp","effects":[],"folder":null,"sort":0,"flags":{"core":{"sourceId":"Item.Dy9dzVhXbNAVm3zn"}},"_id":"nzve5qucVN6FC5wn","system":{"description":"<p>Arc composite recourbé fait de bois, d’os et d’acier, l’arc en os melnibonéen est une arme extraordinairement puissante entre les mains d’un guerrier melnibonéen ou d’un archer esclave du Glorieux Empire. On peut se le procurer dans les Jeunes Royaumes après la chute d’Imrryr.</p>","typearme":"tir","isdefense":false,"bonusmaniementoff":3,"bonusmaniementdef":0,"degats":"1d8 + 1","nonletaux":false,"deuxmains":false,"courte":30,"moyenne":60,"longue":125,"tr":2,"rarete":10,"prix":500,"equipped":false},"ownership":{"default":0,"RiMAsQHaUMojde7N":3},"_stats":{"systemId":"fvtt-mournblade","systemVersion":"10.0.9","coreVersion":"10.286","createdTime":1664572964299,"modifiedTime":1664573659385,"lastModifiedBy":"1Hr6ON03ooIXzvIm"}}
|
||||
{"_id":"sHj90bPcMaDlOw51","name":"Bâton ferré ou lesté","type":"arme","img":"systems/fvtt-mournblade/assets/icons/arme.webp","effects":[],"folder":null,"sort":0,"flags":{"core":{"sourceId":"Item.zoBHSbvJPnjbtPh6"}},"system":{"description":"","typearme":"contact","isdefense":true,"bonusmaniementoff":1,"bonusmaniementdef":2,"degats":"1D8","nonletaux":true,"deuxmains":true,"courte":0,"moyenne":0,"longue":0,"tr":0,"rarete":0,"prix":1,"equipped":false},"ownership":{"default":0,"RiMAsQHaUMojde7N":3},"_stats":{"systemId":"fvtt-mournblade","systemVersion":"10.0.9","coreVersion":"10.286","createdTime":1664572964299,"modifiedTime":1664573659386,"lastModifiedBy":"1Hr6ON03ooIXzvIm"}}
|
||||
{"_id":"sju2r73hUHyGbHYg","name":"Épée courte / Glaive","type":"arme","img":"systems/fvtt-mournblade/assets/icons/arme.webp","effects":[],"folder":null,"sort":0,"flags":{"core":{"sourceId":"Item.Mxv5gMHRvRrsuhPA"}},"system":{"description":"","typearme":"contact","isdefense":true,"bonusmaniementoff":2,"bonusmaniementdef":1,"degats":"1D6+1","nonletaux":false,"deuxmains":false,"courte":0,"moyenne":0,"longue":0,"tr":0,"rarete":4,"prix":40,"equipped":false},"ownership":{"default":0,"RiMAsQHaUMojde7N":3},"_stats":{"systemId":"fvtt-mournblade","systemVersion":"10.0.9","coreVersion":"10.286","createdTime":1664572964300,"modifiedTime":1664573659386,"lastModifiedBy":"1Hr6ON03ooIXzvIm"}}
|
||||
{"_id":"t2uQcWe7kirUOp3D","name":"Faucheur","type":"arme","img":"systems/fvtt-mournblade/assets/icons/arme.webp","effects":[],"folder":null,"sort":0,"flags":{"core":{"sourceId":"Item.OlmzE29fh9DFd8TF"}},"system":{"description":"","typearme":"contact","isdefense":true,"bonusmaniementoff":2,"bonusmaniementdef":1,"degats":"1d4 + 1","nonletaux":false,"deuxmains":false,"courte":0,"moyenne":0,"longue":0,"tr":0,"rarete":7,"prix":100,"equipped":false},"ownership":{"default":0,"RiMAsQHaUMojde7N":3},"_stats":{"systemId":"fvtt-mournblade","systemVersion":"10.0.9","coreVersion":"10.286","createdTime":1664572964300,"modifiedTime":1664573659386,"lastModifiedBy":"1Hr6ON03ooIXzvIm"}}
|
||||
{"_id":"uatjBTFCE5ZCqhAd","name":"Fléau lourd","type":"arme","img":"systems/fvtt-mournblade/assets/icons/arme.webp","effects":[],"folder":null,"sort":0,"flags":{"core":{"sourceId":"Item.vDDw0qqM1Kg7Pu6T"}},"system":{"description":"","typearme":"contact","isdefense":true,"bonusmaniementoff":1,"bonusmaniementdef":0,"degats":"1d10+ 3","nonletaux":false,"deuxmains":true,"courte":0,"moyenne":0,"longue":0,"tr":0,"rarete":7,"prix":150,"equipped":false},"ownership":{"default":0,"RiMAsQHaUMojde7N":3},"_stats":{"systemId":"fvtt-mournblade","systemVersion":"10.0.9","coreVersion":"10.286","createdTime":1664572964300,"modifiedTime":1664573659387,"lastModifiedBy":"1Hr6ON03ooIXzvIm"}}
|
||||
{"_id":"v7ymzlEALvsk0poA","name":"Hache","type":"arme","img":"systems/fvtt-mournblade/assets/icons/arme.webp","effects":[],"folder":null,"sort":0,"flags":{"core":{"sourceId":"Item.2MwgptY2kE4tgYBe"}},"system":{"description":"","typearme":"contact","isdefense":true,"bonusmaniementoff":2,"bonusmaniementdef":0,"degats":"1d6 + 2","nonletaux":false,"deuxmains":false,"courte":0,"moyenne":0,"longue":0,"tr":0,"rarete":2,"prix":30,"equipped":false},"ownership":{"default":0,"RiMAsQHaUMojde7N":3},"_stats":{"systemId":"fvtt-mournblade","systemVersion":"10.0.9","coreVersion":"10.286","createdTime":1664572964300,"modifiedTime":1664573659388,"lastModifiedBy":"1Hr6ON03ooIXzvIm"}}
|
||||
{"_id":"wWk0Wfer06Ttmouv","name":"Épée large","type":"arme","img":"systems/fvtt-mournblade/assets/icons/arme.webp","effects":[],"folder":null,"sort":0,"flags":{"core":{"sourceId":"Item.iuAizxCvnUxmsjrn"}},"system":{"description":"","typearme":"contact","isdefense":true,"bonusmaniementoff":2,"bonusmaniementdef":1,"degats":"1d6+ 2","nonletaux":false,"deuxmains":false,"courte":0,"moyenne":0,"longue":0,"tr":0,"rarete":5,"prix":70,"equipped":false},"ownership":{"default":0,"RiMAsQHaUMojde7N":3},"_stats":{"systemId":"fvtt-mournblade","systemVersion":"10.0.9","coreVersion":"10.286","createdTime":1664572964300,"modifiedTime":1664573659386,"lastModifiedBy":"1Hr6ON03ooIXzvIm"}}
|
||||
{"_id":"wv5EiePmPTpqFutt","name":"Épée longue","type":"arme","img":"systems/fvtt-mournblade/assets/icons/arme.webp","effects":[],"folder":null,"sort":0,"flags":{"core":{"sourceId":"Item.yiYtZ0sCUpMihvzz"}},"system":{"description":"","typearme":"contact","isdefense":true,"bonusmaniementoff":2,"bonusmaniementdef":0,"degats":"2d6 + 1","nonletaux":false,"deuxmains":true,"courte":0,"moyenne":0,"longue":0,"tr":0,"rarete":8,"prix":250,"equipped":false},"ownership":{"default":0,"RiMAsQHaUMojde7N":3},"_stats":{"systemId":"fvtt-mournblade","systemVersion":"10.0.9","coreVersion":"10.286","createdTime":1664572964301,"modifiedTime":1664573659386,"lastModifiedBy":"1Hr6ON03ooIXzvIm"}}
|
||||
|
||||
BIN
packs/armes/000235.ldb
Normal file
0
packs/armes/000306.log
Normal file
1
packs/armes/CURRENT
Normal file
@@ -0,0 +1 @@
|
||||
MANIFEST-000304
|
||||
0
packs/armes/LOCK
Normal file
8
packs/armes/LOG
Normal file
@@ -0,0 +1,8 @@
|
||||
2026/01/09-16:51:34.709189 7f1c56bff6c0 Recovering log #302
|
||||
2026/01/09-16:51:34.720652 7f1c56bff6c0 Delete type=3 #300
|
||||
2026/01/09-16:51:34.720827 7f1c56bff6c0 Delete type=0 #302
|
||||
2026/01/09-17:10:52.171232 7f1c54bfb6c0 Level-0 table #307: started
|
||||
2026/01/09-17:10:52.171270 7f1c54bfb6c0 Level-0 table #307: 0 bytes OK
|
||||
2026/01/09-17:10:52.181182 7f1c54bfb6c0 Delete type=0 #305
|
||||
2026/01/09-17:10:52.181380 7f1c54bfb6c0 Manual compaction at level-0 from '!items!0swiE8k5zfUIqmXu' @ 72057594037927935 : 1 .. '!items!wv5EiePmPTpqFutt' @ 0 : 0; will stop at (end)
|
||||
2026/01/09-17:10:52.181415 7f1c54bfb6c0 Manual compaction at level-1 from '!items!0swiE8k5zfUIqmXu' @ 72057594037927935 : 1 .. '!items!wv5EiePmPTpqFutt' @ 0 : 0; will stop at (end)
|
||||
8
packs/armes/LOG.old
Normal file
@@ -0,0 +1,8 @@
|
||||
2026/01/09-16:50:28.487537 7f1c56bff6c0 Recovering log #298
|
||||
2026/01/09-16:50:28.498450 7f1c56bff6c0 Delete type=3 #296
|
||||
2026/01/09-16:50:28.498515 7f1c56bff6c0 Delete type=0 #298
|
||||
2026/01/09-16:51:28.840653 7f1c54bfb6c0 Level-0 table #303: started
|
||||
2026/01/09-16:51:28.840708 7f1c54bfb6c0 Level-0 table #303: 0 bytes OK
|
||||
2026/01/09-16:51:28.847927 7f1c54bfb6c0 Delete type=0 #301
|
||||
2026/01/09-16:51:28.868475 7f1c54bfb6c0 Manual compaction at level-0 from '!items!0swiE8k5zfUIqmXu' @ 72057594037927935 : 1 .. '!items!wv5EiePmPTpqFutt' @ 0 : 0; will stop at (end)
|
||||
2026/01/09-16:51:28.868551 7f1c54bfb6c0 Manual compaction at level-1 from '!items!0swiE8k5zfUIqmXu' @ 72057594037927935 : 1 .. '!items!wv5EiePmPTpqFutt' @ 0 : 0; will stop at (end)
|
||||
BIN
packs/armes/MANIFEST-000304
Normal file
30
packs/dons.db
Normal file
@@ -0,0 +1,30 @@
|
||||
{"name":"Protection du Sorcier","type":"don","img":"systems/fvtt-mournblade/assets/icons/don.webp","data":{"description":"<p>L’Élu est protégé contre les attaques des créatures nées ou invoquées par la sorcellerie (un type d’Élémentaire, les Démons, les Automata…). La protection dont il bénéficie dépend du nombre de points d’Âme sacrifiés.</p>","allegeance":"chaos","prerequis":"6 ou plus en Trempe.","sacrifice":"<ul>\n<li>1 point d’Âme pour 1 point de protection. Accès réservé aux Novices et aux Adeptes.</li>\n<li>2 points d’Âme pour 2 points de protection. Accès réservé aux Chevaliers et aux Hérauts.</li>\n<li>3 points d’Âme pour un 3 points de protection. Accès réservé aux Champions.</li>\n</ul>"},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"RiMAsQHaUMojde7N":3},"flags":{"core":{"sourceId":"Item.WUPne9oDFTcdLtW9"}},"_id":"5dGXNiL3WN4cAk7X"}
|
||||
{"name":"Conscience extraplanaire","type":"don","img":"systems/fvtt-mournblade/assets/icons/don.webp","data":{"description":"<p>L’Élu a conscience du tissu de la réalité. Il peut percevoir les passages et les portails menant vers d’autres plans dans une zone de 10 mètres par point d’Aspect chaotique grâce à un simple test de Clairvoyance + Perception / 15. S’il ignore l’existence de ce passage et qu’il passe devant, le MJ peut faire un test de Clairvoyance + Perception / 25 pour l’Élu derrière son écran.</p>","allegeance":"chaos","prerequis":"6 ou plus en Clairvoyance.","sacrifice":"<p>1 point d’Âme.</p>"},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"RiMAsQHaUMojde7N":3},"flags":{"core":{"sourceId":"Item.1nIGWsNtx1NKxjPn"}},"_id":"5v0Y35LzqfAd0KnX"}
|
||||
{"name":"Santé renforcée (Loi)","type":"don","img":"systems/fvtt-mournblade/assets/icons/don.webp","data":{"description":"<p>Les points de Santé de l’Élu sont recalculés en ajoutant à [(Puissance + Trempe) x 2]+ 5 le nombre de points d’Âme sacrifiés. Ce Don ne peut être pris qu’une seule fois même si l’Élu conclut plusieurs Pactes.</p>","allegeance":"loi","prerequis":"6 ou plus en Trempe.","sacrifice":"<p>1 point d’Âme par point de Santé supplémentaire, pour un maximum égal à l’Aspect du personnage.</p>"},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"RiMAsQHaUMojde7N":3},"flags":{"core":{"sourceId":"Item.4ow7N6kdAWXbTApf"}},"_id":"6IS4zstVwJxG2lwy"}
|
||||
{"name":"Repos de l’Âme","type":"don","img":"systems/fvtt-mournblade/assets/icons/don.webp","data":{"description":"<p>L’Élu récupère deux fois plus vite ses points d’Âme, soit 2 par heure et 4 en cas de repos.</p>","allegeance":"chaos","prerequis":"6 ou plus en Présence.","sacrifice":"<p>3 points d’Âme.</p>"},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"RiMAsQHaUMojde7N":3},"flags":{"core":{"sourceId":"Item.KXciI0xwd6gSOLcZ"}},"_id":"8WLUjxBJtd33mZFp"}
|
||||
{"name":"Trait chaotique","type":"don","img":"systems/fvtt-mournblade/assets/icons/don.webp","data":{"description":"<p>L’Élu gagne un trait du Chaos qu’il tire au hasard dans le tableau de la page 185 avec un d20. Il peut prendre ce Don trois fois. S’il tire un trait qu’il possède déjà, il doit relancer le d20. Ces traits sont permanents et définitifs, à moins que les Seigneurs du Chaos n’en décident autrement, notamment si l’Élu les dissimule trop à leur goût alors qu’il n’y est pas absolument contraint par des impératifs de survie immédiats.</p>","allegeance":"chaos","prerequis":"aucun","sacrifice":"<p>2 points d’Âme par Trait chaotique. L’Élu ne peut en avoir plus que sa Marge.</p>"},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"RiMAsQHaUMojde7N":3},"flags":{"core":{"sourceId":"Item.BKzeOjGA13wQgO0S"}},"_id":"BuZM5BnSaPIGEiEq"}
|
||||
{"name":"Guérison","type":"don","img":"systems/fvtt-mournblade/assets/icons/don.webp","data":{"description":"<p>L’Élu régénère rapidement. Chaque jour de repos, il regagne un nombre de points de Santé égal à sa Trempe /2 + son Aspect.</p>","allegeance":"loi","prerequis":"6 ou plus en Trempe.","sacrifice":"<p>3 point d’Âme.</p>"},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"RiMAsQHaUMojde7N":3},"flags":{"core":{"sourceId":"Item.yvY0G3PffZWEl92R"}},"_id":"Eme2iVAF670LCeIH"}
|
||||
{"name":"Aide Élémentaire","type":"don","img":"systems/fvtt-mournblade/assets/icons/don.webp","data":{"description":"<p>Ce Don permet d’appeler un Élémentaire à son secours une fois par scénario. La Puissance de l’Élémentaire est fi xée lors de l’octroi du Don. La nature de l’Élémentaire correspond à celle du Seigneur Élémentaire avec lequel le Pacte a été passé. Ce Don ne peut être pris qu’une fois par Seigneur Élémentaire vénéré.</p>","allegeance":"elementaires","prerequis":"","sacrifice":"<ul>\n<li>1 point d’Âme pour un Élémentaire mineur disposant de 5 points d’Âme. Accès réservé aux Novices et aux Adeptes.</li>\n<li>3 points d’Âme pour un Élémentaire médian disposant de 10 points d’Âme. Accès réservé aux Chevaliers et aux Hérauts.</li>\n<li>5 points d’Âme pour un Élémentaire majeur disposant de 15 points d’Âme. Accès réservé aux Champions.</li>\n</ul>"},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"RiMAsQHaUMojde7N":3},"flags":{"core":{"sourceId":"Item.Wo42z8L33wLerUM8"}},"_id":"JAkSopwrh4QmKrPY"}
|
||||
{"name":"Augmentation du modificateur de dégâts","type":"don","img":"systems/fvtt-mournblade/assets/icons/don.webp","data":{"description":"<p>Les dégâts causés par l’Élu bénéficient d’un bonus pour <em>un type d’armes donné</em>. Le bonus dépend du nombre de points d’Âme sacrifiés.</p>","allegeance":"loi","prerequis":"6 ou plus en Puissance.","sacrifice":"<ul>\n<li>1 point d’Âme pour un bonus de + 1. Accès réservé aux Novices et aux Adeptes.</li>\n<li>3 points d’Âme pour un bonus de + 2. Accès réservé aux Chevaliers et aux Hérauts.</li>\n<li>5 points d’Âme pour un bonus de + 3. Accès réservé aux Champions.</li>\n</ul>"},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"RiMAsQHaUMojde7N":3},"flags":{"core":{"sourceId":"Item.bqdkbOf7EsdsCRqu"}},"_id":"K4H2VC0jTCy7pYj7"}
|
||||
{"name":"L’exemple du Juste","type":"don","img":"systems/fvtt-mournblade/assets/icons/don.webp","data":{"description":"<p>L’Élu est un exemple rayonnant pour ses camarades. Une fois par scénario, si l’Élu adresse pendant un tour de jeu une prière à une divinité de la Loi, lui et ses camarades (une dizaine tout au plus) seront bénis et recevront jusqu’à la fin de la scène un bonus à toutes leurs actions.</p>","allegeance":"loi","prerequis":"6 ou plus en Trempe.","sacrifice":"<ul>\n<li>1 point d’Âme pour un bonus de + 1. Accès réservé aux Novices et aux Adeptes.</li>\n<li>2 points d’Âme pour un bonus de + 2. Accès réservé aux Chevaliers et aux Hérauts.</li>\n<li>3 points d’Âme pour un bonus de + 3. Accès réservé aux Champions. </li>\n</ul>"},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"RiMAsQHaUMojde7N":3},"flags":{"core":{"sourceId":"Item.C5ofSFNXoXZFo8ak"}},"_id":"KlfScJjqvlPtkcdZ"}
|
||||
{"name":"Abstinence","type":"don","img":"systems/fvtt-mournblade/assets/icons/don.webp","data":{"description":"<p>L’Élu peut survivre en se privant d’un élément vital (nourriture, eau, sommeil, mais pas air) pendant un certain temps. La durée de ce pouvoir dépend du nombre de points d’Âme sacrifiés.</p>","allegeance":"tous","prerequis":"6 ou plus en Trempe","sacrifice":"<ul>\n<li>2 points d’Âme pour un jour. Accès réservé aux Novices et aux Adeptes.</li>\n<li>6 points d’Âme pour une semaine. Accès réservé aux Che\u0002valiers et aux Hérauts.</li>\n<li>10 points d’Âme pour un mois. Accès réservé aux Cham\u0002pions.</li>\n</ul>"},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"RiMAsQHaUMojde7N":3},"flags":{"core":{"sourceId":"Item.Q4Sy7vOGgU7Zgi9p"}},"_id":"OJKMNtFsuVgkV3gh"}
|
||||
{"name":"Rupture Chaotique","type":"don","img":"systems/fvtt-mournblade/assets/icons/don.webp","data":{"description":"<p>Lorsque l’Élu manie un certain type d’armes, il peut ajouter un bonus à son initiative ou bénéficier d’un bonus aux dégâts lors d’un combat, une fois par séance de jeu.</p>","allegeance":"chaos","prerequis":"6 ou plus en Puissance.","sacrifice":"<ul>\n<li>1 point d’Âme pour un bonus de + 1 aux dégâts ou + 5 en initiative. Accès réservé aux Novices et aux Adeptes.</li>\n<li>3 points d’Âme pour un bonus de + 2 aux dégâts ou + 7 en initiative. Accès réservé aux Chevaliers et aux Hérauts.</li>\n<li>5 points d’Âme pour un bonus de + 3 aux dégâts ou + 10 en initiative. Accès réservé aux Champions.</li>\n</ul>"},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"RiMAsQHaUMojde7N":3},"flags":{"core":{"sourceId":"Item.gMI6F4qY5Fi6okZ7"}},"_id":"Q1xDyjQy59lr5wAG"}
|
||||
{"name":"Sens du Pur","type":"don","img":"systems/fvtt-mournblade/assets/icons/don.webp","data":{"description":"<p>L’Élu a immédiatement conscience de la présence passée ou actuelle du Chaos (sortilège à l’œuvre, puissant serviteur…). Le personnage est très sensible aux émanations chaotiques, elles lui soulèvent le cœur. La distance de détection peut aug\u0002menter en sacrifiant davantage de points d’Âme</p>","allegeance":"loi","prerequis":"6 ou plus en Adresse ou Clairvoyance.","sacrifice":"<ul>\n<li>1 point d’Âme pour détecter les ennemis dans un rayon de 10 mètres. Accès réservé aux Novices et aux Adeptes.</li>\n<li>2 points d’Âme pour détecter les ennemis dans un rayon de 100 mètres. Accès réservé aux Chevaliers et aux Hérauts.</li>\n<li>3 points d’Âme pour détecter les ennemis dans un rayon de 1000 mètres. Accès réservé aux Champions.</li>\n</ul>"},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"RiMAsQHaUMojde7N":3},"flags":{"core":{"sourceId":"Item.tp2435vHrj63GeAK"}},"_id":"RYgdBIikcBfN8xAp"}
|
||||
{"name":"Gardien des Millions de Sphères","type":"don","img":"systems/fvtt-mournblade/assets/icons/don.webp","data":{"description":"<p>L’Élu a conscience du tissu de la réalité. Il peut sceller, par de longues prières psalmodiées, les passages et les portails donnant sur d’autres plans du Multivers. Cette action lui coûte le sacrifice d’un point d’Éclat. Tant que sa concentration reste tournée vers ce passage, le portail demeure scellé, comme si Donblas lui-même le gardait. Mais dès que le personnage s’endort, la porte, bien que fermée, n’est plus scellée. Certains plans très importants possèdent plusieurs passages menant vers les Jeunes Royaumes.</p>","allegeance":"loi","prerequis":"6 ou plus en Clairvoyance.","sacrifice":"<p>5 points d’Âme.</p>"},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"RiMAsQHaUMojde7N":3},"flags":{"core":{"sourceId":"Item.tm1fjaETqhMAldqJ"}},"_id":"TKCaHLHccYw7JvFy"}
|
||||
{"name":"Vivacité","type":"don","img":"systems/fvtt-mournblade/assets/icons/don.webp","data":{"description":"<p>Lors d’un test de Capacité Offensive, l’Élu voit la marge nécessaire à l’obtention d’une réussite héroïque diminuer de 1 (9 ou plus), de 2 (8 ou plus) ou de 3 (7 ou plus). </p>","allegeance":"tous","prerequis":"6 ou plus en Adresse ou Clairvoyance.","sacrifice":"<ul>\n<li>3 points d’Âme pour diminuer la marge de 1 (réussite héroïque sur 9 ou plus). Accès réservé aux Novices et aux Adeptes.</li>\n<li>5 points d’Âme pour diminuer la marge de 2 (réussite héroïque sur 8 ou plus). Accès réservé aux Chevaliers et aux Hérauts.</li>\n<li>7 points d’Âme pour diminuer la marge de 3 (réussite héroïque sur 7 ou plus). Accès réservé aux Champions.</li>\n</ul>"},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"RiMAsQHaUMojde7N":3},"flags":{"core":{"sourceId":"Item.GlhqSASDW0XdR243"}},"_id":"XaJAo8otOXmgtjzA"}
|
||||
{"name":"Augmentation de compétence (Chaos)","type":"don","img":"systems/fvtt-mournblade/assets/icons/don.webp","data":{"description":"<p>Ce Don permet d’augmenter une compétence importante pour la voie spirituelle choisie. Le bonus octroyé dépend du nombre de points d’Âme sacrifi és. Ce Don peut être choisi plusieurs fois, mais il ne peut s’appliquer qu’une fois par compétence. </p>","allegeance":"chaos","prerequis":"6 ou plus en Clairvoyance.","sacrifice":"<ul>\n<li>1 point d’Âme pour un + 1 à une compétence. Accès réservé aux Novices et aux Adeptes.</li>\n<li>2 points d’Âme pour un + 2 à une compétence. Accès réservé aux Chevaliers et aux Hérauts.</li>\n<li>3 points d’Âme pour un + 3 à une compétence. Accès réservé aux Champions.</li>\n</ul>"},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"RiMAsQHaUMojde7N":3},"flags":{"core":{"sourceId":"Item.75OYBq5iGgdXVQcA"}},"_id":"aP4vSk6WOL4wXyyb"}
|
||||
{"name":"Dur à cuire","type":"don","img":"systems/fvtt-mournblade/assets/icons/don.webp","data":{"description":"<p>L’Élu résiste aux effets liés à la fatigue et à la maladie. Le béné\u0002fi ciaire de ce Don a droit à un bonus de + 1 lors de ses tests de Trempe pour résister à la fatigue et à la maladie. Ce bonus peut augmenter en sacrifi ant davantage de points d’Âme.</p>","allegeance":"tous","prerequis":"6 ou plus en Trempe.","sacrifice":"<ul>\n<li>1 point d’Âme pour un bonus de + 2. Accès réservé aux Novices et aux Adeptes.</li>\n<li>2 points d’Âme pour un bonus de + 3. Accès réservé aux Chevaliers et aux Hérauts.</li>\n<li>3 points d’Âme pour un bonus de + 4. Accès réservé aux Champions.</li>\n</ul>"},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"RiMAsQHaUMojde7N":3},"flags":{"core":{"sourceId":"Item.jNeLj9DyylUj7LAl"}},"_id":"gK3glTgKTKRw9ref"}
|
||||
{"name":"Animal apprivoisé","type":"don","img":"systems/fvtt-mournblade/assets/icons/don.webp","data":{"description":"<p>Le croyant se voit confier un animal normal (c’est-à-dire non surnaturel). L’animal apprivoisé est un membre standard de son espèce et obéit à des ordres simples, mais sans jamais aller contre sa nature. Le coût de ce Don dépend de la Puissance de la créature qui est fixée lors de son octroi. Si 1 point d’Âme supplémentaire est investi, la créature peut communiquer télé\u0002pathiquement avec son maître (et uniquement avec lui).</p>","allegeance":"betes","prerequis":"6 ou plus en Présence.","sacrifice":"<ul>\n<li>1 point d’Âme pour une créature d’une Puissance de 0 à 4. Accès réservé aux Novices et aux Adeptes.</li>\n<li>3 points d’Âme pour une créature d’une Puissance de 5 à 7. Accès réservé aux Chevaliers et aux Hérauts.</li>\n<li>5 points d’Âme pour une créature d’une Puissance de 8 à 10. Accès réservé aux Champions.</li>\n</ul>"},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"RiMAsQHaUMojde7N":3},"flags":{"core":{"sourceId":"Item.qDUei4wRjpRYi9Ps"}},"_id":"gN7DtvMJPASpPpQl"}
|
||||
{"name":"Protection du Mage","type":"don","img":"systems/fvtt-mournblade/assets/icons/don.webp","data":{"description":"<p>L’Élu est protégé contre les attaques des créatures engendrées ou invoquées par la Sorcellerie (les Élémentaires, les Démons, les Automata…). La protection dont il bénéficie dépend du nombre de points d’Âme sacrifiés.</p>","allegeance":"loi","prerequis":"6 ou plus en Trempe.","sacrifice":"<ul>\n<li>1 point d’Âme pour 1 point de protection. Accès réservé aux Novices et aux Adeptes.</li>\n<li>2 points d’Âme pour 2 points de protection. Accès réservé aux Chevaliers et aux Hérauts.</li>\n<li>3 points d’Âme pour un 3 points de protection. Accès réservé aux Champions.</li>\n</ul>"},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"RiMAsQHaUMojde7N":3},"flags":{"core":{"sourceId":"Item.NVIG52HOiWGm6JcW"}},"_id":"j7iTQOFdiJUviTC9"}
|
||||
{"name":"Sang-Froid","type":"don","img":"systems/fvtt-mournblade/assets/icons/don.webp","data":{"description":"<p>L’Élu peut supporter n’importe quel type de souffrance psy\u0002chique. Il ne subit pas les pénalités dues à l’état Déstabilisé (– 2) et Choqué (– 5). Il est immunisé à la torture mentale.</p>","allegeance":"chaos","prerequis":"6 ou plus en Trempe.","sacrifice":"<p>1 point d’Âme.</p>"},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"RiMAsQHaUMojde7N":3},"flags":{"core":{"sourceId":"Item.KvdQLDhSpfAd2Iig"}},"_id":"lWXxInM05EiBu6uX"}
|
||||
{"name":"Dur à cuire (Chaos)","type":"don","img":"systems/fvtt-mournblade/assets/icons/don.webp","data":{"description":"<p>L’Élu résiste aux effets liés à la fatigue et à la maladie. Le bénéfi ciaire de ce Don a droit à un bonus de + 1 lors de ses tests de Trempe pour résister à la fatigue et à la maladie. Ce bonus peut augmenter en sacrifi ant davantage de points d’Âme.</p>","allegeance":"chaos","prerequis":"6 ou plus en Trempe.","sacrifice":"<ul>\n<li>1 point d’Âme pour un bonus de + 1. Accès réservé aux Novices et aux Adeptes.</li>\n<li>2 points d’Âme pour un bonus de + 2. Accès réservé aux Chevaliers et aux Hérauts.</li>\n<li>3 points d’Âme pour un bonus de + 3.Accès réservé aux Champions.</li>\n</ul>"},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"RiMAsQHaUMojde7N":3},"flags":{"core":{"sourceId":"Item.E0kyJQ5gqCEcm0Aj"}},"_id":"oAKqbsLVd8cX4tjN"}
|
||||
{"name":"Augmentation de compétence","type":"don","img":"systems/fvtt-mournblade/assets/icons/don.webp","data":{"description":"<p>Ce Don permet d’augmenter une compétence relative à la voie spirituelle choisie. Le bonus octroyé dépend du nombre de points d’Âme sacrifi és. Ce Don peut être choisi plusieurs fois, mais il ne peut s’appliquer qu’une fois par compétence. </p>","allegeance":"tous","prerequis":"6 ou plus en Clairvoyance.","sacrifice":"<ul>\n<li>1 point d’Âme pour un + 1 à une compétence. Accès réservé aux Novices et aux Adeptes.</li>\n<li>2 points d’Âme pour un + 2 à une compétence. Accès réservé aux Chevaliers et aux Hérauts.</li>\n<li>3 points d’Âme pour un + 3 à une compétence. Accès réservé aux Champions.</li>\n</ul>"},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"RiMAsQHaUMojde7N":3},"flags":{"core":{"sourceId":"Item.djDFklKJaW1oVTds"}},"_id":"pPNKneH7scfaEmGq"}
|
||||
{"name":"Augmentation de compétence (Loi)","type":"don","img":"systems/fvtt-mournblade/assets/icons/don.webp","data":{"description":"<p>Ce Don permet d’augmenter une compétence importante pour la voie spirituelle choisie. Le bonus octroyé dépend du nombre de points d’Âme sacrifiés. Ce Don peut être choisi plusieurs fois mais il ne peut s’appliquer qu’une fois par compétence.</p>","allegeance":"loi","prerequis":"6 ou plus en Clairvoyance.","sacrifice":"<ul>\n<li>1 point d’Âme pour un + 1 à une compétence. Accès réservé aux Novices et aux Adeptes.</li>\n<li>2 points d’Âme pour un + 2 à une compétence. Accès réservé aux Chevaliers et aux Hérauts.</li>\n<li>3 points d’Âme pour un + 3 à une compétence. Accès réservé aux Champions.</li>\n</ul>"},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"RiMAsQHaUMojde7N":3},"flags":{"core":{"sourceId":"Item.gNL9lD7hofK32H7D"}},"_id":"qhOE8OTe5hNNgDtt"}
|
||||
{"name":"Santé renforcée","type":"don","img":"systems/fvtt-mournblade/assets/icons/don.webp","data":{"description":"<p>Les points de Santé de l’Élu sont recalculés en ajoutant à [(Puissance + Trempe) x 2]+ 5 le nombre de points d’Âme sacrifiés. Ce Don ne peut être pris qu’une seule fois même si l’Élu conclut plusieurs Pactes.</p>","allegeance":"tous","prerequis":"6 ou plus en Trempe.","sacrifice":"<p>1 point d’Âme par point de Santé supplémentaire.</p>"},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"RiMAsQHaUMojde7N":3},"flags":{"core":{"sourceId":"Item.dJnYsDcETkidd2s5"}},"_id":"sLgGn6zhkDdbpQlH"}
|
||||
{"name":"Rectitude","type":"don","img":"systems/fvtt-mournblade/assets/icons/don.webp","data":{"description":"<p>L’Élu peut supporter n’importe quel type de souffrance. Il ne subit pas les pénalités dues à l’état Blessé (-2) et Gravement Blessé (-5). Il est immunisé contre la torture.</p>","allegeance":"loi","prerequis":"6 ou plus en Trempe.","sacrifice":"<p>1 point d’Âme.</p>"},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"RiMAsQHaUMojde7N":3},"flags":{"core":{"sourceId":"Item.HpoTP9idEKi1NQGL"}},"_id":"t7Ez0rzqYOf48GfY"}
|
||||
{"name":"La voie du milieu","type":"don","img":"systems/fvtt-mournblade/assets/icons/don.webp","data":{"description":"<p>Lors d’un combat, l’Élu ne subit plus les effets d’une réussite héroïque contre lui lors des tests de Capacité offensive. Il n’en profite plus non plus. À un haut niveau, il ne peut plus être affecté par les échecs dramatiques.</p>","allegeance":"loi","prerequis":"6 ou plus en Adresse ou Clairvoyance.","sacrifice":"<ul>\n<li>3 points d’Âme pour ne plus être affecté par les réussite héroïques.</li>\n<li>7 points d’Âme pour ne plus être affecté ni par les réus\u0002sites héroïques ni par les échecs dramatiques. Accès réser\u0002vé aux Champions</li>\n</ul>"},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"RiMAsQHaUMojde7N":3},"flags":{"core":{"sourceId":"Item.rOXDZ2020snvhtR2"}},"_id":"taXCPXiPEuOIKaUO"}
|
||||
{"name":"Perfection","type":"don","img":"systems/fvtt-mournblade/assets/icons/don.webp","data":{"description":"<p>L’un des attributs de l’Élu est augmenté, grâce à la bienveil\u0002lance de la divinité. Il ne peut dépasser le maximum imposé par l’espèce. Ce Don peut être choisi plusieurs fois, mais il ne peut s’appliquer qu’une fois par attribut.</p>","allegeance":"tous","prerequis":"6 ou plus dans l’attribut modifié.","sacrifice":"<ul>\n<li>3 points d’Âme pour un bonus de + 1. Accès réservé aux Novices et aux Adeptes.</li>\n<li>6 points d’Âme pour un bonus de + 2. Accès réservé aux Chevaliers et aux Hérauts.</li>\n<li>9 points d’Âme pour un bonus de + 3. Accès réservé aux Champions.</li>\n</ul>"},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"RiMAsQHaUMojde7N":3},"flags":{"core":{"sourceId":"Item.nSlFw6q7TCqxZ6tH"}},"_id":"vZBNRTeGGU5hsXtT"}
|
||||
{"name":"Sixième sens","type":"don","img":"systems/fvtt-mournblade/assets/icons/don.webp","data":{"description":"<p>L’Élu sait où se trouvent des ennemis dont il a conscience et qui cherchent à lui nuire directement dans un rayon de 10 mètres. Attention, cette détection ne fonctionnera pas pour deviner que quelqu’un est simplement hostile à l’Élu ou le hait viscéralement. Il s’agit d’un pouvoir de localisation et de vigilance. La distance de détection peut augmenter en sacrifiant davantage de points d’Âme.</p>","allegeance":"chaos","prerequis":"6 ou plus en Adresse ou Clairvoyance.","sacrifice":"<ul>\n<li>1 point d’Âme pour détecter les ennemis dans un rayon de 10 mètres. Accès réservé aux Novices et aux Adeptes.</li>\n<li>2 points d’Âme pour détecter les ennemis dans un rayon de 100 mètres. Accès réservé aux Chevaliers et aux Hérauts.</li>\n<li>3 points d’Âme pour détecter les ennemis dans un rayon de 1000 mètres. Accès réservé aux Champions.</li>\n</ul>"},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"RiMAsQHaUMojde7N":3},"flags":{"core":{"sourceId":"Item.6CIPAVjSVsOqZBYc"}},"_id":"wsbGuOoFjHO6aQEm"}
|
||||
{"name":"Endurance","type":"don","img":"systems/fvtt-mournblade/assets/icons/don.webp","data":{"description":"<p>L’Élu peut supporter n’importe quel type de souffrance. Il ne subit pas les pénalités dues à l’état Blessé (-2) et Gravement Blessé (-5). Il est immunisé à la torture si elle est infl igée à partir d’un des éléments tutélaires du personnage.</p>","allegeance":"elementaires","prerequis":"6 ou plus en Trempe.","sacrifice":"<p>3 points d’Âme.</p>"},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"RiMAsQHaUMojde7N":3},"flags":{"core":{"sourceId":"Item.on94N7pylXJ8gtdF"}},"_id":"yJ6K9dYrdNxr5uWj"}
|
||||
{"name":"Le pilier de la Loi","type":"don","img":"systems/fvtt-mournblade/assets/icons/don.webp","data":{"description":"<p>Une fois par scénario, l’Élu peut résister à une menace ou agres\u0002sion, physique ou mentale, sans jeter les dés. Il est toutefois néces\u0002saire que l’Élu ait conscience du danger. L’Élu pourra par exemple résister à la terreur provoquée par une créature du Chaos parti\u0002culièrement abominable ou légendaire, mais ne pourra pas éviter d’être assommé par un habile voleur de Bakshaan qu’il n’avait pas vu. Cette résistance peut même être « extraordinaire » si l’Aspect de l’Élu est très haut.</p>\n<p>S’il est un Adepte ou un Novice, l’Élu peut résister à l’ivresse lors d’une nuit de beuverie chez un Prince-Marchand de Bakshaan.</p>\n<p>S’il est un Chevalier ou un Héraut, l’Élu peut résister à un coup surpuissant (celui-ci est annulé) ou à l’apparition gla\u0002çante d’un Démon. S’il est un Champion, il peut par exemple soutenir l’arche d’un temple qui s’écroule pendant quelques précieuses secondes afi n de laisser le temps à ses camarades de se mettre à l’abri (songez à Maciste, à Samson, ou tout simplement à Conan). Bref, n’hésitez pas à faire dans l’extraordinaire, mais ne bas\u0002culez pas dans le grosbillisme sans limite (ou alors ne nous le dites pas). Il revient au MJ de doser avec justesse ce Don.</p>","allegeance":"loi","prerequis":"7 ou plus en Trempe","sacrifice":"<p>3 points d’Âme.</p>"},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"RiMAsQHaUMojde7N":3},"flags":{"core":{"sourceId":"Item.yZ84qzrGeIDfZXr1"}},"_id":"zef3VQat06Ronc5W"}
|
||||
{"name":"Œil exercé","type":"don","img":"systems/fvtt-mournblade/assets/icons/don.webp","data":{"description":"<p>L’Élu reçoit de la divinité qu’il vénère l’équivalent d’une Prédilection dans la Capacité spéciale Œil du sorcier (voir p. 199). Une fois par séance, il peut donc relancer le test de Clairvoyance + Perception.</p>","allegeance":"chaos","prerequis":"6 ou plus en Clairvoyance.","sacrifice":"<p>2 points d’Âme.</p>"},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"RiMAsQHaUMojde7N":3},"flags":{"core":{"sourceId":"Item.9Xrm1cfrCmkRtOBc"}},"_id":"zzz9JrtWjELdoAfK"}
|
||||
BIN
packs/dons/000234.ldb
Normal file
0
packs/dons/000305.log
Normal file
1
packs/dons/CURRENT
Normal file
@@ -0,0 +1 @@
|
||||
MANIFEST-000303
|
||||
0
packs/dons/LOCK
Normal file
8
packs/dons/LOG
Normal file
@@ -0,0 +1,8 @@
|
||||
2026/01/09-16:51:34.750271 7f1c55bfd6c0 Recovering log #301
|
||||
2026/01/09-16:51:34.760726 7f1c55bfd6c0 Delete type=3 #299
|
||||
2026/01/09-16:51:34.760813 7f1c55bfd6c0 Delete type=0 #301
|
||||
2026/01/09-17:10:52.202603 7f1c54bfb6c0 Level-0 table #306: started
|
||||
2026/01/09-17:10:52.202692 7f1c54bfb6c0 Level-0 table #306: 0 bytes OK
|
||||
2026/01/09-17:10:52.216180 7f1c54bfb6c0 Delete type=0 #304
|
||||
2026/01/09-17:10:52.229242 7f1c54bfb6c0 Manual compaction at level-0 from '!items!5dGXNiL3WN4cAk7X' @ 72057594037927935 : 1 .. '!items!zzz9JrtWjELdoAfK' @ 0 : 0; will stop at (end)
|
||||
2026/01/09-17:10:52.229348 7f1c54bfb6c0 Manual compaction at level-1 from '!items!5dGXNiL3WN4cAk7X' @ 72057594037927935 : 1 .. '!items!zzz9JrtWjELdoAfK' @ 0 : 0; will stop at (end)
|
||||
8
packs/dons/LOG.old
Normal file
@@ -0,0 +1,8 @@
|
||||
2026/01/09-16:50:28.529034 7f1c56bff6c0 Recovering log #297
|
||||
2026/01/09-16:50:28.539837 7f1c56bff6c0 Delete type=3 #295
|
||||
2026/01/09-16:50:28.539910 7f1c56bff6c0 Delete type=0 #297
|
||||
2026/01/09-16:51:28.861880 7f1c54bfb6c0 Level-0 table #302: started
|
||||
2026/01/09-16:51:28.861911 7f1c54bfb6c0 Level-0 table #302: 0 bytes OK
|
||||
2026/01/09-16:51:28.868272 7f1c54bfb6c0 Delete type=0 #300
|
||||
2026/01/09-16:51:28.868530 7f1c54bfb6c0 Manual compaction at level-0 from '!items!5dGXNiL3WN4cAk7X' @ 72057594037927935 : 1 .. '!items!zzz9JrtWjELdoAfK' @ 0 : 0; will stop at (end)
|
||||
2026/01/09-16:51:28.868572 7f1c54bfb6c0 Manual compaction at level-1 from '!items!5dGXNiL3WN4cAk7X' @ 72057594037927935 : 1 .. '!items!zzz9JrtWjELdoAfK' @ 0 : 0; will stop at (end)
|
||||