refactor % roll into separate class;

skills and stats function, other rolls need work
This commit is contained in:
jalensailin
2023-09-18 18:04:10 -04:00
parent 350c212cfa
commit 835866233b
3 changed files with 108 additions and 91 deletions
+6 -3
View File
@@ -1,6 +1,7 @@
/* globals $ game Roll ChatMessage AudioHelper ActorSheet mergeObject Dialog TextEditor ActiveEffect ui duplicate fromUuidSync */
import {
DGPercentileRoll,
sendPercentileTestToChat,
sendLethalityTestToChat,
sendDamageRollToChat,
@@ -611,7 +612,8 @@ export class DeltaGreenActorSheet extends ActorSheet {
case "sanity": {
// const confirmRoll = showModifyPercentileTestDialogue(this.actor);
// if (!confirmRoll) return;
sendPercentileTestToChat(dataset.rolltype, dataset.key, this.actor);
const roll = new DGPercentileRoll(dataset.rolltype, dataset.key, this.actor)
sendPercentileTestToChat(roll);
break;
}
@@ -620,13 +622,14 @@ export class DeltaGreenActorSheet extends ActorSheet {
return ui.notifications.error("No item id provided.")
}
const item = this.actor.items.get(dataset.iid);
sendPercentileTestToChat(dataset.rolltype, dataset.key, this.actor, item);
const roll = new DGPercentileRoll(dataset.rolltype, dataset.key, this.actor, item)
sendPercentileTestToChat(roll);
break;
}
case "damage": {
let diceFormula = dataset.roll;
let skillType = dataset.skill ? dataset.skill : '';
let skillType = dataset.key;
if(this.actor.type === 'agent' && (skillType === 'unarmed_combat' || skillType === 'melee_weapons')){
diceFormula += this.actor.system.statistics.str.meleeDamageBonusFormula;
}
+4 -1
View File
@@ -3,7 +3,7 @@ import { DeltaGreenActor } from "./actor/actor.js";
import { DeltaGreenActorSheet } from "./actor/actor-sheet.js";
import { DeltaGreenItem } from "./item/item.js";
import { DeltaGreenItemSheet } from "./item/item-sheet.js";
import { sendPercentileTestToChat, sendLethalityTestToChat, sendDamageRollToChat } from "./roll/roll.js";
import { sendPercentileTestToChat, sendLethalityTestToChat, sendDamageRollToChat, DGPercentileRoll } from "./roll/roll.js";
import { registerSystemSettings } from "./settings.js"
import { preloadHandlebarsTemplates } from "./templates.js";
import { ParseDeltaGreenStatBlock } from "./other/stat-parser-macro.js";
@@ -29,6 +29,9 @@ Hooks.once('init', async function() {
decimals: 0
};
// Register custom dice rolls
CONFIG.Dice.rolls.push(DGPercentileRoll);
// Register System Settings
registerSystemSettings();
+98 -87
View File
@@ -2,119 +2,130 @@
import {localizeWithFallback} from "../other/utility-functions.js"
export class DGRoll extends Roll {
constructor(formula, data, rollType, options) {
super(formula, data, options);
export class DGPercentileRoll extends Roll {
constructor(rollType, key, actor, item, options) {
super("1D100", {}, options);
this.type = rollType;
this.key = key;
this.actor = actor;
this.item = item;
switch (rollType) {
case "stat":
this.rollBasis = actor.system.statistics[key]
this.target = this.rollBasis.x5;
this.localizedKey = key.toUpperCase();
break;
case "skill":
this.rollBasis = actor.system.skills[key];
this.target = this.rollBasis.proficiency;
this.localizedKey = game.i18n.localize(`DG.Skills.${key}`);
break;
default:
break;
}
}
/**
* "Inhuman" stat being rolled, logic is different per page 188 of the Handler's Guide.
* Note - originally implemented by Uriele, but my attempt at merging conficts went poorly, so re-implementing.
* For an inhuman check, the roll succeeds except on a roll of 100 which fails AND fumbles.
* If the roll is a matching digit roll, it is a critical as normal.
* Also, if the roll is below the regular (non-x5) value of the stat, it is a critical. E.g. a CON of 25, a d100 roll of 21 would be a critical.
*
*/
get isInhuman() {
if (this.target > 99 && this.type === "stat") {
return true;
}
return false;
}
/**
* Determines if a roll result is critical.
* If roll has not been evaluated, return null.
*
* @returns {null|Boolean}
*/
get isCritical() {
// If roll isn't evaluated, return null.
if (!this.total) {
return null;
}
let isCritical = false
// 1, 100, or any matching dice are a crit, i.e. 11, 22, 33...99.
if (this.total === 1 || this.total === 100 || this.total % 11 === 0) {
// really good, or reeaaaally bad
isCritical = true;
}
// If inhuman and the roll is below the regular (non-x5) value of the stat, it is a critical.
// E.g. a CON of 25, a d100 roll of 21 would be a critical.
if (this.isInhuman && this.total <= (this.target / 5)) {
isCritical = true;
}
return isCritical;
}
/**
* Determines if a roll succeeded.
* If roll has not been evaluated, return null.
*
* @returns {null|Boolean}
*/
get isSuccess() {
// If roll isn't evaluated, return null.
if (!this.total) {
return null;
}
// A roll of 100 always (critically) fails, even for inhuman rolls.
if (this.total === 100) return false;
return this.total <= this.target;
}
}
export async function sendPercentileTestToChat(rollType, rollKey, actor, item){
let roll = new Roll('1D100', actor.system)
export async function sendPercentileTestToChat(roll){
await roll.evaluate({async: true});
const msg = await roll.toMessage({}, {create: false});
let total = roll.total;
let isCritical = false;
let isSuccess = false;
let html = '';
let label = '';
let resultString = '';
let styleOverride = '';
let target;
let rollBasis;
let localizedKey;
switch (rollType) {
case "stat":
rollBasis = actor.system.statistics[rollKey]
target = rollBasis.x5;
localizedKey = rollKey.toUpperCase();
break;
case "skill":
rollBasis = actor.system.skills[rollKey];
target = rollBasis.proficiency;
localizedKey = game.i18n.localize(`DG.Skills.${rollKey}`);
break;
default:
break;
}
let rollMode = game.settings.get("core", "rollMode");
// if using private san rolls, must hide any SAN roll unless user is a GM
let setting = false;
setting = game.settings.get("deltagreen", "keepSanityPrivate");
if(setting && (rollKey === 'sanity' || rollKey === 'ritual') && !game.user.isGM){
const privateSanSetting = game.settings.get("deltagreen", "keepSanityPrivate");
if (privateSanSetting && (roll.key === 'sanity' || roll.key === 'ritual') && !game.user.isGM){
rollMode = 'blindroll';
}
// "Inhuman" stat being rolled, logic is different per page 188 of the Handler's Guide.
// Note - originally implemented by Uriele, but my attempt at merging conficts went poorly, so re-implementing.
// For an inhuman check, the roll succeeds except on a roll of 100 which fails AND fumbles.
// If the roll is a matching digit roll, it is a critical as normal.
// Also, if the roll is below the regular (non-x5) value of the stat, it is a critical. E.g. a CON of 25, a d100 roll of 21 would be a critical.
if(target > 99 && rollType === "stat"){
label = `${game.i18n.localize("DG.Roll.Rolling")} <b>${localizedKey} [${game.i18n.localize("DG.Roll.Inhuman").toUpperCase()}]</b> ${game.i18n.localize("DG.Roll.Target")} ${Math.floor(target / 5)}`;
if(total === 100){
// only possible fail criteria, and also a fumble.
isSuccess = false;
isCritical = true;
}
else{
isSuccess = true;
if(total <= (target / 5.0)){
isCritical = true;
}
else if(skillCheckResultIsCritical(total)){
isCritical = true;
}
else{
isCritical = false;
}
}
}
else{
label = `${game.i18n.localize("DG.Roll.Rolling")} <b>${localizedKey}</b> ${game.i18n.localize("DG.Roll.Target")} ${target}`;
isCritical = skillCheckResultIsCritical(total);
if(total <= target){
isSuccess = true;
}
let label = '';
// "Inhuman" stat being rolled. See function for details.
if (roll.isInhuman) {
label = `${game.i18n.localize("DG.Roll.Rolling")} <b>${roll.localizedKey} [${game.i18n.localize("DG.Roll.Inhuman").toUpperCase()}]</b> ${game.i18n.localize("DG.Roll.Target")} ${Math.floor(roll.target / 5)}`;
} else {
label = `${game.i18n.localize("DG.Roll.Rolling")} <b>${roll.localizedKey}</b> ${game.i18n.localize("DG.Roll.Target")} ${roll.target}`;
}
if(isCritical){
let resultString = '', styleOverride = '';
if (roll.isCritical) {
resultString = `${game.i18n.localize("DG.Roll.Critical")} `;
}
if(isSuccess){
if (roll.isSuccess) {
resultString += `${game.i18n.localize("DG.Roll.Success")}`;
if(isCritical){
if (roll.isCritical){
resultString = resultString.toUpperCase() + '!';
styleOverride="color: green";
}
}
else{
} else {
resultString += `${game.i18n.localize("DG.Roll.Failure")}`;
if(isCritical){
if(roll.isCritical){
resultString = resultString.toUpperCase() + '!';
styleOverride="color: red";
}
}
let html = '';
html += `<div class="dice-roll">`
html += ` <div class="dice-result">`
html += ` <div style="${styleOverride}" class="dice-formula">${resultString}</div>`
@@ -135,7 +146,7 @@ export async function sendPercentileTestToChat(rollType, rollKey, actor, item){
html += `</div>`
let chatData = {
speaker: ChatMessage.getSpeaker({actor: actor}),
speaker: ChatMessage.getSpeaker({actor: roll.actor}),
content: html,
flavor: label,
type: 5, //CHAT_MESSAGE_TYPES.ROLL,