diff --git a/module/actor/actor.js b/module/actor/actor.js
index 18054663..c3d98e5f 100644
--- a/module/actor/actor.js
+++ b/module/actor/actor.js
@@ -217,7 +217,7 @@ export class BoLActor extends Actor {
for (let protect of protectWorn) {
if ( protect.data.subtype == 'helm') {
formula += "+1"
- } else {
+ } else if ( protect.data.subtype == 'armor') {
formula += "+" + protect.data.properties.soak.formula;
}
}
diff --git a/module/controllers/bol-rolls.js b/module/controllers/bol-rolls.js
index b5f11b95..9b6c4959 100644
--- a/module/controllers/bol-rolls.js
+++ b/module/controllers/bol-rolls.js
@@ -1,356 +1,365 @@
import { BoLUtility } from "../system/bol-utility.js";
export class BoLRoll {
- static options() {
- return { classes: ["bol", "dialog"] };
- }
-
- static attributeCheck(actor, actorData, dataset, event) {
- // const elt = $(event.currentTarget)[0];
- // let key = elt.attributes["data-rolling"].value;
- const key = dataset.key;
- const adv = dataset.adv;
- let attribute = eval(`actor.data.data.attributes.${key}`);
- let label = (attribute.label) ? game.i18n.localize(attribute.label) : null;
- let description = actor.name + " - " + game.i18n.localize('BOL.ui.attributeCheck') + " - " + game.i18n.localize(attribute.label) ;
- return this.attributeRollDialog(actor, actorData, attribute, label, description, adv, 0);
- }
-
- static aptitudeCheck(actor, actorData, dataset, event) {
- // const elt = $(event.currentTarget)[0];
- // let key = elt.attributes["data-rolling"].value;
- const key = dataset.key;
- const adv = dataset.adv;
- let aptitude = eval(`actor.data.data.aptitudes.${key}`);
- let label = (aptitude.label) ? game.i18n.localize(aptitude.label) : null;
- let description = actor.name + " - " + game.i18n.localize('BOL.ui.aptitudeCheck') + " - " + game.i18n.localize(aptitude.label) ;
- return this.aptitudeRollDialog(actor, actorData, aptitude, label, description, adv, 0);
- }
-
- static weaponCheck(actor, actorData, dataset, event) {
- // const elt = $(event.currentTarget)[0];
- // let key = elt.attributes["data-rolling"].value;
- let target = BoLUtility.getTarget()
- const li = $(event.currentTarget).parents(".item");
- const weapon = actor.items.get(li.data("item-id"));
- if (!weapon) {
- ui.notifications.warn("Unable to find weapon !");
- return;
- }
- let weaponData = weapon.data.data;
- let attackDef= {
- id:randomID(16),
- attacker: actor,
- attackerData: actorData,
- weapon :weapon,
- mod: 0,
- target : target,
- defender: (target) ? game.actors.get(target.data.actorId) : undefined,
- adv :dataset.adv || 0,
- attribute : eval(`actor.data.data.attributes.${weaponData.properties.attackAttribute}`),
- aptitude : eval(`actor.data.data.aptitudes.${weaponData.properties.attackAptitude}`),
- label : (weapon.name) ? weapon.name : game.i18n.localize('BOL.ui.noWeaponName'),
- description : actor.name + " - " + game.i18n.localize('BOL.ui.weaponAttack'),
- }
- console.log("WEAPON!", attackDef, weaponData);
- return this.weaponRollDialog(attackDef);
+ static options() {
+ return { classes: ["bol", "dialog"] };
}
- /* -------------------------------------------- */
- /* ROLL DIALOGS */
- /* -------------------------------------------- */
- static async attributeRollDialog(actor, actorData, attribute, label, description, adv, mod, onEnter = "submit") {
- const rollOptionTpl = 'systems/bol/templates/dialogs/attribute-roll-dialog.hbs';
- const dialogData = {
- adv:adv,
- mod: mod,
- attr:attribute,
- careers:actorData.features.careers,
- boons:actorData.features.boons,
- flaws:actorData.features.flaws
- };
-
- const rollOptionContent = await renderTemplate(rollOptionTpl, dialogData);
- let d = new Dialog({
- title: label,
- content: rollOptionContent,
- buttons: {
- cancel: {
- icon: '',
- label: game.i18n.localize("BOL.ui.cancel"),
- callback: () => {
- }
- },
- submit: {
- icon: '',
- label: game.i18n.localize("BOL.ui.submit"),
- callback: (html) => {
- const attr = html.find('#attr').val();
- const adv = html.find('#adv').val();
- const mod = html.find('#mod').val();
- let careers = html.find('#career').val();
- const career = (careers.length == 0) ? 0 : Math.max(...careers.map(i => parseInt(i)));
- const isMalus = adv < 0;
- const dicePool = (isMalus) ? 2 - parseInt(adv) : 2 + parseInt(adv);
- const attrValue = eval(`actor.data.data.attributes.${attr}.value`);
- const modifiers = parseInt(attrValue) + parseInt(mod) + parseInt(career);
- const formula = (isMalus) ? dicePool + "d6kl2 + " + modifiers : dicePool + "d6kh2 + " + modifiers;
- let r = new BoLDefaultRoll(label, formula, description);
- r.roll(actor);
- }
- }
- },
- default: onEnter,
- close: () => {}
- }, this.options());
- return d.render(true);
- }
+ static attributeCheck(actor, actorData, dataset, event) {
+ // const elt = $(event.currentTarget)[0];
+ // let key = elt.attributes["data-rolling"].value;
+ const key = dataset.key;
+ const adv = dataset.adv;
+ let attribute = eval(`actor.data.data.attributes.${key}`);
+ let label = (attribute.label) ? game.i18n.localize(attribute.label) : null;
+ let description = actor.name + " - " + game.i18n.localize('BOL.ui.attributeCheck') + " - " + game.i18n.localize(attribute.label);
+ return this.attributeRollDialog(actor, actorData, attribute, label, description, adv, 0);
+ }
- static async weaponRollDialog( attackDef) {
- const rollOptionTpl = 'systems/bol/templates/dialogs/weapon-roll-dialog.hbs';
- const dialogData = {
- attr:attackDef.attribute,
- adv:attackDef.adv,
- mod: attackDef.mod,
- apt:attackDef.aptitude,
- weapon: attackDef.weapon,
- attackId: attackDef.id,
- careers: attackDef.attackerData.features.careers,
- boons: attackDef.attackerData.features.boons,
- flaws: attackDef.attackerData.features.flaws,
- };
- if ( attackDef.defender) {
- dialogData.defence = attackDef.defender.defenseValue,
- dialogData.shieldBlock = 'none'
- let shields = attackDef.defender.shields
- for( let shield of shields) {
- dialogData.shieldBlock = (shield.data.properties.blocking.blockingAll) ? 'blockall' : 'blockone';
- dialogData.shieldAttackMalus = (shield.data.properties.blocking.malus)? shield.data.properties.blocking.malus : 1;
- dialogData.applyShieldMalus = false
+ static aptitudeCheck(actor, actorData, dataset, event) {
+ // const elt = $(event.currentTarget)[0];
+ // let key = elt.attributes["data-rolling"].value;
+ const key = dataset.key;
+ const adv = dataset.adv;
+ let aptitude = eval(`actor.data.data.aptitudes.${key}`);
+ let label = (aptitude.label) ? game.i18n.localize(aptitude.label) : null;
+ let description = actor.name + " - " + game.i18n.localize('BOL.ui.aptitudeCheck') + " - " + game.i18n.localize(aptitude.label);
+ return this.aptitudeRollDialog(actor, actorData, aptitude, label, description, adv, 0);
+ }
+
+ static weaponCheck(actor, actorData, dataset, event) {
+ // const elt = $(event.currentTarget)[0];
+ // let key = elt.attributes["data-rolling"].value;
+ let target = BoLUtility.getTarget()
+ const li = $(event.currentTarget).parents(".item");
+ const weapon = actor.items.get(li.data("item-id"));
+ if (!weapon) {
+ ui.notifications.warn("Unable to find weapon !");
+ return;
+ }
+ let weaponData = weapon.data.data;
+ let attackDef = {
+ id: randomID(16),
+ attacker: actor,
+ attackerData: actorData,
+ weapon: weapon,
+ mod: 0,
+ target: target,
+ defender: (target) ? game.actors.get(target.data.actorId) : undefined,
+ adv: dataset.adv || 0,
+ attribute: eval(`actor.data.data.attributes.${weaponData.properties.attackAttribute}`),
+ aptitude: eval(`actor.data.data.aptitudes.${weaponData.properties.attackAptitude}`),
+ label: (weapon.name) ? weapon.name : game.i18n.localize('BOL.ui.noWeaponName'),
+ description: actor.name + " - " + game.i18n.localize('BOL.ui.weaponAttack'),
+ }
+ console.log("WEAPON!", attackDef, weaponData);
+ return this.weaponRollDialog(attackDef);
+ }
+
+ /* -------------------------------------------- */
+ /* ROLL DIALOGS */
+ /* -------------------------------------------- */
+ static async attributeRollDialog(actor, actorData, attribute, label, description, adv, mod, onEnter = "submit") {
+ const rollOptionTpl = 'systems/bol/templates/dialogs/attribute-roll-dialog.hbs';
+ const dialogData = {
+ adv: adv,
+ mod: mod,
+ attr: attribute,
+ careers: actorData.features.careers,
+ boons: actorData.features.boons,
+ flaws: actorData.features.flaws
+ };
+
+ const rollOptionContent = await renderTemplate(rollOptionTpl, dialogData);
+ let d = new Dialog({
+ title: label,
+ content: rollOptionContent,
+ buttons: {
+ cancel: {
+ icon: '',
+ label: game.i18n.localize("BOL.ui.cancel"),
+ callback: () => {
+ }
+ },
+ submit: {
+ icon: '',
+ label: game.i18n.localize("BOL.ui.submit"),
+ callback: (html) => {
+ const attr = html.find('#attr').val();
+ const adv = html.find('#adv').val();
+ const mod = html.find('#mod').val();
+ let careers = html.find('#career').val();
+ const career = (careers.length == 0) ? 0 : Math.max(...careers.map(i => parseInt(i)));
+ const isMalus = adv < 0;
+ const dicePool = (isMalus) ? 2 - parseInt(adv) : 2 + parseInt(adv);
+ const attrValue = eval(`actor.data.data.attributes.${attr}.value`);
+ const modifiers = parseInt(attrValue) + parseInt(mod) + parseInt(career);
+ const formula = (isMalus) ? dicePool + "d6kl2 + " + modifiers : dicePool + "d6kh2 + " + modifiers;
+ let r = new BoLDefaultRoll(label, formula, description);
+ r.roll(actor);
+ }
}
+ },
+ default: onEnter,
+ close: () => { }
+ }, this.options());
+ return d.render(true);
+ }
+
+ static async weaponRollDialog(attackDef) {
+ const rollOptionTpl = 'systems/bol/templates/dialogs/weapon-roll-dialog.hbs';
+ const dialogData = {
+ attr: attackDef.attribute,
+ adv: attackDef.adv,
+ mod: attackDef.mod,
+ apt: attackDef.aptitude,
+ weapon: attackDef.weapon,
+ attackId: attackDef.id,
+ careers: attackDef.attackerData.features.careers,
+ boons: attackDef.attackerData.features.boons,
+ flaws: attackDef.attackerData.features.flaws,
+ };
+ if (attackDef.defender) {
+ dialogData.defence = attackDef.defender.defenseValue,
+ dialogData.shieldBlock = 'none'
+ let shields = attackDef.defender.shields
+ for (let shield of shields) {
+ dialogData.shieldBlock = (shield.data.properties.blocking.blockingAll) ? 'blockall' : 'blockone';
+ dialogData.shieldAttackMalus = (shield.data.properties.blocking.malus) ? shield.data.properties.blocking.malus : 1;
+ dialogData.applyShieldMalus = false
}
- const rollOptionContent = await renderTemplate(rollOptionTpl, dialogData);
- let d = new Dialog({
- title: attackDef.label,
- content: rollOptionContent,
- buttons: {
- cancel: {
- icon: '',
- label: game.i18n.localize("BOL.ui.cancel"),
- callback: () => {
- }
- },
- submit: {
- icon: '',
- label: game.i18n.localize("BOL.ui.submit"),
- callback: (html) => {
- const attr = html.find('#attr').val();
- const apt = html.find('#apt').val();
- const adv = html.find('#adv').val();
- const mod = html.find('#mod').val() || 0;
-
- let shieldMalus = 0;
- const applyShieldMalus = html.find('#applyShieldMalus').val() || false;
- if (applyShieldMalus || dialogData.shieldBlock =='blockall') {
- shieldMalus = dialogData.shieldAttackMalus;
- }
-
- let careers = html.find('#career').val();
- const career = (careers.length == 0) ? 0 : Math.max(...careers.map(i => parseInt(i)));
- const isMalus = adv < 0;
- const dicePool = (isMalus) ? 2 - parseInt(adv) : 2 + parseInt(adv);
- const attrValue = eval(`attackDef.attacker.data.data.attributes.${attr}.value`);
- const aptValue = eval(`attackDef.attacker.data.data.aptitudes.${apt}.value`);
- const modifiers = parseInt(attrValue) + parseInt(aptValue) + parseInt(mod) + parseInt(career) - dialogData.defence - shieldMalus;
- const formula = (isMalus) ? dicePool + "d6kl2 + " + modifiers : dicePool + "d6kh2 + " + modifiers;
- attackDef.formula = formula;
- let r = new BoLAttackRoll(attackDef);
- r.roll();
- }
- }
- },
- default: 'submit',
- close: () => {}
- }, this.options());
- return d.render(true);
}
+ const rollOptionContent = await renderTemplate(rollOptionTpl, dialogData);
+ let d = new Dialog({
+ title: attackDef.label,
+ content: rollOptionContent,
+ buttons: {
+ cancel: {
+ icon: '',
+ label: game.i18n.localize("BOL.ui.cancel"),
+ callback: () => {
+ }
+ },
+ submit: {
+ icon: '',
+ label: game.i18n.localize("BOL.ui.submit"),
+ callback: (html) => {
+ const attr = html.find('#attr').val();
+ const apt = html.find('#apt').val();
+ const adv = html.find('#adv').val();
+ const mod = html.find('#mod').val() || 0;
- static async aptitudeRollDialog(actor, actorData, aptitude, label, description, adv, mod, onEnter = "submit") {
- const rollOptionTpl = 'systems/bol/templates/dialogs/aptitude-roll-dialog.hbs';
- const dialogData = {
- adv:adv,
- mod: mod,
- apt:aptitude,
- careers:actorData.features.careers,
- boons:actorData.features.boons,
- flaws:actorData.features.flaws
- };
- const rollOptionContent = await renderTemplate(rollOptionTpl, dialogData);
- let d = new Dialog({
- title: label,
- content: rollOptionContent,
- buttons: {
- cancel: {
- icon: '',
- label: game.i18n.localize("BOL.ui.cancel"),
- callback: () => {
- }
- },
- submit: {
- icon: '',
- label: game.i18n.localize("BOL.ui.submit"),
- callback: (html) => {
- const apt = html.find('#apt').val();
- const adv = html.find('#adv').val();
- const mod = html.find('#mod').val();
- let careers = html.find('#career').val();
- const career = (careers.length == 0) ? 0 : Math.max(...careers.map(i => parseInt(i)));
- const isMalus = adv < 0;
- const dicePool = (isMalus) ? 2 - parseInt(adv) : 2 + parseInt(adv);
- const aptValue = eval(`actor.data.data.aptitudes.${apt}.value`);
- const modifiers = parseInt(aptValue) + parseInt(mod) + parseInt(career);
- const formula = (isMalus) ? dicePool + "d6kl2 + " + modifiers : dicePool + "d6kh2 + " + modifiers;
- let r = new BoLDefaultRoll(label, formula, description);
- r.roll(actor);
- }
- }
- },
- default: onEnter,
- close: () => {}
- }, this.options());
- return d.render(true);
- }
+ let shieldMalus = 0;
+ const applyShieldMalus = html.find('#applyShieldMalus').val() || false;
+ if (applyShieldMalus || dialogData.shieldBlock == 'blockall') {
+ shieldMalus = dialogData.shieldAttackMalus;
+ }
+
+ let careers = html.find('#career').val();
+ const career = (careers.length == 0) ? 0 : Math.max(...careers.map(i => parseInt(i)));
+ const isMalus = adv < 0;
+ const dicePool = (isMalus) ? 2 - parseInt(adv) : 2 + parseInt(adv);
+ const attrValue = eval(`attackDef.attacker.data.data.attributes.${attr}.value`);
+ const aptValue = eval(`attackDef.attacker.data.data.aptitudes.${apt}.value`);
+ const modifiers = parseInt(attrValue) + parseInt(aptValue) + parseInt(mod) + parseInt(career) - dialogData.defence - shieldMalus;
+ const formula = (isMalus) ? dicePool + "d6kl2 + " + modifiers : dicePool + "d6kh2 + " + modifiers;
+ attackDef.formula = formula;
+ let r = new BoLAttackRoll(attackDef);
+ r.roll();
+ }
+ }
+ },
+ default: 'submit',
+ close: () => { }
+ }, this.options());
+ return d.render(true);
+ }
+
+ static async aptitudeRollDialog(actor, actorData, aptitude, label, description, adv, mod, onEnter = "submit") {
+ const rollOptionTpl = 'systems/bol/templates/dialogs/aptitude-roll-dialog.hbs';
+ const dialogData = {
+ adv: adv,
+ mod: mod,
+ apt: aptitude,
+ careers: actorData.features.careers,
+ boons: actorData.features.boons,
+ flaws: actorData.features.flaws
+ };
+ const rollOptionContent = await renderTemplate(rollOptionTpl, dialogData);
+ let d = new Dialog({
+ title: label,
+ content: rollOptionContent,
+ buttons: {
+ cancel: {
+ icon: '',
+ label: game.i18n.localize("BOL.ui.cancel"),
+ callback: () => {
+ }
+ },
+ submit: {
+ icon: '',
+ label: game.i18n.localize("BOL.ui.submit"),
+ callback: (html) => {
+ const apt = html.find('#apt').val();
+ const adv = html.find('#adv').val();
+ const mod = html.find('#mod').val();
+ let careers = html.find('#career').val();
+ const career = (careers.length == 0) ? 0 : Math.max(...careers.map(i => parseInt(i)));
+ const isMalus = adv < 0;
+ const dicePool = (isMalus) ? 2 - parseInt(adv) : 2 + parseInt(adv);
+ const aptValue = eval(`actor.data.data.aptitudes.${apt}.value`);
+ const modifiers = parseInt(aptValue) + parseInt(mod) + parseInt(career);
+ const formula = (isMalus) ? dicePool + "d6kl2 + " + modifiers : dicePool + "d6kh2 + " + modifiers;
+ let r = new BoLDefaultRoll(label, formula, description);
+ r.roll(actor);
+ }
+ }
+ },
+ default: onEnter,
+ close: () => { }
+ }, this.options());
+ return d.render(true);
+ }
}
export class BoLDefaultRoll {
- constructor(label, formula, description, isWeapon=false){
- this._label = label;
- this._formula = formula;
- this._isSuccess = false;
- this._isCritical = false;
- this._isFumble = false;
- this._isWeapon = isWeapon;
- this._description = description;
- }
+ constructor(label, formula, description, isWeapon = false) {
+ this._label = label;
+ this._formula = formula;
+ this._isSuccess = false;
+ this._isCritical = false;
+ this._isFumble = false;
+ this._isWeapon = isWeapon;
+ this._description = description;
+ }
- async roll(actor){
- const r = new Roll(this._formula);
- await r.roll({"async": true});
- const activeDice = r.terms[0].results.filter(r => r.active);
- const diceTotal = activeDice.map(r => r.result).reduce((a, b) => a + b);
- this._isSuccess = (r.total >= 9);
- this._isCritical = (diceTotal === 12);
- this._isFumble = (diceTotal === 2);
- this._buildChatMessage(actor).then(msgFlavor => {
- r.toMessage({
- user: game.user.id,
- flavor: msgFlavor,
- speaker: ChatMessage.getSpeaker({actor: actor}),
- flags : {msgType : "default"}
- });
- });
- if (this._isSuccess && this._isWeapon) {
+ async roll(actor) {
+ const r = new Roll(this._formula);
+ await r.roll({ "async": true });
+ const activeDice = r.terms[0].results.filter(r => r.active);
+ const diceTotal = activeDice.map(r => r.result).reduce((a, b) => a + b);
+ this._isSuccess = (r.total >= 9);
+ this._isCritical = (diceTotal === 12);
+ this._isFumble = (diceTotal === 2);
+ this._buildChatMessage(actor).then(msgFlavor => {
+ r.toMessage({
+ user: game.user.id,
+ flavor: msgFlavor,
+ speaker: ChatMessage.getSpeaker({ actor: actor }),
+ flags: { msgType: "default" }
+ });
+ });
+ if (this._isSuccess && this._isWeapon) {
- }
}
+ }
- _buildChatMessage(actor) {
- const rollMessageTpl = 'systems/bol/templates/chat/rolls/default-roll-card.hbs';
- const tplData = {
- actor : actor,
- label : this._label,
- isSuccess : this._isSuccess,
- isFailure : !this._isSuccess,
- isCritical : this._isCritical,
- isFumble : this._isFumble,
- hasDescription : this._description && this._description.length > 0,
- description : this._description
- };
- return renderTemplate(rollMessageTpl, tplData);
- }
+ _buildChatMessage(actor) {
+ const rollMessageTpl = 'systems/bol/templates/chat/rolls/default-roll-card.hbs';
+ const tplData = {
+ actor: actor,
+ label: this._label,
+ isSuccess: this._isSuccess,
+ isFailure: !this._isSuccess,
+ isCritical: this._isCritical,
+ isFumble: this._isFumble,
+ hasDescription: this._description && this._description.length > 0,
+ description: this._description
+ };
+ return renderTemplate(rollMessageTpl, tplData);
+ }
}
export class BoLAttackRoll {
- constructor(attackDef){
- this.attackDef = attackDef;
- this._isSuccess = false;
- this._isCritical = false;
- this._isFumble = false;
-}
+ constructor(attackDef) {
+ this.attackDef = attackDef;
+ this._isSuccess = false;
+ this._isCritical = false;
+ this._isFumble = false;
+ }
- async roll(){
- const r = new Roll(this.attackDef.formula);
- await r.roll({"async": false});
- const activeDice = r.terms[0].results.filter(r => r.active);
- const diceTotal = activeDice.map(r => r.result).reduce((a, b) => a + b);
- this._isSuccess = (r.total >= 9);
- this._isCritical = (diceTotal === 12);
- this._isFumble = (diceTotal === 2);
- this._buildChatMessage(this.attackDef.attacker).then(msgFlavor => {
- r.toMessage({
- user: game.user.id,
- flavor: msgFlavor,
- speaker: ChatMessage.getSpeaker({actor: this.attackDef.attacker}),
- flags : {msgType : "default"}
- });
+ async roll() {
+ const r = new Roll(this.attackDef.formula);
+ await r.roll({ "async": false });
+ //await BoLUtility.showDiceSoNice(r);
+ const activeDice = r.terms[0].results.filter(r => r.active);
+ const diceTotal = activeDice.map(r => r.result).reduce((a, b) => a + b);
+ this._isSuccess = (r.total >= 9);
+ this._isCritical = (diceTotal === 12);
+ this._isFumble = (diceTotal === 2);
+ this._buildChatMessage(this.attackDef.attacker).then(msgFlavor => {
+ r.toMessage({
+ user: game.user.id,
+ flavor: msgFlavor,
+ speaker: ChatMessage.getSpeaker({ actor: this.attackDef.attacker }),
+ flags: { msgType: "default" }
});
+ });
- if (this._isSuccess ) {
- let attrDamage = this.attackDef.weapon.data.data.properties.damageAttribute;
- let weaponFormula = BoLUtility.getDamageFormula(this.attackDef.weapon.data.data.properties.damage)
- let damageFormula = weaponFormula + "+" + this.attackDef.attacker.data.data.attributes[attrDamage].value;
- this.damageRoll = new Roll(damageFormula);
- await this.damageRoll.roll({"async": false});
- // Update attackDef object
- this.attackDef.damageFormula = damageFormula;
- this.attackDef.damageRoll = this.damageRoll;
+ if (this._isSuccess) {
+ let attrDamage = this.attackDef.weapon.data.data.properties.damageAttribute;
+ let weaponFormula = BoLUtility.getDamageFormula(this.attackDef.weapon.data.data.properties.damage)
+ let damageFormula = weaponFormula + "+" + this.attackDef.attacker.data.data.attributes[attrDamage].value;
+ this.damageRoll = new Roll(damageFormula);
+ await this.damageRoll.roll({ "async": false });
+ //await BoLUtility.showDiceSoNice(this.damageRoll);
+ // Update attackDef object
+ this.attackDef.damageFormula = damageFormula;
+ this.attackDef.damageRoll = this.damageRoll;
- this._buildDamageChatMessage(this.attackDef.attacker, this.attackDef.weapon, this.damageRoll.total).then(msgFlavor => {
- this.damageRoll.toMessage({
- user: game.user.id,
- flavor: msgFlavor,
- speaker: ChatMessage.getSpeaker({actor: this.attackDef.attacker}),
- flags : {msgType : "default"}
- }).then( result => {
- if (this.attackDef.target) {
- // Broadcast to GM or process it directly in case of GM defense
- if ( !game.user.isGM) {
- game.socket.emit("system.bol", { msg: "msg_attack_success", data: this.attackDef });
- } else {
- BoLUtility.processAttackSuccess( this.attackDef);
- }
- }
- });
+ this._buildDamageChatMessage(this.attackDef.attacker, this.attackDef.weapon, this.damageRoll.total).then(msgFlavor => {
+ this.damageRoll.toMessage({
+ user: game.user.id,
+ flavor: msgFlavor,
+ speaker: ChatMessage.getSpeaker({ actor: this.attackDef.attacker }),
+ flags: { msgType: "default" }
+ });
});
- }
+ if (this._isCritical) {
+ ChatMessage.create({
+ alias: this.attackDef.attacker.name,
+ whisper: BoLUtility.getWhisperRecipientsAndGMs(this.attackDef.attacker.name),
+ content: await renderTemplate('systems/bol/templates/chat/rolls/attack-heroic-card.hbs', {
+ attackId: attackDef.id,
+ attacker: attackDef.attacker,
+ defender: attackDef.defender,
+ defenderWeapons: defenderWeapons,
+ damageTotal: attackDef.damageRoll.total
+ })
+ })
+ } else {
+ BoLUtility.sendAttackSuccess( this.attackDef);
+ }
}
+ }
_buildDamageChatMessage(actor, weapon, total) {
- const rollMessageTpl = 'systems/bol/templates/chat/rolls/damage-roll-card.hbs';
- const tplData = {
- actor : actor,
- label : this._label,
- weapon: weapon,
- damage: total,
- };
- return renderTemplate(rollMessageTpl, tplData);
-}
+ const rollMessageTpl = 'systems/bol/templates/chat/rolls/damage-roll-card.hbs';
+ const tplData = {
+ actor: actor,
+ label: this._label,
+ weapon: weapon,
+ damage: total,
+ isCritical: this._isCritical,
+ };
+ return renderTemplate(rollMessageTpl, tplData);
+ }
_buildChatMessage(actor) {
- const rollMessageTpl = 'systems/bol/templates/chat/rolls/default-roll-card.hbs';
- const tplData = {
- actor : actor,
- label : this._label,
- isSuccess : this._isSuccess,
- isFailure : !this._isSuccess,
- isCritical : this._isCritical,
- isFumble : this._isFumble,
- hasDescription : this._description && this._description.length > 0,
- description : this._description
- };
- return renderTemplate(rollMessageTpl, tplData);
- }
+ const rollMessageTpl = 'systems/bol/templates/chat/rolls/default-roll-card.hbs';
+ const tplData = {
+ actor: actor,
+ label: this._label,
+ isSuccess: this._isSuccess,
+ isFailure: !this._isSuccess,
+ isCritical: this._isCritical,
+ isFumble: this._isFumble,
+ hasDescription: this._description && this._description.length > 0,
+ description: this._description
+ };
+ return renderTemplate(rollMessageTpl, tplData);
+ }
}
// export class BoLWeaponRoll {
diff --git a/module/system/bol-utility.js b/module/system/bol-utility.js
index 320bfed8..1dcfe970 100644
--- a/module/system/bol-utility.js
+++ b/module/system/bol-utility.js
@@ -95,9 +95,31 @@ export class BoLUtility {
game.socket.emit("system.fvtt-fragged-kingdom", { msg: "msg_gm_chat_message", data: chatGM });
}
+ /* -------------------------------------------- */
+ static sendAttackSuccess(attackDef) {
+ if (attackDef.target) {
+ // Broadcast to GM or process it directly in case of GM defense
+ if (!game.user.isGM) {
+ game.socket.emit("system.bol", { msg: "msg_attack_success", data: attackDef });
+ } else {
+ BoLUtility.processAttackSuccess(attackDef);
+ }
+ }
+ }
+
/* -------------------------------------------- */
static async chatListeners(html) {
// Damage handling
+ html.on("click", '.damage-increase', event => {
+ let attackId = event.currentTarget.attributes['data-attack-id'].value;
+ let damageMode = event.currentTarget.attributes['data-damage-mode'].value;
+ if ( game.user.isGM) {
+ BoLUtility.processDamageIncrease(event, attackId, damageMode)
+ } else {
+ game.socket.emit("system.bol", { msg: "msg_damage_increase", data: {event: event, attackId: attackId, damageMode: damageMode} });
+ }
+ });
+
html.on("click", '.damage-handling', event => {
let attackId = event.currentTarget.attributes['data-attack-id'].value;
let defenseMode = event.currentTarget.attributes['data-defense-mode'].value;
@@ -111,6 +133,31 @@ export class BoLUtility {
});
}
+ /* -------------------------------------------- */
+ static async processDamageIncrease(event, attackId, damageMode ) {
+ if ( !game.user.isGM) {
+ return;
+ }
+ BoLUtility.removeChatMessageId(BoLUtility.findChatMessageId(event.currentTarget));
+
+ // Only GM process this
+ let attackDef = this.attackStore[attackId];
+ if (attackDef) {
+ attackDef.damageMode = damageMode;
+ if (defenseMode == 'damage-plus-6') {
+ attackDef.damageRoll.total += 6;
+ }
+ if (defenseMode == 'damage-plus-12') {
+ attackDef.damageRoll.total += 12;
+ attackDef.defender.subHeroPoints(1);
+ }
+ if (defenseMode == 'damage-normal') {
+ // Do nothing !
+ }
+ BoLUtility.sendAttackSuccess( this.attackDef);
+ }
+ }
+
/* -------------------------------------------- */
static async processDamageHandling(event, attackId, defenseMode, weaponId=-1) {
if ( !game.user.isGM) {
@@ -120,14 +167,14 @@ export class BoLUtility {
// Only GM process this
let attackDef = this.attackStore[attackId];
- console.log("DEFENSE2", attackId, defenseMode, weaponId, attackDef);
if (attackDef) {
attackDef.defenseMode = defenseMode;
if (defenseMode == 'damage-with-armor') {
- let armorFormula = attackDef.defender.getArmorFormula();
+ let armorFormula = attackDef.defender.getArmorFormula();
attackDef.rollArmor = new Roll(armorFormula)
attackDef.rollArmor.roll( {async: false} );
- attackDef.finalDamage = attackDef.damageRoll.total - attackDef.rollArmor.total;
+ attackDef.armorProtect = (attackDef.rollArmor.total<0) ? 0 : attackDef.rollArmor.total;
+ attackDef.finalDamage = attackDef.damageRoll.total - attackDef.armorProtect;
attackDef.finalDamage = (attackDef.finalDamage<0) ? 0 : attackDef.finalDamage;
attackDef.defender.sufferDamage(attackDef.finalDamage);
}
@@ -136,9 +183,13 @@ export class BoLUtility {
attackDef.defender.sufferDamage(attackDef.finalDamage);
}
if (defenseMode == 'hero-reduce-damage') {
+ let armorFormula = attackDef.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.damageRoll.total - attackDef.rollHero.total;
+ attackDef.finalDamage = attackDef.damageRoll.total - attackDef.rollHero.total - attackDef.armorProtect;
attackDef.finalDamage = (attackDef.finalDamage<0) ? 0 : attackDef.finalDamage;
attackDef.defender.sufferDamage(attackDef.finalDamage);
attackDef.defender.subHeroPoints(1);
@@ -157,6 +208,7 @@ export class BoLUtility {
rollArmor: attackDef.rollArmor,
rollHero: attackDef.rollHero,
weaponHero : attackDef.weaponHero,
+ armorProtect: attackDef.armorProtect,
defender: attackDef.defender,
defenseMode: attackDef.defenseMode,
finalDamage: attackDef.finalDamage
@@ -313,6 +365,9 @@ export class BoLUtility {
if (sockmsg.name == "msg_damage_handling") {
BoLUtility.processDamageHandling(sockmsg.data.event, sockmsg.data.attackId, sockmsg.data.defenseMode)
}
+ if (sockmsg.name == "msg_damage_increase") {
+ BoLUtility.processDamageIncrease(sockmsg.data.event, sockmsg.data.attackId, sockmsg.data.damageMode)
+ }
}
/* -------------------------------------------- */
@@ -338,6 +393,30 @@ export class BoLUtility {
let formula = nbDice + "d" + res[2] + postForm + ((res[modIndex]) ? res[modIndex] : "");
return formula;
}
+ /* -------------------------------------------- */
+ static async showDiceSoNice(roll, rollMode) {
+ if (game.modules.get("dice-so-nice")?.active) {
+ if (game.dice3d) {
+ let whisper = null;
+ let blind = false;
+ rollMode = rollMode ?? game.settings.get("core", "rollMode");
+ switch (rollMode) {
+ case "blindroll": //GM only
+ blind = true;
+ case "gmroll": //GM + rolling player
+ whisper = BoLUtility.getUsers(user => user.isGM);
+ break;
+ case "roll": //everybody
+ whisper = BoLUtility.getUsers(user => user.active);
+ break;
+ case "selfroll":
+ whisper = [game.user.id];
+ break;
+ }
+ await game.dice3d.showForRoll(roll, game.user, true, whisper, blind);
+ }
+ }
+ }
/* -------------------------------------------- */
static async confirmDelete(actorSheet, li) {
diff --git a/system.json b/system.json
index d5fefc5f..611ad13a 100644
--- a/system.json
+++ b/system.json
@@ -7,7 +7,7 @@
"url": "https://github.com/ZigmundKreud/bol",
"license": "LICENSE.txt",
"flags": {},
- "version": "0.8.9.0",
+ "version": "0.8.9.1",
"minimumCoreVersion": "0.8.6",
"compatibleCoreVersion": "9",
"scripts": [],
diff --git a/templates/chat/rolls/attack-heroic-card.hbs b/templates/chat/rolls/attack-heroic-card.hbs
new file mode 100644
index 00000000..27f4c92a
--- /dev/null
+++ b/templates/chat/rolls/attack-heroic-card.hbs
@@ -0,0 +1,6 @@
+
+Jet Héroïque !
+
+
+
+
diff --git a/templates/chat/rolls/defense-result-card.hbs b/templates/chat/rolls/defense-result-card.hbs
index 69807bd4..30e08c62 100644
--- a/templates/chat/rolls/defense-result-card.hbs
+++ b/templates/chat/rolls/defense-result-card.hbs
@@ -3,13 +3,14 @@