diff --git a/lang/fr.json b/lang/fr.json index 7fac37f..013dbf0 100644 --- a/lang/fr.json +++ b/lang/fr.json @@ -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.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)", diff --git a/module/actor/actor.js b/module/actor/actor.js index d4690cb..79bfa83 100644 --- a/module/actor/actor.js +++ b/module/actor/actor.js @@ -40,10 +40,10 @@ export class BoLActor extends Actor { /* -------------------------------------------- */ 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 +51,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,13 +62,13 @@ 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') { @@ -137,7 +137,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) } } @@ -389,7 +389,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 +432,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 +458,28 @@ 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) { + if (rollData.horoscopeType == "major") { + if (rollData.isSuccess) { this.subHeroPoints(1) } else { this.addHeroPoints(1) - } + } } - 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 +487,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 +499,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 +521,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")) } } } @@ -716,17 +718,17 @@ 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({ @@ -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 }) }) } 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 +753,45 @@ 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, + actorId: this.id, + lossHP: lossHP, + recupHP: Math.floor(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() { - this.unsetFlag("world", "last-initiative" ) + this.unsetFlag("world", "last-initiative") } /*-------------------------------------------- */ @@ -766,50 +804,50 @@ export class BoLActor extends Actor { /*-------------------------------------------- */ getInitiativeRank(rollData = undefined, isCombat = false, combatData) { - if (!rollData) { + if (!rollData) { rollData = this.getFlag("world", "last-initiative") } let fvttInit = 4 // Pietaille par defaut - if (this.type == 'character' ) { + if (this.type == 'character') { fvttInit = 5 - if (!rollData) { + if (!rollData) { fvttInit = -1 - if ( isCombat ) { + if (isCombat) { ui.notifications.info(game.i18n.localize("BOL.ui.warninitiative")) - BoLRoll.aptitudeCheck(this, "init", undefined, combatData ) + 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; @@ -839,13 +877,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 } diff --git a/module/controllers/bol-rolls.js b/module/controllers/bol-rolls.js index fb4bb8c..0151cc2 100644 --- a/module/controllers/bol-rolls.js +++ b/module/controllers/bol-rolls.js @@ -766,13 +766,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() diff --git a/module/system/bol-combat.js b/module/system/bol-combat.js index 8d84f3d..a434f6d 100644 --- a/module/system/bol-combat.js +++ b/module/system/bol-combat.js @@ -40,6 +40,16 @@ export class BoLCombatManager extends Combat { } 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() { @@ -47,6 +57,7 @@ export class BoLCombatManager extends Combat { for (let c of combatants) { let actor = game.actors.get(c.actorId) actor.clearInitiative() + actor.displayRecuperation() } super._onDelete() } diff --git a/module/system/bol-utility.js b/module/system/bol-utility.js index fa4df0b..c27ccb7 100644 --- a/module/system/bol-utility.js +++ b/module/system/bol-utility.js @@ -8,8 +8,6 @@ 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é)", @@ -298,13 +296,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) } } } @@ -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 } }) } }) + + 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) { 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) { 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 +469,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, @@ -552,28 +565,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) } /* -------------------------------------------- */ diff --git a/system.json b/system.json index a31cc96..2cd653b 100644 --- a/system.json +++ b/system.json @@ -14,7 +14,7 @@ ], "url": "https://www.uberwald.me/gitea/public/bol", "license": "LICENSE.txt", - "version": "10.5.8", + "version": "10.5.9", "compatibility": { "minimum": "10", "verified": "10" @@ -202,7 +202,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.8.zip", + "download": "https://www.uberwald.me/gitea/public/bol/archive/bol-v10.5.9.zip", "background": "systems/bol/ui/page_accueil.webp", "gridDistance": 1.5, "gridUnits": "m", diff --git a/templates/chat/chat-recup-information.hbs b/templates/chat/chat-recup-information.hbs new file mode 100644 index 0000000..f414420 --- /dev/null +++ b/templates/chat/chat-recup-information.hbs @@ -0,0 +1,12 @@ +
+ {{name}} +

{{name}}

+
+ +
+ + {{localize "BOL.chat.losshp" lossHP=lossHP recupHP=recupHP}} + + +
+