From 7be97146c2adb10326e955b30d6868cefc1c680e Mon Sep 17 00:00:00 2001 From: U~man Date: Fri, 3 Jul 2020 23:05:49 +0200 Subject: [PATCH] ENH: Rolls! --- src/lang/en.json | 2 + src/module/actor/entity.js | 31 ++- src/module/dice.js | 142 +++++++++--- src/scss/actor-base.scss | 2 +- src/scss/apps.scss | 205 ++++++++++-------- src/scss/core.scss | 2 +- src/template.json | 1 + .../partials/character-attributes-tab.html | 37 +++- src/templates/chat/roll-attack.html | 7 + 9 files changed, 304 insertions(+), 125 deletions(-) create mode 100644 src/templates/chat/roll-attack.html diff --git a/src/lang/en.json b/src/lang/en.json index 5d63ab1..556e93c 100644 --- a/src/lang/en.json +++ b/src/lang/en.json @@ -71,6 +71,8 @@ "OSE.SpellDC": "Spell DC", "OSE.SpellDCShort": "DC", "OSE.Thac0": "THAC0", + "OSE.ABShort": "AB", + "OSE.AB": "Attack Bonus", "OSE.MeleeShort": "MEL", "OSE.Melee": "Melee", "OSE.MeleeBonus": "Melee Bonus", diff --git a/src/module/actor/entity.js b/src/module/actor/entity.js index de6c976..2874697 100644 --- a/src/module/actor/entity.js +++ b/src/module/actor/entity.js @@ -16,11 +16,18 @@ export class OseActor extends Actor { const label = game.i18n.localize(`OSE.saves.${save}.long`); const rollParts = ['1d20']; + const data = {...this.data, ...{ + rollData : { + type: 'Save', + stat: save + } + }}; + // Roll and return return OseDice.Roll({ event: options.event, parts: rollParts, - data: this.data, + data: data, speaker: ChatMessage.getSpeaker({ actor: this }), flavor: `${label} ${game.i18n.localize('OSE.SavingThrow')}`, title: `${label} ${game.i18n.localize('OSE.SavingThrow')}`, @@ -31,11 +38,18 @@ export class OseActor extends Actor { const label = game.i18n.localize(`OSE.scores.${score}.long`); const rollParts = ['1d20']; + const data = {...this.data, ...{ + rollData : { + type: 'Check', + stat: score + } + }}; + // Roll and return return OseDice.Roll({ event: options.event, parts: rollParts, - data: this.data, + data: data, speaker: ChatMessage.getSpeaker({ actor: this }), flavor: `${label} ${game.i18n.localize('OSE.AbilityCheck')}`, title: `${label} ${game.i18n.localize('OSE.AbilityCheck')}`, @@ -62,12 +76,23 @@ export class OseActor extends Actor { this.data.data.thac0.mod.melee.toString() ); } + if (game.settings.get('ose', 'ascendingAC')) { + rollParts.push('+', this.data.data.thac0.bba.toString()); + } + + const data = {...this.data, ...{ + rollData : { + type: 'Attack', + stat: attack, + mods: mods + } + }}; // Roll and return return OseDice.Roll({ event: options.event, parts: rollParts, - data: this.data, + data: data, speaker: ChatMessage.getSpeaker({ actor: this }), flavor: `${label} ${game.i18n.localize('OSE.Attack')}`, title: `${label} ${game.i18n.localize('OSE.Attack')}`, diff --git a/src/module/dice.js b/src/module/dice.js index 0a33078..9e37804 100644 --- a/src/module/dice.js +++ b/src/module/dice.js @@ -1,4 +1,111 @@ export class OseDice { + static digestResult(data, roll) { + let details = ""; + + // ATTACKS + let die = roll.parts[0].total; + if (data.rollData.type == "Attack") { + if (game.settings.get("ose", "ascendingAC")) { + let bba = data.data.thac0.bba; + bba += + data.rollData.stat == "Melee" + ? data.data.thac0.mod.melee + data.rollData.mods.str + : data.data.thac0.mod.missile + data.rollData.mods.dex; + details = `
Failure (${bba})
`; + if (die == 1) { + return details; + } + details = `
Hits AC ${roll.total} (${bba})
`; + } else { + // B/X Historic THAC0 Calculation + let thac = data.data.thac0.value; + thac -= + data.rollData.stat == "Melee" + ? data.data.thac0.mod.melee + data.rollData.mods.str + : data.data.thac0.mod.missile + data.rollData.mods.dex; + + details = `
Failure (${thac})
`; + if (thac - roll.total > 9) { + return details; + } + details = `
Hits AC ${Math.clamped(thac - roll.total,-3,9)} (${thac})
`; + } + } else if (data.rollData.type == "Save") { + // SAVING THROWS + let sv = data.data.saves[data.rollData.stat].value; + if (roll.total >= sv) { + details = `
Success! (${sv})
`; + } else { + details = `
Failure (${sv})
`; + } + } else if (data.rollData.type == "Check") { + // SCORE CHECKS + let sc = data.data.scores[data.rollData.stat].value; + if (die == 1 || (roll.total <= sc && die < 20)) { + details = `
Success! (${sc})
`; + } else { + details = `
Failure (${sc})
`; + } + } + return details; + } + + static async sendRoll( + parts = [], + data = {}, + title = null, + flavor = null, + speaker = null, + form = null + ) { + const template = "systems/ose/templates/chat/roll-attack.html"; + + let chatData = { + user: game.user._id, + speaker: speaker, + }; + + let templateData = { + title: title, + flavor: flavor, + data: data, + }; + + // Optionally include a situational bonus + if (form !== null) data["bonus"] = form.bonus.value; + if (data["bonus"]) parts.push(data["bonus"]); + + const roll = new Roll(parts.join(""), data).roll(); + + // Convert the roll to a chat message and return the roll + let rollMode = game.settings.get("core", "rollMode"); + rollMode = form ? form.rollMode.value : rollMode; + + templateData.details = OseDice.digestResult(data, roll); + roll.render().then((r) => { + templateData.rollOSE = r; + renderTemplate(template, templateData).then((content) => { + chatData.content = content; + chatData.sound = CONFIG.sounds.dice; + if (game.dice3d) { + game.dice3d + .showForRoll( + roll, + game.user, + true, + chatData.whisper, + chatData.blind + ) + .then((displayed) => ChatMessage.create(chatData)); + } else { + ChatMessage.create(chatData); + } + }); + }); + + return roll; + } + // eslint-disable-next-line no-unused-vars static async Roll({ parts = [], @@ -12,32 +119,10 @@ export class OseDice { } = {}) { let rollMode = game.settings.get("core", "rollMode"); let rolled = false; - let filtered = parts.filter(function (el) { - return el != "" && el; - }); - - const _roll = (form = null, raise = false) => { - // Optionally include a situational bonus - if (form !== null) data["bonus"] = form.bonus.value; - if (data["bonus"]) filtered.push(data["bonus"]); - - const roll = new Roll(filtered.join(""), data).roll(); - // Convert the roll to a chat message and return the roll - rollMode = form ? form.rollMode.value : rollMode; - roll.toMessage( - { - speaker: speaker, - flavor: flavor, - }, - { rollMode } - ); - rolled = true; - return roll; - }; const template = "systems/ose/templates/chat/roll-dialog.html"; let dialogData = { - formula: filtered.join(" "), + formula: parts.join(" "), data: data, rollMode: rollMode, rollModes: CONFIG.Dice.rollModes, @@ -48,7 +133,14 @@ export class OseDice { label: game.i18n.localize("OSE.Roll"), icon: '', callback: (html) => { - roll = _roll(html[0].children[0]); + roll = OseDice.sendRoll( + parts, + data, + title, + flavor, + speaker, + html[0].children[0] + ); }, }, cancel: { @@ -70,7 +162,7 @@ export class OseDice { buttons: buttons, default: "ok", close: () => { - resolve(rolled ? roll : false) + resolve(rolled ? roll : false); }, }).render(true); }); diff --git a/src/scss/actor-base.scss b/src/scss/actor-base.scss index 445b6d0..dd546f4 100644 --- a/src/scss/actor-base.scss +++ b/src/scss/actor-base.scss @@ -188,7 +188,7 @@ text-indent: 8px; } font-weight: 300; - font-size: 12px; + font-size: 13px; background: $darkBackground; color: white; input { diff --git a/src/scss/apps.scss b/src/scss/apps.scss index fcd39d7..0222691 100644 --- a/src/scss/apps.scss +++ b/src/scss/apps.scss @@ -1,97 +1,124 @@ - -.ose.chat-card { - font-style: normal; - font-size: 12px; - - .card-header { - padding: 3px 0; - border-top: 2px groove #FFF; - border-bottom: 2px groove #FFF; - - img { - flex: 0 0 36px; - margin-right: 5px; +.ose.chat-block { + margin: 0; + .chat-title { + background: $darkBackground; + border: 1px solid black; + border-radius: 3px; + color: white; + padding: 2px; + box-shadow: 0 0 2px #FFF inset; + text-align: center; + margin: 4px 0; + font-size: 16px; + } + .chat-details { + padding: 4px; + font-size: 13px; + .roll-result { + text-align: center; + &.roll-success { + color: #18520b; } - - h3 { - flex: 1; - margin: 0; - line-height: 36px; - color: $colorOlive; - &:hover { - color: #111; - text-shadow: 0 0 10px red; - } - } - } - - .card-content { - margin: 5px 0; - - h3 { - font-size: 12px; - margin: 0; - font-weight: bold; - } - - > * { - -webkit-user-select: text; - -moz-user-select: text; - -ms-user-select: text; - user-select: text; - } - } - - .card-buttons { - margin: 5px 0; - - span { - display: block; - line-height: 28px; - text-align: center; - border: 1px solid $colorTan; - } - - button { - font-size: 12px; - height: 24px; - line-height: 20px; - margin: 2px 0; - } - } - - .card-footer { - padding: 3px 0 0; - border-top: 2px groove #FFF; - - span { - border-right: 2px groove #FFF; - padding: 0 5px 0 0; - font-size: 10px; - - &:last-child { - border-right: none; - padding-right: 0; - } + &.roll-fail { + color: #aa0200; } } } - - .dice-roll .dice-total { - &.success { - color: inherit; - background: #c7d0c0; - border: 1px solid #006c00; +} + +.ose.chat-card { + font-style: normal; + font-size: 12px; + + .card-header { + padding: 3px 0; + border-top: 2px groove #fff; + border-bottom: 2px groove #fff; + + img { + flex: 0 0 36px; + margin-right: 5px; } - &.failure { - color: inherit; - background: #ffdddd; - border: 1px solid #6e0000; + + h3 { + flex: 1; + margin: 0; + line-height: 36px; + color: $colorOlive; + &:hover { + color: #111; + text-shadow: 0 0 10px red; + } } - &.critical { - color: green; + } + + .card-content { + margin: 5px 0; + + h3 { + font-size: 12px; + margin: 0; + font-weight: bold; } - &.fumble { - color: red; + + > * { + -webkit-user-select: text; + -moz-user-select: text; + -ms-user-select: text; + user-select: text; } - } \ No newline at end of file + } + + .card-buttons { + margin: 5px 0; + + span { + display: block; + line-height: 28px; + text-align: center; + border: 1px solid $colorTan; + } + + button { + font-size: 12px; + height: 24px; + line-height: 20px; + margin: 2px 0; + } + } + + .card-footer { + padding: 3px 0 0; + border-top: 2px groove #fff; + + span { + border-right: 2px groove #fff; + padding: 0 5px 0 0; + font-size: 10px; + + &:last-child { + border-right: none; + padding-right: 0; + } + } + } +} + +.dice-roll .dice-total { + &.success { + color: inherit; + background: #c7d0c0; + border: 1px solid #006c00; + } + &.failure { + color: inherit; + background: #ffdddd; + border: 1px solid #6e0000; + } + &.critical { + color: green; + } + &.fumble { + color: red; + } +} diff --git a/src/scss/core.scss b/src/scss/core.scss index d90a3f0..c146942 100644 --- a/src/scss/core.scss +++ b/src/scss/core.scss @@ -37,4 +37,4 @@ .resizable { overflow: auto; } -} +} \ No newline at end of file diff --git a/src/template.json b/src/template.json index c4688e6..0841ef6 100644 --- a/src/template.json +++ b/src/template.json @@ -24,6 +24,7 @@ }, "thac0": { "value": 19, + "bba": 0, "mod": { "missile": 0, "melee": 0 diff --git a/src/templates/actors/partials/character-attributes-tab.html b/src/templates/actors/partials/character-attributes-tab.html index 2dbaaec..6b8f2e4 100644 --- a/src/templates/actors/partials/character-attributes-tab.html +++ b/src/templates/actors/partials/character-attributes-tab.html @@ -114,15 +114,32 @@