diff --git a/lang/en.json b/lang/en.json index 2de175f..989f516 100644 --- a/lang/en.json +++ b/lang/en.json @@ -54,6 +54,7 @@ "BOL.ui.roll" : "Utiliser", "BOL.ui.equipment" : "Équipement", "BOL.ui.equipmentProperties" : "Propiétés d'équipement", + "BOL.ui.weaponAttack" : "Weapon attack", "BOL.ui.weaponProperties" : "Propiétés offensives", "BOL.ui.protectionProperties" : "Protection", "BOL.ui.magicalProperties" : "Propriétés magiques", @@ -107,7 +108,8 @@ "BOL.ui.duration": "Duration", "BOL.ui.spellkeep": "Maintain", "BOL.ui.concentrate": "Concentrate", - + "BOL.ui.registerInit": "Register Init.", + "BOL.featureCategory.origins": "Origines", "BOL.featureCategory.races": "Races", "BOL.featureCategory.careers": "Carrières", diff --git a/lang/fr.json b/lang/fr.json index 670e5bd..12151f9 100644 --- a/lang/fr.json +++ b/lang/fr.json @@ -54,6 +54,7 @@ "BOL.ui.roll" : "Utiliser", "BOL.ui.equipment" : "Équipement", "BOL.ui.equipmentProperties" : "Propriétés d'équipement", + "BOL.ui.weaponAttack" : "Attaque d'arme", "BOL.ui.weaponProperties" : "Propriétés offensives", "BOL.ui.protectionProperties" : "Protection", "BOL.ui.magicalProperties" : "Propriétés magiques", @@ -108,7 +109,8 @@ "BOL.ui.duration": "Durée", "BOL.ui.spellkeep": "Prolongation", "BOL.ui.concentrate": "Concentration", - + "BOL.ui.registerInit": "Enregistrer comme Init. de combat", + "BOL.featureCategory.origins": "Origines", "BOL.featureCategory.races": "Races", "BOL.featureCategory.careers": "Carrières", diff --git a/module/actor/actor-sheet.js b/module/actor/actor-sheet.js index 18070af..b062461 100644 --- a/module/actor/actor-sheet.js +++ b/module/actor/actor-sheet.js @@ -182,6 +182,7 @@ export class BoLActorSheet extends ActorSheet { const dataset = element.dataset; const actorData = this.getData(); const rollType = dataset.rollType; + const li = $(event.currentTarget).closest(".item"); switch(rollType) { case "attribute" : BoLRoll.attributeCheck(this.actor, actorData, dataset, event); @@ -192,6 +193,12 @@ export class BoLActorSheet extends ActorSheet { case "weapon": BoLRoll.weaponCheck(this.actor, actorData, dataset, event); break; + case "protection": + this.actor.rollProtection(li.data("item-id")) + break; + case "damage": + this.actor.rollWeaponDamage(li.data("item-id")) + break; default : break; } } diff --git a/module/actor/actor.js b/module/actor/actor.js index e02dcb8..2e4b8e5 100644 --- a/module/actor/actor.js +++ b/module/actor/actor.js @@ -1,3 +1,5 @@ +import { BoLDefaultRoll } from "../controllers/bol-rolls.js"; + /** * Extend the base Actor entity by defining a custom roll data structure which is ideal for the Simple system. * @extends {Actor} @@ -241,6 +243,16 @@ export class BoLActor extends Actor { } } + /*-------------------------------------------- */ + registerInit(initScore, isCritical, isFumble) { + this.update( { 'data.combat.lastinit': initScore, 'data.combat.iscritical': isCritical, 'data.combat.isfumble': isFumble} ) + } + + /*-------------------------------------------- */ + getLastInitData() { + return this.data.data.combat + } + /*-------------------------------------------- */ async subHeroPoints( nb) { let newHeroP = this.data.data.resources.hero.value - nb; @@ -270,6 +282,27 @@ export class BoLActor extends Actor { return (formula == "") ? 0 :formula; } + /* -------------------------------------------- */ + rollProtection( itemId) { + let armor = this.data.items.get( itemId ) + if ( armor ) { + let armorFormula = armor.data.data.properties.soak.formula; + let rollArmor = new Roll(armorFormula) + rollArmor.roll( {async: false} ).toMessage(); + } + } + + /* -------------------------------------------- */ + rollWeaponDamage( itemId) { + let weapon = this.data.items.get(itemId ) + if ( weapon ) { + console.log("WE", weapon) + let r = new BoLDefaultRoll( { id: randomID(16), isSuccess: true, mode: "weapon", weapon: weapon, actor: this} ) + r.setSuccess(true) + r.processResult() + } + } + /* -------------------------------------------- */ toggleEquipItem(item) { const equipable = item.data.data.properties.equipable; diff --git a/module/bol.js b/module/bol.js index 750dec5..ad5ead6 100644 --- a/module/bol.js +++ b/module/bol.js @@ -8,9 +8,9 @@ import { preloadHandlebarsTemplates } from "./system/templates.js"; import { registerHandlebarsHelpers } from "./system/helpers.js"; import { registerSystemSettings } from "./system/settings.js"; import registerHooks from "./system/hooks.js"; -// import {DataLoader} from "./system/data.js"; import { Macros } from "./system/macros.js"; import { BoLUtility } from "./system/bol-utility.js"; +import { BoLCombatManager } from "./system/bol-combat.js"; Hooks.once('init', async function () { @@ -33,12 +33,13 @@ Hooks.once('init', async function () { */ CONFIG.Combat.initiative = { formula: "2d6+@attributes.mind.value+@aptitudes.init.value", - decimals: 0 + decimals: 3 }; - 0 + // Define custom Entity classes CONFIG.Actor.documentClass = BoLActor; CONFIG.Item.documentClass = BoLItem; + CONFIG.Combat.documentClass = BoLCombatManager; // Register sheet application classes Actors.unregisterSheet("core", ActorSheet); diff --git a/module/controllers/bol-rolls.js b/module/controllers/bol-rolls.js index 91ee36f..384d3b5 100644 --- a/module/controllers/bol-rolls.js +++ b/module/controllers/bol-rolls.js @@ -1,10 +1,20 @@ import { BoLUtility } from "../system/bol-utility.js"; +const __adv2dice = { ["1B"]: 3, ["2B"]: 4, ["2"]: 2, ["1M"]: 3, ["2M"]: 4} +const _apt2attr = {init: "mind", melee: "agility", ranged: "agility", def: "vigor"} + export class BoLRoll { static options() { return { classes: ["bol", "dialog"] }; } + static convertToAdv( adv) { + if (adv == 0) return "2" + return Math.abs(adv) + (adv < 0)?'M':'B'; + } + static getDefaultAttribute( key ) { + return _apt2attr[key] + } static attributeCheck(actor, actorData, dataset, event) { // const elt = $(event.currentTarget)[0]; // let key = elt.attributes["data-rolling"].value; @@ -13,7 +23,17 @@ export class BoLRoll { 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); + return this.displayRollDialog( + { + mode: "attribute", + actor: actor, + actorData: actorData, + attribute: attribute, + label: label, + description: description, + adv: this.convertToAdv(adv), + mod: 0 + }); } static aptitudeCheck(actor, actorData, dataset, event) { @@ -21,10 +41,25 @@ export class BoLRoll { // let key = elt.attributes["data-rolling"].value; const key = dataset.key; const adv = dataset.adv; + let aptitude = eval(`actor.data.data.aptitudes.${key}`); + let attrKey = this.getDefaultAttribute(key) + let attribute = eval(`actor.data.data.attributes.${attrKey}`); + 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); + return this.displayRollDialog( + { + mode: "aptitude", + actor: actor, + actorData: actorData, + attribute: attribute, + aptitude: aptitude, + label: label, + description: description, + adv: this.convertToAdv(adv), + mod: 0 + }); } static weaponCheck(actor, actorData, dataset, event) { @@ -39,102 +74,57 @@ export class BoLRoll { } let weaponData = weapon.data.data; let attackDef = { - id: randomID(16), - attacker: actor, - attackerData: actorData, + mode: "weapon", + actor: actor, + actorData: 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'), + adv: "2", + } console.debug("WEAPON!", attackDef, weaponData); - return this.weaponRollDialog(attackDef); + return this.displayRollDialog(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 - }; + static async displayRollDialog(rollData, onEnter = "submit") { - 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 || 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); - } + const rollOptionTpl = `systems/bol/templates/dialogs/${rollData.mode}-roll-dialog.hbs` + rollData.careers = rollData.actorData.features.careers + rollData.boons = rollData.actorData.features.boons + rollData.flaws = rollData.actorData.features.flaws + rollData.defence = 0 + rollData.mod = 0 + rollData.id = randomID(16) + + // Weapon mode specific management + if (rollData.mode == "weapon") { + if (rollData.defender) { // If target is selected + rollData.defence = rollData.defender.defenseValue, + rollData.shieldBlock = 'none' + let shields = rollData.defender.shields + for (let shield of shields) { + rollData.shieldBlock = (shield.data.properties.blocking.blockingAll) ? 'blockall' : 'blockone'; + rollData.shieldAttackMalus = (shield.data.properties.blocking.malus) ? shield.data.properties.blocking.malus : 1; + rollData.applyShieldMalus = false } - }, - 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, - defence: 0 - }; - - 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); + + console.log("ROL1", rollData) + + const rollOptionContent = await renderTemplate(rollOptionTpl, rollData); let d = new Dialog({ - title: attackDef.label, + title: rollData.label, content: rollOptionContent, + rollData: rollData, buttons: { cancel: { icon: '', @@ -146,74 +136,35 @@ export class BoLRoll { 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; - + rollData.attrKey = html.find('#attr').val(); + rollData.aptKey = html.find('#apt').val(); + rollData.adv = $("input[name='adv']:checked").val() || "2"; + //rollData.adv = html.find('#adv').val() || 0; + rollData.mod = html.find('#mod').val() || 0; + let careers = html.find('#career').val(); + rollData.career = (!careers || careers.length == 0) ? 0 : Math.max(...careers.map(i => parseInt(i))); + rollData.registerInit = (rollData.aptKey == 'init') ? $('#register-init').is(":checked") : false; + let shieldMalus = 0; - const applyShieldMalus = html.find('#applyShieldMalus').val() || false; - if (applyShieldMalus || dialogData.shieldBlock == 'blockall') { - shieldMalus = dialogData.shieldAttackMalus; + if ( rollData.mode == "weapon") { + const applyShieldMalus = html.find('#applyShieldMalus').val() || false; + if (applyShieldMalus || rollData.shieldBlock == 'blockall') { + shieldMalus = rollData.shieldAttackMalus; + } } - let careers = html.find('#career').val(); - const career = (!careers || 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 isMalus = rollData.adv.includes('M'); + const dicePool = __adv2dice[rollData.adv] + //// const dicePool = (isMalus) ? 2 - parseInt(rollData.adv) : 2 + parseInt(rollData.adv); + const attrValue = (rollData.attrKey) && eval(`rollData.actor.data.data.attributes.${rollData.attrKey}.value`) || 0; + const aptValue = (rollData.aptKey) && eval(`rollData.actor.data.data.aptitudes.${rollData.aptKey}.value`) || 0 + + const modifiers = parseInt(attrValue) + parseInt(aptValue) + parseInt(rollData.mod) + parseInt(rollData.career) - rollData.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); - } + rollData.formula = formula; - 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 || 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); + let r = new BoLDefaultRoll(rollData); + r.roll(); } } }, @@ -225,192 +176,96 @@ export class BoLRoll { } 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; - } - - 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, - reroll: actor.heroReroll(), - 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(rollData) { + BoLUtility.storeRoll(rollData); + this.rollData = rollData + this.rollData.isSuccess = false; + this.rollData.isCritical = false; + this.rollData.isFumble = false; } async roll() { - console.log("Attack def",this.attackDef.formula ) - const r = new Roll(this.attackDef.formula); + console.log("ROLL", this.rollData) + + const r = new Roll(this.rollData.formula); await r.roll({ "async": false }); - await BoLUtility.showDiceSoNice(r); + //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 => { + this.rollData.isSuccess = (r.total >= 9); + this.rollData.isCritical = (diceTotal === 12); + this.rollData.isFumble = (diceTotal === 2); + this.rollData.isFailure = !this.rollData.isSuccess + this.rollData.reroll = this.rollData.actor.heroReroll() + + if (this.rollData.registerInit) { + this.rollData.actor.registerInit( r.total, this.rollData.isCritical); + } + + this._buildChatMessage(this.rollData).then(msgFlavor => { r.toMessage({ user: game.user.id, flavor: msgFlavor, - speaker: ChatMessage.getSpeaker({ actor: this.attackDef.attacker }), + speaker: ChatMessage.getSpeaker({ actor: this.rollData.actor }), flags: { msgType: "default" } - }).then( this.processResult() ); + }).then(this.processResult()); }); } async processDefense() { - if (this._isCritical) { + if (this.rollData.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 - }) + alias: this.rollData.actor.name, + whisper: BoLUtility.getWhisperRecipientsAndGMs(this.rollData.actor.name), + content: await renderTemplate('systems/bol/templates/chat/rolls/attack-heroic-card.hbs', this.rollData ) }) } else { - BoLUtility.sendAttackSuccess( this.attackDef); + BoLUtility.sendAttackSuccess(this.rollData); } } + + setSuccess( flag) { + this.rollData.isSuccess = flag + } - async processResult( ) { - if (this._isSuccess) { - let attrDamage = this.attackDef.weapon.data.data.properties.damageAttribute; - let weaponFormula = BoLUtility.getDamageFormula(this.attackDef.weapon.data.data.properties.damage, - this.attackDef.weapon.data.data.properties.damageModifiers, - this.attackDef.weapon.data.data.properties.damageMultiplier) - let damageFormula = weaponFormula + "+" + this.attackDef.attacker.data.data.attributes[attrDamage].value; - console.log("Formula", damageFormula) - 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; + async processResult() { + if ( this.rollData.mode != "weapon") { // Only specific process in Weapon mode + return; + } - this._buildDamageChatMessage(this.attackDef.attacker, this.attackDef.weapon, this.damageRoll.total).then(msgFlavor => { - this.damageRoll.toMessage({ + if (this.rollData.isSuccess) { + let attrDamage = this.rollData.weapon.data.data.properties.damageAttribute; + let weaponFormula = BoLUtility.getDamageFormula(this.rollData.weapon.data.data.properties.damage, + this.rollData.weapon.data.data.properties.damageModifiers, + this.rollData.weapon.data.data.properties.damageMultiplier) + let damageFormula = weaponFormula + ((attrDamage) ? "+" + this.rollData.actor.data.data.attributes[attrDamage].value : "+0"); + + //console.log("Formula", weaponFormula, damageFormula, this.rollData.weapon.data.data.properties.damage) + this.rollData.damageRoll = new Roll(damageFormula); + await this.rollData.damageRoll.roll({ "async": false }); + await BoLUtility.showDiceSoNice(this.rollData.damageRoll); + // Update rollData object + this.rollData.damageFormula = damageFormula; + + this._buildDamageChatMessage( this.rollData ).then(msgFlavor => { + this.rollData.damageRoll.toMessage({ user: game.user.id, flavor: msgFlavor, - speaker: ChatMessage.getSpeaker({ actor: this.attackDef.attacker }), + speaker: ChatMessage.getSpeaker({ actor: this.rollData.actor }), flags: { msgType: "default" } - }).then( this.processDefense() ); + }).then(this.processDefense()); }); } } - _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, - isCritical: this._isCritical, - }; - return renderTemplate(rollMessageTpl, tplData); - } + _buildDamageChatMessage(rollData) { + const rollMessageTpl = 'systems/bol/templates/chat/rolls/damage-roll-card.hbs'; + return renderTemplate(rollMessageTpl, rollData); + } - _buildChatMessage(actor) { - const rollMessageTpl = 'systems/bol/templates/chat/rolls/default-roll-card.hbs'; - const tplData = { - actor: actor, - label: this._label, - reroll: actor.heroReroll(), - 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(rollData) { + const rollMessageTpl = 'systems/bol/templates/chat/rolls/default-roll-card.hbs'; + return renderTemplate(rollMessageTpl, rollData); + } } -// export class BoLWeaponRoll { -// constructor(actor, label, formula, isCritical, description){ -// this._label = label; -// this._formula = formula; -// this._isCritical = isCritical; -// this._description = description; -// } -// -// _buildChatMessage() { -// const rollMessageTpl = 'systems/bol/templates/chat/rolls/weapon-roll-card.hbs'; -// const tplData = { -// label : this._label, -// isCritical : this._isCritical, -// hasDescription : this._description && this._description.length > 0, -// description : this._description -// }; -// return renderTemplate(rollMessageTpl, tplData); -// } -// } - -// export class BoLSpellRoll { -// constructor(actor, label, formula, isCritical, description){ -// this._label = label; -// this._formula = formula; -// this._isCritical = isCritical; -// this._description = description; -// } -// -// _buildChatMessage() { -// const rollMessageTpl = 'systems/bol/templates/chat/rolls/spell-roll-card.hbs'; -// const tplData = { -// label : this._label, -// isCritical : this._isCritical, -// hasDescription : this._description && this._description.length > 0, -// description : this._description -// }; -// return renderTemplate(rollMessageTpl, tplData); -// } -// } diff --git a/module/system/bol-combat.js b/module/system/bol-combat.js index 2162ed5..9b9b6dc 100644 --- a/module/system/bol-combat.js +++ b/module/system/bol-combat.js @@ -1,5 +1,17 @@ +/* +Init order = + 10 - Legendary + 9 - Heroic + 8 - Success + 7 - Rivals/adversary + 6 - Coriaces/tough + 5 - Failure + 4 - Pietaille + 3 - Echec critique +*/ -export class RdDCombatManager extends Combat { + +export class BoLCombatManager extends Combat { /************************************************************************************/ async rollInitiative(ids, formula = undefined, messageOptions = {}) { @@ -7,15 +19,35 @@ export class RdDCombatManager extends Combat { // Structure input data ids = typeof ids === "string" ? [ids] : ids; const currentId = this.combatant._id; - + // calculate initiative - if ( game.combat.current.round == 1) { - for (let cId = 0; cId < ids.length; cId++) { - const combatant = this.combatants.get(ids[cId]); - // TODO - console.log("TODO : Compute init for actor"); + for (let cId = 0; cId < ids.length; cId++) { + const combatant = this.combatants.get(ids[cId]); + let fvttInit = 5 + if (combatant.actor.type == 'character') { + let initData = combatant.actor.getLastInitData(); + if (initData.isLegendary) { + fvttInit = 10 + } else if (initData.isCritical) { + fvttInit = 9 + } else if (initData.lastinit >= 9) { + fvttInit = 8 + } else if (initData.isFumble) { + fvttInit = 3 + } + } else { + fvttInit = 4 // Pietaille par defaut + if ( combatant.actor.getSubtype == 'adversary') { + fvttInit = 7 + } + if ( combatant.actor.getSubtype == 'tough') { + fvttInit = 6 + } } + fvttInit += (cId / 100) + await this.updateEmbeddedDocuments("Combatant", [{ _id: ids[cId], initiative: fvttInit }]); } + console.log("TODO : Compute init for actor"); } +} -} \ No newline at end of file diff --git a/module/system/bol-utility.js b/module/system/bol-utility.js index 6ff321a..3932411 100644 --- a/module/system/bol-utility.js +++ b/module/system/bol-utility.js @@ -1,11 +1,11 @@ +import { BoLDefaultRoll } from "../controllers/bol-rolls.js"; export class BoLUtility { /* -------------------------------------------- */ static async init() { - this.attackStore = {}; - Hooks.on('renderChatLog', (log, html, data) => BoLUtility.chatListeners(html)); + this.attackStore = {} } /* -------------------------------------------- */ @@ -25,6 +25,16 @@ export class BoLUtility { return it; } + /* -------------------------------------------- */ + static storeRoll(roll) { + this.lastRoll = roll + } + + /* -------------------------------------------- */ + static getLastRoll() { + return this.lastRoll + } + /* -------------------------------------------- */ static createDirectOptionList(min, max) { let options = {}; @@ -121,9 +131,13 @@ export class BoLUtility { } }); - html.on("click", '.hero-reroll', event => { + html.on("click", '.hero-reroll', event => { event.preventDefault(); - ui.notifications.warn("Not implemented up to now"); + + let rollData = BoLUtility.getLastRoll() + rollData.actor.subHeroPoints(1) + let r = new BoLDefaultRoll( rollData ) + r.roll(); } ); html.on("click", '.damage-handling', event => { diff --git a/module/system/helpers.js b/module/system/helpers.js index c7dadb5..5c3cb0c 100644 --- a/module/system/helpers.js +++ b/module/system/helpers.js @@ -112,6 +112,7 @@ export const registerHandlebarsHelpers = function () { return eval(expr); }); + } \ No newline at end of file diff --git a/module/system/templates.js b/module/system/templates.js index 42fe80e..afea3a2 100644 --- a/module/system/templates.js +++ b/module/system/templates.js @@ -30,9 +30,15 @@ export const preloadHandlebarsTemplates = async function () { "systems/bol/templates/item/parts/properties/feature/flaw-properties.hbs", "systems/bol/templates/item/parts/properties/feature/origin-properties.hbs", "systems/bol/templates/item/parts/properties/feature/race-properties.hbs", + // DIALOGS "systems/bol/templates/roll/parts/roll-dialog-modifiers.hbs", - "systems/bol/templates/roll/parts/roll-dialog-attribute.hbs" + "systems/bol/templates/roll/parts/roll-dialog-attribute.hbs", + "systems/bol/templates/dialogs/aptitude-roll-part.hbs", + "systems/bol/templates/dialogs/attribute-roll-part.hbs", + "systems/bol/templates/dialogs/mod-roll-part.hbs", + "systems/bol/templates/dialogs/adv-roll-part.hbs", + "systems/bol/templates/dialogs/career-roll-part.hbs", ]; // Load the template parts diff --git a/system.json b/system.json index ebedc65..c1b135e 100644 --- a/system.json +++ b/system.json @@ -7,8 +7,8 @@ "url": "https://github.com/ZigmundKreud/bol", "license": "LICENSE.txt", "flags": {}, - "version": "0.8.9.6", - "templateVersion": 14, + "version": "0.8.9.9", + "templateVersion": 16, "minimumCoreVersion": "0.8.6", "compatibleCoreVersion": "9", "scripts": [], diff --git a/template.json b/template.json index 16645eb..a26f869 100644 --- a/template.json +++ b/template.json @@ -11,6 +11,12 @@ "notes": "", "languages": [] }, + "combat": { + "lastinit": 0, + "iscritical": false, + "isfumble": false, + "islegendary": false + }, "prot": { "key": "prot", "label": "BOL.aptitudes.prot", diff --git a/template2.json b/template2.json deleted file mode 100644 index 699a1c7..0000000 --- a/template2.json +++ /dev/null @@ -1,193 +0,0 @@ -{ - "Actor": { - "types": [ - "character", - "encounter" - ], - "templates": { - "base": { - "details": { - "biography": "", - "notes": "", - "languages": [] - }, - "prot": { - "key": "prot", - "label": "BOL.aptitudes.prot", - "base": 0, - "value": 0, - "bonus": 0 - }, - "attributes": { - "vigor": { - "key": "vigor", - "label": "BOL.attributes.vigor", - "base": 0, - "value": 0, - "min": -1, - "max": 5, - "bonus": 0 - }, - "agility": { - "key": "agility", - "label": "BOL.attributes.agility", - "base": 0, - "value": 0, - "min": -1, - "max": 5, - "bonus": 0 - }, - "mind": { - "key": "mind", - "label": "BOL.attributes.mind", - "base": 0, - "value": 0, - "min": -1, - "max": 5, - "bonus": 0 - }, - "appeal": { - "key": "appeal", - "label": "BOL.attributes.appeal", - "base": 0, - "value": 0, - "bonus": 0 - } - }, - "aptitudes": { - "init": { - "key": "init", - "label": "BOL.aptitudes.init", - "base": 0, - "value": 0, - "bonus": 0 - }, - "melee": { - "key": "melee", - "label": "BOL.aptitudes.melee", - "base": 0, - "value": 0, - "bonus": 0 - }, - "ranged": { - "key": "ranged", - "label": "BOL.aptitudes.ranged", - "base": 0, - "value": 0, - "bonus": 0 - }, - "def": { - "key": "def", - "label": "BOL.aptitudes.def", - "base": 0, - "value": 0, - "bonus": 0 - } - }, - "resources": { - "hp": { - "key": "hp", - "label": "BOL.resources.hp", - "base": 0, - "value": 0, - "bonus": 0, - "max": 0 - }, - "hero": { - "key": "hero", - "label": "BOL.resources.hero", - "value": 5, - "max": 5 - }, - "faith": { - "key": "faith", - "label": "BOL.resources.faith", - "value": 0, - "max": 0 - }, - "power": { - "key": "power", - "label": "BOL.resources.power", - "value": 0, - "max": 0 - } - } - } - }, - "character": { - "templates": [ "base" ], - "type": "npc", - "villainy": false, - "xp": { - "key": "xp", - "label": "BOL.traits.xp", - "total": 0, - "spent": 0 - }, - "creation": { - "key": "creation", - "label": "BOL.resources.creation", - "value": 0, - "max": 0 - } - }, - "encounter": { - "templates": [ "base" ], - "type": "tough", - "size": "", - "environment": "" - } - }, - "Item": { - "types": [ - "item", - "feature" - ], - "templates": { - "base": { - "category": null, - "subtype": "default", - "description": "", - "properties": {} - }, - "equipment": { - "quantity": 1, - "weight": 0, - "price": 0, - "worn": false, - "properties": { - "ranged": false, - "melee": false, - "spell": false, - "protection": false, - "weapon": false, - "armor": false, - "helm": false, - "shield": false, - "equipable": false, - "consumable": false, - "magical": false, - "2H": false, - "reloadable": false, - "bow": false, - "crossbow": false, - "throwing": false - } - } - }, - "item": { - "templates": [ - "base", - "equipment" - ] - }, - "feature": { - "rank": 0, - "templates": [ - "base" - ], - "properties": {} - } - } -} - diff --git a/templates/actor/parts/tabs/actor-actions.hbs b/templates/actor/parts/tabs/actor-actions.hbs index e6c0974..f46a60b 100644 --- a/templates/actor/parts/tabs/actor-actions.hbs +++ b/templates/actor/parts/tabs/actor-actions.hbs @@ -11,9 +11,9 @@