Compare commits

...

19 Commits

Author SHA1 Message Date
ca33defd75 Update v11 2023-06-23 09:02:45 +02:00
2e616e3e31 Update v11 2023-06-23 08:37:56 +02:00
3be7f4bf9f Update v11 2023-06-23 08:37:50 +02:00
1b8e0840b0 Update v11 2023-06-22 23:05:50 +02:00
2cdd096c98 Update v11 2023-06-22 23:05:36 +02:00
8fcb17b566 Update v11 2023-06-22 23:05:04 +02:00
ad79dbb015 New combat options 2023-06-22 20:36:40 +02:00
73ccf44dd4 New combat options 2023-06-22 20:34:17 +02:00
ec3649799f v10/v11 compat 2023-05-25 16:29:43 +02:00
3f5f090bb9 Points de creation OK again 2023-05-24 14:00:24 +02:00
268ac0a25a Review initiative 2023-05-01 18:50:32 +02:00
59ee6684ab Fix #19 - Horoscope majeur 2023-04-29 21:48:51 +02:00
41fbc094bb Combat Tracker + power enhancements 2023-04-06 20:15:04 +02:00
5b91041a3f Fix options de combat 2023-04-04 13:41:22 +02:00
e7f3851daa Fix dice default 2023-03-29 23:04:02 +02:00
75d562f922 Nouvelle option d'ignorer les dommages 2023-03-25 08:42:14 +01:00
ba7e25e8c7 Fix and +/- 2023-03-18 13:51:46 +01:00
83d3f17dd0 Messages de recuperation 2023-03-18 10:24:30 +01:00
0c502a2188 Meilleure gestion initiative 2023-03-15 17:35:07 +01:00
31 changed files with 682 additions and 415 deletions

109
.gitignore vendored
View File

@ -1,108 +1 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
package-lock.json
# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
*.lcov
# nyc test coverage
.nyc_output
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# TypeScript v1 declaration files
typings/
# TypeScript cache
*.tsbuildinfo
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
.env.test
# parcel-bundler cache (https://parceljs.org/)
.cache
# Next.js build output
.next
# Nuxt.js build / generate output
.nuxt
dist
# Gatsby files
.cache/
# Comment in the public line in if your project uses Gatsby and *not* Next.js
# https://nextjs.org/blog/next-9-1#public-directory-support
# public
# vuepress build output
.vuepress/dist
# Serverless directories
.serverless/
# FuseBox cache
.fusebox/
# DynamoDB Local files
.dynamodb/
# TernJS port file
.tern-port
# BOL Data
#/data/
.history/

View File

@ -1044,9 +1044,18 @@ body.system-bol img#logo {
justify-content: flex-start;
flex-direction: column;
position: absolute;
top: 2.75rem;
/*transform: translate(0, -30%);*/
top: -4rem;
max-width: 250px;
left: 4rem;
}
.tokenhudext.right2 {
justify-content: flex-start;
flex-direction: column;
position: absolute;
top: -4rem;
left: 12rem;
}
.control-icon.tokenhudicon {
width: fit-content;
height: fit-content;
@ -1063,7 +1072,7 @@ body.system-bol img#logo {
z-index: 2;
}
.bol-hud-menu label {
font-size: 0.75rem;
font-size: 0.6rem;
}
.bol-margin-tb-2 {
margin-top: 2px;

View File

@ -156,6 +156,7 @@
"BOL.ui.armorAgiMalus": "Rüschtung+Schild-Malus (Geschick)",
"BOL.ui.armorInitMalus": "Rüstungsmalus (Init)",
"BOL.ui.attackValue": "Angriffswert",
"BOL.ui.initMalus": "Init malus",
"BOL.featureCategory.origins": "Herkünfte",
"BOL.featureCategory.races": "Rassen",

View File

@ -154,6 +154,8 @@
"BOL.ui.armorInitMalus": "Armor Modifier (Init)",
"BOL.ui.attackValue": "Attack Value",
"BOL.ui.weaponbonus": "Cette arme bénéficie déja d'un Dé de Bonus (Arme Favorite prise en compte, par exemple)",
"BOL.ui.initMalus": "Init malus",
"BOL.ui.isspecial": "Spécial ?",
"BOL.featureCategory.origins": "Origins",
"BOL.featureCategory.races": "Races",
@ -185,6 +187,7 @@
"BOL.fightOptionTypes.fulldefense": "Full Defense",
"BOL.fightOptionTypes.defense": "Defensive Posture",
"BOL.fightOptionTypes.attack": "Offensive Posture",
"BOL.fightOptionTypes.other": "Other",
"BOL.itemCategory.object": "Object",
"BOL.itemCategory.equipment": "Equipment",

View File

@ -132,6 +132,7 @@
"BOL.ui.concentrate": "Concentration à maintenir ?",
"BOL.ui.aggressive": "Sort aggressif ?",
"BOL.ui.registerInit": "Enregistrer comme Init. de combat",
"BOL.ui.initMalus": "Malus d'initiative",
"BOL.ui.magicnewrules": "Règles supplémentaires (cf. supplément fan-made Sorcellerie!)",
"BOL.ui.isSorcerer": "Carrière de Sorcier ?",
@ -217,6 +218,7 @@
"BOL.ui.itemnotfound": "Impossible de trouver l'objet de cette macro",
"BOL.ui.noinit": "Pas d'initiative trouvée, veuillez en enregistrer une.",
"BOL.ui.warninitiative": "Votre initiative n'est pas disponible. Effectuez un jet d'Initiative pour ce combat.",
"BOL.ui.isspecial": "Spéciale ?",
"BOL.featureCategory.origins": "Origines",
"BOL.featureCategory.races": "Races",
@ -251,6 +253,7 @@
"BOL.fightOptionTypes.fulldefense": "Défense totale",
"BOL.fightOptionTypes.defense": "Posture défensive",
"BOL.fightOptionTypes.attack": "Posture offensive",
"BOL.fightOptionTypes.other": "Autres",
"BOL.itemCategory.object": "Objet",
"BOL.itemCategory.equipment": "Équipement",
@ -459,10 +462,10 @@
"BOL.chat.isdead": "{name} est mort !",
"BOL.chat.epitaph": "Que son nom soit honoré sur les champs de batailles de Lémurie !",
"BOL.chat.vitalityzero": "La Vitalité de {name} est {hp} : il va s'écrouler au sol et sombrer dans l'inconscience !",
"BOL.chat.vitalityheroism": "Vous pouvez dépenser 1 Point d'Héroisme pour reprendre vos esprits pendant 1 round.",
"BOL.chat.vitalityheroism": "Vous pouvez dépenser 1 Point d'Héroisme/Vilainie pour reprendre vos esprits pendant 1 round.",
"BOL.chat.vitalityheroismhint": "Dans ce cas votre vitalité remonte à son maximum divisé par 2 (arrondi au supérieur).",
"BOL.chat.vitalitydying": "La Vitalité de {name} est de {hp} ! Il est mourant ...",
"BOL.chat.vitalitydyingheroism": "Vous pouvez cependant dépenser 1 Point d'Héroisme pour Défier la Mort (cf. page 58).",
"BOL.chat.vitalitydyingheroism": "Vous pouvez cependant dépenser 1 Point d'Héroisme/Vilainie pour Défier la Mort (cf. page 58).",
"BOL.chat.alchemytitle": "Préparation Alchimique : {name}",
"BOL.chat.alchemypoints": "Points de Création Investis : {pcCostCurrent}",
"BOL.chat.alchemysuccess": "La préparation alchimique a été réalisée avec succès !<br>Créez l'item ou l'effet correspondant dans votre Inventaire.<br>L'avancement dans la préparation a été remis à 0.",
@ -475,19 +478,20 @@
"BOL.chat.applydamagetotarget": "Appliquer les dommages à la cible",
"BOL.chat.fightoption": "Option de combat",
"BOL.chat.reroll": "Relancer (1 P. Heroisme)",
"BOL.chat.toheroic": "Transformer en succés Héroïque (1 P. Héroisme)",
"BOL.chat.tolegend": "Transformer en succes Légendaire (1 P. Heroisme)",
"BOL.chat.heroicreminder": "En plus des actions indiquées sur les boutons ci-dessous, vous pouvez : <ul><li>Carnage : Attaquer une seconde fois le même adversaire</li><li>Coup précis : Un dé de malus à votre adversaire sur une localisation choisie</li><li>Désarmement</li><li>Massacrer la piétaille</li><li>Renversement : Renversez votre adversaire (1 taille de plus max)</li></ul>Si vous dépensez un Point dh'Eheoisme en plus, tout ces effets peuvent être doublés",
"BOL.chat.toheroic": "Transformer en succés Héroïque (1 P. Héroisme/Vilainie)",
"BOL.chat.tolegend": "Transformer en succes Légendaire (1 P. Heroisme/Vilainie)",
"BOL.chat.hurttitle": "{name} va encaisser {damageTotal} dégats !",
"BOL.chat.armordefault": "C'est une attaque au défaut de l'armure : vous devez encaisser SANS la protection de l'armure !",
"BOL.chat.witharmor": "Encaisser avec la protection de l'armure",
"BOL.chat.withoutarmor": "Encaisser sans la protection de l'armure",
"BOL.chat.shakeoff": "Juste une égratignure (1 Point d'Héroisme)",
"BOL.chat.splinteredshield": "Parade in Extremis avec {name} (1 Point d'Héroisme)",
"BOL.chat.shakeoff": "Juste une égratignure (1 Point d'Héroisme/Vilainie)",
"BOL.chat.splinteredshield": "Parade in Extremis avec {name} (1 Point d'Héroisme/Vilainie)",
"BOL.chat.damagesummary": "Dégats subis par {name}",
"BOL.chat.protectvalue": "Protection de l'armure",
"BOL.chat.noprotectvalue": "Aucune protection d'armure !",
"BOL.chat.heroreducedamage": "Un point d'héroisme dépensé, pour une réduction des dommages supplémentaire de {total}.",
"BOL.chat.herosplintered": "Aucun dommage encaissé, grâce à la parade in-extremis avec {weaponHero.name}. L'arme a été détruite pendant cette parade ! Un point d'héroisme a également été dépensé.",
"BOL.chat.heroreducedamage": "Un point d'héroisme/vilainie dépensé, pour une réduction des dommages supplémentaire de {total}.",
"BOL.chat.herosplintered": "Aucun dommage encaissé, grâce à la parade in-extremis avec {weaponHero.name}. L'arme a été détruite pendant cette parade ! Un point d'héroisme/vilainie a également été dépensé.",
"BOL.chat.finaldamage": "Encaissement final : {finalDamage} dégats !",
"BOL.chat.spell": "Sort",
"BOL.chat.spellcost": "Cout en Points de Pouvoir",
@ -518,23 +522,27 @@
"BOL.chat.horoscopepoints": "Coût : {points} Points d'Astrologie",
"BOL.chat.horoscopeminorsuccess": "Votre horoscope mineur est un succès : éditez le nom de l'horoscope sur votre fiche. Vous bénéficiez d'1 dé Bonus pour cette situation.",
"BOL.chat.horoscopeminorfailure": "Votre horoscope mineur est un échec : éditez le nom de l'horoscope sur votre fiche. Vous souffrez d'1 dé Malus pour cette situation.",
"BOL.chat.horoscopemajorsuccess": "Votre horoscope majeur est un succès : vous bénéficiez d'1 point d'Héroisme pour cette aventure. Ce point a été ajouté automatiquement.",
"BOL.chat.horoscopemajorfailure": "Votre horoscope majeur est un échec : vous perdez 1 point d'Héroisme pour cette aventure. Ce point a été enlevé automatiquement.",
"BOL.chat.horoscopemajorsuccess": "Votre horoscope majeur est un succès : {horoscopeName} bénéficie d'1 point d'Héroisme de plus pour cette aventure. Ce point a été ajouté automatiquement.",
"BOL.chat.horoscopemajorfailure": "Votre horoscope majeur est un échec : {horoscopeName} a perdu 1 point d'Héroisme pour cette aventure. Ce point a été enlevé automatiquement.",
"BOL.chat.horoscopemajorgroupsuccess": "Votre horoscope majeur de groupe est un succès. Vous et vos amis bénéficiez de {careerBonus} dés bonus pendant cette aventure.",
"BOL.chat.horoscopemajorgroupfailure": "Votre horoscope majeur de groupe est un échec. Vous et vos amis souffrez de {careerBonus} dés malus pendant cette aventure.",
"BOL.chat.usedhoroscope": "Horoscope utilisé",
"BOL.chat.horoscopedeleted": "Le(s) Horoscopes utilisé(s) a/ont été supprimé(s) automatiquement.",
"BOL.chat.criticaloptions": "Succès critique !! Vous pouvez faire (1 option au choix) :",
"BOL.chat.criticalcarnage": "Faire un Carnage : vous avez une attaque gratuite supplémentaire. Cette seconde attaque ne peut bénéficier d'un Point d'Héroisme.",
"BOL.chat.criticalcarnage": "Faire un Carnage : vous avez une attaque gratuite supplémentaire. Cette seconde attaque ne peut bénéficier d'un Point d'Héroisme/vilainie.",
"BOL.chat.criticalplus6": "Coup Dévastateur : +6 aux dommages (cf bouton ci-dessous).",
"BOL.chat.criticalprecise": "Coup Précis : Vous frappez pour diminuer les capacités de votre adversaire. Décrivez ce que vous faites, et si le MJ l'accepte, votre opposant subira un Dé de Malus pour les actions concernées.",
"BOL.chat.criticalunarm": "Désarmement : Si votre adversaire a une arme en main, vous le désarmez.",
"BOL.chat.criticalrabble": "Massacrer la piétaille : Si vous combattez de la Piétaille, les résultats des dommages indiquent le nombre d'adversaires mis hors de combat.",
"BOL.chat.criticalpush": "Renversement : Si la taille le permet, vous poussez votre adversaire au sol, il souffrira d'1 Dé de Malus pour toutes ses actions au round suivant.",
"BOL.chat.criticalup": "Transformer en Légendaire : En dépensant 1 point d'Héroisme, vous pouvez transformer ce Succès Héroïque en Légendaire, qui vous permet de prendre 2 options dans la liste ci-dessus (cf. bouton pour un +12 aux dommages par exemple).",
"BOL.chat.criticalup": "Transformer en Légendaire : En dépensant 1 point d'Héroisme/Vilainie, vous pouvez transformer ce Succès Héroïque en Légendaire, qui vous permet de prendre 2 options dans la liste ci-dessus (cf. bouton pour un +12 aux dommages par exemple).",
"BOL.chat.criticalinfo": "C'est un succès Héroïque ou Légendaire ! Choisissez vos options et effets !",
"BOL.chat.criticalbuttonjournal": "Succès Héroïque/Légendaire",
"BOL.chat.losshp": "{{name}} a perdu {lossHP} points de Vitalité. Si il se repose quelques minutes, il peut récupérer {recupHP} points de Vitalité.",
"BOL.chat.applyrecup": "Récupérer pendant quelques minutes (+{recupHP} Vitalité)",
"BOL.chat.inforecup": "{name} vient de récupérer {recupHP} points de Vitalité après quelques minutes de repos.",
"BOL.dialog.soeasy": "Inmanquable (+4)",
"BOL.dialog.veryeasy": "Trés Facile (+2)",
"BOL.dialog.easy": "Facile (+1)",
@ -573,6 +581,6 @@
"BOL.chat.welcome3": "Les cartes intégrées au système le sont grace à l'aimable autorisation de leur auteur Guillaume Tavernier et des éditions Ludospherik. Merci à eux !.",
"BOL.chat.welcome4": "Tout le support et le suivi de ce système est disponible via le <a href='https://discord.gg/pPSDNJk'>Discord Foundry FR</a>.",
"BOL.chat.welcome5": "Consulter l'aide en ligne pour plus d'informations : @UUID[Compendium.bol.aides-de-jeu.97rugQOtiwt8zPfQ]{Aide du Jeu}.",
"BOL.chat.welcome6": "Bon jeu en Lemurie !"
"BOL.chat.welcome6": "Bon jeu en Lemurie !",
"BOL.chat.nodamage": "Ne pas appliquer les dommages"
}

View File

@ -60,6 +60,12 @@ export class BoLActorSheet extends ActorSheet {
const li = $(ev.currentTarget).parents(".item");
this.actor.spendAlchemyPoint(li.data("itemId"), 1)
})
html.find(".inc-dec-btns-resource").click((ev) => {
const dataset = ev.currentTarget.dataset;
const target = dataset.target
const incr = parseInt(dataset.incr)
this.actor.incDecResources(target, incr)
})
// Incr./Decr. career ranks
html.find(".inc-dec-btns").click((ev) => {

View File

@ -1,6 +1,5 @@
import { BoLDefaultRoll } from "../controllers/bol-rolls.js";
import { BoLDefaultRoll, BoLRoll } from "../controllers/bol-rolls.js";
import { BoLUtility } from "../system/bol-utility.js";
import { BoLRoll } from "../controllers/bol-rolls.js";
/**
* Extend the base Actor entity by defining a custom roll data structure which is ideal for the Simple system.
@ -22,6 +21,17 @@ export class BoLActor extends Actor {
super.prepareData()
}
/* -------------------------------------------- */
isHeroAdversary() {
if (this.type === 'character') {
return true
}
if (this.type === 'encounter' && this.chartype == "adversary") {
return true
}
return false
}
/* -------------------------------------------- */
getCharType() {
if (this.type === 'character') {
@ -32,18 +42,24 @@ export class BoLActor extends Actor {
/* -------------------------------------------- */
getVillainy() {
if (this.type === 'character') {
return false
if (this.type === 'encounter' && this.chartype == "adversary") {
return true
}
return true
return false
}
/* -------------------------------------------- */
getInitiativeMalus() {
if ( this.type === 'encounter' && (this.chartype == "adversary" || this.chartype == "tough")) {
return this.system.aptitudes.init.value
}
return 0
}
/* -------------------------------------------- */
getBougette() {
if ( this.type == "character") {
if (this.type == "character") {
let b = duplicate(this.system.bougette)
b.label = game.i18n.localize( game.bol.config.bougetteState[String(this.system.bougette.value)] )
b.diceImg = "icons/dice/" + game.bol.config.bougetteDice[String(this.system.bougette.value)] + "black.svg"
b.label = game.i18n.localize(game.bol.config.bougetteState[String(this.system.bougette.value)])
b.diceImg = "icons/dice/" + game.bol.config.bougetteDice[String(this.system.bougette.value)] + "black.svg"
return b
}
return undefined
@ -51,9 +67,9 @@ export class BoLActor extends Actor {
/* -------------------------------------------- */
async rollBougette() {
if ( this.type == "character") {
if (this.type == "character") {
let attribute = duplicate(this.system.attributes.vigor)
let rollData = BoLRoll.getCommonRollData(this, "bougette", attribute, undefined )
let rollData = BoLRoll.getCommonRollData(this, "bougette", attribute, undefined)
rollData.formula = game.bol.config.bougetteDice[String(this.system.bougette.value)]
let r = new BoLDefaultRoll(rollData)
r.roll()
@ -62,23 +78,25 @@ export class BoLActor extends Actor {
/* -------------------------------------------- */
decBougette() {
if ( this.type == "character") {
let bougette = duplicate(this.system.bougette)
bougette.value = Math.max( Number(bougette.value) - 1, 0)
this.update( { 'system.bougette': bougette } )
if (this.type == "character") {
let bougette = duplicate(this.system.bougette)
bougette.value = Math.max(Number(bougette.value) - 1, 0)
this.update({ 'system.bougette': bougette })
}
}
/* -------------------------------------------- */
updateResourcesData() {
if (this.type == 'character') {
let newVitality = 10 + this.system.attributes.vigor.value + this.system.resources.hp.bonus
if (this.system.resources.hp.max != newVitality) {
this.update({ 'system.resources.hp.max': newVitality })
let actor = this
setTimeout( function() { actor.update({ 'system.resources.hp.max': newVitality }) }, 800 )
}
let newPower = 10 + this.system.attributes.mind.value + this.system.resources.power.bonus
if (this.system.resources.power.max != newPower) {
this.update({ 'system.resources.power.max': newPower })
let actor = this
setTimeout( function() { actor.update({ 'system.resources.power.max': newPower }) }, 800 )
}
}
}
@ -89,8 +107,10 @@ export class BoLActor extends Actor {
} else {
super.prepareDerivedData()
this.updateResourcesData()
this.manageHealthState();
if (this.id) {
this.updateResourcesData()
this.manageHealthState()
}
}
}
@ -98,11 +118,29 @@ export class BoLActor extends Actor {
get details() {
return this.system.details
}
addEffectModifiers( myList, dataPath) {
for (let attr of myList) {
attr.numModifier = 0
attr.diceModifier = ""
let effects = this.items.filter( i => i.type === "feature" && i.system.subtype === "boleffect" && i.system.properties.identifier == dataPath+attr.key)
for (let effect of effects) {
if ( Number(effect.system.properties.modifier)) {
attr.numModifier += Number(effect.system.properties.modifier)
} else {
attr.diceModifier += "+"+effect.system.properties.modifier
}
}
}
}
get attributes() {
return Object.values(this.system.attributes)
let attrList = duplicate(Object.values(this.system.attributes))
this.addEffectModifiers(attrList, "system.attributes.")
return attrList
}
get aptitudes() {
return Object.values(this.system.aptitudes)
let aptList = Object.values(this.system.aptitudes)
this.addEffectModifiers(aptList, "system.aptitudes.")
return aptList
}
/* -------------------------------------------- */
@ -137,7 +175,7 @@ export class BoLActor extends Actor {
}
// Apply defense effects
for (let i of this.items) {
if (i.type === "feature" && i.system.subtype === "boleffect" && i.system.properties.identifier.includes("aptitudes.def") ) {
if (i.type === "feature" && i.system.subtype === "boleffect" && i.system.properties.identifier.includes("aptitudes.def")) {
defMod += Number(i.system.properties.modifier)
}
}
@ -230,19 +268,18 @@ export class BoLActor extends Actor {
/*-------------------------------------------- */
get armorMalusValue() { // used for Fight Options
for (let armor of this.armors) {
if (armor.system.properties.armorQuality.includes("light")) {
if (armor.system.properties.armorQuality?.includes("light")) {
return 1
}
if (armor.system.properties.armorQuality.includes("medium")) {
if (armor.system.properties.armorQuality?.includes("medium")) {
return 2
}
if (armor.system.properties.armorQuality.includes("heavy")) {
if (armor.system.properties.armorQuality?.includes("heavy")) {
return 3
}
}
return 0
}
get resources() {
return Object.values(this.system.resources)
}
@ -389,7 +426,7 @@ export class BoLActor extends Actor {
}
// Apply vigor effects
for (let i of this.items) {
if (i.type === "feature" && i.system.subtype === "boleffect" && i.system.properties.identifier.includes("vigor") ) {
if (i.type === "feature" && i.system.subtype === "boleffect" && i.system.properties.identifier.includes("vigor")) {
attrDamageValue += Number(i.system.properties.modifier)
}
}
@ -432,25 +469,25 @@ export class BoLActor extends Actor {
this.updateEmbeddedDocuments('Item', [{ _id: alchemy.id, 'system.properties.pccurrent': 0 }])
}
}
/*-------------------------------------------- */
spentAstrologyPoints(points) {
let astrology = duplicate(this.system.resources.astrologypoints)
astrology.value -= points
astrology.value = Math.max(astrology.value,0)
this.update( { 'system.resources.astrologypoints': astrology} )
astrology.value = Math.max(astrology.value, 0)
this.update({ 'system.resources.astrologypoints': astrology })
}
/*-------------------------------------------- */
getHoroscopesBonus() {
let astro = this.items.filter(it => it.type == "feature" && it.system.subtype == "horoscope" && !it.system.properties.ishoroscopemajor
&& it.system.properties.horoscopeanswer == "favorable")
let astro = this.items.filter(it => it.type == "feature" && it.system.subtype == "horoscope" && !it.system.properties.ishoroscopemajor
&& it.system.properties.horoscopeanswer == "favorable")
return astro
}
/*-------------------------------------------- */
getHoroscopesMalus() {
let astro = this.items.filter(it => it.type == "feature" && it.system.subtype == "horoscope" && !it.system.properties.ishoroscopemajor
&& it.system.properties.horoscopeanswer == "unfavorable")
let astro = this.items.filter(it => it.type == "feature" && it.system.subtype == "horoscope" && !it.system.properties.ishoroscopemajor
&& it.system.properties.horoscopeanswer == "unfavorable")
return astro
}
@ -458,26 +495,34 @@ export class BoLActor extends Actor {
manageHoroscope(rollData) {
//Spent points
this.spentAstrologyPoints(rollData.astrologyPointsCost)
if ( rollData.horoscopeType == "minor") {
let horoscope = { name: "SITUATION A SPECIFIER", type :"feature",
if (rollData.horoscopeType == "minor") {
let horoscope = {
name: "SITUATION A SPECIFIER", type: "feature",
img: "icons/magic/perception/eye-ringed-glow-angry-large-red.webp",
system :{subtype: "horoscope", properties: {
ishoroscopemajor: false,
horoscopeanswer: (rollData.isSuccess) ? "favorable": "unfavorable",
rank: rollData.careerBonus
}
system: {
subtype: "horoscope", properties: {
ishoroscopemajor: false,
horoscopeanswer: (rollData.isSuccess) ? "favorable" : "unfavorable",
rank: rollData.careerBonus
}
}
}
this.createEmbeddedDocuments('Item', [horoscope])
}
if ( rollData.horoscopeType == "major" ) {
if ( rollData.isSuccess) {
this.subHeroPoints(1)
if (rollData.horoscopeType == "major") {
let actorHoroscope = this
if(rollData.targetId) {
let token = game.scenes.current.tokens.get(rollData.targetId)
actorHoroscope = token.actor
}
if (rollData.isSuccess) {
actorHoroscope.addHeroPoints(1)
} else {
this.addHeroPoints(1)
}
actorHoroscope.subHeroPoints(1)
}
rollData.horoscopeName = actorHoroscope.name
}
if ( rollData.horoscopeType == "majorgroup" ) {
if (rollData.horoscopeType == "majorgroup") {
let rID = randomID(16)
let horoscopes = duplicate(game.settings.get("bol", "horoscope-group"))
horoscopes[rID] = {
@ -485,7 +530,7 @@ export class BoLActor extends Actor {
name: game.i18n.localize("BOL.ui.groupHoroscope") + this.name,
maxDice: rollData.careerBonus,
availableDice: rollData.careerBonus,
type: (rollData.isSuccess) ? "bonus": "malus"
type: (rollData.isSuccess) ? "bonus" : "malus"
}
game.settings.set("bol", "horoscope-group", horoscopes)
}
@ -497,10 +542,10 @@ export class BoLActor extends Actor {
return this.system.resources.astrologypoints.value
}
/*-------------------------------------------- */
removeHoroscopeMinor( rollData) {
removeHoroscopeMinor(rollData) {
let toDel = []
for(let horo of rollData.selectedHoroscope) {
toDel.push( horo._id )
for (let horo of rollData.selectedHoroscope) {
toDel.push(horo._id)
}
if (toDel.length > 0) {
this.deleteEmbeddedDocuments('Item', toDel)
@ -519,7 +564,7 @@ export class BoLActor extends Actor {
newPC = alchemy.system.properties.pccurrent + pcCost
await this.updateEmbeddedDocuments('Item', [{ _id: alchemy.id, 'system.properties.pccurrent': newPC }])
} else {
ui.notifications.warn( game.i18n.localize("BOL.ui.nomorealchemypoints") )
ui.notifications.warn(game.i18n.localize("BOL.ui.nomorealchemypoints"))
}
}
}
@ -707,7 +752,7 @@ export class BoLActor extends Actor {
/*-------------------------------------------- */
buildListeActions() {
return this.melee.concat(this.ranged).concat(this.natural)
return this.melee.concat(this.ranged).concat(this.natural).concat(this.fightoptions)
}
/*-------------------------------------------- */
@ -716,30 +761,30 @@ export class BoLActor extends Actor {
let lastHP = await this.getFlag("world", hpID)
if (lastHP != this.system.resources.hp.value && game.user.isGM) { // Only GM sends this
await this.setFlag("world", hpID, this.system.resources.hp.value)
let prone = this.effects.find( ef => ef.label == "EFFECT.StatusProne")
let dead = this.effects.find( ef => ef.label == "EFFECT.StatusDead")
let prone = this.effects.find(ef => ef.label == "EFFECT.StatusProne")
let dead = this.effects.find(ef => ef.label == "EFFECT.StatusDead")
if (this.system.resources.hp.value <= 0) {
if ( !prone) {
if (!prone) {
await this.createEmbeddedDocuments("ActiveEffect", [
{label: 'EFFECT.StatusProne', icon: 'icons/svg/falling.svg', flags: { core: { statusId: 'prone' } } }
{ label: 'EFFECT.StatusProne', icon: 'icons/svg/falling.svg', flags: { core: { statusId: 'prone' } } }
])
}
if ( this.system.resources.hp.value < -5 && !dead) {
if (this.system.resources.hp.value < -5 && !dead) {
await this.createEmbeddedDocuments("ActiveEffect", [
{label: 'EFFECT.StatusDead', icon: 'icons/svg/skull.svg', flags: { core: { statusId: 'dead' } } }
{ label: 'EFFECT.StatusDead', icon: 'icons/svg/skull.svg', flags: { core: { statusId: 'dead' } } }
])
}
ChatMessage.create({
alias: this.name,
whisper: BoLUtility.getWhisperRecipientsAndGMs(this.name),
content: await renderTemplate('systems/bol/templates/chat/chat-vitality-zero.hbs', { name: this.name, img: this.img, hp: this.system.resources.hp.value })
content: await renderTemplate('systems/bol/templates/chat/chat-vitality-zero.hbs', { name: this.name, img: this.img, hp: this.system.resources.hp.value, isHeroAdversary: this.isHeroAdversary() })
})
} else {
if ( prone ) {
await this.deleteEmbeddedDocuments("ActiveEffect", [ prone.id ] )
if (prone) {
await this.deleteEmbeddedDocuments("ActiveEffect", [prone.id])
}
if ( dead ) {
await this.deleteEmbeddedDocuments("ActiveEffect", [ dead.id ] )
if (dead) {
await this.deleteEmbeddedDocuments("ActiveEffect", [dead.id])
}
}
}
@ -751,9 +796,47 @@ export class BoLActor extends Actor {
await this.setFlag("world", "last-initiative", rollData)
}
/*-------------------------------------------- */
storeVitaliteCombat() {
this.setFlag("world", "vitalite-before-combat", duplicate(this.system.resources.hp))
}
/*-------------------------------------------- */
async displayRecuperation() {
let previousHP = this.getFlag("world", "vitalite-before-combat")
let lossHP = previousHP.value - this.system.resources.hp.value
//console.log(">>>>> RECUP INFO", previousHP, this.system.resources.hp.value)
if (previousHP && lossHP > 0 && this.system.resources.hp.value > 0) {
let msg = await ChatMessage.create({
alias: this.name,
whisper: BoLUtility.getWhisperRecipientsAndGMs(this.name),
content: await renderTemplate('systems/bol/templates/chat/chat-recup-information.hbs', {
name: this.name,
img: this.img,
actorId: this.id,
lossHP: lossHP,
recupHP: Math.ceil(lossHP / 2)
})
})
}
this.unsetFlag("world", "vitalite-before-combat")
}
/*-------------------------------------------- */
async applyRecuperation(recupHP) {
let hp = duplicate(this.system.resources.hp)
//console.log("RECUP !!!!", hp, recupHP)
hp.value += Number(recupHP)
hp.value = Math.min(hp.value, hp.max)
this.update({ 'system.resources.hp': hp })
let msg = await ChatMessage.create({
alias: this.name,
whisper: BoLUtility.getWhisperRecipientsAndGMs(this.name),
content: game.i18n.format( "BOL.chat.inforecup", {name: this.name, recupHP: recupHP} )
})
}
/*-------------------------------------------- */
clearInitiative() {
this.unsetFlag("world", "last-initiative" )
this.unsetFlag("world", "last-initiative")
}
/*-------------------------------------------- */
@ -763,52 +846,81 @@ export class BoLActor extends Actor {
}
return game.bol.config.creatureSize["medium"].order // Medium size per default
}
/*-------------------------------------------- */
checkNumeric(myObject) {
if ( myObject) {
for (let key in myObject) {
if ( myObject[key].value === null ) {
myObject[key].value = 0
}
if ( myObject[key].value === NaN ) {
myObject[key].value = 0
}
}
}
}
/*-------------------------------------------- */
getInitiativeRank(rollData = undefined, isCombat = false) {
if (!rollData) {
rollData = this.getFlag("world", "last-initiative")
_preUpdate(data, options, userId) {
if (data.system?.attributes) {
this.checkNumeric(data.system.attributes)
}
if (data.system?.aptitudes) {
this.checkNumeric(data.system.aptitudes)
}
if (data.system?.resources) {
this.checkNumeric(data.system.resources)
}
super._preUpdate(data, options, userId)
}
/*-------------------------------------------- */
getInitiativeRank(rollData = undefined, isCombat = false, combatData) {
let fvttInit = 4 // Pietaille par defaut
if (this.type == 'character' ) {
if (this.type == 'character') {
fvttInit = 5
if (!rollData) {
fvttInit = -1
if ( isCombat ) {
ui.notifications.warn(game.i18n.localize("BOL.ui.warninitiative"))
if (!rollData) {
if (isCombat) {
if (game.user.isGM ) {
if (this.hasPlayerOwner) {
game.socket.emit("system.bol", { name: "msg_request_init_roll", data: { actorId: this.id, combatData } })
} else {
BoLRoll.aptitudeCheck(this, "init", undefined, combatData);
}
}
}
} else {
if (rollData.isLegendary) {
fvttInit = 10
} else if (rollData.isCritical) {
fvttInit = 9
} else if (rollData.isSuccess ) {
} else if (rollData.isSuccess) {
fvttInit = 8
} else if (rollData.isFumble) {
fvttInit = 3
}
}
}
}
if ( this.getCharType() == 'adversary') {
if (this.getCharType() == 'adversary') {
fvttInit = 7
}
if ( this.getCharType() == 'tough') {
}
if (this.getCharType() == 'tough') {
fvttInit = 6
}
if ( this.getCharType() == 'creature') {
if (this.getCharType() == 'creature') {
let mySize = this.getSize()
let sizeSmall = game.bol.config.creatureSize["small"].order
let sizeMedium = game.bol.config.creatureSize["medium"].order
if ( mySize >= sizeSmall && mySize <= sizeMedium) {
if (mySize >= sizeSmall && mySize <= sizeMedium) {
fvttInit = 6
}
if ( mySize > sizeMedium) {
if (mySize > sizeMedium) {
fvttInit = 7
}
}
return fvttInit
}
/*-------------------------------------------- */
async subHeroPoints(nb) {
let newHeroP = this.system.resources.hero.value - nb;
@ -822,6 +934,11 @@ export class BoLActor extends Actor {
await this.update({ 'system.resources.hero.value': newHeroP });
}
/*-------------------------------------------- */
incDecResources(target, value) {
let newValue = this.system.resources[target].value + value
this.update({ [`system.resources.${target}.value`]: newValue })
}
/*-------------------------------------------- */
async sufferDamage(damage) {
let newHP = this.system.resources.hp.value - damage
@ -838,13 +955,13 @@ export class BoLActor extends Actor {
} else if (protect.system.subtype == 'armor') {
if (BoLUtility.getRollArmor()) {
if (!protect.system.properties.soak.formula || protect.system.properties.soak.formula == "") {
ui.notifications.warn( game.i18n.localize("BOL.ui.armornoformula", protect.name) )
ui.notifications.warn(game.i18n.localize("BOL.ui.armornoformula", protect.name))
} else {
formula += "+" + " max(" + protect.system.properties.soak.formula + ",0)"
}
} else {
if (protect.system.properties.soak.value == undefined) {
ui.notifications.warn( game.i18n.localize("BOL.ui.armornoformula", protect.name) )
ui.notifications.warn(game.i18n.localize("BOL.ui.armornoformula", protect.name))
} else {
formula += "+ " + protect.system.properties.soak.value
}

View File

@ -122,7 +122,7 @@ Hooks.once('ready', async function () {
BoLUtility.ready()
BoLCharacterSummary.ready()
registerUsageCount('bol')
registerUsageCount(game.system.id)
welcomeMessage()

View File

@ -33,11 +33,11 @@ export class BoLRoll {
/* -------------------------------------------- */
static buildHoroscopeGroupList() {
let horoscopes = game.settings.get("bol", "horoscope-group")
let horoList = [ { id: -1, name: "Aucun", type: "malus", nbDice: 0 }]
let horoList = [{ id: -1, name: "Aucun", type: "malus", nbDice: 0 }]
for (let id in horoscopes) {
let horo = horoscopes[id]
for (let i=0; i<horo.availableDice; i++) {
horoList.push( { id: id, name: horo.name, type: horo.type, nbDice: i+1})
for (let i = 0; i < horo.availableDice; i++) {
horoList.push({ id: id, name: horo.name, type: horo.type, nbDice: i + 1 })
}
}
return horoList
@ -78,7 +78,7 @@ export class BoLRoll {
}
/* -------------------------------------------- */
static attributeCheck(actor, key) {
static attributeCheck(actor, key, event, combatData) {
let attribute = eval(`actor.system.attributes.${key}`)
@ -91,7 +91,7 @@ export class BoLRoll {
}
/* -------------------------------------------- */
static aptitudeCheck(actor, key) {
static aptitudeCheck(actor, key, event, combatData) {
let aptitude = eval(`actor.system.aptitudes.${key}`)
let attrKey = this.getDefaultAttribute(key)
@ -101,6 +101,7 @@ export class BoLRoll {
rollData.label = (aptitude.label) ? game.i18n.localize(aptitude.label) : null
rollData.description = game.i18n.localize('BOL.ui.aptitudeCheck') + " - " + game.i18n.localize(aptitude.label)
rollData.combatData = combatData // For initiative mainly
return this.displayRollDialog(rollData)
}
@ -159,7 +160,7 @@ export class BoLRoll {
// Manage specific case
let fightOption = actor.getActiveFightOption()
if (fightOption && fightOption.system.fightoptiontype == "fulldefense") {
if (fightOption && fightOption.system.properties.fightoptiontype == "fulldefense") {
ui.notifications.warn(`{{actor.name}} est en Défense Totale ! Il ne peut pas attaquer ce round.`)
return
}
@ -219,8 +220,11 @@ export class BoLRoll {
/* -------------------------------------------- */
static horoscopeCheck(actor, event, horoscopeType) {
let cost = (horoscopeType == "minor") ? 1 : 2
if (cost > actor.getAstrologyPoints() ) {
let target = BoLUtility.getTarget()
let cost = (horoscopeType == "minor") ? 1 : 2
if (cost > actor.getAstrologyPoints()) {
ui.notifications.warn(game.i18n.localize("BOL.ui.astrologyNoPoints"))
return
}
@ -228,10 +232,11 @@ export class BoLRoll {
rollData.careerBonus = actor.getAstrologerBonus()
rollData.horoscopeType = horoscopeType
rollData.horoscopeTypeLabel = "BOL.ui."+horoscopeType
rollData.horoscopeTypeLabel = "BOL.ui." + horoscopeType
rollData.astrologyPointsCost = cost
rollData.label = game.i18n.localize('BOL.ui.makeHoroscope')
rollData.description = game.i18n.localize('BOL.ui.makeHoroscope') + " " + game.i18n.localize(rollData.horoscopeTypeLabel)
rollData.targetId = target?.id
console.log("HOROSCOPE!", rollData);
return this.displayRollDialog(rollData);
@ -283,7 +288,7 @@ export class BoLRoll {
for (let effect of this.rollData.bolApplicableEffects) {
if (effect.system.properties.modifier == "1B") {
this.rollData.bmDice++;
} else if (effect.system.properties.modifier == "1B") {
} else if (effect.system.properties.modifier == "2B") {
this.rollData.bmDice += 2;
} else if (effect.system.properties.modifier == "1M") {
this.rollData.bmDice--;
@ -295,7 +300,7 @@ export class BoLRoll {
}
this.rollData.bmDice += this.rollData.horoscopeBonus
this.rollData.bmDice -= this.rollData.horoscopeMalus
if ( this.rollData.selectedGroupHoroscopeIndex && this.rollData.selectedGroupHoroscopeIndex > 0) {
if (this.rollData.selectedGroupHoroscopeIndex && this.rollData.selectedGroupHoroscopeIndex > 0) {
let horo = this.rollData.horoscopeGroupList[this.rollData.selectedGroupHoroscopeIndex]
this.rollData.bmDice += (horo.type == "malus") ? -horo.nbDice : horo.nbDice;
}
@ -449,8 +454,8 @@ export class BoLRoll {
html.find('#horoscope-bonus-applied').change((event) => {
this.rollData.selectedHoroscope = []
for (let option of event.currentTarget.selectedOptions) {
this.rollData.selectedHoroscope.push( duplicate(this.rollData.horoscopeBonusList[Number(option.index)]) )
}
this.rollData.selectedHoroscope.push(duplicate(this.rollData.horoscopeBonusList[Number(option.index)]))
}
let horoscopes = $('#horoscope-bonus-applied').val()
this.rollData.horoscopeBonus = (!horoscopes || horoscopes.length == 0) ? 0 : horoscopes.length
this.updateTotalDice()
@ -459,8 +464,8 @@ export class BoLRoll {
html.find('#horoscope-malus-applied').change((event) => {
this.rollData.selectedHoroscope = []
for (let option of event.currentTarget.selectedOptions) {
this.rollData.selectedHoroscope.push( duplicate(this.rollData.horoscopeBonusList[Number(option.index)]) )
}
this.rollData.selectedHoroscope.push(duplicate(this.rollData.horoscopeBonusList[Number(option.index)]))
}
let horoscopes = $('#horoscope-malus-applied').val()
this.rollData.horoscopeMalus = (!horoscopes || horoscopes.length == 0) ? 0 : horoscopes.length
this.updateTotalDice()
@ -469,7 +474,7 @@ export class BoLRoll {
this.rollData.selectedGroupHoroscopeIndex = event.currentTarget.value
this.updateTotalDice()
})
}
@ -522,6 +527,7 @@ export class BoLRoll {
rollData.nbBoons = 0
rollData.nbFlaws = 0
rollData.nbDice = 0
rollData.isHeroAdversary = actor.isHeroAdversary()
if (rollData.shieldBlock == 'blockall') {
rollData.shieldMalus = rollData.shieldAttackMalus;
} else {
@ -577,8 +583,9 @@ export class BoLRoll {
rollbase = 0
}
let diceData = BoLUtility.getDiceData()
const modifiers = rollbase + rollData.careerBonus + rollData.mod + rollData.weaponModifier - rollData.defence - rollData.modArmorMalus + rollData.shieldMalus + rollData.attackModifier + rollData.appliedArmorMalus + rollData.effectModifier
let diceData = BoLUtility.getDiceData()
let malusInit = rollData.combatData?.malusInit || 0
const modifiers = rollbase + rollData.careerBonus + rollData.mod + rollData.weaponModifier - rollData.defence - rollData.modArmorMalus + rollData.shieldMalus + rollData.attackModifier + rollData.appliedArmorMalus + rollData.effectModifier - malusInit
const formula = (isMalus) ? rollData.nbDice + "d" + diceData.diceFormula + "kl2 + " + modifiers : rollData.nbDice + "d" + diceData.diceFormula + "kh2 + " + modifiers
rollData.formula = formula
rollData.modifiers = modifiers
@ -624,7 +631,7 @@ export class BoLDefaultRoll {
await r.roll({ "async": false })
let diceData = BoLUtility.getDiceData()
console.log("DICEDATA", diceData)
//console.log("DICEDATA", diceData)
const activeDice = r.terms[0].results.filter(r => r.active)
const diceTotal = activeDice.map(r => r.result).reduce((a, b) => a + b)
this.rollData.roll = r
@ -641,8 +648,13 @@ export class BoLDefaultRoll {
this.rollData.reroll = actor.heroReroll()
}
if (this.rollData.registerInit) {
actor.registerInit(this.rollData)
await actor.registerInit(this.rollData)
this.rollData.initiativeRank = actor.getInitiativeRank(this.rollData)
if (this.rollData.combatData) { // If combatData present
let combat = game.combats.get(this.rollData.combatData.combatId)
console.log("SET INIT!!!!!", this.rollData.initiativeRank)
combat.setInitiative(this.rollData.combatData.combatantId, this.rollData.initiativeRank)
}
}
if (this.rollData.isSuccess && this.rollData.mode == "spell") { // PP cost management
this.rollData.remainingPP = actor.spendPowerPoint(this.rollData.ppCost + this.rollData.ppCostArmor)
@ -672,13 +684,14 @@ export class BoLDefaultRoll {
async sendChatMessage() {
let actor = BoLUtility.getActorFromRollData(this.rollData)
this._buildChatMessage(this.rollData).then(async msgFlavor => {
//console.log("MSG", msgFlavor )
let msg = await this.rollData.roll.toMessage({
user: game.user.id,
rollMode: game.settings.get("core", "rollMode"),
//whisper: BoLUtility.getWhisperRecipientsAndGMs(this.rollData.actor.name),
flavor: msgFlavor,
speaker: ChatMessage.getSpeaker({ actor: actor }),
})
this.rollData.roll = duplicate(this.rollData.roll) // Remove object, keep data (v111 ready)
msg.setFlag("world", "bol-roll-data", this.rollData)
})
}
@ -731,6 +744,7 @@ export class BoLDefaultRoll {
speaker: ChatMessage.getSpeaker({ actor: actor }),
flags: { msgType: "default" }
})
this.rollData.damageRoll = duplicate(this.rollData.damageRoll)
this.rollData.actor = undefined // Cleanup
msg.setFlag("world", "bol-roll-data", this.rollData)
})
@ -761,13 +775,13 @@ export class BoLDefaultRoll {
let weaponFormula = BoLUtility.getDamageFormula(this.rollData.weapon.system, this.rollData.fightOption)
let damageFormula = weaponFormula + "+" + bonusDmg + "+" + attrDamageValue
console.log("DAMAGE !!!", damageFormula, attrDamageValue, this.rollData)
//console.log("Formula", weaponFormula, damageFormula, this.rollData.weapon.data.data.properties.damage)
this.rollData.damageFormula = damageFormula
this.rollData.damageRoll = new Roll(damageFormula)
await this.rollData.damageRoll.roll({ "async": false })
this.rollData.damageTotal = this.rollData.damageRoll.total
console.log("DAMAGE !!!", damageFormula, attrDamageValue, this.rollData)
}
BoLUtility.cleanupButtons(this.rollData.optionsId)
this.sendDamageMessage()

View File

@ -27,23 +27,23 @@ export class BoLItemSheet extends ItemSheet {
data.category = itemData.system.category
data.isGM = game.user.isGM;
data.itemProperties = this.item.itemProperties;
data.description = await TextEditor.enrichHTML(this.object.system.description, {async: true})
data.description = await TextEditor.enrichHTML(this.object.system.description, { async: true })
// Dynamic default data fix/adapt
if (itemData.type == "item") {
if (!itemData.system.category) {
itemData.system.category = "equipment"
}
if ( itemData.system.category == "equipment" && itemData.system.properties.equipable) {
if (itemData.system.category == "equipment" && itemData.system.properties.equipable) {
if (!itemData.system.properties.slot) {
itemData.system.properties.slot = "-"
}
}
if (itemData.system.category == 'spell') {
if(!itemData.system.properties.mandatoryconditions) {
if (!itemData.system.properties.mandatoryconditions) {
itemData.system.properties.mandatoryconditions = []
}
if(!itemData.system.properties.optionnalconditions) {
if (!itemData.system.properties.optionnalconditions) {
itemData.system.properties.optionnalconditions = []
}
for (let i = 0; i < 4; i++) {
@ -64,7 +64,27 @@ export class BoLItemSheet extends ItemSheet {
}
/* -------------------------------------------- */
_getHeaderButtons() {
let buttons = super._getHeaderButtons();
buttons.unshift({
class: "post",
icon: "fas fa-comment",
onclick: ev => this.postItem()
});
return buttons
}
/* -------------------------------------------- */
postItem() {
let chatData = duplicate(this.item)
if (this.actor) {
chatData.actor = { id: this.actor.id };
}
BoLUtility.postItem(chatData);
}
/* -------------------------------------------- */
/** @override */
setPosition(options = {}) {
const position = super.setPosition(options);

View File

@ -1,5 +1,6 @@
/* -------------------------------------------- */
import { BoLRoll } from "../controllers/bol-rolls.js";
import { BoLUtility } from "../system/bol-utility.js";
/* -------------------------------------------- */
export class BoLTokenHud {
@ -30,10 +31,17 @@ export class BoLTokenHud {
(event) => {
let actionIndex = Number(event.currentTarget.attributes['data-action-index'].value)
let action = hudData.actionsList[actionIndex]
const weapon = actor.items.get( action._id )
BoLRoll.weaponCheckWithWeapon(hudData.actor, duplicate(weapon))
//console.log("Clicked", action)
} )
const actionItem = actor.items.get(action._id)
if (actionItem.system.subtype == "weapon") {
BoLRoll.weaponCheckWithWeapon(hudData.actor, duplicate(actionItem))
} else if (actionItem.system.subtype == "fightoption") {
let chatData = duplicate(actionItem)
if (actionItem.actor) {
chatData.actor = { id: actionItem.actor._id };
}
BoLUtility.postItem(chatData);
}
})
const controlIconTarget = html.find('.control-icon[data-action=target]');
// att+apt+career
@ -41,18 +49,18 @@ export class BoLTokenHud {
(event) => {
let rollIndex = Number(event.currentTarget.attributes['data-roll-index'].value)
let roll = hudData.rollsList[rollIndex]
if ( roll.type == "aptitude") {
BoLRoll.aptitudeCheck(actor, roll.key )
} else if ( roll.type == "attribute") {
BoLRoll.attributeCheck(actor, roll.key )
if (roll.type == "aptitude") {
BoLRoll.aptitudeCheck(actor, roll.key)
} else if (roll.type == "attribute") {
BoLRoll.attributeCheck(actor, roll.key)
}
})
}
/* -------------------------------------------- */
static async addTokenHudExtensions(app, html, tokenId) {
const controlIconCombat = html.find('.control-icon[data-action=combat]')
if (controlIconCombat.length>0 ) {
const controlIconCombat = html.find('.control-icon[data-action=combat]')
if (controlIconCombat.length > 0) {
BoLTokenHud.addExtensionHud(app, html, tokenId);
}
}
@ -61,9 +69,9 @@ export class BoLTokenHud {
static async _configureSubMenu(insertionPoint, template, hudData, onMenuItem) {
const hud = $(await renderTemplate(template, hudData))
const list = hud.find('div.bol-hud-list')
BoLTokenHud._toggleHudListActive(hud, list);
hud.find('img.bol-hud-togglebutton').click(event => BoLTokenHud._toggleHudListActive(hud, list));
list.find('.bol-hud-menu').click(onMenuItem);

View File

@ -20,12 +20,15 @@ export class BoLCombatManager extends Combat {
console.log(`${game.system.title} | Combat.rollInitiative()`, ids, formula, messageOptions);
// Structure input data
ids = typeof ids === "string" ? [ids] : ids;
//const currentId = this.combatant.id;
// Get initiative malus from tough/adversary
let malusInit = 0
for (let combatant of this.combatants) {
malusInit = Math.max(malusInit, combatant.actor.getInitiativeMalus())
}
// calculate initiative
for (let cId = 0; cId < ids.length; cId++) {
for (let cId = 0; cId < ids.length; cId++) {
const combatant = this.combatants.get(ids[cId])
let fvttInit = combatant.actor.getInitiativeRank(false, true)
let fvttInit = combatant.actor.getInitiativeRank(false, true, { combatId: this.id, combatantId: combatant.id, malusInit })
fvttInit += (cId / 100)
await this.updateEmbeddedDocuments("Combatant", [{ _id: ids[cId], initiative: fvttInit }]);
}
@ -33,23 +36,49 @@ export class BoLCombatManager extends Combat {
/************************************************************************************/
nextRound() {
let combatants = this.combatants.contents
for (let c of combatants) {
let actor = game.actors.get( c.actorId )
actor.clearRoundModifiers()
if (game.user.isGM) {
let combatants = this.combatants.contents
let autoRemoveDead = game.settings.get("bol", "auto-remove-dead") // Optionnal auto-removal of dead char.
for (let c of combatants) {
//let actor = game.actors.get(c.actorId)
c.actor.clearRoundModifiers()
let toRemove = []
if (autoRemoveDead && c.actor.type == "encounter" && (c.actor.system.chartype == "tough" || c.actor.system.chartype == "creature" || c.actor.system.chartype == "base") && c.actor.system.resources.hp.value <= 0) {
toRemove.push(c.id || c._id)
}
//console.log("REM", autoRemoveDead, toRemove, c.actor)
if (toRemove.length > 0) {
this.deleteEmbeddedDocuments('Combatant', toRemove)
}
}
}
super.nextRound()
}
/************************************************************************************/
startCombat() {
if (game.user.isGM) {
let combatants = this.combatants.contents
for (let c of combatants) {
let actor = game.actors.get(c.actorId)
actor.storeVitaliteCombat()
}
}
return super.startCombat()
}
/*-***********************************************************************************/
_onDelete() {
let combatants = this.combatants.contents
for (let c of combatants) {
let actor = game.actors.get(c.actorId)
actor.clearInitiative()
if (game.user.isGM) {
let combatants = this.combatants.contents
for (let c of combatants) {
let actor = game.actors.get(c.actorId)
actor.clearInitiative()
actor.displayRecuperation()
}
}
super._onDelete()
}
}

View File

@ -1,15 +1,13 @@
import { BoLDefaultRoll } from "../controllers/bol-rolls.js";
import { BoLRoll, BoLDefaultRoll } from "../controllers/bol-rolls.js";
// Spell circle to min PP cost
const __circle2minpp = { 0: 0, 1: 2, 2: 6, 3: 11 }
const __validDices = {"6": 1, "8": 1, "10": 1, "12": 1}
const __validDices = { "6": 1, "8": 1, "10": 1, "12": 1 }
export class BoLUtility {
/* -------------------------------------------- */
static init() {
this.attackStore = {}
game.settings.register("bol", "rollArmor", {
name: "Effectuer des jets pour les armures",
hint: "Effectue un jet de dés pour les armures (valeur fixe si désactivé)",
@ -28,15 +26,23 @@ export class BoLUtility {
type: Boolean,
onChange: lang => window.location.reload()
})
game.settings.register("bol", "auto-remove-dead", {
name: "Enlever les PNJs morts automatiquement au round suivant",
hint: "Supprime les PNJ (piétaille, créatures, coriaces) automatiquement du combat lorsqu'ils sont à 0 Vitalité ou moins, lors du passage au round suivant",
scope: "world",
config: true,
default: false,
type: Boolean
})
game.settings.register("bol", "dice-formula", {
name: "Formule de dés",
hint: "Sélectionne la formule de dés (par défaut 2d6)",
scope: "world",
config: true,
default: "2d6",
default: "6",
type: String,
choices: { "6": "2d6", "8":"2d8", "10":"2d10", "12":"2d12", "20":"2d20"},
onChange: value => {
choices: { "6": "2d6", "8": "2d8", "10": "2d10", "12": "2d12", "20": "2d20" },
onChange: value => {
BoLUtility.setDiceFormula(value)
}
})
@ -52,7 +58,7 @@ export class BoLUtility {
step: 1
},
type: Number,
onChange: value => {
onChange: value => {
BoLUtility.setSuccessValue(value)
}
})
@ -68,7 +74,7 @@ export class BoLUtility {
step: 1
},
type: Number,
onChange: value => {
onChange: value => {
BoLUtility.setCriticalSuccessValue(value)
}
})
@ -84,7 +90,7 @@ export class BoLUtility {
step: 1
},
type: Number,
onChange: value => {
onChange: value => {
BoLUtility.setCriticalFailureValue(value)
}
})
@ -147,12 +153,12 @@ export class BoLUtility {
}
static getDiceData() {
let df = this.diceFormula
if ( !__validDices[String(this.diceFormula)]) {
if (!__validDices[String(this.diceFormula)]) {
df = "6"
}
return {
diceFormula: this.diceFormula,
successValue : this.successValue,
diceFormula: df,
successValue: this.successValue,
criticalSuccessValue: this.criticalSuccessValue,
criticalFailureValue: this.criticalFailureValue
}
@ -194,28 +200,43 @@ export class BoLUtility {
}
/* -------------------------------------------- */
static templateData(it) {
return BoLUtility.data(it)?.data ?? {}
}
static chatDataSetup(content, modeOverride, isRoll = false, forceWhisper) {
let chatData = {
user: game.user.id,
rollMode: modeOverride || game.settings.get("core", "rollMode"),
content: content
};
/* -------------------------------------------- */
static data(it) {
if (it instanceof Actor || it instanceof Item || it instanceof Combatant) {
return it.data;
if (["gmroll", "blindroll"].includes(chatData.rollMode)) chatData["whisper"] = ChatMessage.getWhisperRecipients("GM").map(u => u.id);
if (chatData.rollMode === "blindroll") chatData["blind"] = true;
else if (chatData.rollMode === "selfroll") chatData["whisper"] = [game.user];
if (forceWhisper) { // Final force !
chatData["speaker"] = ChatMessage.getSpeaker();
chatData["whisper"] = ChatMessage.getWhisperRecipients(forceWhisper);
}
return it;
return chatData;
}
/* -------------------------------------------- */
static storeRoll(roll) {
this.rollTab[roll.id] = roll
}
static postItem(chatData) {
// Don't post any image for the item (which would leave a large gap) if the default image is used
if (chatData.img.includes("/blank.png")) {
chatData.img = null;
}
// JSON object for easy creation
chatData.jsondata = JSON.stringify(
{
compendium: "postedItem",
payload: chatData,
});
/* -------------------------------------------- */
static getRoll(rollId) {
return this.rollTab[roll.id]
renderTemplate('systems/bol/templates/item/post-item.hbs', chatData).then(html => {
let chatOptions = BoLUtility.chatDataSetup(html);
ChatMessage.create(chatOptions, "selfroll")
});
}
/* -------------------------------------------- */
static createDirectOptionList(min, max) {
let options = {};
@ -260,7 +281,7 @@ export class BoLUtility {
}
/* -------------------------------------------- */
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) {
@ -298,13 +319,13 @@ export class BoLUtility {
}
/* -------------------------------------------- */
static sendAttackSuccess(attackDef) {
if (attackDef.targetId) {
static sendAttackSuccess(rollData) {
if (rollData.targetId) {
// Broadcast to GM or process it directly in case of GM defense
if (!game.user.isGM) {
game.socket.emit("system.bol", { name: "msg_attack_success", data: duplicate(attackDef) })
game.socket.emit("system.bol", { name: "msg_attack_success", data: duplicate(rollData) })
} else {
BoLUtility.processAttackSuccess(attackDef)
BoLUtility.processAttackSuccess(rollData)
}
}
}
@ -330,6 +351,14 @@ export class BoLUtility {
let message = game.messages.get(messageId)
return message.getFlag("world", "bol-roll-data")
}
/* -------------------------------------------- */
static requestInitRoll(actorId, combatData) {
let actor = game.actors.get(actorId)
if (actor && actor.isOwner) {
ui.notifications.info(game.i18n.localize("BOL.ui.warninitiative"))
BoLRoll.aptitudeCheck(actor, "init", undefined, combatData)
}
}
/* -------------------------------------------- */
static cleanupButtons(id) {
@ -397,6 +426,19 @@ export class BoLUtility {
game.socket.emit("system.bol", { name: "msg_damage_handling", data: { msgId: msgId, attackId: attackId, defenseMode: defenseMode, weaponId: weaponId } })
}
})
html.on("click", '.recup-vitalite', event => {
event.preventDefault()
let actorId = event.currentTarget.attributes['data-actor-id'].value
let recupHP = event.currentTarget.attributes['data-recup-hp'].value
let actor = game.actors.get(actorId)
let messageId = BoLUtility.findChatMessageId(event.currentTarget)
BoLUtility.removeChatMessageId(messageId)
actor.applyRecuperation(recupHP)
})
}
/* -------------------------------------------- */
@ -404,48 +446,50 @@ export class BoLUtility {
if (!game.user.isGM) {
return
}
let message = game.messages.get(msgId)
let rollData = message.getFlag("world", "bol-roll-data")
BoLUtility.removeChatMessageId(msgId)
console.log("Damage Handling", attackId, defenseMode, weaponId)
// Only GM process this
let attackDef = this.attackStore[attackId]
if (attackDef && attackDef.defenderId) {
if (attackDef.defenseDone) {
if (rollData && rollData.defenderId) {
if (rollData.defenseDone || defenseMode == 'damage-not-applied') {
return
} // ?? Why ???
attackDef.defenseDone = true
attackDef.defenseMode = defenseMode
let token = game.scenes.current.tokens.get(attackDef.targetId)
rollData.defenseDone = true
rollData.defenseMode = defenseMode
let token = game.scenes.current.tokens.get(rollData.targetId)
let defender = token.actor
if (defenseMode == 'damage-with-armor') {
let armorFormula = defender.getArmorFormula()
attackDef.rollArmor = new Roll(armorFormula)
attackDef.rollArmor.roll({ async: false })
attackDef.armorProtect = (attackDef.rollArmor.total < 0) ? 0 : attackDef.rollArmor.total
attackDef.finalDamage = attackDef.damageTotal - attackDef.armorProtect
attackDef.finalDamage = (attackDef.finalDamage < 0) ? 0 : attackDef.finalDamage
defender.sufferDamage(attackDef.finalDamage)
console.log("Armor roll -> result ", attackDef)
rollData.rollArmor = new Roll(armorFormula)
rollData.rollArmor.roll({ async: false })
rollData.armorProtect = (rollData.rollArmor.total < 0) ? 0 : rollData.rollArmor.total
rollData.finalDamage = rollData.damageTotal - rollData.armorProtect
rollData.finalDamage = (rollData.finalDamage < 0) ? 0 : rollData.finalDamage
defender.sufferDamage(rollData.finalDamage)
console.log("Armor roll -> result ", rollData)
}
if (defenseMode == 'damage-without-armor') {
attackDef.finalDamage = attackDef.damageTotal
defender.sufferDamage(attackDef.finalDamage)
rollData.finalDamage = atrollDatatackDef.damageTotal
defender.sufferDamage(rollData.finalDamage)
}
if (defenseMode == 'hero-reduce-damage') {
let armorFormula = defender.getArmorFormula()
attackDef.rollArmor = new Roll(armorFormula)
attackDef.rollArmor.roll({ async: false })
attackDef.armorProtect = (attackDef.rollArmor.total < 0) ? 0 : attackDef.rollArmor.total
attackDef.rollHero = new Roll("1d6")
attackDef.rollHero.roll({ async: false })
attackDef.finalDamage = attackDef.damageTotal - attackDef.rollHero.total - attackDef.armorProtect
attackDef.finalDamage = (attackDef.finalDamage < 0) ? 0 : attackDef.finalDamage
defender.sufferDamage(attackDef.finalDamage)
rollData.rollArmor = new Roll(armorFormula)
rollData.rollArmor.roll({ async: false })
rollData.armorProtect = (rollData.rollArmor.total < 0) ? 0 : rollData.rollArmor.total
rollData.rollHero = new Roll("1d6")
rollData.rollHero.roll({ async: false })
rollData.finalDamage = rollData.damageTotal - rollData.rollHero.total - rollData.armorProtect
rollData.finalDamage = (rollData.finalDamage < 0) ? 0 : rollData.finalDamage
defender.sufferDamage(rollData.finalDamage)
defender.subHeroPoints(1)
}
if (defenseMode == 'hero-in-extremis') {
attackDef.finalDamage = 0;
attackDef.weaponHero = defender.weapons.find(item => item._id == weaponId);
rollData.finalDamage = 0;
rollData.weaponHero = defender.weapons.find(item => item._id == weaponId);
defender.deleteEmbeddedDocuments("Item", [weaponId]);
}
@ -456,16 +500,16 @@ export class BoLUtility {
}
}
let damageResults = {
attackId: attackDef.id,
attacker: attackDef.attacker,
rollArmor: attackDef.rollArmor,
rollHero: attackDef.rollHero,
weaponHero: attackDef.weaponHero,
armorProtect: attackDef.armorProtect,
attackId: rollData.id,
attacker: rollData.attacker,
rollArmor: rollData.rollArmor,
rollHero: rollData.rollHero,
weaponHero: rollData.weaponHero,
armorProtect: rollData.armorProtect,
name: defender.name,
defender: defender,
defenseMode: attackDef.defenseMode,
finalDamage: attackDef.finalDamage
defenseMode: rollData.defenseMode,
finalDamage: rollData.finalDamage
}
ChatMessage.create({
alias: defender.name,
@ -509,7 +553,7 @@ export class BoLUtility {
}
/* -------------------------------------------- */
static isRangedWeapon(weapon) {
return weapon.data.type == 'ranged' || weapon.data.thrown;
return weapon.system.type == 'ranged' || weapon.system.thrown;
}
/* -------------------------------------------- */
@ -552,28 +596,28 @@ export class BoLUtility {
}
/* -------------------------------------------- */
static async processAttackSuccess(attackDef) {
console.log("Attack success processing", attackDef)
if (!game.user.isGM || !attackDef.defenderId) { // Only GM process this
static async processAttackSuccess(rollData) {
console.log("Attack success processing", rollData)
if (!game.user.isGM || !rollData.defenderId) { // Only GM process this
return
}
// Build and send the defense message to the relevant people (ie GM + defender)
let defender = game.actors.get(attackDef.defenderId)
console.log("DEF WEP", attackDef, defender)
let defender = game.actors.get(rollData.defenderId)
let defenderWeapons = defender.weapons || []
this.attackStore[attackDef.id] = attackDef // Store !
ChatMessage.create({
let msg = await ChatMessage.create({
alias: defender.name,
whisper: BoLUtility.getWhisperRecipientsAndGMs(defender.name),
content: await renderTemplate('systems/bol/templates/chat/rolls/defense-request-card.hbs', {
attackId: attackDef.id,
attacker: attackDef.attacker,
attackId: rollData.id,
attacker: rollData.attacker,
defender: defender,
defenderWeapons: defenderWeapons,
damageTotal: attackDef.damageRoll.total,
damagesIgnoresArmor: attackDef.damagesIgnoresArmor,
damageTotal: rollData.damageTotal,
damagesIgnoresArmor: rollData.damagesIgnoresArmor,
})
})
msg.setFlag("world", "bol-roll-data", rollData)
console.log("DEF WEP", rollData, defender)
}
/* -------------------------------------------- */
@ -584,6 +628,9 @@ export class BoLUtility {
if (sockmsg.name == "msg_cleanup_buttons") {
$(`#${sockmsg.data.id}`).hide() // Hide the options roll buttons
}
if (sockmsg.name == "msg_request_init_roll") {
this.requestInitRoll(sockmsg.data.actorId, sockmsg.data.combatData)
}
if (sockmsg.name == "msg_damage_handling") {
BoLUtility.processDamageHandling(sockmsg.data.attackId, sockmsg.data.defenseMode, sockmsg.data.weaponId, sockmsg.data.msgId)
}
@ -591,15 +638,15 @@ export class BoLUtility {
/* -------------------------------------------- */
static computeSpellCost(spell, nbOptCond = 0) {
let pp = spell.data.properties.ppcost
let minpp = __circle2minpp[spell.data.properties.circle]
let pp = spell.system.properties.ppcost
let minpp = __circle2minpp[spell.system.properties.circle]
pp = (pp - nbOptCond < minpp) ? minpp : pp - nbOptCond
return pp
}
/* -------------------------------------------- */
static getDamageFormula(weaponData, fightOption) {
let upgradeDamage = (fightOption && fightOption.data.properties.fightoptiontype == "twoweaponsatt")
let upgradeDamage = (fightOption && fightOption.system.properties.fightoptiontype == "twoweaponsatt")
let damageString = weaponData.properties.damage
let modifier = weaponData.properties.damageModifiers ?? 0
let multiplier = weaponData.properties.damageMultiplier ?? 1

View File

@ -281,6 +281,7 @@ BOL.fightOptionTypes = {
"fulldefense": "BOL.fightOptionTypes.fulldefense",
"defense": "BOL.fightOptionTypes.defense",
"attack": "BOL.fightOptionTypes.attack",
"other": "BOL.fightOptionTypes.other"
}
BOL.itemIcons = {

View File

@ -118,7 +118,7 @@ export const registerHandlebarsHelpers = function () {
})
Handlebars.registerHelper('includesKey', function (items, type, key) {
// console.log(items);
return items.filter(i => i.type === type).map(i => i.data.key).includes(key);
return items.filter(i => i.type === type).map(i => i.system.key).includes(key);
})
Handlebars.registerHelper('includes', function (array, val) {
return array.includes(val);

View File

@ -49,7 +49,7 @@ export default function registerHooks() {
let macro = game.macros.entities.find(m => (m.name === actor.name) && (m.command === command));
if (!macro) {
macro = await Macro.create({
name: actor.data.name,
name: actor.name,
type: "script",
img: "icons/svg/dice-target.svg",
command: command
@ -65,9 +65,9 @@ export default function registerHooks() {
let macro = game.macros.entities.find(m => (m.name === journal.name) && (m.command === command));
if (!macro) {
macro = await Macro.create({
name: journal.data.name,
name: journal.name,
type: "script",
img: (journal.data.img) ? journal.data.img : "icons/svg/book.svg",
img: (journal.img) ? journal.img : "icons/svg/book.svg",
command: command
}, {displaySheet: false})
game.user.assignHotbarMacro(macro, slot);

View File

@ -37,13 +37,13 @@ export class Macros {
};
if(rollType === "attribute") {
let attribute = eval(`actor.data.data.attributes.${key}`);
let attribute = eval(`actor.system.attributes.${key}`);
let rollLabel = (attribute.label) ? game.i18n.localize(attribute.label) : null;
let description = actor.name + " - " + game.i18n.localize('BOL.ui.attributeCheck') + " - " + game.i18n.localize(attribute.label) ;
BoLRoll.attributeRollDialog(actor, actorData, attribute, rollLabel, description, adv, mod);
}
else if(rollType === "aptitude") {
let aptitude = eval(`actor.data.data.aptitudes.${key}`);
let aptitude = eval(`actor.system.aptitudes.${key}`);
let rollLabel = (aptitude.label) ? game.i18n.localize(aptitude.label) : null;
let description = actor.name + " - " + game.i18n.localize('BOL.ui.aptitudeCheck') + " - " + game.i18n.localize(aptitude.label) ;
BoLRoll.aptitudeRollDialog(actor, actorData, aptitude, rollLabel, description, adv, mod);

View File

@ -1,7 +1,30 @@
{"_id":"4VsEmcj4YpdAaaZY","name":"Attaque au Défaut d'armure","type":"feature","img":"icons/skills/melee/weapons-crossed-poleaxes-white.webp","data":{"category":null,"subtype":"fightoption","description":"<p>Vous visez une zone du corps non prot&eacute;g&eacute;e ou&nbsp;un point faible de l&rsquo;armure de votre adversaire.</p>\n<p>Appliquez la valeur de protection fixe de l&rsquo;armure comme malus &agrave; votre jet d&rsquo;attaque (-1 pour une armure l&eacute;g&egrave;re, -2 pour une armure moyenne et -3 pour une armure lourde). Si votre attaque passe malgr&eacute; ce malus, les d&eacute;g&acirc;ts de votre coup ignorent la protection de l&rsquo;armure.</p>\n<p>Si le MJ l&rsquo;accepte, cette option de combat pourra &eacute;galement permettre de trouver le d&eacute;faut de l&rsquo;armure naturelle d&rsquo;une cr&eacute;ature.</p>","properties":{"ismalusdice":false,"isbonusdice":false,"fightoptiontype":"armordefault","activated":false},"rank":0,"fightoptiontype":"armordefault"},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"kQghu0tL1dft5xLu":3},"flags":{"core":{"sourceId":"Item.3nzfQvMvkK4ujRqI"}}}
{"name":"Posture Défensive","type":"feature","img":"icons/skills/melee/weapons-crossed-poleaxes-white.webp","data":{"category":null,"subtype":"fightoption","description":"<p>Vous choisissez d&rsquo;adopter une attitude prudente, en restant toujours pr&ecirc;t &agrave; parer ou &agrave; esquiver l&rsquo;attaque de votre adversaire. Combattre en posture d&eacute;fensive vous conf&egrave;re un bonus de +1 en d&eacute;fense, mais vous subissez un malus de -1 &agrave; votre jet d&rsquo;attaque.</p>","properties":{"ismalusdice":false,"isbonusdice":false,"fightoptiontype":"defense","activated":false},"rank":0,"fightoptiontype":"defense"},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"kQghu0tL1dft5xLu":3},"flags":{"core":{"sourceId":"Item.CS1fCtHTxp5v1krr"}},"_id":"FQPqaB86ZkRzsKwG"}
{"name":"Défense Totale","type":"feature","img":"icons/skills/melee/weapons-crossed-poleaxes-white.webp","data":{"category":null,"subtype":"fightoption","description":"<p>Vous consacrez votre round &agrave; esquiver, parer et vous prot&eacute;ger des coups. Vous n&rsquo; effectuez pas d&rsquo;attaque durant le round, mais b&eacute;n&eacute;ficiez d&rsquo;un bonus de +2 en d&eacute;fense, qui s&rsquo;ajoute &eacute;ventuellement &agrave; celui que pourrait vous apporter un bouclier ou une arme secondaire de parade.</p>","properties":{"ismalusdice":false,"isbonusdice":false,"fightoptiontype":"fulldefense","activated":false},"rank":0,"fightoptiontype":"fulldefense"},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"kQghu0tL1dft5xLu":3},"flags":{"core":{"sourceId":"Item.t8v7isBpnFzAbmUI"}},"_id":"JRboSn5RuGILpH0B"}
{"name":"Combat à Deux Armes (Défensif)","type":"feature","img":"icons/skills/melee/weapons-crossed-poleaxes-white.webp","data":{"category":null,"subtype":"fightoption","description":"<p>Vous ne pouvez utiliser que des armes l&eacute;g&egrave;res&nbsp;ou moyennes.</p>\n<p>Vous attaquez avec une arme et parez avec l&rsquo;autre. Vous consid&eacute;rez l&rsquo;arme de parade comme l&rsquo;&eacute;quivalent d&rsquo;un petit bouclier (+1 en d&eacute;fense contre une attaque), mais vous subissez un malus de -1 sur votre jet d&rsquo;attaque avec votre autre arme.</p>","properties":{"ismalusdice":false,"isbonusdice":false,"fightoptiontype":"twoweaponsdef","activated":false},"rank":0,"fightoptiontype":"twoweapons"},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"kQghu0tL1dft5xLu":3},"flags":{"core":{"sourceId":"Item.lyMbLMPnFk0oXaSr"}},"_id":"JtU8EmKuda0M4Onv"}
{"_id":"a3Ev9xm8aM9kAmi3","name":"Attaque Intrépide","type":"feature","img":"icons/skills/melee/weapons-crossed-poleaxes-white.webp","data":{"category":null,"subtype":"fightoption","description":"<p>Vous attaquez avec la plus extr&ecirc;me t&eacute;m&eacute;rit&eacute;.</p>\n<p>Vous ne b&eacute;n&eacute;ficiez pas de l&rsquo;&eacute;ventuel bonus d&rsquo;un&nbsp;bouclier ou d&rsquo;une arme secondaire de parade et subissez un malus de -2 &agrave; la d&eacute;fense. En revanche,&nbsp;vous b&eacute;n&eacute;ficiez d&rsquo;un bonus de +2 au jet d&rsquo;attaque.</p>","properties":{"ismalusdice":false,"isbonusdice":false,"fightoptiontype":"intrepid","activated":false},"rank":0,"fightoptiontype":"intrepid"},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"kQghu0tL1dft5xLu":3},"flags":{"core":{"sourceId":"Item.589BS9KBGnUazrFA"}}}
{"name":"Posture Offensive","type":"feature","img":"icons/skills/melee/weapons-crossed-poleaxes-white.webp","data":{"category":null,"subtype":"fightoption","description":"<p>Vous vous concentrez sur l&rsquo;attaque, au d&eacute;triment&nbsp;de votre d&eacute;fense. Cette option vous conf&egrave;re un bonus de +1 au jet d&rsquo;attaque, mais vous subissez un malus de -1 en d&eacute;fense.</p>","properties":{"ismalusdice":false,"isbonusdice":false,"fightoptiontype":"attack","activated":false},"rank":0,"fightoptiontype":"attack"},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"kQghu0tL1dft5xLu":3},"flags":{"core":{"sourceId":"Item.BF7F5WvL1pbWVHNq"}},"_id":"hgUHJP6JFxbeiRQL"}
{"name":"Combat à Deux Armes (Offensif)","type":"feature","img":"icons/skills/melee/weapons-crossed-poleaxes-white.webp","data":{"category":null,"subtype":"fightoption","description":"<p>Vous ne pouvez utiliser que des armes l&eacute;g&egrave;res&nbsp;ou moyennes.</p>\n<p><span style=\"font-family: var(--font-primary); font-size: var(--font-size-14);\">Vous attaquez avec vos deux armes. </span><span style=\"font-family: var(--font-primary); font-size: var(--font-size-14);\">Vous n&rsquo;effectuez qu&rsquo;un seul jet d&rsquo;attaque avec un </span>malus de -1, mais vous infligez des d&eacute;g&acirc;ts comme&nbsp;si vous maniez une arme moyenne (si vous utilisez deux armes l&eacute;g&egrave;res) ou une arme lourde (si vous&nbsp;utilisez une arme moyenne et une arme l&eacute;g&egrave;re, ou deux armes moyennes).</p>","properties":{"ismalusdice":false,"isbonusdice":false,"fightoptiontype":"twoweaponsatt","activated":false},"rank":0,"fightoptiontype":"twoweapons"},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"kQghu0tL1dft5xLu":3},"flags":{"core":{"sourceId":"Item.lyMbLMPnFk0oXaSr"}},"_id":"wM4ZIVSSKApgzEmN"}
{"name":"La Passe du Khastok","type":"feature","img":"icons/skills/melee/weapons-crossed-poleaxes-white.webp","effects":[],"flags":{"core":{"sourceId":"Item.lyMbLMPnFk0oXaSr"}},"system":{"category":null,"subtype":"fightoption","description":"<p>Uniquement avec un Khastok de Malakut. Vous fauchez les jambes (ou les membres inf&eacute;rieurs) de<br>votre adversaire.</p>\n<p>Votre attaque souffre d&rsquo;un malus de -2, mais si elle occasionne des d&eacute;g&acirc;ts, la cible doit r&eacute;ussir un test d&rsquo;Agilit&eacute;, avec votre score de M&ecirc;l&eacute;e en malus ou tomber au sol.</p>","properties":{"ismalusdice":false,"isbonusdice":false,"fightoptiontype":"other","isspecial":false,"activated":false},"rank":0,"fightoptiontype":"twoweapons"},"_stats":{"systemId":"bol","systemVersion":"11.0.0","coreVersion":"10.291","createdTime":1687456310231,"modifiedTime":1687457965170,"lastModifiedBy":"kQghu0tL1dft5xLu"},"folder":null,"sort":0,"ownership":{"default":0,"kQghu0tL1dft5xLu":3},"_id":"4EmWdK1cv7EX0X3E"}
{"name":"Le Saut du Voleur (Distraire)","type":"feature","img":"icons/skills/melee/weapons-crossed-poleaxes-white.webp","effects":[],"flags":{"core":{"sourceId":"Item.lyMbLMPnFk0oXaSr"}},"system":{"category":null,"subtype":"fightoption","description":"<p>Vous faites une man&oelig;uvre ayant pour &nbsp;objectif de distraire l&rsquo;adversaire. Vous ne portez pas<br>d&rsquo;attaque.</p>\n<p>Si vous r&eacute;ussissez un test de R&eacute;action (Esprit+Initiative) avec l&rsquo;Esprit de votre cible en malus, elle<br>subit un malus de -1 pour toutes ses actions dans le round en cours.</p>","properties":{"ismalusdice":false,"isbonusdice":false,"fightoptiontype":"other","isspecial":false,"activated":false},"rank":0,"fightoptiontype":"twoweapons"},"_stats":{"systemId":"bol","systemVersion":"11.0.0","coreVersion":"10.291","createdTime":1687456310231,"modifiedTime":1687457965165,"lastModifiedBy":"kQghu0tL1dft5xLu"},"folder":null,"sort":0,"ownership":{"default":0,"kQghu0tL1dft5xLu":3},"_id":"5L42okgdCMC8MZb6"}
{"name":"La Fureur de Charkond (Intimider)","type":"feature","img":"icons/skills/melee/weapons-crossed-poleaxes-white.webp","effects":[],"flags":{"core":{"sourceId":"Item.lyMbLMPnFk0oXaSr"}},"system":{"category":null,"subtype":"fightoption","description":"<p>Vous faites une man&oelig;uvre physique dans l&rsquo;objectif d&rsquo;impressionner votre adversaire en lieu et place de votre attaque.</p>\n<p>Si vous r&eacute;ussissez un test de Vigueur+M&ecirc;l&eacute;e, avec l&rsquo;Esprit de votre cible en malus, elle subit un malus de -2 sur tout ses tests d&rsquo;attaque pour le reste du round. Ne fonctionne que sur un adversaire sur lequel l&rsquo;Intimidation est applicable, donc en g&eacute;n&eacute;ral ne fonctionne pas sur les cr&eacute;atures.</p>","properties":{"ismalusdice":false,"isbonusdice":false,"fightoptiontype":"other","isspecial":false,"activated":false},"rank":0,"fightoptiontype":"twoweapons"},"_stats":{"systemId":"bol","systemVersion":"11.0.0","coreVersion":"10.291","createdTime":1687456310231,"modifiedTime":1687457965166,"lastModifiedBy":"kQghu0tL1dft5xLu"},"folder":null,"sort":0,"ownership":{"default":0,"kQghu0tL1dft5xLu":3},"_id":"6D42OgoKxwtV5tDD"}
{"name":"Les Poignards de Karyzon (Lancer x2)","type":"feature","img":"icons/skills/melee/weapons-crossed-poleaxes-white.webp","effects":[],"flags":{"core":{"sourceId":"Item.lyMbLMPnFk0oXaSr"}},"system":{"category":null,"subtype":"fightoption","description":"<p>Uniquement avec deux Couteaux ou Poignards de lancer. Arm&eacute; d&rsquo;un Poignard dans chaque main, vous<br>les lancez sur 2 cibles diff&eacute;rentes en m&ecirc;me temps</p>\n<p>Chaque attaque &nbsp;est &nbsp;r&eacute;solue s&eacute;par&eacute;ment et souffre d&rsquo;un malus de -2.</p>","properties":{"ismalusdice":false,"isbonusdice":false,"fightoptiontype":"other","isspecial":false,"activated":false},"rank":0,"fightoptiontype":"twoweapons"},"_stats":{"systemId":"bol","systemVersion":"11.0.0","coreVersion":"10.291","createdTime":1687456310231,"modifiedTime":1687457965173,"lastModifiedBy":"kQghu0tL1dft5xLu"},"folder":null,"sort":0,"ownership":{"default":0,"kQghu0tL1dft5xLu":3},"_id":"6tiu12ROxOPE31qU"}
{"name":"Le Halakh-Kriss (Spéciale Kriss)","type":"feature","img":"icons/skills/melee/weapons-crossed-poleaxes-white.webp","effects":[],"flags":{"core":{"sourceId":"Item.lyMbLMPnFk0oXaSr"}},"system":{"category":null,"subtype":"fightoption","description":"<p>Uniquement avec un Kriss d&rsquo;Halakh. Vous portez un coup vicieux &agrave; votre adversaire.</p>\n<p>Votre attaque souffre d&rsquo;un malus de -1, mais si elle r&eacute;ussit, vous augmentez les d&eacute;g&acirc;ts de 1 point.</p>","properties":{"ismalusdice":false,"isbonusdice":false,"fightoptiontype":"other","isspecial":false,"activated":false},"rank":0,"fightoptiontype":"twoweapons"},"_stats":{"systemId":"bol","systemVersion":"11.0.0","coreVersion":"10.291","createdTime":1687456310231,"modifiedTime":1687457965169,"lastModifiedBy":"kQghu0tL1dft5xLu"},"folder":null,"sort":0,"ownership":{"default":0,"kQghu0tL1dft5xLu":3},"_id":"6zSkgyYkk7EV4BGU"}
{"name":"Le Plomb de lAxos (Fronde Axos)","type":"feature","img":"icons/skills/melee/weapons-crossed-poleaxes-white.webp","effects":[],"flags":{"core":{"sourceId":"Item.lyMbLMPnFk0oXaSr"}},"system":{"category":null,"subtype":"fightoption","description":"<p>Uniquement avec une Fronde de l&rsquo;Axos. Vous faites tournoyer votre fronde &agrave; grande vitesse.</p>\n<p>Votre tir souffre d&rsquo;un malus de -2, mais vos d&eacute;g&acirc;ts b&eacute;n&eacute;ficient de la vigueur enti&egrave;re &agrave; la place de la moiti&eacute; de la Vigueur.</p>","properties":{"ismalusdice":false,"isbonusdice":false,"fightoptiontype":"other","isspecial":false,"activated":false},"rank":0,"fightoptiontype":"twoweapons"},"_stats":{"systemId":"bol","systemVersion":"11.0.0","coreVersion":"10.291","createdTime":1687456310231,"modifiedTime":1687457965169,"lastModifiedBy":"kQghu0tL1dft5xLu"},"folder":null,"sort":0,"ownership":{"default":0,"kQghu0tL1dft5xLu":3},"_id":"8p1EsWyLxvmrXc7p"}
{"name":"Le Coup de Mangaï (Entraver - Fouet)","type":"feature","img":"icons/skills/melee/weapons-crossed-poleaxes-white.webp","effects":[],"flags":{"core":{"sourceId":"Item.lyMbLMPnFk0oXaSr"}},"system":{"category":null,"subtype":"fightoption","description":"<p>Uniquement avec un fouet. Vous fouettez votre adversaire pour le g&ecirc;ner et l&rsquo;entraver.</p>\n<p>Votre attaque souffre d&rsquo;un malus de -2, mais si elle r&eacute;ussit, votre fouet s&rsquo;enroule autour d&rsquo;un membre de votre cible. Tant que vous maintenez le fouet, elle subit un malus de -2 pour toutes ses actions, et -1 en d&eacute;fense. En lieu et place d&rsquo;une attaque, la cible peut tenter de se lib&eacute;rer en r&eacute;ussissant un jet de Vigueur+Initiative, avec votre Vigueur en malus.</p>","properties":{"ismalusdice":false,"isbonusdice":false,"fightoptiontype":"other","isspecial":false,"activated":false},"rank":0,"fightoptiontype":"twoweapons"},"_stats":{"systemId":"bol","systemVersion":"11.0.0","coreVersion":"10.291","createdTime":1687456310231,"modifiedTime":1687457965168,"lastModifiedBy":"kQghu0tL1dft5xLu"},"folder":null,"sort":0,"ownership":{"default":0,"kQghu0tL1dft5xLu":3},"_id":"9My3kH5KeAdFmF1F"}
{"name":"Le Trait du Beshaar (Javelot)","type":"feature","img":"icons/skills/melee/weapons-crossed-poleaxes-white.webp","effects":[],"flags":{"core":{"sourceId":"Item.lyMbLMPnFk0oXaSr"}},"system":{"category":null,"subtype":"fightoption","description":"<p>Uniquement avec un Javelot. Vous lancez votre javelot &agrave; une distance plus grande que la plupart des<br>autres aventuriers.</p>\n<p>Votre tir souffre d&rsquo;un malus de -1, mais la port&eacute;e du javelot est doubl&eacute;e (12m au lieu de 6m).</p>","properties":{"ismalusdice":false,"isbonusdice":false,"fightoptiontype":"other","isspecial":false,"activated":false},"rank":0,"fightoptiontype":"twoweapons"},"_stats":{"systemId":"bol","systemVersion":"11.0.0","coreVersion":"10.291","createdTime":1687456310231,"modifiedTime":1687457942168,"lastModifiedBy":"kQghu0tL1dft5xLu"},"_id":"9d4rHBS7CMZI0t4E","folder":null,"sort":0,"ownership":{"default":0,"kQghu0tL1dft5xLu":3}}
{"name":"La pose de lEsclave (Posture Défensive)","type":"feature","img":"icons/skills/melee/weapons-crossed-poleaxes-white.webp","effects":[],"flags":{"core":{"sourceId":"Item.CS1fCtHTxp5v1krr"}},"system":{"category":null,"subtype":"fightoption","description":"<p>Vous choisissez d&rsquo;adopter une attitude prudente, en restant toujours pr&ecirc;t &agrave; parer ou &agrave; esquiver l&rsquo;attaque de votre adversaire. Combattre en posture d&eacute;fensive vous conf&egrave;re un bonus de +1 en d&eacute;fense, mais vous subissez un malus de -1 &agrave; votre jet d&rsquo;attaque.</p>","properties":{"ismalusdice":false,"isbonusdice":false,"fightoptiontype":"defense","isspecial":false,"activated":false},"rank":0,"fightoptiontype":"defense"},"_stats":{"systemId":"bol","systemVersion":"11.0.0","coreVersion":"10.291","createdTime":1687456310228,"modifiedTime":1687457965159,"lastModifiedBy":"kQghu0tL1dft5xLu"},"folder":null,"sort":0,"ownership":{"default":0,"kQghu0tL1dft5xLu":3},"_id":"AoT2c0af4lY6aBsx"}
{"name":"La Passe de Charkond (Feinte)","type":"feature","img":"icons/skills/melee/weapons-crossed-poleaxes-white.webp","effects":[],"flags":{"core":{"sourceId":"Item.lyMbLMPnFk0oXaSr"}},"system":{"category":null,"subtype":"fightoption","description":"<p>Vous placez une botte sp&eacute;ciale, pour tromper et profiter de la d&eacute;fense de votre adversaire. Uniquement possible avec un dague ou une arme de type &eacute;p&eacute;e (sabre, cimeterre, etc.).</p>\n<p>Si vous r&eacute;ussissez un jet d&rsquo;Esprit +Carri&egrave;re guerri&egrave;re (mercenaire, soldat, etc.) en plus de votre<br>attaque, la d&eacute;fense de votre adversaire s&rsquo;ajoute &agrave; vos d&eacute;g&acirc;ts.</p>","properties":{"ismalusdice":false,"isbonusdice":false,"fightoptiontype":"other","isspecial":false,"activated":false},"rank":0,"fightoptiontype":"twoweapons"},"_stats":{"systemId":"bol","systemVersion":"11.0.0","coreVersion":"10.291","createdTime":1687456310231,"modifiedTime":1687457965167,"lastModifiedBy":"kQghu0tL1dft5xLu"},"folder":null,"sort":0,"ownership":{"default":0,"kQghu0tL1dft5xLu":3},"_id":"Cs2yV3V8D7kHBTmT"}
{"name":"Le Coup du Soldat (Désarmer)","type":"feature","img":"icons/skills/melee/weapons-crossed-poleaxes-white.webp","effects":[],"flags":{"core":{"sourceId":"Item.lyMbLMPnFk0oXaSr"}},"system":{"category":null,"subtype":"fightoption","description":"<p>Vous ne pouvez utiliser que des armes l&eacute;g&egrave;res ou moyennes. Vous visez l&rsquo;arme de votre adversaire<br>pour la faire tomber.</p>\n<p>Vous portez une attaque sur l&rsquo;arme, avec pour malus l&rsquo;Agilit&eacute;+M&ecirc;l&eacute;e de votre adversaire. En cas de r&eacute;ussite, l&rsquo;arme vis&eacute;e tombe au sol &agrave; 1d6-2 m&egrave;tres de votre opposant.</p>","properties":{"ismalusdice":false,"isbonusdice":false,"fightoptiontype":"other","isspecial":false,"activated":false},"rank":0,"fightoptiontype":"twoweapons"},"_stats":{"systemId":"bol","systemVersion":"11.0.0","coreVersion":"10.291","createdTime":1687456310231,"modifiedTime":1687457942165,"lastModifiedBy":"kQghu0tL1dft5xLu"},"_id":"EN3xW64gAAj6GxZs","folder":null,"sort":0,"ownership":{"default":0,"kQghu0tL1dft5xLu":3}}
{"name":"La Main dAfyra (Se Reposer)","type":"feature","img":"icons/skills/melee/weapons-crossed-poleaxes-white.webp","effects":[],"flags":{"core":{"sourceId":"Item.lyMbLMPnFk0oXaSr"}},"system":{"category":null,"subtype":"fightoption","description":"<p>Vous restez au contact de votre adversaire, mais vous vous concentrez sur vous-m&ecirc;me. Vous<br>ne pouvez pas attaquer ce round.</p>\n<p>Si vous r&eacute;ussissez un jet de Vigueur, vous r&eacute;cup&eacute;rez 2 Points de Vitalit&eacute;, 4 sur un succ&egrave;s H&eacute;ro&iuml;que. Ces points ne peuvent &ecirc;tre r&eacute;cup&eacute;r&eacute;s que si ils ont &eacute;t&eacute; perdus lors du combat en cours.</p>","properties":{"ismalusdice":false,"isbonusdice":false,"fightoptiontype":"other","isspecial":false,"activated":false},"rank":0,"fightoptiontype":"twoweapons"},"_stats":{"systemId":"bol","systemVersion":"11.0.0","coreVersion":"10.291","createdTime":1687456310231,"modifiedTime":1687457942166,"lastModifiedBy":"kQghu0tL1dft5xLu"},"_id":"EvADUhFjuz7G7ts9","folder":null,"sort":0,"ownership":{"default":0,"kQghu0tL1dft5xLu":3}}
{"name":"Le Doigt de Karyzon (Tir x2)","type":"feature","img":"icons/skills/melee/weapons-crossed-poleaxes-white.webp","effects":[],"flags":{"core":{"sourceId":"Item.lyMbLMPnFk0oXaSr"}},"system":{"category":null,"subtype":"fightoption","description":"<p>Vous encha&icirc;nez 2 tirs au lieu d&rsquo;un, sans pr&eacute;cision. Uniquement avec armes de jet et arcs.</p>\n<p>Vous tirez (ou lancer) tr&egrave;s rapidement, sans pr&eacute;cision, sur la m&ecirc;me cible. Chaque tir/lancer souffre d&rsquo;un malus de -2.</p>","properties":{"ismalusdice":false,"isbonusdice":false,"fightoptiontype":"other","isspecial":false,"activated":false},"rank":0,"fightoptiontype":"twoweapons"},"_stats":{"systemId":"bol","systemVersion":"11.0.0","coreVersion":"10.291","createdTime":1687456310231,"modifiedTime":1687457965168,"lastModifiedBy":"kQghu0tL1dft5xLu"},"folder":null,"sort":0,"ownership":{"default":0,"kQghu0tL1dft5xLu":3},"_id":"FMJGgMYdXztCBTtc"}
{"name":"La Rage du Barbare (Posture Offensive)","type":"feature","img":"icons/skills/melee/weapons-crossed-poleaxes-white.webp","effects":[],"flags":{"core":{"sourceId":"Item.BF7F5WvL1pbWVHNq"}},"system":{"category":null,"subtype":"fightoption","description":"<p>Vous vous concentrez sur l&rsquo;attaque, au d&eacute;triment&nbsp;de votre d&eacute;fense. Cette option vous conf&egrave;re un bonus de +1 au jet d&rsquo;attaque, mais vous subissez un malus de -1 en d&eacute;fense.</p>","properties":{"ismalusdice":false,"isbonusdice":false,"fightoptiontype":"attack","activated":false},"rank":0,"fightoptiontype":"attack"},"ownership":{"default":0,"kQghu0tL1dft5xLu":3},"_stats":{"systemId":"bol","systemVersion":"11.0.2","coreVersion":"10.291","createdTime":1687456310231,"modifiedTime":1687467695919,"lastModifiedBy":"kQghu0tL1dft5xLu"},"folder":null,"sort":0,"_id":"MMcnWBowztvbmXgN"}
{"name":"La Passe de lAssassin (Avantage)","type":"feature","img":"icons/skills/melee/weapons-crossed-poleaxes-white.webp","effects":[],"flags":{"core":{"sourceId":"Item.lyMbLMPnFk0oXaSr"}},"system":{"category":null,"subtype":"fightoption","description":"<p>Vous vous placez de mani&egrave;re &agrave; obtenir &nbsp;une &nbsp;position &nbsp;plus avantageuse pour portez vos attaques.</p>\n<p>En plus de votre attaque normale, vous devez r&eacute;ussir un jet de R&eacute;action (Esprit+Initiative). Sur une<br>r&eacute;ussite, vous b&eacute;n&eacute;ficiez d&rsquo;un d&eacute; bonus pour votre prochaine attaque. Si vous renoncez &agrave; votre attaque, vous b&eacute;n&eacute;ficiez d&rsquo;un bonus de +2 pour le jet de R&eacute;action. Sur un &eacute;chec, c&rsquo;est votre adversaire qui b&eacute;n&eacute;ficie d&rsquo;un d&eacute; bonus pour sa prochaine attaque.</p>","properties":{"ismalusdice":false,"isbonusdice":false,"fightoptiontype":"other","isspecial":false,"activated":false},"rank":0,"fightoptiontype":"twoweapons"},"_stats":{"systemId":"bol","systemVersion":"11.0.0","coreVersion":"10.291","createdTime":1687456310231,"modifiedTime":1687457942165,"lastModifiedBy":"kQghu0tL1dft5xLu"},"_id":"PCa0SQruR9VZUbPh","folder":null,"sort":0,"ownership":{"default":0,"kQghu0tL1dft5xLu":3}}
{"name":"La Folie de Dyr (Occuper)","type":"feature","img":"icons/skills/melee/weapons-crossed-poleaxes-white.webp","effects":[],"flags":{"core":{"sourceId":"Item.lyMbLMPnFk0oXaSr"}},"system":{"category":null,"subtype":"fightoption","description":"<p>Vous faites tournoyer votre arme dans tout les sens, pour faire reculer votre adversaire.</p>\n<p>Votre attaque re&ccedil;oit un malus suppl&eacute;mentaire de -1 et n&rsquo;occasionne pas de d&eacute;g&acirc;ts. En cas<br>de succ&egrave;s, votre adversaire ne peut pas attaquer ce round. Uniquement sur des adversaires au maximum de de taille sup&eacute;rieure d&rsquo;un cran &agrave; la v&ocirc;tre.</p>","properties":{"ismalusdice":false,"isbonusdice":false,"fightoptiontype":"other","isspecial":false,"activated":false},"rank":0,"fightoptiontype":"twoweapons"},"_stats":{"systemId":"bol","systemVersion":"11.0.0","coreVersion":"10.291","createdTime":1687456310231,"modifiedTime":1687457942168,"lastModifiedBy":"kQghu0tL1dft5xLu"},"_id":"PENp7jlG0DirTQeo","folder":null,"sort":0,"ownership":{"default":0,"kQghu0tL1dft5xLu":3}}
{"name":"Le Dit de Iondal (Moquer)","type":"feature","img":"icons/skills/melee/weapons-crossed-poleaxes-white.webp","effects":[],"flags":{"core":{"sourceId":"Item.lyMbLMPnFk0oXaSr"}},"system":{"category":null,"subtype":"fightoption","description":"<p>Vous moquez votre adversaire avec une phrase bien sentie.</p>\n<p>Si vous r&eacute;ussissez un test d&rsquo;Esprit+Carri&egrave;re appropri&eacute;e, avec l&rsquo;Esprit de votre cible en malus, elle<br>subit un malus de -2 en d&eacute;fense pour le reste du round.</p>","properties":{"ismalusdice":false,"isbonusdice":false,"fightoptiontype":"other","isspecial":false,"activated":false},"rank":0,"fightoptiontype":"twoweapons"},"_stats":{"systemId":"bol","systemVersion":"11.0.0","coreVersion":"10.291","createdTime":1687456310231,"modifiedTime":1687457942166,"lastModifiedBy":"kQghu0tL1dft5xLu"},"_id":"VSOjm28jhFhyWk6b","folder":null,"sort":0,"ownership":{"default":0,"kQghu0tL1dft5xLu":3}}
{"name":"Le Tranchant de Parsool (Hache de Parsool)","type":"feature","img":"icons/skills/melee/weapons-crossed-poleaxes-white.webp","effects":[],"flags":{"core":{"sourceId":"Item.lyMbLMPnFk0oXaSr"}},"system":{"category":null,"subtype":"fightoption","description":"<p>Uniquement avec une Hache d&rsquo;Abordage de Parsool. Vous placez une attaque visant l&rsquo;armure de votre adversaire pour la d&eacute;truire.</p>\n<p>Votre attaque souffre d&rsquo;un malus de -1, mais si elle r&eacute;ussit, vous faites sauter une pi&egrave;ce d&rsquo;armure de votre adversaire au lieu de faire des d&eacute;g&acirc;ts. L&rsquo;armure touch&eacute;e se d&eacute;grade d&rsquo;un rang de protection. Uniquement valable sur des adversaires portant une armure artificielle.</p>","properties":{"ismalusdice":false,"isbonusdice":false,"fightoptiontype":"other","isspecial":false,"activated":false},"rank":0,"fightoptiontype":"twoweapons"},"_stats":{"systemId":"bol","systemVersion":"11.0.0","coreVersion":"10.291","createdTime":1687456310231,"modifiedTime":1687457942168,"lastModifiedBy":"kQghu0tL1dft5xLu"},"_id":"VfTa073U4xhs1JWp","folder":null,"sort":0,"ownership":{"default":0,"kQghu0tL1dft5xLu":3}}
{"name":"La Corde de Tyrus (Arc de Tyrus)","type":"feature","img":"icons/skills/melee/weapons-crossed-poleaxes-white.webp","effects":[],"flags":{"core":{"sourceId":"Item.lyMbLMPnFk0oXaSr"}},"system":{"category":null,"subtype":"fightoption","description":"<p>Uniquement avec un arc long de Tyrus. Vous tendez la corde si fort que votre fl&egrave;che porte plus loin.</p>\n<p>Votre attaque souffre d&rsquo;un malus de -2, mais si elle r&eacute;ussit, vous doublez la distance de tir de l&rsquo;Arc (44m au lieu de 22m).</p>","properties":{"ismalusdice":false,"isbonusdice":false,"fightoptiontype":"other","isspecial":false,"activated":false},"rank":0,"fightoptiontype":"twoweapons"},"_stats":{"systemId":"bol","systemVersion":"11.0.0","coreVersion":"10.291","createdTime":1687456310231,"modifiedTime":1687457942169,"lastModifiedBy":"kQghu0tL1dft5xLu"},"_id":"WQkzlwaww7KgarAt","folder":null,"sort":0,"ownership":{"default":0,"kQghu0tL1dft5xLu":3}}
{"name":"Loeil du Mercenaire (Observer)","type":"feature","img":"icons/skills/melee/weapons-crossed-poleaxes-white.webp","effects":[],"flags":{"core":{"sourceId":"Item.lyMbLMPnFk0oXaSr"}},"system":{"category":null,"subtype":"fightoption","description":"<p>Vous observez attentivement l&rsquo;un des adversaires ou un groupe d&rsquo;adversaires similaires. Vous ne<br>portez pas d&rsquo;attaque.</p>\n<p>Si vous r&eacute;ussissez un jet d&rsquo;Esprit + Carri&egrave;re &nbsp;guerri&egrave;re (mercenaire, soldat, etc.) en observant l&rsquo;adversaire, vous pouvez donner un bonus de +2 &agrave; l&rsquo;attaque ou &agrave; la d&eacute;fense &agrave; l&rsquo;un de vos alli&eacute; contre ce m&ecirc;me adversaire pour sa prochaine action de ce type. Une seule assistance peut &ecirc;tre obtenue pour un m&ecirc;me adversaire.</p>","properties":{"ismalusdice":false,"isbonusdice":false,"fightoptiontype":"other","isspecial":false,"activated":false},"rank":0,"fightoptiontype":"twoweapons"},"_stats":{"systemId":"bol","systemVersion":"11.0.0","coreVersion":"10.291","createdTime":1687456310231,"modifiedTime":1687458428494,"lastModifiedBy":"kQghu0tL1dft5xLu"},"_id":"X7mIyzm1ad543fLY","folder":null,"sort":0,"ownership":{"default":0,"kQghu0tL1dft5xLu":3}}
{"name":"La Force de Grondil (Frappe Brutale)","type":"feature","img":"icons/skills/melee/weapons-crossed-poleaxes-white.webp","effects":[],"flags":{"core":{"sourceId":"Item.lyMbLMPnFk0oXaSr"}},"system":{"category":null,"subtype":"fightoption","description":"<p>Vous placez une attaque brutale, sans finesse, mais avec toute votre force. Uniquement avec des armes moyenne ou plus (minimum d6 d&eacute;g&acirc;ts).</p>\n<p>Votre attaque souffre d&rsquo;un malus de -2, mais si elle r&eacute;ussit, vous pouvez ajouter la moiti&eacute; de votre Vigueur pour le calcul des d&eacute;g&acirc;ts (minimum 1). Ce bonus vient en plus du bonus de Vigueur de base d&eacute;j&agrave; applicable.</p>","properties":{"ismalusdice":false,"isbonusdice":false,"fightoptiontype":"other","isspecial":false,"activated":false},"rank":0,"fightoptiontype":"twoweapons"},"_stats":{"systemId":"bol","systemVersion":"11.0.0","coreVersion":"10.291","createdTime":1687456310231,"modifiedTime":1687457965167,"lastModifiedBy":"kQghu0tL1dft5xLu"},"folder":null,"sort":0,"ownership":{"default":0,"kQghu0tL1dft5xLu":3},"_id":"Xeoqf4YtG7Yh9GUz"}
{"name":"La Ruade de lAxos (Déséquilibrer)","type":"feature","img":"icons/skills/melee/weapons-crossed-poleaxes-white.webp","effects":[],"flags":{"core":{"sourceId":"Item.lyMbLMPnFk0oXaSr"}},"system":{"category":null,"subtype":"fightoption","description":"<p>Vous cherchez &agrave; d&eacute;s&eacute;quilibrer votre adversaire. Vous ne portez pas d&rsquo;attaque.</p>\n<p>Si vous r&eacute;ussissez un jet de R&eacute;action (Esprit+Initiative) avec l&rsquo;Agilit&eacute; de votre cible comme malus, elle re&ccedil;oit un d&eacute; malus pour sa prochaine action et un malus de -1 en d&eacute;fense sur la prochaine attaque. Sur un succ&egrave;s h&eacute;ro&iuml;que et que votre cible est de la pi&eacute;taille ou un coriace, elle tombe au sol.</p>","properties":{"ismalusdice":false,"isbonusdice":false,"fightoptiontype":"other","isspecial":false,"activated":false},"rank":0,"fightoptiontype":"twoweapons"},"_stats":{"systemId":"bol","systemVersion":"11.0.0","coreVersion":"10.291","createdTime":1687456310231,"modifiedTime":1687457942166,"lastModifiedBy":"kQghu0tL1dft5xLu"},"_id":"aYGjdR5eWrIEq842","folder":null,"sort":0,"ownership":{"default":0,"kQghu0tL1dft5xLu":3}}
{"name":"La Feinte du Druide (Attaque au Défaut d'armure)","type":"feature","img":"icons/skills/melee/weapons-crossed-poleaxes-white.webp","effects":[],"flags":{"core":{"sourceId":"Item.3nzfQvMvkK4ujRqI"}},"system":{"category":null,"subtype":"fightoption","description":"<p>Vous visez une zone du corps non prot&eacute;g&eacute;e ou&nbsp;un point faible de l&rsquo;armure de votre adversaire.</p>\n<p>Appliquez la valeur de protection fixe de l&rsquo;armure comme malus &agrave; votre jet d&rsquo;attaque (-1 pour une armure l&eacute;g&egrave;re, -2 pour une armure moyenne et -3 pour une armure lourde). Si votre attaque passe malgr&eacute; ce malus, les d&eacute;g&acirc;ts de votre coup ignorent la protection de l&rsquo;armure.</p>\n<p>Si le MJ l&rsquo;accepte, cette option de combat pourra &eacute;galement permettre de trouver le d&eacute;faut de l&rsquo;armure naturelle d&rsquo;une cr&eacute;ature.</p>","properties":{"ismalusdice":false,"isbonusdice":false,"fightoptiontype":"armordefault","isspecial":false,"activated":false},"rank":0,"fightoptiontype":"armordefault"},"_stats":{"systemId":"bol","systemVersion":"11.0.1","coreVersion":"10.291","createdTime":1687456310227,"modifiedTime":1687458575673,"lastModifiedBy":"kQghu0tL1dft5xLu"},"folder":null,"sort":0,"ownership":{"default":0,"kQghu0tL1dft5xLu":3},"_id":"bfQMXfvqS236M0OJ"}
{"name":"La Frappe Lémurienne (Attaque Standard)","type":"feature","img":"icons/skills/melee/weapons-crossed-poleaxes-white.webp","effects":[],"flags":{"core":{"sourceId":"Item.lyMbLMPnFk0oXaSr"}},"system":{"category":null,"subtype":"fightoption","description":"<p>Vous portez une attaque &agrave; votre adversaire, avec votre arme. Au contact ou &agrave; distance.</p>","properties":{"ismalusdice":false,"isbonusdice":false,"fightoptiontype":"other","isspecial":false,"activated":false},"rank":0,"fightoptiontype":"twoweapons"},"_stats":{"systemId":"bol","systemVersion":"11.0.0","coreVersion":"10.291","createdTime":1687456310231,"modifiedTime":1687457942165,"lastModifiedBy":"kQghu0tL1dft5xLu"},"_id":"cqvDDFdlc6oOICxl","folder":null,"sort":0,"ownership":{"default":0,"kQghu0tL1dft5xLu":3}}
{"name":"La Folie du Gladiateur (Attaque Intrépide)","type":"feature","img":"icons/skills/melee/weapons-crossed-poleaxes-white.webp","effects":[],"flags":{"core":{"sourceId":"Item.589BS9KBGnUazrFA"}},"system":{"category":null,"subtype":"fightoption","description":"<p>Vous attaquez avec la plus extr&ecirc;me t&eacute;m&eacute;rit&eacute;.</p>\n<p>Vous ne b&eacute;n&eacute;ficiez pas de l&rsquo;&eacute;ventuel bonus d&rsquo;un&nbsp;bouclier ou d&rsquo;une arme secondaire de parade et subissez un malus de -2 &agrave; la d&eacute;fense. En revanche,&nbsp;vous b&eacute;n&eacute;ficiez d&rsquo;un bonus de +2 au jet d&rsquo;attaque.</p>","properties":{"ismalusdice":false,"isbonusdice":false,"fightoptiontype":"intrepid","isspecial":false,"activated":false},"rank":0,"fightoptiontype":"intrepid"},"_stats":{"systemId":"bol","systemVersion":"11.0.0","coreVersion":"10.291","createdTime":1687456310230,"modifiedTime":1687457965158,"lastModifiedBy":"kQghu0tL1dft5xLu"},"folder":null,"sort":0,"ownership":{"default":0,"kQghu0tL1dft5xLu":3},"_id":"fTNUNRlUmfoNTkil"}
{"name":"Le Coup du Gladiateur (Combat à Deux Armes - Offensif)","type":"feature","img":"icons/skills/melee/weapons-crossed-poleaxes-white.webp","effects":[],"flags":{"core":{"sourceId":"Item.lyMbLMPnFk0oXaSr"}},"system":{"category":null,"subtype":"fightoption","description":"<p>Vous ne pouvez utiliser que des armes l&eacute;g&egrave;res&nbsp;ou moyennes.</p>\n<p><span style=\"font-family: var(--font-primary); font-size: var(--font-size-14);\">Vous attaquez avec vos deux armes. </span><span style=\"font-family: var(--font-primary); font-size: var(--font-size-14);\">Vous n&rsquo;effectuez qu&rsquo;un seul jet d&rsquo;attaque avec un </span>malus de -1, mais vous infligez des d&eacute;g&acirc;ts comme&nbsp;si vous maniez une arme moyenne (si vous utilisez deux armes l&eacute;g&egrave;res) ou une arme lourde (si vous&nbsp;utilisez une arme moyenne et une arme l&eacute;g&egrave;re, ou deux armes moyennes).</p>","properties":{"ismalusdice":false,"isbonusdice":false,"fightoptiontype":"twoweaponsatt","isspecial":false,"activated":false},"rank":0,"fightoptiontype":"twoweapons"},"_stats":{"systemId":"bol","systemVersion":"11.0.0","coreVersion":"10.291","createdTime":1687456310231,"modifiedTime":1687457965160,"lastModifiedBy":"kQghu0tL1dft5xLu"},"folder":null,"sort":0,"ownership":{"default":0,"kQghu0tL1dft5xLu":3},"_id":"iWIttyo2UIafVsRB"}
{"name":"La Vengeance du Valgard (Epee Valgardienne)","type":"feature","img":"icons/skills/melee/weapons-crossed-poleaxes-white.webp","effects":[],"flags":{"core":{"sourceId":"Item.lyMbLMPnFk0oXaSr"}},"system":{"category":null,"subtype":"fightoption","description":"<p>Uniquement avec une &eacute;p&eacute;e Valgardienne. Si vous avez subit des d&eacute;g&acirc;ts lors de l&rsquo;attaque pr&eacute;c&eacute;dente, vous profitez du poids de votre arme pour appuyer votre coup.</p>\n<p>Si vous avez perdu des Points de Vitalit&eacute; &nbsp;lors &nbsp;de &nbsp;l&rsquo;attaque pr&eacute;c&eacute;dente, vous pouvez faire un<br>jet de Vigueur+Barbare en plus de votre attaque. Si les deux jets sont r&eacute;ussis, vous augmentez les d&eacute;g&acirc;ts de 2 points. Si seule l&rsquo;attaque est r&eacute;ussi, appliquez les d&eacute;g&acirc;ts normaux.</p>","properties":{"ismalusdice":false,"isbonusdice":false,"fightoptiontype":"other","isspecial":false,"activated":false},"rank":0,"fightoptiontype":"twoweapons"},"_stats":{"systemId":"bol","systemVersion":"11.0.0","coreVersion":"10.291","createdTime":1687456310231,"modifiedTime":1687457942169,"lastModifiedBy":"kQghu0tL1dft5xLu"},"_id":"ixpHCL4Uc9DUoBJ4","folder":null,"sort":0,"ownership":{"default":0,"kQghu0tL1dft5xLu":3}}
{"name":"LOeil du Chasseur (Viser)","type":"feature","img":"icons/skills/melee/weapons-crossed-poleaxes-white.webp","effects":[],"flags":{"core":{"sourceId":"Item.lyMbLMPnFk0oXaSr"}},"system":{"category":null,"subtype":"fightoption","description":"<p>Armes de jet ou de tir uniquement. Vous passez le round &agrave; viser. Vous b&eacute;n&eacute;ficiez d&rsquo;un bonus de +2 &agrave; votre prochain jet de tir ou de lancer.</p>","properties":{"ismalusdice":false,"isbonusdice":false,"fightoptiontype":"other","isspecial":false,"activated":false},"rank":0,"fightoptiontype":"twoweapons"},"_stats":{"systemId":"bol","systemVersion":"11.0.2","coreVersion":"10.291","createdTime":1687456310231,"modifiedTime":1687458793253,"lastModifiedBy":"kQghu0tL1dft5xLu"},"folder":null,"sort":0,"ownership":{"default":0,"kQghu0tL1dft5xLu":3},"_id":"leslYWbb3hfGHPlX"}
{"name":"La Danseuse (Combat à Deux Armes - Défensif)","type":"feature","img":"icons/skills/melee/weapons-crossed-poleaxes-white.webp","effects":[],"flags":{"core":{"sourceId":"Item.lyMbLMPnFk0oXaSr"}},"system":{"category":null,"subtype":"fightoption","description":"<p>Vous ne pouvez utiliser que des armes l&eacute;g&egrave;res&nbsp;ou moyennes.</p>\n<p>Vous attaquez avec une arme et parez avec l&rsquo;autre. Vous consid&eacute;rez l&rsquo;arme de parade comme l&rsquo;&eacute;quivalent d&rsquo;un petit bouclier (+1 en d&eacute;fense contre une attaque), mais vous subissez un malus de -1 sur votre jet d&rsquo;attaque avec votre autre arme.</p>","properties":{"ismalusdice":false,"isbonusdice":false,"fightoptiontype":"twoweaponsdef","isspecial":false,"activated":false},"rank":0,"fightoptiontype":"twoweapons"},"_stats":{"systemId":"bol","systemVersion":"11.0.0","coreVersion":"10.291","createdTime":1687456310229,"modifiedTime":1687457965157,"lastModifiedBy":"kQghu0tL1dft5xLu"},"folder":null,"sort":0,"ownership":{"default":0,"kQghu0tL1dft5xLu":3},"_id":"uRuOskeAALWwxDEM"}
{"name":"La Parade de lErudit (Défense Totale)","type":"feature","img":"icons/skills/melee/weapons-crossed-poleaxes-white.webp","effects":[],"flags":{"core":{"sourceId":"Item.t8v7isBpnFzAbmUI"}},"system":{"category":null,"subtype":"fightoption","description":"<p>Vous consacrez votre round &agrave; esquiver, parer et vous prot&eacute;ger des coups. Vous n&rsquo; effectuez pas d&rsquo;attaque durant le round, mais b&eacute;n&eacute;ficiez d&rsquo;un bonus de +2 en d&eacute;fense, qui s&rsquo;ajoute &eacute;ventuellement &agrave; celui que pourrait vous apporter un bouclier ou une arme secondaire de parade.</p>","properties":{"ismalusdice":false,"isbonusdice":false,"fightoptiontype":"fulldefense","isspecial":false,"activated":false},"rank":0,"fightoptiontype":"fulldefense"},"_stats":{"systemId":"bol","systemVersion":"11.0.0","coreVersion":"10.291","createdTime":1687456310229,"modifiedTime":1687457965159,"lastModifiedBy":"kQghu0tL1dft5xLu"},"folder":null,"sort":0,"ownership":{"default":0,"kQghu0tL1dft5xLu":3},"_id":"vGydqADwTsHZ9B3j"}

View File

@ -1,7 +1,7 @@
{
"id": "bol",
"title": "Barbarians of Lemuria",
"description": "The Barbarians of Lemuria system for FoundryVTT!",
"description": "The Barbarians of Lemuria system for FoundryVTT !",
"authors": [
{
"name": "LeRatierBretonnien",
@ -14,10 +14,11 @@
],
"url": "https://www.uberwald.me/gitea/public/bol",
"license": "LICENSE.txt",
"version": "10.5.7",
"version": "11.0.7",
"compatibility": {
"minimum": "10",
"verified": "10"
"maximum": "11",
"verified": "11"
},
"esmodules": [
"module/bol.js"
@ -202,7 +203,7 @@
],
"socket": true,
"manifest": "https://www.uberwald.me/gitea/public/bol/raw/v10/system.json",
"download": "https://www.uberwald.me/gitea/public/bol/archive/bol-v10.5.7.zip",
"download": "https://www.uberwald.me/gitea/public/bol/archive/bol-v11.0.7.zip",
"background": "systems/bol/ui/page_accueil.webp",
"gridDistance": 1.5,
"gridUnits": "m",

View File

@ -30,6 +30,14 @@
{{/if}}
{{#if isAlchemist}}
<ol class="items-list">
<li class="item flexrow item-header">
<div class="item-name flex4 left">{{localize "BOL.resources.alchemypoints"}}</div>
<input class="field-value" type="text" name="system.resources.alchemypoints.value" value="{{resources.alchemypoints.value}}" data-dtype="Number"/>
</li>
</ol>
<ol class="items-list">
<li class="item flexrow item-header">
<div class="item-name flex4 left">{{localize "BOL.ui.alchemy"}}</div>

View File

@ -1,8 +1,18 @@
<div class="attributes flexrow">
{{#each attributes as |attribute id|}}
<div class="attribute stat flex1 flex-group-center {{key}}">
<label class="stat-label"><a class="rollable" data-roll-type="attribute" data-roll="2d6+@attributes.{{key}}.value" data-adv="0" data-key="{{key}}">{{localize label}}</a></label><br/>
<input class="stat-value rounded" type="text" name="system.attributes.{{key}}.value" value="{{numberFormat value decimals=0 sign=true}}" data-dtype="Number"/><br/>
<label class="stat-label"><a class="rollable" data-roll-type="attribute" data-roll="2d6+@attributes.{{key}}.value" data-adv="0" data-key="{{key}}">{{localize label}}</a></label>
{{#if attribute.numModifier}}
<label class="stat-value rounded">{{attribute.numModifier}}</label>
{{/if}}
{{#if (count attribute.diceModifier)}}
<label class="stat-value rounded">{{attribute.diceModifier}}</label>
{{/if}}
<br/>
<input class="stat-value rounded" type="text" name="system.attributes.{{key}}.value" value="{{numberFormat value decimals=0 sign=true}}" data-dtype="Number"/>
<br/>
<span class="stat-roll rollable" title="2d6" data-roll-type="attribute" data-roll="2d6+@attributes.{{key}}.value" data-adv="0" data-key="{{key}}">
<i class="darkgreen fas fa-dice"></i>
</span>
@ -24,8 +34,17 @@
<div class="aptitudes flexrow">
{{#each aptitudes as |aptitude id|}}
<div class="aptitude stat flex1 flex-group-center">
<label class="stat-label"><a class="rollable" data-roll-type="aptitude" data-roll="2d6+@aptitudes.{{key}}.value" data-adv="0" data-key="{{key}}">{{localize label}}</a></label><br/>
<label class="stat-label"><a class="rollable" data-roll-type="aptitude" data-roll="2d6+@aptitudes.{{key}}.value" data-adv="0" data-key="{{key}}">{{localize label}}</a></label>
{{#if aptitude.numModifier}}
<label class="stat-value rounded">{{aptitude.numModifier}}</label>
{{/if}}
{{#if (count aptitude.diceModifier)}}
<label class="stat-value rounded">{{aptitude.diceModifier}}</label>
{{/if}}
<br/>
<input class="stat-value rounded-border" type="text" name="system.aptitudes.{{key}}.value" value="{{numberFormat value decimals=0 sign=true}}" data-dtype="Number"/><br/>
<span class="stat-roll rollable" title="2d6" data-roll-type="aptitude" data-roll="2d6+@aptitudes.{{key}}.value" data-adv="0" data-key="{{key}}">
<i class="darkgreen fas fa-dice"></i>
</span>
@ -50,6 +69,10 @@
<div class="resource stat flex1 flex-group-center">
<label class="stat-label">{{localize label}}</label><br/>
<input class="stat-value resources-value" type="text" name="system.resources.{{key}}.value" value="{{numberFormat value decimals=0 sign=false}}" data-dtype="Number"/>
<a class="inc-dec-btns-resource" data-target="{{key}}" data-incr="-1"><i class="fas fa-minus-square"></i></a>&nbsp;
<a class="inc-dec-btns-resource" data-target="{{key}}" data-incr="1"><i class="fas fa-plus-square"></i></a>&nbsp;
{{#if (eq @root.charType 'player')}}
{{#if (exists bonus)}}
<span class="flexrow"><label class="stat-max bonus-text">Bonus</label><input class="resource-bonus resources-value" type="text" name="system.resources.{{key}}.bonus" value="{{numberFormat bonus decimals=0 sign=false}}" data-dtype="Number"/></span>

View File

@ -0,0 +1,12 @@
<div>
<img class="chat-icon" src="{{img}}" alt="{{name}}"/>
<h2 class="bad"><strong>{{name}}</strong></h2>
</div>
<div class="flexrow">
{{localize "BOL.chat.losshp" lossHP=lossHP recupHP=recupHP}}
<button class="recup-vitalite" data-actor-id="{{actorId}}" data-recup-hp="{{recupHP}}">{{localize "BOL.chat.applyrecup" recupHP=recupHP}}</button>
</div>

View File

@ -4,20 +4,25 @@
</div>
<div class="flexrow">
{{#if (eq hp 0)}}
{{localize "BOL.chat.vitalityzero" name=name hp=hp}}
<br>{{localize "BOL.chat.vitalityheroism"}}
<br>{{localize "BOL.chat.vitalityheroismhint"}}
{{else}}
{{localize "BOL.chat.vitalitydying" name=name hp=hp}}
<br>{{localize "BOL.chat.vitalitydyingheroism"}}
{{/if}}
{{#if (lt hp -5)}}
<br><strong>{{localize "BOL.chat.isdead" name=name}}</strong>
<br>{{localize "BOL.chat.epitaph"}}
{{/if}}
{{#if isHeroAdversary}}
{{#if (eq hp 0)}}
{{localize "BOL.chat.vitalityzero" name=name hp=hp}}
<br>{{localize "BOL.chat.vitalityheroism"}}
<br>{{localize "BOL.chat.vitalityheroismhint"}}
{{else}}
{{localize "BOL.chat.vitalitydying" name=name hp=hp}}
<br>{{localize "BOL.chat.vitalitydyingheroism"}}
{{/if}}
{{#if (lt hp -5)}}
<br><strong>{{localize "BOL.chat.isdead" name=name}}</strong>
<br>{{localize "BOL.chat.epitaph"}}
{{/if}}
{{else}}
<br><strong>{{localize "BOL.chat.isdead" name=name}}</strong>
<br>{{localize "BOL.chat.epitaph"}}
{{/if}}
</div>

View File

@ -3,5 +3,7 @@
{{#if isCritical}}
<button class="chat-damage-roll bol-margin-tb-2 " data-damage-mode="damage-plus-6" data-attack-id="{{id}}">{{localize "BOL.chat.rolldamage6"}}</button>
<button class="chat-damage-roll bol-margin-tb-2" data-damage-mode="damage-plus-12" data-attack-id="{{id}}">{{localize "BOL.chat.rolldamage12"}}</button>
{{/if}}
{{#if isRealCritical}}
<button class="chat-damage-roll bol-margin-tb-2" data-damage-mode="damage-plus-12" data-attack-id="{{id}}">{{localize "BOL.chat.rolldamage12"}}</button>
{{/if}}
{{/if}}

View File

@ -1,20 +1,20 @@
<div>
{{#if isSuccess}}
{{#if isLegendary}}
<h2 class="success critical"><i class="fas fa-check-double"></i>&nbsp;{{localize "BOL.ui.criticallegend"}}...
<h2 class="success critical"><i class="fas fa-check-double"></i> {{localize "BOL.ui.criticallegend"}}...
{{else}}
{{#if isCritical}}
<h2 class="success critical"><i class="fas fa-check-double"></i>&nbsp;{{localize "BOL.ui.critical"}}...
<h2 class="success critical"><i class="fas fa-check-double"></i> {{localize "BOL.ui.critical"}}...
{{else}}
<h2 class="success"><i class="fas fa-check"></i>&nbsp;{{localize "BOL.ui.success"}}...
<h2 class="success"><i class="fas fa-check"></i> {{localize "BOL.ui.success"}}...
{{/if}}
{{/if}}
{{/if}}
{{#if isFailure}}
{{#if isFumble}}
<h2 class="failure fumble"><i class="fas fa-skull-crossbones"></i>&nbsp;{{localize "BOL.ui.fumble"}}...
<h2 class="failure fumble"><i class="fas fa-skull-crossbones"></i> {{localize "BOL.ui.fumble"}}...
{{else}}
<h2 class="failure"><i class="fas fa-times"></i>&nbsp;{{localize "BOL.ui.failure"}}...
<h2 class="failure"><i class="fas fa-times"></i> {{localize "BOL.ui.failure"}}...
{{/if}}
{{/if}}
<img class="chat-icon" src="{{img}}" alt="{{actor.name}}"/>
@ -52,9 +52,6 @@
{{/if}}
<div id="{{optionsId}}">
{{#if isCritical}}
<div>
{{localize "BOL.chat.criticalinfo"}}
@ -63,11 +60,17 @@
<a class="content-link" draggable="true" data-uuid="Compendium.bol.aides-de-jeu.Yl1RKQb0BjVUtilk" data-id="Yl1RKQb0BjVUtilk" data-type="JournalEntry" data-pack="bol.aides-de-jeu" data-tooltip="un journal">
<i class="fas fa-book-open"></i>{{localize "BOL.chat.criticalbuttonjournal"}}</a>
</div>
{{#if (and isCritical weapon)}}
<div>
{{{localize "BOL.chat.heroicreminder"}}}
</div>
{{/if}}
{{/if}}
{{#if (and isSuccess weapon)}}
{{> "systems/bol/templates/chat/rolls/attack-damage-card.hbs"}}
{{/if}}
{{#if (and isSuccess spell)}}
{{> "systems/bol/templates/chat/rolls/spell-roll-card.hbs"}}
{{/if}}
@ -83,14 +86,14 @@
{{/if}}
{{#if reroll}}
<button class="chat-button button hero-reroll bol-margin-tb-2" data-roll-id=="{{rollId}}" data-actor-id="{{actor.id}}">{{localize "BOL.chat.reroll"}}</button>
<button class="chat-button button hero-reroll bol-margin-tb-2" data-actor-id="{{actorId}}">{{localize "BOL.chat.reroll"}}</button>
{{/if}}
{{#if (and isSuccess (not isCritical))}}
<button class="chat-button button transform-heroic-roll bol-margin-tb-2" data-roll-id=="{{rollId}}" data-actor-id="{{actor.id}}">{{localize "BOL.chat.toheroic"}}</button>
<button class="chat-button button transform-heroic-roll bol-margin-tb-2" data-actor-id="{{actorId}}">{{localize "BOL.chat.toheroic"}}</button>
{{/if}}
{{#if isRealCritical}}
<button class="chat-button button transform-legendary-roll bol-margin-tb-2" data-roll-id=="{{rollId}}" data-actor-id="{{actor.id}}">{{localize "BOL.chat.tolegend"}}</button>
<button class="chat-button button transform-legendary-roll bol-margin-tb-2" data-actor-id="{{actorId}}">{{localize "BOL.chat.tolegend"}}</button>
{{/if}}
<br>

View File

@ -6,13 +6,17 @@
{{/if}}
<button class="damage-handling" data-defense-mode="damage-with-armor" data-attack-id="{{attackId}}">{{localize "BOL.chat.witharmor"}}</button>
<button class="damage-handling" data-defense-mode="damage-without-armor" data-attack-id="{{attackId}}">{{localize "BOL.chat.withoutarmor"}}</button>
<button class="damage-handling" data-defense-mode="damage-without-armor" data-attack--id="{{attackId}}">{{localize "BOL.chat.withoutarmor"}}</button>
{{#if defender.system.resources.hero.value}}
<button class="damage-handling" data-defense-mode="hero-reduce-damage" data-attack-id="{{attackId}}">{{localize "BOL.chat.shakeoff"}}</button>
{{#if isHeroAdversary}}
{{#if (gt defender.system.resources.hero.value 0)}}
<button class="damage-handling" data-defense-mode="hero-reduce-damage" data-attack-id="{{attackId}}">{{localize "BOL.chat.shakeoff"}}</button>
{{#each defenderWeapons as |weapon idx|}}
<button class="damage-handling" data-defense-mode="hero-in-extremis" data-attack-id="{{@root.attackId}}" data-weapon-id="{{weapon._id}}">{{localize "BOL.chat.splinteredshield" name=weapon.name}}</button>
{{/each}}
{{#each defenderWeapons as |weapon idx|}}
<button class="damage-handling" data-defense-mode="hero-in-extremis" data-attack-id="{{@root.attackId}}" data-weapon-id="{{weapon._id}}">{{localize "BOL.chat.splinteredshield" name=weapon.name}}</button>
{{/each}}
{{/if}}
{{/if}}
<button class="damage-handling" data-defense-mode="damage-not-applied" data-attack-id="{{attackId}}">{{localize "BOL.chat.nodamage"}}</button>
{{/if}}

View File

@ -11,9 +11,9 @@
{{#if (eq horoscopeType "major")}}
{{#if isSuccess}}
{{localize "BOL.chat.horoscopemajorsuccess"}}
{{localize "BOL.chat.horoscopemajorsuccess" horoscopeName=horoscopeName}}
{{else}}
{{localize "BOL.chat.horoscopemajorfailure"}}
{{localize "BOL.chat.horoscopemajorfailure" horoscopeName=horoscopeName}}
{{/if}}
{{/if}}

View File

@ -22,8 +22,13 @@
<input class="field-value" type="checkbox" name="register-init" id="register-init" checked />
</label>
</div>
</div>
</div>
<div class="flexrow" style="margin-bottom: 1px;">
<div class="flex1 center bg-darkred">
<label for="mod">{{localize 'BOL.ui.initMalus'}}</label>
</div>
<div class="flex1 center cell">{{combatData.malusInit}}</div>
</div>
{{/if}}
{{> "systems/bol/templates/dialogs/career-roll-part.hbs"}}

View File

@ -1,19 +1,25 @@
<h3 class="form-header">{{localize "BOL.ui.fightOption"}}</h3>
<div class="form-group">
<label class="property-label">{{localize "BOL.ui.fightOptionType"}}</label>
<div class="form-fields">
<select name="system.properties.fightoptiontype" data-dtype="String">
{{#select item.system.properties.fightoptiontype}}
{{#each config.fightOptionTypes as |item id|}}
<option value="{{id}}">{{localize item}}</option>
{{/each}}
{{/select}}
</select>
</div>
</div>
<div class="property flexrow">
<label class="property-label">{{localize "BOL.ui.activated"}}</label>
<input class="field-value" type="checkbox" name="system.properties.activated" {{checked item.system.properties.activated}}>
<label class="property-label">{{localize "BOL.ui.fightOptionType"}}</label>
<div class="form-fields">
<select name="system.properties.fightoptiontype" data-dtype="String">
{{#select item.system.properties.fightoptiontype}}
{{#each config.fightOptionTypes as |item id|}}
<option value="{{id}}">{{localize item}}</option>
{{/each}}
{{/select}}
</select>
</div>
</div>
<div class="property flexrow">
<label class="property-label">{{localize "BOL.ui.activated"}}</label>
<input class="field-value" type="checkbox" name="system.properties.activated" {{checked
item.system.properties.activated}}>
</div>
<div class="property flexrow">
<label class="property-label">{{localize "BOL.ui.isspecial"}}</label>
<input class="field-value" type="checkbox" name="system.properties.isspecial" {{checked
item.system.properties.isspecial}}>
</div>

View File

@ -0,0 +1,8 @@
<div class="post-item" data-transfer="{{transfer}}">
<h3><b>{{name}}</b></h3>
{{#if img}}
<img class="chat-icon" src="{{img}}" title="{{name}}" />
{{/if}}
<h4><b>Description : </b></h4>
<p class="card-content">{{{system.description}}}</p>
</div>

View File

@ -2,9 +2,20 @@
<img class="bol-hud-togglebutton" src="icons/svg/sword.svg" width="36" height="36" title="Action" />
<div class="bol-hud-list tokenhudext right">
{{#each actionsList as |action key|}}
{{#if (eq system.subtype "weapon")}}
<div class="control-icon tokenhudicon bol-hud-menu" data-action-index="{{key}}" title="{{action.name}}">
<label>{{action.name}}</label>
</div>
{{/if}}
{{/each}}
</div>
</div>
<div class="bol-hud-list tokenhudext right2">
{{#each actionsList as |action key|}}
{{#if (eq system.subtype "fightoption")}}
<div class="control-icon tokenhudicon bol-hud-menu" data-action-index="{{key}}" title="{{action.name}}">
<label>{{action.name}}</label>
</div>
{{/if}}
{{/each}}
</div>
</div>