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 @@
-
-
+
+ {{#if config.ascendingAC}}
+ {{add data.thac0.mod.melee (add mods.str data.thac0.bba)}}
+ {{else}}
{{subtract data.thac0.mod.melee (subtract mods.str data.thac0.value)}}
+ {{/if}}
- -
-
-
+
{{ localize "OSE.ABShort"}}
+
+
+
+ {{else}}
+ -
+
{{ localize "OSE.Thac0"}}
+ {{/if}}
-
-
+
+ {{#if config.ascendingAC}}
+ {{add data.thac0.mod.missile (add mods.dex data.thac0.bba)}}
+ {{else}}
{{subtract data.thac0.mod.missile (subtract mods.dex data.thac0.value)}}
+ {{/if}}
@@ -144,7 +167,8 @@
-
-
{{localize 'OSE.MovementEncounterShort'}}
+
+ {{localize 'OSE.MovementEncounterShort'}}
{{divide data.movement.base 3}}
@@ -160,7 +184,8 @@
-
-
{{localize 'OSE.MovementOverlandShort'}}
+
+ {{localize 'OSE.MovementOverlandShort'}}
{{divide data.movement.base 5}}
diff --git a/src/templates/chat/roll-attack.html b/src/templates/chat/roll-attack.html
new file mode 100644
index 0000000..81cca7a
--- /dev/null
+++ b/src/templates/chat/roll-attack.html
@@ -0,0 +1,7 @@
+
+
+
{{title}}
+ {{#if details}}
{{{details}}}
{{/if}}
+ {{#if rollOSE}}
{{{rollOSE}}}
{{/if}}
+
+
\ No newline at end of file