Compare commits

..

4 Commits

Author SHA1 Message Date
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
11 changed files with 240 additions and 246 deletions

109
.gitignore vendored
View File

@ -1,108 +1 @@
# Logs .history/
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/

View File

@ -535,6 +535,10 @@
"BOL.chat.criticalinfo": "C'est un succès Héroïque ou Légendaire ! Choisissez vos options et effets !", "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.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.soeasy": "Inmanquable (+4)",
"BOL.dialog.veryeasy": "Trés Facile (+2)", "BOL.dialog.veryeasy": "Trés Facile (+2)",
"BOL.dialog.easy": "Facile (+1)", "BOL.dialog.easy": "Facile (+1)",
@ -573,6 +577,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.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.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.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"); const li = $(ev.currentTarget).parents(".item");
this.actor.spendAlchemyPoint(li.data("itemId"), 1) 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 // Incr./Decr. career ranks
html.find(".inc-dec-btns").click((ev) => { html.find(".inc-dec-btns").click((ev) => {

View File

@ -40,10 +40,10 @@ export class BoLActor extends Actor {
/* -------------------------------------------- */ /* -------------------------------------------- */
getBougette() { getBougette() {
if ( this.type == "character") { if (this.type == "character") {
let b = duplicate(this.system.bougette) let b = duplicate(this.system.bougette)
b.label = game.i18n.localize( game.bol.config.bougetteState[String(this.system.bougette.value)] ) 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.diceImg = "icons/dice/" + game.bol.config.bougetteDice[String(this.system.bougette.value)] + "black.svg"
return b return b
} }
return undefined return undefined
@ -51,9 +51,9 @@ export class BoLActor extends Actor {
/* -------------------------------------------- */ /* -------------------------------------------- */
async rollBougette() { async rollBougette() {
if ( this.type == "character") { if (this.type == "character") {
let attribute = duplicate(this.system.attributes.vigor) 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)] rollData.formula = game.bol.config.bougetteDice[String(this.system.bougette.value)]
let r = new BoLDefaultRoll(rollData) let r = new BoLDefaultRoll(rollData)
r.roll() r.roll()
@ -62,13 +62,13 @@ export class BoLActor extends Actor {
/* -------------------------------------------- */ /* -------------------------------------------- */
decBougette() { decBougette() {
if ( this.type == "character") { if (this.type == "character") {
let bougette = duplicate(this.system.bougette) let bougette = duplicate(this.system.bougette)
bougette.value = Math.max( Number(bougette.value) - 1, 0) bougette.value = Math.max(Number(bougette.value) - 1, 0)
this.update( { 'system.bougette': bougette } ) this.update({ 'system.bougette': bougette })
} }
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
updateResourcesData() { updateResourcesData() {
if (this.type == 'character') { if (this.type == 'character') {
@ -137,7 +137,7 @@ export class BoLActor extends Actor {
} }
// Apply defense effects // Apply defense effects
for (let i of this.items) { 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) defMod += Number(i.system.properties.modifier)
} }
} }
@ -389,7 +389,7 @@ export class BoLActor extends Actor {
} }
// Apply vigor effects // Apply vigor effects
for (let i of this.items) { 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) attrDamageValue += Number(i.system.properties.modifier)
} }
} }
@ -432,25 +432,25 @@ export class BoLActor extends Actor {
this.updateEmbeddedDocuments('Item', [{ _id: alchemy.id, 'system.properties.pccurrent': 0 }]) this.updateEmbeddedDocuments('Item', [{ _id: alchemy.id, 'system.properties.pccurrent': 0 }])
} }
} }
/*-------------------------------------------- */ /*-------------------------------------------- */
spentAstrologyPoints(points) { spentAstrologyPoints(points) {
let astrology = duplicate(this.system.resources.astrologypoints) let astrology = duplicate(this.system.resources.astrologypoints)
astrology.value -= points astrology.value -= points
astrology.value = Math.max(astrology.value,0) astrology.value = Math.max(astrology.value, 0)
this.update( { 'system.resources.astrologypoints': astrology} ) this.update({ 'system.resources.astrologypoints': astrology })
} }
/*-------------------------------------------- */ /*-------------------------------------------- */
getHoroscopesBonus() { getHoroscopesBonus() {
let astro = this.items.filter(it => it.type == "feature" && it.system.subtype == "horoscope" && !it.system.properties.ishoroscopemajor let astro = this.items.filter(it => it.type == "feature" && it.system.subtype == "horoscope" && !it.system.properties.ishoroscopemajor
&& it.system.properties.horoscopeanswer == "favorable") && it.system.properties.horoscopeanswer == "favorable")
return astro return astro
} }
/*-------------------------------------------- */ /*-------------------------------------------- */
getHoroscopesMalus() { getHoroscopesMalus() {
let astro = this.items.filter(it => it.type == "feature" && it.system.subtype == "horoscope" && !it.system.properties.ishoroscopemajor let astro = this.items.filter(it => it.type == "feature" && it.system.subtype == "horoscope" && !it.system.properties.ishoroscopemajor
&& it.system.properties.horoscopeanswer == "unfavorable") && it.system.properties.horoscopeanswer == "unfavorable")
return astro return astro
} }
@ -458,26 +458,28 @@ export class BoLActor extends Actor {
manageHoroscope(rollData) { manageHoroscope(rollData) {
//Spent points //Spent points
this.spentAstrologyPoints(rollData.astrologyPointsCost) this.spentAstrologyPoints(rollData.astrologyPointsCost)
if ( rollData.horoscopeType == "minor") { if (rollData.horoscopeType == "minor") {
let horoscope = { name: "SITUATION A SPECIFIER", type :"feature", let horoscope = {
name: "SITUATION A SPECIFIER", type: "feature",
img: "icons/magic/perception/eye-ringed-glow-angry-large-red.webp", img: "icons/magic/perception/eye-ringed-glow-angry-large-red.webp",
system :{subtype: "horoscope", properties: { system: {
ishoroscopemajor: false, subtype: "horoscope", properties: {
horoscopeanswer: (rollData.isSuccess) ? "favorable": "unfavorable", ishoroscopemajor: false,
rank: rollData.careerBonus horoscopeanswer: (rollData.isSuccess) ? "favorable" : "unfavorable",
} rank: rollData.careerBonus
}
} }
} }
this.createEmbeddedDocuments('Item', [horoscope]) this.createEmbeddedDocuments('Item', [horoscope])
} }
if ( rollData.horoscopeType == "major" ) { if (rollData.horoscopeType == "major") {
if ( rollData.isSuccess) { if (rollData.isSuccess) {
this.subHeroPoints(1) this.subHeroPoints(1)
} else { } else {
this.addHeroPoints(1) this.addHeroPoints(1)
} }
} }
if ( rollData.horoscopeType == "majorgroup" ) { if (rollData.horoscopeType == "majorgroup") {
let rID = randomID(16) let rID = randomID(16)
let horoscopes = duplicate(game.settings.get("bol", "horoscope-group")) let horoscopes = duplicate(game.settings.get("bol", "horoscope-group"))
horoscopes[rID] = { horoscopes[rID] = {
@ -485,7 +487,7 @@ export class BoLActor extends Actor {
name: game.i18n.localize("BOL.ui.groupHoroscope") + this.name, name: game.i18n.localize("BOL.ui.groupHoroscope") + this.name,
maxDice: rollData.careerBonus, maxDice: rollData.careerBonus,
availableDice: rollData.careerBonus, availableDice: rollData.careerBonus,
type: (rollData.isSuccess) ? "bonus": "malus" type: (rollData.isSuccess) ? "bonus" : "malus"
} }
game.settings.set("bol", "horoscope-group", horoscopes) game.settings.set("bol", "horoscope-group", horoscopes)
} }
@ -497,10 +499,10 @@ export class BoLActor extends Actor {
return this.system.resources.astrologypoints.value return this.system.resources.astrologypoints.value
} }
/*-------------------------------------------- */ /*-------------------------------------------- */
removeHoroscopeMinor( rollData) { removeHoroscopeMinor(rollData) {
let toDel = [] let toDel = []
for(let horo of rollData.selectedHoroscope) { for (let horo of rollData.selectedHoroscope) {
toDel.push( horo._id ) toDel.push(horo._id)
} }
if (toDel.length > 0) { if (toDel.length > 0) {
this.deleteEmbeddedDocuments('Item', toDel) this.deleteEmbeddedDocuments('Item', toDel)
@ -519,7 +521,7 @@ export class BoLActor extends Actor {
newPC = alchemy.system.properties.pccurrent + pcCost newPC = alchemy.system.properties.pccurrent + pcCost
await this.updateEmbeddedDocuments('Item', [{ _id: alchemy.id, 'system.properties.pccurrent': newPC }]) await this.updateEmbeddedDocuments('Item', [{ _id: alchemy.id, 'system.properties.pccurrent': newPC }])
} else { } else {
ui.notifications.warn( game.i18n.localize("BOL.ui.nomorealchemypoints") ) ui.notifications.warn(game.i18n.localize("BOL.ui.nomorealchemypoints"))
} }
} }
} }
@ -716,17 +718,17 @@ export class BoLActor extends Actor {
let lastHP = await this.getFlag("world", hpID) let lastHP = await this.getFlag("world", hpID)
if (lastHP != this.system.resources.hp.value && game.user.isGM) { // Only GM sends this if (lastHP != this.system.resources.hp.value && game.user.isGM) { // Only GM sends this
await this.setFlag("world", hpID, this.system.resources.hp.value) await this.setFlag("world", hpID, this.system.resources.hp.value)
let prone = this.effects.find( ef => ef.label == "EFFECT.StatusProne") let prone = this.effects.find(ef => ef.label == "EFFECT.StatusProne")
let dead = this.effects.find( ef => ef.label == "EFFECT.StatusDead") let dead = this.effects.find(ef => ef.label == "EFFECT.StatusDead")
if (this.system.resources.hp.value <= 0) { if (this.system.resources.hp.value <= 0) {
if ( !prone) { if (!prone) {
await this.createEmbeddedDocuments("ActiveEffect", [ 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", [ 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({ ChatMessage.create({
@ -735,11 +737,11 @@ export class BoLActor extends Actor {
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 })
}) })
} else { } else {
if ( prone ) { if (prone) {
await this.deleteEmbeddedDocuments("ActiveEffect", [ prone.id ] ) await this.deleteEmbeddedDocuments("ActiveEffect", [prone.id])
} }
if ( dead ) { if (dead) {
await this.deleteEmbeddedDocuments("ActiveEffect", [ dead.id ] ) await this.deleteEmbeddedDocuments("ActiveEffect", [dead.id])
} }
} }
} }
@ -751,9 +753,45 @@ export class BoLActor extends Actor {
await this.setFlag("world", "last-initiative", rollData) 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,
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)
hp.value += 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() { clearInitiative() {
this.unsetFlag("world", "last-initiative" ) this.unsetFlag("world", "last-initiative")
} }
/*-------------------------------------------- */ /*-------------------------------------------- */
@ -765,50 +803,51 @@ export class BoLActor extends Actor {
} }
/*-------------------------------------------- */ /*-------------------------------------------- */
getInitiativeRank(rollData = undefined, isCombat = false) { getInitiativeRank(rollData = undefined, isCombat = false, combatData) {
if (!rollData) { if (!rollData) {
rollData = this.getFlag("world", "last-initiative") rollData = this.getFlag("world", "last-initiative")
} }
let fvttInit = 4 // Pietaille par defaut let fvttInit = 4 // Pietaille par defaut
if (this.type == 'character' ) { if (this.type == 'character') {
fvttInit = 5 fvttInit = 5
if (!rollData) { if (!rollData) {
fvttInit = -1 fvttInit = -1
if ( isCombat ) { if (isCombat) {
ui.notifications.warn(game.i18n.localize("BOL.ui.warninitiative")) ui.notifications.info(game.i18n.localize("BOL.ui.warninitiative"))
BoLRoll.aptitudeCheck(this, "init", undefined, combatData)
} }
} else { } else {
if (rollData.isLegendary) { if (rollData.isLegendary) {
fvttInit = 10 fvttInit = 10
} else if (rollData.isCritical) { } else if (rollData.isCritical) {
fvttInit = 9 fvttInit = 9
} else if (rollData.isSuccess ) { } else if (rollData.isSuccess) {
fvttInit = 8 fvttInit = 8
} else if (rollData.isFumble) { } else if (rollData.isFumble) {
fvttInit = 3 fvttInit = 3
} }
} }
} }
if ( this.getCharType() == 'adversary') { if (this.getCharType() == 'adversary') {
fvttInit = 7 fvttInit = 7
} }
if ( this.getCharType() == 'tough') { if (this.getCharType() == 'tough') {
fvttInit = 6 fvttInit = 6
} }
if ( this.getCharType() == 'creature') { if (this.getCharType() == 'creature') {
let mySize = this.getSize() let mySize = this.getSize()
let sizeSmall = game.bol.config.creatureSize["small"].order let sizeSmall = game.bol.config.creatureSize["small"].order
let sizeMedium = game.bol.config.creatureSize["medium"].order let sizeMedium = game.bol.config.creatureSize["medium"].order
if ( mySize >= sizeSmall && mySize <= sizeMedium) { if (mySize >= sizeSmall && mySize <= sizeMedium) {
fvttInit = 6 fvttInit = 6
} }
if ( mySize > sizeMedium) { if (mySize > sizeMedium) {
fvttInit = 7 fvttInit = 7
} }
} }
return fvttInit return fvttInit
} }
/*-------------------------------------------- */ /*-------------------------------------------- */
async subHeroPoints(nb) { async subHeroPoints(nb) {
let newHeroP = this.system.resources.hero.value - nb; let newHeroP = this.system.resources.hero.value - nb;
@ -822,6 +861,11 @@ export class BoLActor extends Actor {
await this.update({ 'system.resources.hero.value': newHeroP }); 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) { async sufferDamage(damage) {
let newHP = this.system.resources.hp.value - damage let newHP = this.system.resources.hp.value - damage
@ -838,13 +882,13 @@ export class BoLActor extends Actor {
} else if (protect.system.subtype == 'armor') { } else if (protect.system.subtype == 'armor') {
if (BoLUtility.getRollArmor()) { if (BoLUtility.getRollArmor()) {
if (!protect.system.properties.soak.formula || protect.system.properties.soak.formula == "") { 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 { } else {
formula += "+" + " max(" + protect.system.properties.soak.formula + ",0)" formula += "+" + " max(" + protect.system.properties.soak.formula + ",0)"
} }
} else { } else {
if (protect.system.properties.soak.value == undefined) { 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 { } else {
formula += "+ " + protect.system.properties.soak.value formula += "+ " + protect.system.properties.soak.value
} }

View File

@ -33,11 +33,11 @@ export class BoLRoll {
/* -------------------------------------------- */ /* -------------------------------------------- */
static buildHoroscopeGroupList() { static buildHoroscopeGroupList() {
let horoscopes = game.settings.get("bol", "horoscope-group") 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) { for (let id in horoscopes) {
let horo = horoscopes[id] let horo = horoscopes[id]
for (let i=0; i<horo.availableDice; i++) { for (let i = 0; i < horo.availableDice; i++) {
horoList.push( { id: id, name: horo.name, type: horo.type, nbDice: i+1}) horoList.push({ id: id, name: horo.name, type: horo.type, nbDice: i + 1 })
} }
} }
return horoList 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}`) 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 aptitude = eval(`actor.system.aptitudes.${key}`)
let attrKey = this.getDefaultAttribute(key) let attrKey = this.getDefaultAttribute(key)
@ -101,6 +101,7 @@ export class BoLRoll {
rollData.label = (aptitude.label) ? game.i18n.localize(aptitude.label) : null rollData.label = (aptitude.label) ? game.i18n.localize(aptitude.label) : null
rollData.description = game.i18n.localize('BOL.ui.aptitudeCheck') + " - " + game.i18n.localize(aptitude.label) rollData.description = game.i18n.localize('BOL.ui.aptitudeCheck') + " - " + game.i18n.localize(aptitude.label)
rollData.combatData = combatData // For initiative mainly
return this.displayRollDialog(rollData) return this.displayRollDialog(rollData)
} }
@ -219,8 +220,8 @@ export class BoLRoll {
/* -------------------------------------------- */ /* -------------------------------------------- */
static horoscopeCheck(actor, event, horoscopeType) { static horoscopeCheck(actor, event, horoscopeType) {
let cost = (horoscopeType == "minor") ? 1 : 2 let cost = (horoscopeType == "minor") ? 1 : 2
if (cost > actor.getAstrologyPoints() ) { if (cost > actor.getAstrologyPoints()) {
ui.notifications.warn(game.i18n.localize("BOL.ui.astrologyNoPoints")) ui.notifications.warn(game.i18n.localize("BOL.ui.astrologyNoPoints"))
return return
} }
@ -228,7 +229,7 @@ export class BoLRoll {
rollData.careerBonus = actor.getAstrologerBonus() rollData.careerBonus = actor.getAstrologerBonus()
rollData.horoscopeType = horoscopeType rollData.horoscopeType = horoscopeType
rollData.horoscopeTypeLabel = "BOL.ui."+horoscopeType rollData.horoscopeTypeLabel = "BOL.ui." + horoscopeType
rollData.astrologyPointsCost = cost rollData.astrologyPointsCost = cost
rollData.label = game.i18n.localize('BOL.ui.makeHoroscope') rollData.label = game.i18n.localize('BOL.ui.makeHoroscope')
rollData.description = game.i18n.localize('BOL.ui.makeHoroscope') + " " + game.i18n.localize(rollData.horoscopeTypeLabel) rollData.description = game.i18n.localize('BOL.ui.makeHoroscope') + " " + game.i18n.localize(rollData.horoscopeTypeLabel)
@ -295,7 +296,7 @@ export class BoLRoll {
} }
this.rollData.bmDice += this.rollData.horoscopeBonus this.rollData.bmDice += this.rollData.horoscopeBonus
this.rollData.bmDice -= this.rollData.horoscopeMalus 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] let horo = this.rollData.horoscopeGroupList[this.rollData.selectedGroupHoroscopeIndex]
this.rollData.bmDice += (horo.type == "malus") ? -horo.nbDice : horo.nbDice; this.rollData.bmDice += (horo.type == "malus") ? -horo.nbDice : horo.nbDice;
} }
@ -449,8 +450,8 @@ export class BoLRoll {
html.find('#horoscope-bonus-applied').change((event) => { html.find('#horoscope-bonus-applied').change((event) => {
this.rollData.selectedHoroscope = [] this.rollData.selectedHoroscope = []
for (let option of event.currentTarget.selectedOptions) { 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() let horoscopes = $('#horoscope-bonus-applied').val()
this.rollData.horoscopeBonus = (!horoscopes || horoscopes.length == 0) ? 0 : horoscopes.length this.rollData.horoscopeBonus = (!horoscopes || horoscopes.length == 0) ? 0 : horoscopes.length
this.updateTotalDice() this.updateTotalDice()
@ -459,8 +460,8 @@ export class BoLRoll {
html.find('#horoscope-malus-applied').change((event) => { html.find('#horoscope-malus-applied').change((event) => {
this.rollData.selectedHoroscope = [] this.rollData.selectedHoroscope = []
for (let option of event.currentTarget.selectedOptions) { 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() let horoscopes = $('#horoscope-malus-applied').val()
this.rollData.horoscopeMalus = (!horoscopes || horoscopes.length == 0) ? 0 : horoscopes.length this.rollData.horoscopeMalus = (!horoscopes || horoscopes.length == 0) ? 0 : horoscopes.length
this.updateTotalDice() this.updateTotalDice()
@ -469,7 +470,7 @@ export class BoLRoll {
this.rollData.selectedGroupHoroscopeIndex = event.currentTarget.value this.rollData.selectedGroupHoroscopeIndex = event.currentTarget.value
this.updateTotalDice() this.updateTotalDice()
}) })
} }
@ -577,7 +578,7 @@ export class BoLRoll {
rollbase = 0 rollbase = 0
} }
let diceData = BoLUtility.getDiceData() 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 const modifiers = rollbase + rollData.careerBonus + rollData.mod + rollData.weaponModifier - rollData.defence - rollData.modArmorMalus + rollData.shieldMalus + rollData.attackModifier + rollData.appliedArmorMalus + rollData.effectModifier
const formula = (isMalus) ? rollData.nbDice + "d" + diceData.diceFormula + "kl2 + " + modifiers : rollData.nbDice + "d" + diceData.diceFormula + "kh2 + " + modifiers const formula = (isMalus) ? rollData.nbDice + "d" + diceData.diceFormula + "kl2 + " + modifiers : rollData.nbDice + "d" + diceData.diceFormula + "kh2 + " + modifiers
rollData.formula = formula rollData.formula = formula
@ -624,7 +625,7 @@ export class BoLDefaultRoll {
await r.roll({ "async": false }) await r.roll({ "async": false })
let diceData = BoLUtility.getDiceData() let diceData = BoLUtility.getDiceData()
console.log("DICEDATA", diceData) //console.log("DICEDATA", diceData)
const activeDice = r.terms[0].results.filter(r => r.active) const activeDice = r.terms[0].results.filter(r => r.active)
const diceTotal = activeDice.map(r => r.result).reduce((a, b) => a + b) const diceTotal = activeDice.map(r => r.result).reduce((a, b) => a + b)
this.rollData.roll = r this.rollData.roll = r
@ -643,6 +644,10 @@ export class BoLDefaultRoll {
if (this.rollData.registerInit) { if (this.rollData.registerInit) {
actor.registerInit(this.rollData) actor.registerInit(this.rollData)
this.rollData.initiativeRank = actor.getInitiativeRank(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)
combat.setInitiative(this.rollData.combatData.combatantId, this.rollData.initiativeRank)
}
} }
if (this.rollData.isSuccess && this.rollData.mode == "spell") { // PP cost management if (this.rollData.isSuccess && this.rollData.mode == "spell") { // PP cost management
this.rollData.remainingPP = actor.spendPowerPoint(this.rollData.ppCost + this.rollData.ppCostArmor) this.rollData.remainingPP = actor.spendPowerPoint(this.rollData.ppCost + this.rollData.ppCostArmor)
@ -761,13 +766,13 @@ export class BoLDefaultRoll {
let weaponFormula = BoLUtility.getDamageFormula(this.rollData.weapon.system, this.rollData.fightOption) let weaponFormula = BoLUtility.getDamageFormula(this.rollData.weapon.system, this.rollData.fightOption)
let damageFormula = weaponFormula + "+" + bonusDmg + "+" + attrDamageValue let damageFormula = weaponFormula + "+" + bonusDmg + "+" + attrDamageValue
console.log("DAMAGE !!!", damageFormula, attrDamageValue, this.rollData)
//console.log("Formula", weaponFormula, damageFormula, this.rollData.weapon.data.data.properties.damage) //console.log("Formula", weaponFormula, damageFormula, this.rollData.weapon.data.data.properties.damage)
this.rollData.damageFormula = damageFormula this.rollData.damageFormula = damageFormula
this.rollData.damageRoll = new Roll(damageFormula) this.rollData.damageRoll = new Roll(damageFormula)
await this.rollData.damageRoll.roll({ "async": false }) await this.rollData.damageRoll.roll({ "async": false })
this.rollData.damageTotal = this.rollData.damageRoll.total this.rollData.damageTotal = this.rollData.damageRoll.total
console.log("DAMAGE !!!", damageFormula, attrDamageValue, this.rollData)
} }
BoLUtility.cleanupButtons(this.rollData.optionsId) BoLUtility.cleanupButtons(this.rollData.optionsId)
this.sendDamageMessage() this.sendDamageMessage()

View File

@ -25,7 +25,7 @@ export class BoLCombatManager extends Combat {
// calculate initiative // 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]) 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 } )
fvttInit += (cId / 100) fvttInit += (cId / 100)
await this.updateEmbeddedDocuments("Combatant", [{ _id: ids[cId], initiative: fvttInit }]); await this.updateEmbeddedDocuments("Combatant", [{ _id: ids[cId], initiative: fvttInit }]);
} }
@ -40,6 +40,16 @@ export class BoLCombatManager extends Combat {
} }
super.nextRound() super.nextRound()
} }
/************************************************************************************/
startCombat() {
let combatants = this.combatants.contents
for (let c of combatants) {
let actor = game.actors.get( c.actorId )
actor.storeVitaliteCombat()
}
return super.startCombat()
}
/************************************************************************************/ /************************************************************************************/
_onDelete() { _onDelete() {
@ -47,6 +57,7 @@ export class BoLCombatManager extends Combat {
for (let c of combatants) { for (let c of combatants) {
let actor = game.actors.get(c.actorId) let actor = game.actors.get(c.actorId)
actor.clearInitiative() actor.clearInitiative()
actor.displayRecuperation()
} }
super._onDelete() super._onDelete()
} }

View File

@ -8,8 +8,6 @@ export class BoLUtility {
/* -------------------------------------------- */ /* -------------------------------------------- */
static init() { static init() {
this.attackStore = {}
game.settings.register("bol", "rollArmor", { game.settings.register("bol", "rollArmor", {
name: "Effectuer des jets pour les armures", name: "Effectuer des jets pour les armures",
hint: "Effectue un jet de dés pour les armures (valeur fixe si désactivé)", hint: "Effectue un jet de dés pour les armures (valeur fixe si désactivé)",
@ -298,13 +296,13 @@ export class BoLUtility {
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static sendAttackSuccess(attackDef) { static sendAttackSuccess(rollData) {
if (attackDef.targetId) { if (rollData.targetId) {
// Broadcast to GM or process it directly in case of GM defense // Broadcast to GM or process it directly in case of GM defense
if (!game.user.isGM) { 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 { } else {
BoLUtility.processAttackSuccess(attackDef) BoLUtility.processAttackSuccess(rollData)
} }
} }
} }
@ -397,6 +395,19 @@ export class BoLUtility {
game.socket.emit("system.bol", { name: "msg_damage_handling", data: { msgId: msgId, attackId: attackId, defenseMode: defenseMode, weaponId: weaponId } }) 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 +415,50 @@ export class BoLUtility {
if (!game.user.isGM) { if (!game.user.isGM) {
return return
} }
let message = game.messages.get(msgId)
let rollData = message.getFlag("world", "bol-roll-data")
BoLUtility.removeChatMessageId(msgId) BoLUtility.removeChatMessageId(msgId)
console.log("Damage Handling", attackId, defenseMode, weaponId) console.log("Damage Handling", attackId, defenseMode, weaponId)
// Only GM process this // Only GM process this
let attackDef = this.attackStore[attackId] if (rollData && rollData.defenderId) {
if (attackDef && attackDef.defenderId) { if (rollData.defenseDone || defenseMode == 'damage-not-applied') {
if (attackDef.defenseDone) {
return return
} // ?? Why ??? } // ?? Why ???
attackDef.defenseDone = true rollData.defenseDone = true
attackDef.defenseMode = defenseMode rollData.defenseMode = defenseMode
let token = game.scenes.current.tokens.get(attackDef.targetId) let token = game.scenes.current.tokens.get(rollData.targetId)
let defender = token.actor let defender = token.actor
if (defenseMode == 'damage-with-armor') { if (defenseMode == 'damage-with-armor') {
let armorFormula = defender.getArmorFormula() let armorFormula = defender.getArmorFormula()
attackDef.rollArmor = new Roll(armorFormula) rollData.rollArmor = new Roll(armorFormula)
attackDef.rollArmor.roll({ async: false }) rollData.rollArmor.roll({ async: false })
attackDef.armorProtect = (attackDef.rollArmor.total < 0) ? 0 : attackDef.rollArmor.total rollData.armorProtect = (rollData.rollArmor.total < 0) ? 0 : rollData.rollArmor.total
attackDef.finalDamage = attackDef.damageTotal - attackDef.armorProtect rollData.finalDamage = rollData.damageTotal - rollData.armorProtect
attackDef.finalDamage = (attackDef.finalDamage < 0) ? 0 : attackDef.finalDamage rollData.finalDamage = (rollData.finalDamage < 0) ? 0 : rollData.finalDamage
defender.sufferDamage(attackDef.finalDamage) defender.sufferDamage(rollData.finalDamage)
console.log("Armor roll -> result ", attackDef) console.log("Armor roll -> result ", rollData)
} }
if (defenseMode == 'damage-without-armor') { if (defenseMode == 'damage-without-armor') {
attackDef.finalDamage = attackDef.damageTotal rollData.finalDamage = atrollDatatackDef.damageTotal
defender.sufferDamage(attackDef.finalDamage) defender.sufferDamage(rollData.finalDamage)
} }
if (defenseMode == 'hero-reduce-damage') { if (defenseMode == 'hero-reduce-damage') {
let armorFormula = defender.getArmorFormula() let armorFormula = defender.getArmorFormula()
attackDef.rollArmor = new Roll(armorFormula) rollData.rollArmor = new Roll(armorFormula)
attackDef.rollArmor.roll({ async: false }) rollData.rollArmor.roll({ async: false })
attackDef.armorProtect = (attackDef.rollArmor.total < 0) ? 0 : attackDef.rollArmor.total rollData.armorProtect = (rollData.rollArmor.total < 0) ? 0 : rollData.rollArmor.total
attackDef.rollHero = new Roll("1d6") rollData.rollHero = new Roll("1d6")
attackDef.rollHero.roll({ async: false }) rollData.rollHero.roll({ async: false })
attackDef.finalDamage = attackDef.damageTotal - attackDef.rollHero.total - attackDef.armorProtect rollData.finalDamage = rollData.damageTotal - rollData.rollHero.total - rollData.armorProtect
attackDef.finalDamage = (attackDef.finalDamage < 0) ? 0 : attackDef.finalDamage rollData.finalDamage = (rollData.finalDamage < 0) ? 0 : rollData.finalDamage
defender.sufferDamage(attackDef.finalDamage) defender.sufferDamage(rollData.finalDamage)
defender.subHeroPoints(1) defender.subHeroPoints(1)
} }
if (defenseMode == 'hero-in-extremis') { if (defenseMode == 'hero-in-extremis') {
attackDef.finalDamage = 0; rollData.finalDamage = 0;
attackDef.weaponHero = defender.weapons.find(item => item._id == weaponId); rollData.weaponHero = defender.weapons.find(item => item._id == weaponId);
defender.deleteEmbeddedDocuments("Item", [weaponId]); defender.deleteEmbeddedDocuments("Item", [weaponId]);
} }
@ -456,16 +469,16 @@ export class BoLUtility {
} }
} }
let damageResults = { let damageResults = {
attackId: attackDef.id, attackId: rollData.id,
attacker: attackDef.attacker, attacker: rollData.attacker,
rollArmor: attackDef.rollArmor, rollArmor: rollData.rollArmor,
rollHero: attackDef.rollHero, rollHero: rollData.rollHero,
weaponHero: attackDef.weaponHero, weaponHero: rollData.weaponHero,
armorProtect: attackDef.armorProtect, armorProtect: rollData.armorProtect,
name: defender.name, name: defender.name,
defender: defender, defender: defender,
defenseMode: attackDef.defenseMode, defenseMode: rollData.defenseMode,
finalDamage: attackDef.finalDamage finalDamage: rollData.finalDamage
} }
ChatMessage.create({ ChatMessage.create({
alias: defender.name, alias: defender.name,
@ -552,28 +565,28 @@ export class BoLUtility {
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static async processAttackSuccess(attackDef) { static async processAttackSuccess(rollData) {
console.log("Attack success processing", attackDef) console.log("Attack success processing", rollData)
if (!game.user.isGM || !attackDef.defenderId) { // Only GM process this if (!game.user.isGM || !rollData.defenderId) { // Only GM process this
return return
} }
// Build and send the defense message to the relevant people (ie GM + defender) // Build and send the defense message to the relevant people (ie GM + defender)
let defender = game.actors.get(attackDef.defenderId) let defender = game.actors.get(rollData.defenderId)
console.log("DEF WEP", attackDef, defender)
let defenderWeapons = defender.weapons || [] let defenderWeapons = defender.weapons || []
this.attackStore[attackDef.id] = attackDef // Store ! let msg = await ChatMessage.create({
ChatMessage.create({
alias: defender.name, alias: defender.name,
whisper: BoLUtility.getWhisperRecipientsAndGMs(defender.name), whisper: BoLUtility.getWhisperRecipientsAndGMs(defender.name),
content: await renderTemplate('systems/bol/templates/chat/rolls/defense-request-card.hbs', { content: await renderTemplate('systems/bol/templates/chat/rolls/defense-request-card.hbs', {
attackId: attackDef.id, attackId: rollData.id,
attacker: attackDef.attacker, attacker: rollData.attacker,
defender: defender, defender: defender,
defenderWeapons: defenderWeapons, defenderWeapons: defenderWeapons,
damageTotal: attackDef.damageRoll.total, damageTotal: rollData.damageTotal,
damagesIgnoresArmor: attackDef.damagesIgnoresArmor, damagesIgnoresArmor: rollData.damagesIgnoresArmor,
}) })
}) })
msg.setFlag("world", "bol-roll-data", rollData)
console.log("DEF WEP", rollData, defender)
} }
/* -------------------------------------------- */ /* -------------------------------------------- */

View File

@ -14,7 +14,7 @@
], ],
"url": "https://www.uberwald.me/gitea/public/bol", "url": "https://www.uberwald.me/gitea/public/bol",
"license": "LICENSE.txt", "license": "LICENSE.txt",
"version": "10.5.7", "version": "10.5.11",
"compatibility": { "compatibility": {
"minimum": "10", "minimum": "10",
"verified": "10" "verified": "10"
@ -202,7 +202,7 @@
], ],
"socket": true, "socket": true,
"manifest": "https://www.uberwald.me/gitea/public/bol/raw/v10/system.json", "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-v10.5.11.zip",
"background": "systems/bol/ui/page_accueil.webp", "background": "systems/bol/ui/page_accueil.webp",
"gridDistance": 1.5, "gridDistance": 1.5,
"gridUnits": "m", "gridUnits": "m",

View File

@ -50,6 +50,10 @@
<div class="resource stat flex1 flex-group-center"> <div class="resource stat flex1 flex-group-center">
<label class="stat-label">{{localize label}}</label><br/> <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"/> <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 (eq @root.charType 'player')}}
{{#if (exists bonus)}} {{#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> <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

@ -6,7 +6,7 @@
{{/if}} {{/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-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}} {{#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> <button class="damage-handling" data-defense-mode="hero-reduce-damage" data-attack-id="{{attackId}}">{{localize "BOL.chat.shakeoff"}}</button>
@ -15,4 +15,6 @@
<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> <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}}
<button class="damage-handling" data-defense-mode="damage-not-applied" data-attack-id="{{attackId}}">{{localize "BOL.chat.nodamage"}}</button>
{{/if}} {{/if}}