From 0ecf80932b3e7979acb09475cb206e745ad4b242 Mon Sep 17 00:00:00 2001
From: marvin9257 <72580196+marvin9257@users.noreply.github.com>
Date: Tue, 5 Dec 2023 15:58:21 -0600
Subject: [PATCH 1/6] feat: preliminary roll table display in Journals
---
src/module/hooks/tableRolls.ts | 10 ++
src/module/utils/enrichers.ts | 163 +++++++++++++++++++++++++++++++++
src/twodsix.ts | 5 +
static/styles/twodsix.css | 6 ++
4 files changed, 184 insertions(+)
create mode 100644 src/module/hooks/tableRolls.ts
create mode 100644 src/module/utils/enrichers.ts
diff --git a/src/module/hooks/tableRolls.ts b/src/module/hooks/tableRolls.ts
new file mode 100644
index 000000000..a545cc013
--- /dev/null
+++ b/src/module/hooks/tableRolls.ts
@@ -0,0 +1,10 @@
+// eslint-disable-next-line @typescript-eslint/ban-ts-comment
+// @ts-nocheck This turns off *all* typechecking, make sure to remove this once foundry-vtt-types are updated to cover v10.
+
+import { handleTableRoll } from "../utils/enrichers";
+
+for (const sheet of ["JournalPageSheet"]) {
+ Hooks.on(`render${sheet}`, (_app, html, _options) => {
+ html.on('click contextmenu', '.table-roll', handleTableRoll.bind());
+ });
+}
diff --git a/src/module/utils/enrichers.ts b/src/module/utils/enrichers.ts
new file mode 100644
index 000000000..8983d4135
--- /dev/null
+++ b/src/module/utils/enrichers.ts
@@ -0,0 +1,163 @@
+// eslint-disable-next-line @typescript-eslint/ban-ts-comment
+// @ts-nocheck This turns off *all* typechecking, make sure to remove this once foundry-vtt-types are updated to cover v10.
+
+//Adapted from https://github.com/pafvel/dragonbane/blob/master/modules/journal.js
+
+export function addCustomEnrichers() {
+ CONFIG.TextEditor.enrichers.push(
+ {
+ pattern: /@DisplayTable\[(.+?)\](?:{(.+?)})?/gm,
+ enricher: enrichDisplayTable
+ },
+ {
+ pattern: /@Table\[(.+?)\](?:{(.+?)})?/gm,
+ enricher: rollTable
+ }
+ );
+}
+
+async function enrichDisplayTable (match, options) {
+ const table = findTable(match[1], options);
+ const tableName = match[2] ?? table?.name;
+ const a = document.createElement("div");
+ if (table) {
+ a.classList.add("display-table");
+ const html = displayTable(match[1], table, tableName);
+ a.innerHTML = await TextEditor.enrichHTML(html, {async: true});
+ } else {
+ a.dataset.tableId = match[1];
+ if (match[2]) {
+ a.dataset.tableName = match[2];
+ }
+ a.classList.add("content-link");
+ a.classList.add("broken");
+ a.innerHTML = ` ${tableName}`;
+ }
+ return a;
+}
+
+async function rollTable (match, options) {
+ const table = findTable(match[1], options);
+ const tableName = match[2] ?? table?.name;
+ const a = document.createElement("a");
+ if (table) {
+ a.classList.add("inline-roll");
+ a.classList.add("table-roll");
+ a.dataset.tableId = table.uuid;
+ a.dataset.tableName = table.name;
+ a.innerHTML = ` ${tableName}`;
+ } else {
+ a.dataset.tableId = match[1];
+ if (match[2]) {
+ a.dataset.tableName = match[2];
+ }
+ a.classList.add("content-link");
+ a.classList.add("broken");
+ a.innerHTML = ` ${tableName}`;
+ }
+ return a;
+}
+
+function displayTable(uuid, table, tableName) {
+ if (!table) {
+ return "";
+ }
+
+ /*
+ // Rollable table in caption
+ let html = `
+
+ @Table[${uuid}]{${tableName}}
+
+ [[/roll ${table.formula}]] |
+ ${game.i18n.localize("DoD.journal.tableResult")} |
+
`;
+ */
+
+ // Rollable table in roll column header
+ let html = `
+
+ ${tableName}
+
+ @Table[${uuid}]{${table.formula}} |
+ ${game.i18n.localize("Table Result")} |
+
`;
+
+ for (const result of table.results) {
+ html += `
+
+ ${result.range[0]}`;
+ if (result.range[1] != result.range[0]) {
+ html += ` - ${result.range[1]}`;
+ }
+ if (result.documentCollection == "RollTable") {
+ const subTable = findTable(result.text);
+ if (subTable?.uuid != table.uuid) {
+ let subTableName = result.text;
+ if(subTableName.startsWith(table.name)) {
+ subTableName = subTableName.slice(table.name.length);
+ if (subTableName.startsWith(" - ")) {
+ subTableName = subTableName.slice(3);
+ }
+ }
+ html += ` |
+ ${subTable?.description} @DisplayTable[RollTable.${result.documentId}]{${subTableName}} |
+
`;
+ } else {
+ html += `
+ ${result.text} |
+ `;
+ }
+ } else if (result.documentCollection == "Item") {
+ html += `
+ @UUID[Item.${result.documentId}]{${result.text}} |
+ `;
+ } else {
+ html += `
+ ${result.text} |
+ `;
+ }
+ }
+ html += `
`;
+ return html;
+}
+
+function findTable(tableName:string, options?:any) {
+ const table = game.tables.find(i => i.name.toLowerCase() == tableName.toLowerCase()) || fromUuidSync(tableName);
+ if (!table) {
+ if (!options?.noWarnings){
+ sendWarning("WARNING.tableNotFound", {id: tableName});
+ }
+ return null;
+ }
+ if (!(table instanceof RollTable)) {
+ if (!options?.noWarning){
+ sendWarning("WARNING.typeMismatch", {id: tableName});
+ }
+ return null;
+ }
+ return table;
+}
+
+function sendWarning(msg, params) {
+ if (!params) {
+ return ui.notifications.warn(game.i18n.localize(msg));
+ } else {
+ return ui.notifications.warn(game.i18n.format(game.i18n.localize(msg), params));
+ }
+}
+
+export async function handleTableRoll(event) {
+ const tableId = event.currentTarget.dataset.tableId;
+ const tableName = event.currentTarget.dataset.tableName;
+ const table = fromUuidSync(tableId) || this.findTable(tableName);
+ if (table) {
+ if (event.type == "click") { // left click
+ table.draw();
+ } else { // right click
+ table.sheet.render(true);
+ }
+ }
+ event.preventDefault();
+ event.stopPropagation();
+}
diff --git a/src/twodsix.ts b/src/twodsix.ts
index 09702408e..894a4b0f1 100644
--- a/src/twodsix.ts
+++ b/src/twodsix.ts
@@ -28,6 +28,7 @@ import { TwodsixRobotSheet } from "./module/sheets/TwodsixRobotSheet";
import { TwodsixSpaceObjectSheet } from "./module/sheets/TwodsixSpaceObjectSheet";
import { TwodsixDiceRoll } from "./module/utils/TwodsixDiceRoll";
import { TwodsixRollSettings } from "./module/utils/TwodsixRollSettings";
+import { addCustomEnrichers } from "./module/utils/enrichers";
// @ts-ignore
hookScriptFiles.forEach((hookFile:string) => import(`./module/hooks/${hookFile}.ts`));
@@ -112,9 +113,13 @@ Hooks.once('init', async function () {
registerHandlebarsHelpers();
registerSettings();
+
//Dice Rolls
CONFIG.Dice.rolls.push(TwodsixDiceRoll);
+ //Add custom Enrichers
+ addCustomEnrichers();
+
/* add fonts */
// @ts-ignore
CONFIG.fontDefinitions["Asap"] = {
diff --git a/static/styles/twodsix.css b/static/styles/twodsix.css
index c17c09f88..6777a47c8 100644
--- a/static/styles/twodsix.css
+++ b/static/styles/twodsix.css
@@ -3071,6 +3071,12 @@ select.form-input, input.form-input, span.form-input {
color: var(--s2d6-stat-input);
}
+.table-caption {
+ color: var(--s2d6-stat-input);
+ font-size: 1.5em;
+ font-style: italic;
+}
+
.chat-message .table-draw .table-results .table-result .result-text {
color: var(--s2d6-dialog-color);
}
From 3fb2f0e06ca86b9f0c8402eb8bbbd5caf047db5b Mon Sep 17 00:00:00 2001
From: marvin9257 <72580196+marvin9257@users.noreply.github.com>
Date: Wed, 6 Dec 2023 14:15:37 -0600
Subject: [PATCH 2/6] feat: improvements
add SkillRoll enrichment
add JSDoc
add localizations
---
src/module/hooks/tableRolls.ts | 5 +-
src/module/utils/enrichers.ts | 122 ++++++++++++++++++++++++++------
static/lang/en.json | 7 +-
static/styles/twodsix_basic.css | 6 ++
4 files changed, 115 insertions(+), 25 deletions(-)
diff --git a/src/module/hooks/tableRolls.ts b/src/module/hooks/tableRolls.ts
index a545cc013..30fc7d003 100644
--- a/src/module/hooks/tableRolls.ts
+++ b/src/module/hooks/tableRolls.ts
@@ -1,10 +1,11 @@
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-nocheck This turns off *all* typechecking, make sure to remove this once foundry-vtt-types are updated to cover v10.
-import { handleTableRoll } from "../utils/enrichers";
-
+import { handleTableRoll, handleSkillRoll } from "../utils/enrichers";
+// Add hooks when clicking on rollable table link
for (const sheet of ["JournalPageSheet"]) {
Hooks.on(`render${sheet}`, (_app, html, _options) => {
html.on('click contextmenu', '.table-roll', handleTableRoll.bind());
+ html.on('click contextmenu', '.skill-roll', handleSkillRoll.bind());
});
}
diff --git a/src/module/utils/enrichers.ts b/src/module/utils/enrichers.ts
index 8983d4135..e66b1aa00 100644
--- a/src/module/utils/enrichers.ts
+++ b/src/module/utils/enrichers.ts
@@ -1,8 +1,12 @@
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-nocheck This turns off *all* typechecking, make sure to remove this once foundry-vtt-types are updated to cover v10.
-//Adapted from https://github.com/pafvel/dragonbane/blob/master/modules/journal.js
+import { getControlledTraveller } from "../sheets/TwodsixVehicleSheet";
+import TwodsixItem from "../entities/TwodsixItem";
+// Adapted from https://github.com/pafvel/dragonbane/blob/master/modules/journal.js
+
+// Add custom enrichers during init phase
export function addCustomEnrichers() {
CONFIG.TextEditor.enrichers.push(
{
@@ -12,11 +16,21 @@ export function addCustomEnrichers() {
{
pattern: /@Table\[(.+?)\](?:{(.+?)})?/gm,
enricher: rollTable
+ },
+ {
+ pattern: /@SkillRoll(?:{(.+?)})?/gm,
+ enricher: rollSkill
}
);
}
-async function enrichDisplayTable (match, options) {
+/**
+ * Convert a rollTable link in a journal entry with a nice format of the table based on roll table name or uuid.
+ * @param {any} match An array matching the RegEx expression. Match[0] is the unernriched JE string. Match[1] is the table name or UUID. Match[2] is the user entered table label.
+ * @param {any} options Options to the roll action
+ * @returns {Promise} The displayed html element for the enriched RollTable reference
+ */
+async function enrichDisplayTable (match: any, options: any): Promise {
const table = findTable(match[1], options);
const tableName = match[2] ?? table?.name;
const a = document.createElement("div");
@@ -36,7 +50,13 @@ async function enrichDisplayTable (match, options) {
return a;
}
-async function rollTable (match, options) {
+/**
+ * A rollable link in a journal entry to a RollTable.
+ * @param {string} match An array matching the RegEx expression. Match[0] is the unernriched JE string. Match[1] is the table name or UUID. Match[2] is the user entered table label.
+ * @param {string} options Options to the roll action
+ * @returns {HTMLAnchorElement} The rolltable in an html format
+ */
+async function rollTable (match: any, options: any): Promise {
const table = findTable(match[1], options);
const tableName = match[2] ?? table?.name;
const a = document.createElement("a");
@@ -58,29 +78,40 @@ async function rollTable (match, options) {
return a;
}
-function displayTable(uuid, table, tableName) {
+/**
+ * A rollable link in a skill.
+ * @param {string} match An array matching the RegEx expression. Match[0] is the unenriched JE string. Match[1] is the skill name. Match[2] is the user entered skill label.
+ * @param {string} options Options to the roll action
+ * @returns {HTMLAnchorElement} The rolltable in an html format
+ */
+async function rollSkill (match: any, _options: any): Promise {
+ const skillName = match[1] ?? match[2];
+ const a = document.createElement("a");
+ a.classList.add("inline-roll");
+ a.classList.add("skill-roll");
+ a.dataset.skillName = skillName;
+ a.innerHTML = ` ${skillName}`;
+ return a;
+}
+
+/**
+ * Convert a rollTable link in a journal entry with a nice format of the table based on roll table name or uuid.
+ * @param {string} uuid The rolltable UUID.
+ * @param {string} tableName The string name of the table
+ * @returns {string} The rolltable in an html format
+ */
+function displayTable(uuid: string, table:any, tableName: string): string {
if (!table) {
return "";
}
- /*
- // Rollable table in caption
- let html = `
-
- @Table[${uuid}]{${tableName}}
-
- [[/roll ${table.formula}]] |
- ${game.i18n.localize("DoD.journal.tableResult")} |
-
`;
- */
-
// Rollable table in roll column header
let html = `
${tableName}
- @Table[${uuid}]{${table.formula}} |
- ${game.i18n.localize("Table Result")} |
+ @Table[${uuid}]{${table.formula}} |
+ ${game.i18n.localize("TWODSIX.Table.TableResults")} |
`;
for (const result of table.results) {
@@ -122,17 +153,23 @@ function displayTable(uuid, table, tableName) {
return html;
}
-function findTable(tableName:string, options?:any) {
+/**
+ * Finds a RollTable document based on either the RollTable name or uuid.
+ * @param {string} tableName The rolltable UUID or name.
+ * @param {any} options The optional find strings
+ * @returns {RollTable} The RollTable document
+ */
+function findTable(tableName:string, options?:any): RollTable {
const table = game.tables.find(i => i.name.toLowerCase() == tableName.toLowerCase()) || fromUuidSync(tableName);
if (!table) {
if (!options?.noWarnings){
- sendWarning("WARNING.tableNotFound", {id: tableName});
+ sendWarning("TWODSIX.Warnings.tableNotFound", {id: tableName});
}
return null;
}
if (!(table instanceof RollTable)) {
if (!options?.noWarning){
- sendWarning("WARNING.typeMismatch", {id: tableName});
+ sendWarning("TWODSIX.Warnings.typeMismatch", {id: tableName});
}
return null;
}
@@ -147,10 +184,16 @@ function sendWarning(msg, params) {
}
}
-export async function handleTableRoll(event) {
+/**
+ * Make a roll from a RollTable from a clickable link in JournalEntry.
+ * @param {Event} event The click event.
+ */
+export async function handleTableRoll(event: Event): Promise {
+ event.preventDefault();
+ event.stopPropagation();
const tableId = event.currentTarget.dataset.tableId;
const tableName = event.currentTarget.dataset.tableName;
- const table = fromUuidSync(tableId) || this.findTable(tableName);
+ const table = fromUuidSync(tableId) || findTable(tableName);
if (table) {
if (event.type == "click") { // left click
table.draw();
@@ -158,6 +201,41 @@ export async function handleTableRoll(event) {
table.sheet.render(true);
}
}
+}
+
+/**
+ * Make a roll from a RollTable from a clickable link in JournalEntry.
+ * @param {Event} event The click event.
+ */
+export async function handleSkillRoll(event: Event): Promise {
event.preventDefault();
event.stopPropagation();
+ const skillName:string = event.currentTarget.dataset.skillName;
+ const skill:TwodsixItem = findSkill(skillName);
+ if (skill) {
+ if (event.type == "click") { // left click
+ await skill.skillRoll(true);
+ } else { // right click
+ skill.sheet.render(true);
+ }
+ }
+}
+
+/**
+ * Finds a Skill Item document based on either the name or uuid.
+ * @param {string} skillName The skill name or UUID.
+ * @param {any} options The optional find strings
+ * @returns {TwodsixItem} The RollTable document
+ */
+function findSkill(skillName:string, _options?:any): TwodsixItem {
+ const actorToUse = getControlledTraveller();
+ if (actorToUse) {
+ let skill = actorToUse.itemTypes.skills?.find(i => i.name.toLowerCase() == skillName.toLowerCase()) || fromUuidSync(skillName);
+ if (!skill) {
+ skill = actorToUse.getUntrainedSkill();
+ }
+ return skill;
+ } else {
+ ui.notifications.warn(game.i18n.localize("TWODSIX.Warnings.NoActorSelected"));
+ }
}
diff --git a/static/lang/en.json b/static/lang/en.json
index 66bd9efcb..5a53b84fc 100644
--- a/static/lang/en.json
+++ b/static/lang/en.json
@@ -380,6 +380,9 @@
}
}
},
+ "Table": {
+ "TableResults": "Table Results"
+ },
"Create": "Create",
"Handlebars": {
"CantShowCharacteristic": "You need to reselect the characteristic for all skills marked with XXX. Sorry..."
@@ -1406,7 +1409,9 @@
"MissingUntrainedSkill": "Actor is missing untrained skill. Reload application to fix.",
"TooManyTargets": "More targets than the number of attacks, targets will be chosen in order selected.",
"WearingMultipleLayers": "Multiple armor layers equipped while wearing non-stackable armor.",
- "ResetEffectForManualDamage": "Effects not included in damage rolls. Resetting effects in manual rolls to false."
+ "ResetEffectForManualDamage": "Effects not included in damage rolls. Resetting effects in manual rolls to false.",
+ "tableNotFound": "Cannot find RollTable in Journal Entry Link.",
+ "typeMismatch": "RollTable link/UUID in Journal Entry is not a RollTable."
}
},
"TYPES": {
diff --git a/static/styles/twodsix_basic.css b/static/styles/twodsix_basic.css
index df703b695..e094fc57d 100644
--- a/static/styles/twodsix_basic.css
+++ b/static/styles/twodsix_basic.css
@@ -2543,6 +2543,12 @@ background: var(--sidebar-background);
word-break: break-all;
font-size: inherit;
}*/
+
+.table-caption {
+ font-size: 1.5em;
+ font-style: italic;
+}
+
.dice-total {
white-space: pre-wrap;
}
From 6a6179515067a8f1034ba424857c82b7028d1e74 Mon Sep 17 00:00:00 2001
From: marvin9257 <72580196+marvin9257@users.noreply.github.com>
Date: Wed, 6 Dec 2023 14:17:13 -0600
Subject: [PATCH 3/6] fix: deepscan issue
---
src/module/utils/enrichers.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/module/utils/enrichers.ts b/src/module/utils/enrichers.ts
index e66b1aa00..9a1a9c642 100644
--- a/src/module/utils/enrichers.ts
+++ b/src/module/utils/enrichers.ts
@@ -227,7 +227,7 @@ export async function handleSkillRoll(event: Event): Promise {
* @param {any} options The optional find strings
* @returns {TwodsixItem} The RollTable document
*/
-function findSkill(skillName:string, _options?:any): TwodsixItem {
+function findSkill(skillName:string): TwodsixItem {
const actorToUse = getControlledTraveller();
if (actorToUse) {
let skill = actorToUse.itemTypes.skills?.find(i => i.name.toLowerCase() == skillName.toLowerCase()) || fromUuidSync(skillName);
From 3f7f601b5abe463fa213f5d476dc9ff2f669fdea Mon Sep 17 00:00:00 2001
From: marvin9257 <72580196+marvin9257@users.noreply.github.com>
Date: Wed, 6 Dec 2023 14:59:26 -0600
Subject: [PATCH 4/6] fix: make SkillRoll regex more robust to inputs
---
src/module/utils/enrichers.ts | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/src/module/utils/enrichers.ts b/src/module/utils/enrichers.ts
index 9a1a9c642..c27e26009 100644
--- a/src/module/utils/enrichers.ts
+++ b/src/module/utils/enrichers.ts
@@ -18,7 +18,7 @@ export function addCustomEnrichers() {
enricher: rollTable
},
{
- pattern: /@SkillRoll(?:{(.+?)})?/gm,
+ pattern: /@SkillRoll(?:\[(.*?)\])?(?:{(.*?)})?/gm,
enricher: rollSkill
}
);
@@ -85,12 +85,13 @@ async function rollTable (match: any, options: any): Promise
* @returns {HTMLAnchorElement} The rolltable in an html format
*/
async function rollSkill (match: any, _options: any): Promise {
- const skillName = match[1] ?? match[2];
+ const skillName = match[1] || match[2];
+ const descrip = match[2] || match[1];
const a = document.createElement("a");
a.classList.add("inline-roll");
a.classList.add("skill-roll");
a.dataset.skillName = skillName;
- a.innerHTML = ` ${skillName}`;
+ a.innerHTML = ` ${descrip}`;
return a;
}
From d67e2b61f70727bd8fad7fe811d796f2557964f2 Mon Sep 17 00:00:00 2001
From: marvin9257 <72580196+marvin9257@users.noreply.github.com>
Date: Fri, 8 Dec 2023 07:52:10 -0600
Subject: [PATCH 5/6] refactor: allow enhancers to use formula skill roll from
ship positions
---
src/module/entities/TwodsixItem.ts | 2 +-
src/module/utils/TwodsixRollSettings.ts | 69 +++++++++++++++-
src/module/utils/TwodsixShipActions.ts | 101 ++++--------------------
src/module/utils/enrichers.ts | 33 +++++---
src/module/utils/utils.ts | 21 +++++
5 files changed, 127 insertions(+), 99 deletions(-)
diff --git a/src/module/entities/TwodsixItem.ts b/src/module/entities/TwodsixItem.ts
index 89aa789bd..933adc1c1 100644
--- a/src/module/entities/TwodsixItem.ts
+++ b/src/module/entities/TwodsixItem.ts
@@ -11,7 +11,7 @@ import TwodsixActor from "./TwodsixActor";
import {DICE_ROLL_MODES} from "@league-of-foundry-developers/foundry-vtt-types/src/foundry/common/constants.mjs";
import {Component, Consumable, Gear, Skills, UsesConsumables, Weapon} from "../../types/template";
import { confirmRollFormula } from "../utils/sheetUtils";
-import { getCharacteristicFromDisplayLabel } from "../utils/TwodsixShipActions";
+import { getCharacteristicFromDisplayLabel } from "../utils/utils";
import ItemTemplate from "../utils/ItemTemplate";
import { getDamageTypes } from "../sheets/TwodsixItemSheet";
import { TWODSIX } from "../config";
diff --git a/src/module/utils/TwodsixRollSettings.ts b/src/module/utils/TwodsixRollSettings.ts
index 7aa6b9916..761417340 100644
--- a/src/module/utils/TwodsixRollSettings.ts
+++ b/src/module/utils/TwodsixRollSettings.ts
@@ -9,7 +9,7 @@ import {Gear, Skills} from "../../types/template";
import TwodsixActor from "../entities/TwodsixActor";
import { simplifySkillName } from "./utils";
import { effectType } from "../hooks/showStatusIcons";
-import { addSign } from "./utils";
+import { addSign, getCharacteristicFromDisplayLabel } from "./utils";
export class TwodsixRollSettings {
difficulty:{ mod:number, target:number };
@@ -361,3 +361,70 @@ export async function getCustomModifiers(selectedActor:TwodsixActor, characteris
}
return returnObject;
}
+
+export function getInitialSettingsFromFormula(parseString: string, actor: TwodsixActor): any {
+ const difficulties = TWODSIX.DIFFICULTIES[(game.settings.get('twodsix', 'difficultyListUsed'))];
+ // eslint-disable-next-line no-useless-escape
+ const re = new RegExp(/^(.[^\/\+=]*?) ?(?:\/([\S]+))? ?(?:(\d{0,2})\+)? ?(?:=(\w*))? ?$/);
+ const parsedResult: RegExpMatchArray | null = re.exec(parseString);
+
+ if (parsedResult !== null) {
+ const [, parsedSkills, char, diff] = parsedResult;
+ const skillOptions = parsedSkills.split("|");
+ let skill:TwodsixItem|undefined = undefined;
+ /* add qualified skill objects to an array*/
+ const skillObjects = actor?.itemTypes.skills?.filter((itm: TwodsixItem) => skillOptions.includes(itm.name));
+
+ // find the most advantageous skill to use from the collection
+ if(skillObjects?.length > 0){
+ skill = skillObjects.reduce((prev, current) => (prev.system.value > current.system.value) ? prev : current);
+ }
+
+ // If skill missing, try to use Untrained
+ if (!skill) {
+ skill = actor?.itemTypes.skills.find((itm: TwodsixItem) => itm.name === game.i18n.localize("TWODSIX.Actor.Skills.Untrained")) as TwodsixItem;
+ if (!skill) {
+ ui.notifications.error(game.i18n.localize("TWODSIX.Ship.ActorLacksSkill").replace("_ACTOR_NAME_", actor?.name ?? "").replace("_SKILL_", parsedSkills));
+ return false;
+ }
+ }
+
+ // get characteristic key, default to skill key if none specificed in formula
+ let characteristicKey = "";
+ const charObject = actor?.system["characteristics"] ?? {};
+ //we need an array
+ const charObjectArray = Object.values(charObject);
+ if(!char) {
+ characteristicKey = getKeyByValue(TWODSIX.CHARACTERISTICS, (skill.system).characteristic);
+ } else {
+ //find the most advantageous characteristic to use based on the displayed (custom) short label
+ const charOptions = char.split("|");
+ let candidateCharObject = undefined;
+ const candidateCharObjects = charObjectArray.filter(ch => charOptions.includes(ch.displayShortLabel));
+ if(candidateCharObjects.length > 0){
+ candidateCharObject = candidateCharObjects.reduce((prev, current) =>(prev.mod > current.mod) ? prev: current);
+ }
+ characteristicKey = candidateCharObject?.key ?? getCharacteristicFromDisplayLabel(char, actor);
+ }
+
+ let shortLabel = "NONE";
+ let displayLabel = "NONE";
+ if (charObject && characteristicKey) {
+ shortLabel = charObject[characteristicKey].shortLabel;
+ displayLabel = charObject[characteristicKey].displayShortLabel;
+ }
+ const returnValues = {
+ skill: skill,
+ skillRoll: true,
+ displayLabel: displayLabel,
+ rollModifiers: {characteristic: shortLabel}
+ };
+ if (diff) {
+ returnValues["difficulty"] = Object.values(difficulties).filter((difficulty: Record) => difficulty.target === parseInt(diff, 10))[0];
+ }
+ return returnValues;
+ } else {
+ ui.notifications.error(game.i18n.localize("TWODSIX.Ship.CannotParseArgument"));
+ return false;
+ }
+}
diff --git a/src/module/utils/TwodsixShipActions.ts b/src/module/utils/TwodsixShipActions.ts
index 60c7fa238..25ee49739 100644
--- a/src/module/utils/TwodsixShipActions.ts
+++ b/src/module/utils/TwodsixShipActions.ts
@@ -1,13 +1,13 @@
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-nocheck This turns off *all* typechecking, make sure to remove this once foundry-vtt-types are updated to cover v10.
-import { Component, Skills } from "src/types/template";
+import { Component} from "src/types/template";
import { AvailableShipActionData, AvailableShipActions, ExtraData } from "../../types/twodsix";
import { TWODSIX } from "../config";
import TwodsixItem from "../entities/TwodsixItem";
import TwodsixActor from "../entities/TwodsixActor";
-import { confirmRollFormula, getKeyByValue } from "./sheetUtils";
-import { TwodsixRollSettings } from "./TwodsixRollSettings";
+import { confirmRollFormula} from "./sheetUtils";
+import { TwodsixRollSettings, getInitialSettingsFromFormula } from "./TwodsixRollSettings";
import { DICE_ROLL_MODES } from "@league-of-foundry-developers/foundry-vtt-types/src/foundry/common/constants.mjs";
export class TwodsixShipActions {
@@ -59,78 +59,26 @@ export class TwodsixShipActions {
public static async skillRoll(text: string, extra: ExtraData) {
const useInvertedShiftClick: boolean = (game.settings.get('twodsix', 'invertSkillRollShiftClick'));
- const showTrowDiag = useInvertedShiftClick ? extra.event["shiftKey"] : !extra.event["shiftKey"];
- const difficulties = TWODSIX.DIFFICULTIES[(game.settings.get('twodsix', 'difficultyListUsed'))];
- // eslint-disable-next-line no-useless-escape
- const re = new RegExp(/^(.[^\/\+=]*?) ?(?:\/([\S]+))? ?(?:(\d{0,2})\+)? ?(?:=(\w*))? ?$/);
- const parsedResult: RegExpMatchArray | null = re.exec(text);
- const selectedActor = extra.actor;
+ const showTrowDiag:boolean = useInvertedShiftClick ? extra.event["shiftKey"] : !extra.event["shiftKey"];
- if (parsedResult !== null) {
- const [, parsedSkills, char, diff] = parsedResult;
- const skillOptions = parsedSkills.split("|");
- let skill = undefined;
- /* add qualified skill objects to an array*/
- const skillObjects = selectedActor?.itemTypes.skills.filter((itm: TwodsixItem) => skillOptions.includes(itm.name));
-
- // find the most advantageous sill to use from the collection
- if(skillObjects?.length > 0){
- skill = skillObjects.reduce((prev, current) => (prev.system.value > current.system.value) ? prev : current);
- }
-
-
- /*if skill missing, try to use Untrained*/
- if (!skill) {
- skill = selectedActor?.itemTypes.skills.find((itm: TwodsixItem) => itm.name === game.i18n.localize("TWODSIX.Actor.Skills.Untrained")) as TwodsixItem;
- if (!skill) {
- ui.notifications.error(game.i18n.localize("TWODSIX.Ship.ActorLacksSkill").replace("_ACTOR_NAME_", selectedActor?.name ?? "").replace("_SKILL_", parsedSkills));
- return false;
- }
- }
-
- /*get characteristic key, default to skill key if none specificed in formula */
- let characteristicKey = "";
- const charObject = selectedActor?.system["characteristics"] ?? {};
- //we need an array
- const charObjectArray = Object.values(charObject);
- if(!char) {
- characteristicKey = getKeyByValue(TWODSIX.CHARACTERISTICS, (skill.system).characteristic);
- } else {
- //find the most advantageous characteristic to use
- const charOptions = char.split("|");
- let candidateCharObject = undefined;
- const candidateCharObjects = charObjectArray.filter(ch => charOptions.includes(ch.displayShortLabel));
- if(candidateCharObjects.length > 0){
- candidateCharObject = candidateCharObjects.reduce((prev, current) =>(prev.mod > current.mod) ? prev: current);
- }
- characteristicKey = candidateCharObject?.key ?? getCharacteristicFromDisplayLabel(char, selectedActor);;
- }
-
-
- let shortLabel = "NONE";
- let displayLabel = "NONE";
- if (charObject && characteristicKey) {
- shortLabel = charObject[characteristicKey].shortLabel;
- displayLabel = charObject[characteristicKey].displayShortLabel;
- }
- const settings = {
- displayLabel: displayLabel,
+ const settings = getInitialSettingsFromFormula(text, extra.actor);
+ if (settings) {
+ Object.assign (settings, {
extraFlavor: game.i18n.localize("TWODSIX.Ship.MakesChatRollAction").replace( "_ACTION_NAME_", extra.actionName || game.i18n.localize("TWODSIX.Ship.Unknown")).replace("_POSITION_NAME_", (extra.positionName || game.i18n.localize("TWODSIX.Ship.Unknown"))),
- rollModifiers: {characteristic: shortLabel, item: extra.diceModifier ? parseInt(extra.diceModifier) : 0},
flags: {tokenUUID: extra.ship?.uuid}
- };
- if (diff) {
- settings["difficulty"] = Object.values(difficulties).filter((difficulty: Record) => difficulty.target === parseInt(diff, 10))[0];
- }
- const options = await TwodsixRollSettings.create(showTrowDiag, settings, skill, extra.component, selectedActor);
+ });
+ Object.assign(settings.rollModifiers, {item: extra.diceModifier ? parseInt(extra.diceModifier) : 0});
+ const skill:TwodsixItem = settings.skill;
+ delete settings.skill;
+ const options = await TwodsixRollSettings.create(showTrowDiag, settings, skill, extra.component, extra.actor);
if (!options.shouldRoll) {
return false;
}
if (extra.component) {
- return extra.component.skillRoll(showTrowDiag, options);
+ return extra.component.skillRoll(false, options);
} else {
- return skill.skillRoll(showTrowDiag, options);
+ return skill.skillRoll(false, options);
}
} else {
@@ -177,24 +125,3 @@ export class TwodsixShipActions {
}
}
}
-
-/**
- * A function for getting the full characteristic label from the displayed short label.
- *
- * @param {string} char The displayed characteristic short label.
- * @param {TwodsixActor} actor The Actor in question.
- * @returns {string} Full logical name of the characteristic.
- */
-export function getCharacteristicFromDisplayLabel(char:string, actor?:TwodsixActor):string {
- let tempObject = {};
- let charObject= {};
- if (actor) {
- charObject = actor.system["characteristics"];
- for (const key in charObject) {
- tempObject[key] = charObject[key].displayShortLabel;
- }
- } else {
- tempObject = TWODSIX.CHARACTERISTICS;
- }
- return getKeyByValue(tempObject, char);
-}
diff --git a/src/module/utils/enrichers.ts b/src/module/utils/enrichers.ts
index c27e26009..af6d8885c 100644
--- a/src/module/utils/enrichers.ts
+++ b/src/module/utils/enrichers.ts
@@ -3,6 +3,8 @@
import { getControlledTraveller } from "../sheets/TwodsixVehicleSheet";
import TwodsixItem from "../entities/TwodsixItem";
+import { getInitialSettingsFromFormula } from "./TwodsixRollSettings";
+import { TwodsixRollSettings } from "./TwodsixRollSettings";
// Adapted from https://github.com/pafvel/dragonbane/blob/master/modules/journal.js
@@ -85,12 +87,12 @@ async function rollTable (match: any, options: any): Promise
* @returns {HTMLAnchorElement} The rolltable in an html format
*/
async function rollSkill (match: any, _options: any): Promise {
- const skillName = match[1] || match[2];
+ const skillName = match[1] || "";
const descrip = match[2] || match[1];
const a = document.createElement("a");
a.classList.add("inline-roll");
a.classList.add("skill-roll");
- a.dataset.skillName = skillName;
+ a.dataset.parseString = skillName;
a.innerHTML = ` ${descrip}`;
return a;
}
@@ -205,20 +207,31 @@ export async function handleTableRoll(event: Event): Promise {
}
/**
- * Make a roll from a RollTable from a clickable link in JournalEntry.
+ * Make a roll from a skill formula using a clickable link in JournalEntry.
* @param {Event} event The click event.
*/
export async function handleSkillRoll(event: Event): Promise {
event.preventDefault();
event.stopPropagation();
- const skillName:string = event.currentTarget.dataset.skillName;
- const skill:TwodsixItem = findSkill(skillName);
- if (skill) {
- if (event.type == "click") { // left click
- await skill.skillRoll(true);
- } else { // right click
- skill.sheet.render(true);
+ const parseString:string = event.currentTarget.dataset.parseString;
+ const actorToUse = getControlledTraveller();
+ if (actorToUse) {
+ const parsedValues:any = getInitialSettingsFromFormula(parseString, actorToUse);
+ if (parsedValues) {
+ const skill:TwodsixItem = parsedValues.skill;
+ if (event.type == "click") { // left click
+ delete parsedValues.skill;
+ const settings:TwodsixRollSettings = await TwodsixRollSettings.create(true, parsedValues, skill, undefined, actorToUse);
+ if (!settings.shouldRoll) {
+ return;
+ }
+ await skill.skillRoll(false, settings);
+ } else { // right click
+ skill.sheet.render(true);
+ }
}
+ } else {
+ ui.notifications.warn(game.i18n.localize("TWODSIX.Warnings.NoActorSelected"));
}
}
diff --git a/src/module/utils/utils.ts b/src/module/utils/utils.ts
index fe9db254a..c6d79a407 100644
--- a/src/module/utils/utils.ts
+++ b/src/module/utils/utils.ts
@@ -1,5 +1,6 @@
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-nocheck This turns off *all* typechecking, make sure to remove this once foundry-vtt-types are updated to cover v10.
+import { getKeyByValue } from "./sheetUtils";
// https://stackoverflow.com/a/34749873
/**
@@ -121,3 +122,23 @@ export function capitalizeFirstLetter(inputString:string):string {
return "";
}
}
+
+/**
+ * A function for getting the full characteristic key from the displayed short label.
+ * @param {string} char The displayed characteristic short label.
+ * @param {TwodsixActor} actor The Actor in question.
+ * @returns {string} Full logical name (key) of the characteristic.
+ */
+export function getCharacteristicFromDisplayLabel(char:string, actor?:TwodsixActor):string {
+ let tempObject = {};
+ let charObject= {};
+ if (actor) {
+ charObject = actor.system["characteristics"];
+ for (const key in charObject) {
+ tempObject[key] = charObject[key].displayShortLabel;
+ }
+ } else {
+ tempObject = TWODSIX.CHARACTERISTICS;
+ }
+ return getKeyByValue(tempObject, char);
+}
From f8077421c6ae8c0f91558b172a446408260c549c Mon Sep 17 00:00:00 2001
From: marvin9257 <72580196+marvin9257@users.noreply.github.com>
Date: Fri, 8 Dec 2023 08:10:04 -0600
Subject: [PATCH 6/6] fix: deepscan issue
---
src/module/utils/enrichers.ts | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/module/utils/enrichers.ts b/src/module/utils/enrichers.ts
index af6d8885c..5e192aa1d 100644
--- a/src/module/utils/enrichers.ts
+++ b/src/module/utils/enrichers.ts
@@ -241,7 +241,7 @@ export async function handleSkillRoll(event: Event): Promise {
* @param {any} options The optional find strings
* @returns {TwodsixItem} The RollTable document
*/
-function findSkill(skillName:string): TwodsixItem {
+/*function findSkill(skillName:string): TwodsixItem {
const actorToUse = getControlledTraveller();
if (actorToUse) {
let skill = actorToUse.itemTypes.skills?.find(i => i.name.toLowerCase() == skillName.toLowerCase()) || fromUuidSync(skillName);
@@ -252,4 +252,4 @@ function findSkill(skillName:string): TwodsixItem {
} else {
ui.notifications.warn(game.i18n.localize("TWODSIX.Warnings.NoActorSelected"));
}
-}
+}*/