diff --git a/module/documents/item.js b/module/documents/item.js index 18ef11e..7583afe 100644 --- a/module/documents/item.js +++ b/module/documents/item.js @@ -1,3 +1,5 @@ +import { RFRPUtility } from "../rfrp-utility.js"; + export class RMSSItem extends Item { /** @override */ @@ -100,21 +102,13 @@ export class RMSSItem extends Item { } calculateSelectedSkillCategoryBonus(itemData) { - if (this.isEmbedded === null) { - console.log(`rmss | item.js | Skill ${this.name} has no owner. Not calculating Skill Category bonus`); - } - else - { - const items = this.parent?.items; - console.log(`rmss | item.js | Skill ${this.name} has owner, calculating skill category bonus.`); - if (items) { - for (const item of items) { - if (item.type === "skill_category" && item._id === itemData.system.category) { - console.log(`rmss | item.js | Calculating Skill Category bonus for skill: ${this.name}`); - this.system.category_bonus = item.system.total_bonus; - } - } - } + // Find the relevant skill category + let skillC = this.parent?.items || RFRPUtility.getSkillCategories(); + if (skillC) { + let item = skillC.find(it => it.type == "skill_category" && it.name.toLowerCase() == itemData.system.category.toLowerCase()); + this.system.category_bonus = item.system.total_bonus; + } else { + ui.notifications.warn("No Skill Categories found. Please create a Skill Category."); } } } diff --git a/module/rfrp-utility.js b/module/rfrp-utility.js new file mode 100644 index 0000000..d7cfa34 --- /dev/null +++ b/module/rfrp-utility.js @@ -0,0 +1,174 @@ +/* -------------------------------------------- */ +export class RFRPUtility { + + + /* -------------------------------------------- */ + static async init() { + } + + /* -------------------------------------------- */ + static async ready() { + const skillCategories = await RFRPUtility.loadCompendium("fvtt-rolemaster-frp.skill_categories") + this.skillCategories = skillCategories.map(i => i.toObject()) + } + + /* -------------------------------------------- */ + static getSkillCategories() { + return this.skillCategories + } + + /* -------------------------------------------- */ + static async loadCompendiumData(compendium) { + const pack = game.packs.get(compendium); + return await pack?.getDocuments() ?? []; + } + + /* -------------------------------------------- */ + static async loadCompendium(compendium, filter = item => true) { + let compendiumData = await RFRPUtility.loadCompendiumData(compendium); + return compendiumData.filter(filter); + } + + /* -------------------------------------------- */ + static removeChatMessageId(messageId) { + if (messageId) { + game.messages.get(messageId)?.delete(); + } + } + + static findChatMessageId(current) { + return RFRPUtility.getChatMessageId(HeritiersUtility.findChatMessage(current)); + } + + static getChatMessageId(node) { + return node?.attributes.getNamedItem('data-message-id')?.value; + } + + static findChatMessage(current) { + return RFRPUtility.findNodeMatching(current, it => it.classList.contains('chat-message') && it.attributes.getNamedItem('data-message-id')) + } + + static findNodeMatching(current, predicate) { + if (current) { + if (predicate(current)) { + return current; + } + return RFRPUtility.findNodeMatching(current.parentElement, predicate); + } + return undefined; + } + + /* -------------------------------------------- */ + static getUsers(filter) { + return game.users.filter(filter).map(user => user._id); + } + + /* -------------------------------------------- */ + static getWhisperRecipients(rollMode, name) { + switch (rollMode) { + case "blindroll": return this.getUsers(user => user.isGM); + case "gmroll": return this.getWhisperRecipientsAndGMs(name); + case "selfroll": return [game.user.id]; + } + return undefined; + } + /* -------------------------------------------- */ + static getWhisperRecipientsAndGMs(name) { + let recep1 = ChatMessage.getWhisperRecipients(name) || []; + return recep1.concat(ChatMessage.getWhisperRecipients('GM')); + } + + /* -------------------------------------------- */ + static blindMessageToGM(chatOptions) { + let chatGM = foundry.utils.duplicate(chatOptions); + chatGM.whisper = this.getUsers(user => user.isGM); + chatGM.content = "Blinde message of " + game.user.name + "
" + chatOptions.content; + console.log("blindMessageToGM", chatGM); + game.socket.emit("system.fvtt-rolemaster-frp", { msg: "msg_gm_chat_message", data: chatGM }); + } + + /* -------------------------------------------- */ + static async searchItem(dataItem) { + let item + if (dataItem.pack) { + let id = dataItem.id || dataItem._id + let items = await this.loadCompendium(dataItem.pack, item => item.id == id) + item = items[0] || undefined + } else { + item = game.items.get(dataItem.id) + } + return item + } + + /* -------------------------------------------- */ + static loadHandlebarsTemplates() { + const templatePaths = [ + "systems/fvtt-rolemaster-frp/templates/sheets/actors/parts/actor-stats.html", + "systems/fvtt-rolemaster-frp/templates/sheets/actors/parts/actor-fixed-info.html", + "systems/fvtt-rolemaster-frp/templates/sheets/actors/parts/actor-armor-info.html", + "systems/fvtt-rolemaster-frp/templates/sheets/actors/parts/actor-resistance.html", + "systems/fvtt-rolemaster-frp/templates/sheets/actors/parts/actor-race-stat-fixed-info.html", + "systems/fvtt-rolemaster-frp/templates/sheets/actors/parts/actor-role-traits.html", + "systems/fvtt-rolemaster-frp/templates/sheets/actors/parts/actor-background-info.html", + "systems/fvtt-rolemaster-frp/templates/sheets/actors/parts/actor-skill-categories.html", + "systems/fvtt-rolemaster-frp/templates/sheets/actors/parts/actor-skills.html", + "systems/fvtt-rolemaster-frp/templates/sheets/actors/parts/actor-fav-skills.html", + "systems/fvtt-rolemaster-frp/templates/sheets/actors/parts/actor-items.html", + "systems/fvtt-rolemaster-frp/templates/sheets/actors/parts/actor-weapons.html", + "systems/fvtt-rolemaster-frp/templates/sheets/actors/parts/actor-money.html", + "systems/fvtt-rolemaster-frp/templates/sheets/actors/parts/actor-skill-categories.html", + "systems/fvtt-rolemaster-frp/templates/sheets/actors/parts/actor-skills.html", + "systems/fvtt-rolemaster-frp/templates/sheets/actors/parts/actor-armor.html", + "systems/fvtt-rolemaster-frp/templates/sheets/actors/parts/actor-herbs.html", + "systems/fvtt-rolemaster-frp/templates/sheets/actors/parts/actor-spells.html", + "systems/fvtt-rolemaster-frp/templates/sheets/actors/parts/actor-fav-spells.html", + "systems/fvtt-rolemaster-frp/templates/sheets/actors/parts/actor-fav-items.html", + "systems/fvtt-rolemaster-frp/templates/sheets/apps/app_skill_category_importer.html" + ]; + return loadTemplates(templatePaths); + } + + /* -------------------------------------------- */ + static loadHandlebarsHelpers() { + + // Handlebars Helpers + Handlebars.registerHelper('count', function (list) { + return list.length; + }) + Handlebars.registerHelper('includes', function (array, val) { + return array.includes(val); + }) + Handlebars.registerHelper('upper', function (text) { + return text.toUpperCase(); + }) + Handlebars.registerHelper('lower', function (text) { + return text.toLowerCase() + }) + Handlebars.registerHelper('upperFirst', function (text) { + if (typeof text !== 'string') return text + return text.charAt(0).toUpperCase() + text.slice(1) + }) + Handlebars.registerHelper('notEmpty', function (list) { + return list.length > 0; + }) + Handlebars.registerHelper('mul', function (a, b) { + return parseInt(a) * parseInt(b); + }) + Handlebars.registerHelper("switch", function (value, options) { + this.switch_value = value; + return options.fn(this); + }); + Handlebars.registerHelper("case", function (value, options) { + if (value === this.switch_value) { + return options.fn(this); + } + }); + // Handle v12 removal of this helper + Handlebars.registerHelper('select', function (selected, options) { + const escapedValue = RegExp.escape(Handlebars.escapeExpression(selected)); + const rgx = new RegExp(' value=[\"\']' + escapedValue + '[\"\']'); + const html = options.fn(this); + return html.replace(rgx, "$& selected"); + }); + } +} \ No newline at end of file diff --git a/module/sheets/actors/rmss_player_sheet.js b/module/sheets/actors/rmss_player_sheet.js index 0037f3e..2ddd700 100644 --- a/module/sheets/actors/rmss_player_sheet.js +++ b/module/sheets/actors/rmss_player_sheet.js @@ -171,7 +171,7 @@ export default class RMSSPlayerSheet extends ActorSheet { for (let s of skillcat) { s.skills = []; for (let sk of playerskill) { - if (sk.system.category === s._id) { + if (sk.system.category.toLowerCase() === s.name.toLowerCase()) { s.skills.push(sk); } } diff --git a/module/sheets/skills/rmss_skill_sheet.js b/module/sheets/skills/rmss_skill_sheet.js index 587c517..8ceb8b3 100644 --- a/module/sheets/skills/rmss_skill_sheet.js +++ b/module/sheets/skills/rmss_skill_sheet.js @@ -1,3 +1,5 @@ +import { RFRPUtility } from "../../rfrp-utility.js"; + // Our Item Sheet extends the default export default class RMSSSkillSheet extends ItemSheet { @@ -70,21 +72,20 @@ export default class RMSSSkillSheet extends ItemSheet { // If this Skill is owned then we will return a list of Skill Categories and allow them to choose // Otherwise we'll just return 'Skill has no owner' prepareSkillCategoryValues() { - let skillNoOwner = { None: "Skill Has No Owner" }; - - if (!this.item.isEmbedded) { - return (skillNoOwner); - } else { - const skillCategories = this.item.parent.getOwnedItemsByType("skill_category"); - return (skillCategories); + let skillCategories = RFRPUtility.getSkillCategories(); + if (this.item.isEmbedded) { + skillCategories = this.item.parent.items.filter(it => it.type == "skill_category"); } + console.log("CATEG", skillCategories); + return (skillCategories); } // Determine which Skill Category is selected and test that it is in the current list of categories. // If it isn't set it to None. prepareSelectedSkillCategory(ownedSkillCategories, selectedSkillCategory) { let defaultSelectedCategory = "None"; - if (Object.keys(ownedSkillCategories).includes(selectedSkillCategory)) { + let skillC = ownedSkillCategories.find(it => it.name.toLowerCase() == selectedSkillCategory.toLowerCase()); + if (skillC) { return (selectedSkillCategory); } else { return (defaultSelectedCategory); @@ -95,18 +96,14 @@ export default class RMSSSkillSheet extends ItemSheet { // Iterate through the owned skill categories and if one of them matches the item id of currently // selected skill category then set the Skill Category Bonus field to the Total Bonus field of the Skill Category prepareSelectedSkillCategoryBonus(selected_skillcat) { - if (this.item.isEmbedded === null) { - console.log("Skill has no owner"); - } - else { - const items = this.object.parent.items; - - for (const item of items) { - if (item.type === "skill_category" && item._id === selected_skillcat) { - console.log(`rmss | rmss_skill_sheet | Calculating Skill Category bonus for skill: ${this.object.name}`); - this.object.system.category_bonus = item.system.total_bonus; - } + let skillC = this.parent?.items || RFRPUtility.getSkillCategories(); + if (skillC) { + let item = skillC.find(it => it.type == "skill_category" && it.name.toLowerCase() == itemData.system.category.toLowerCase()); + if (item) { + this.system.category_bonus = item.system.total_bonus; + return } } + ui.notifications.warn("No Skill Categories found for " + this.name + ". Please create and link a Skill Category."); } } diff --git a/packs/skill_categories/000058.log b/packs/skill_categories/000062.log similarity index 100% rename from packs/skill_categories/000058.log rename to packs/skill_categories/000062.log diff --git a/packs/skill_categories/CURRENT b/packs/skill_categories/CURRENT index 80d9de0..0556986 100644 --- a/packs/skill_categories/CURRENT +++ b/packs/skill_categories/CURRENT @@ -1 +1 @@ -MANIFEST-000056 +MANIFEST-000060 diff --git a/packs/skill_categories/LOG b/packs/skill_categories/LOG index 6fbc724..848126a 100644 --- a/packs/skill_categories/LOG +++ b/packs/skill_categories/LOG @@ -1,8 +1,8 @@ -2024/08/02-16:48:51.596152 7f2b120006c0 Recovering log #54 -2024/08/02-16:48:51.607028 7f2b120006c0 Delete type=3 #52 -2024/08/02-16:48:51.607119 7f2b120006c0 Delete type=0 #54 -2024/08/02-17:06:25.130824 7f2b110006c0 Level-0 table #59: started -2024/08/02-17:06:25.130880 7f2b110006c0 Level-0 table #59: 0 bytes OK -2024/08/02-17:06:25.137382 7f2b110006c0 Delete type=0 #57 -2024/08/02-17:06:25.160338 7f2b110006c0 Manual compaction at level-0 from '!items!1HevhbCbvMonyQXe' @ 72057594037927935 : 1 .. '!items!yRIFroc5VC9Oj3qY' @ 0 : 0; will stop at (end) -2024/08/02-17:06:25.160385 7f2b110006c0 Manual compaction at level-1 from '!items!1HevhbCbvMonyQXe' @ 72057594037927935 : 1 .. '!items!yRIFroc5VC9Oj3qY' @ 0 : 0; will stop at (end) +2024/08/03-16:17:28.988843 7f2b120006c0 Recovering log #58 +2024/08/03-16:17:29.000009 7f2b120006c0 Delete type=3 #56 +2024/08/03-16:17:29.000149 7f2b120006c0 Delete type=0 #58 +2024/08/03-16:40:12.660059 7f2b110006c0 Level-0 table #63: started +2024/08/03-16:40:12.660133 7f2b110006c0 Level-0 table #63: 0 bytes OK +2024/08/03-16:40:12.666773 7f2b110006c0 Delete type=0 #61 +2024/08/03-16:40:12.677428 7f2b110006c0 Manual compaction at level-0 from '!items!1HevhbCbvMonyQXe' @ 72057594037927935 : 1 .. '!items!yRIFroc5VC9Oj3qY' @ 0 : 0; will stop at (end) +2024/08/03-16:40:12.689036 7f2b110006c0 Manual compaction at level-1 from '!items!1HevhbCbvMonyQXe' @ 72057594037927935 : 1 .. '!items!yRIFroc5VC9Oj3qY' @ 0 : 0; will stop at (end) diff --git a/packs/skill_categories/LOG.old b/packs/skill_categories/LOG.old index 4ebb3a5..6fbc724 100644 --- a/packs/skill_categories/LOG.old +++ b/packs/skill_categories/LOG.old @@ -1,8 +1,8 @@ -2024/08/02-16:41:04.243624 7f2b134006c0 Recovering log #50 -2024/08/02-16:41:04.298794 7f2b134006c0 Delete type=3 #48 -2024/08/02-16:41:04.298940 7f2b134006c0 Delete type=0 #50 -2024/08/02-16:47:53.296999 7f2b110006c0 Level-0 table #55: started -2024/08/02-16:47:53.297027 7f2b110006c0 Level-0 table #55: 0 bytes OK -2024/08/02-16:47:53.302866 7f2b110006c0 Delete type=0 #53 -2024/08/02-16:47:53.310260 7f2b110006c0 Manual compaction at level-0 from '!items!1HevhbCbvMonyQXe' @ 72057594037927935 : 1 .. '!items!yRIFroc5VC9Oj3qY' @ 0 : 0; will stop at (end) -2024/08/02-16:47:53.310311 7f2b110006c0 Manual compaction at level-1 from '!items!1HevhbCbvMonyQXe' @ 72057594037927935 : 1 .. '!items!yRIFroc5VC9Oj3qY' @ 0 : 0; will stop at (end) +2024/08/02-16:48:51.596152 7f2b120006c0 Recovering log #54 +2024/08/02-16:48:51.607028 7f2b120006c0 Delete type=3 #52 +2024/08/02-16:48:51.607119 7f2b120006c0 Delete type=0 #54 +2024/08/02-17:06:25.130824 7f2b110006c0 Level-0 table #59: started +2024/08/02-17:06:25.130880 7f2b110006c0 Level-0 table #59: 0 bytes OK +2024/08/02-17:06:25.137382 7f2b110006c0 Delete type=0 #57 +2024/08/02-17:06:25.160338 7f2b110006c0 Manual compaction at level-0 from '!items!1HevhbCbvMonyQXe' @ 72057594037927935 : 1 .. '!items!yRIFroc5VC9Oj3qY' @ 0 : 0; will stop at (end) +2024/08/02-17:06:25.160385 7f2b110006c0 Manual compaction at level-1 from '!items!1HevhbCbvMonyQXe' @ 72057594037927935 : 1 .. '!items!yRIFroc5VC9Oj3qY' @ 0 : 0; will stop at (end) diff --git a/packs/skill_categories/MANIFEST-000056 b/packs/skill_categories/MANIFEST-000056 deleted file mode 100644 index 5251636..0000000 Binary files a/packs/skill_categories/MANIFEST-000056 and /dev/null differ diff --git a/packs/skill_categories/MANIFEST-000060 b/packs/skill_categories/MANIFEST-000060 new file mode 100644 index 0000000..9172303 Binary files /dev/null and b/packs/skill_categories/MANIFEST-000060 differ diff --git a/rmss.js b/rmss.js index 6fc2770..0bbb086 100644 --- a/rmss.js +++ b/rmss.js @@ -19,34 +19,7 @@ import RMSSSkillSheet from "./module/sheets/skills/rmss_skill_sheet.js"; import RMSSPlayerSheet from "./module/sheets/actors/rmss_player_sheet.js"; import RMSSToolsSCImporter from "./module/sheets/apps/rmss_import_skill_categories.js"; import RMSSToolsDiceRoller from "./module/sheets/apps/rmss_dice_roller.js"; - -/** Preload handlebars templates for character sheets */ -async function preloadHandlebarsTemplates() { - const templatePaths = [ - "systems/fvtt-rolemaster-frp/templates/sheets/actors/parts/actor-stats.html", - "systems/fvtt-rolemaster-frp/templates/sheets/actors/parts/actor-fixed-info.html", - "systems/fvtt-rolemaster-frp/templates/sheets/actors/parts/actor-armor-info.html", - "systems/fvtt-rolemaster-frp/templates/sheets/actors/parts/actor-resistance.html", - "systems/fvtt-rolemaster-frp/templates/sheets/actors/parts/actor-race-stat-fixed-info.html", - "systems/fvtt-rolemaster-frp/templates/sheets/actors/parts/actor-role-traits.html", - "systems/fvtt-rolemaster-frp/templates/sheets/actors/parts/actor-background-info.html", - "systems/fvtt-rolemaster-frp/templates/sheets/actors/parts/actor-skill-categories.html", - "systems/fvtt-rolemaster-frp/templates/sheets/actors/parts/actor-skills.html", - "systems/fvtt-rolemaster-frp/templates/sheets/actors/parts/actor-fav-skills.html", - "systems/fvtt-rolemaster-frp/templates/sheets/actors/parts/actor-items.html", - "systems/fvtt-rolemaster-frp/templates/sheets/actors/parts/actor-weapons.html", - "systems/fvtt-rolemaster-frp/templates/sheets/actors/parts/actor-money.html", - "systems/fvtt-rolemaster-frp/templates/sheets/actors/parts/actor-skill-categories.html", - "systems/fvtt-rolemaster-frp/templates/sheets/actors/parts/actor-skills.html", - "systems/fvtt-rolemaster-frp/templates/sheets/actors/parts/actor-armor.html", - "systems/fvtt-rolemaster-frp/templates/sheets/actors/parts/actor-herbs.html", - "systems/fvtt-rolemaster-frp/templates/sheets/actors/parts/actor-spells.html", - "systems/fvtt-rolemaster-frp/templates/sheets/actors/parts/actor-fav-spells.html", - "systems/fvtt-rolemaster-frp/templates/sheets/actors/parts/actor-fav-items.html", - "systems/fvtt-rolemaster-frp/templates/sheets/apps/app_skill_category_importer.html" - ]; - return loadTemplates(templatePaths); -} +import { RFRPUtility } from "./module/rfrp-utility.js"; // Register Scene Controls // registerGetSceneControlButtonsHook(); @@ -107,48 +80,14 @@ Hooks.once("init", function () { // Actors Actors.registerSheet("fvtt-rolemaster-frp", RMSSPlayerSheet, { makeDefault: true, label: "rmss.entity_sheet.player_characrer", types: ["character"] }); - // Preload Handlebars Templates - console.log("rmss | Preloading Handlebars Templates"); - preloadHandlebarsTemplates(); - - // Handlebars Helpers - Handlebars.registerHelper('count', function (list) { - return list.length; - }) - Handlebars.registerHelper('includes', function (array, val) { - return array.includes(val); - }) - Handlebars.registerHelper('upper', function (text) { - return text.toUpperCase(); - }) - Handlebars.registerHelper('lower', function (text) { - return text.toLowerCase() - }) - Handlebars.registerHelper('upperFirst', function (text) { - if (typeof text !== 'string') return text - return text.charAt(0).toUpperCase() + text.slice(1) - }) - Handlebars.registerHelper('notEmpty', function (list) { - return list.length > 0; - }) - Handlebars.registerHelper('mul', function (a, b) { - return parseInt(a) * parseInt(b); - }) - Handlebars.registerHelper("switch", function (value, options) { - this.switch_value = value; - return options.fn(this); - }); - Handlebars.registerHelper("case", function (value, options) { - if (value === this.switch_value) { - return options.fn(this); - } - }); - // Handle v12 removal of this helper - Handlebars.registerHelper('select', function (selected, options) { - const escapedValue = RegExp.escape(Handlebars.escapeExpression(selected)); - const rgx = new RegExp(' value=[\"\']' + escapedValue + '[\"\']'); - const html = options.fn(this); - return html.replace(rgx, "$& selected"); - }); + RFRPUtility.loadHandlebarsTemplates(); + RFRPUtility.loadHandlebarsHelpers(); }); + +Hooks.once("ready", async function () { + console.log("rmss | Ready"); + + // Load Utility + await RFRPUtility.ready(); +}) diff --git a/system.json b/system.json index 8c7f08e..c873e93 100644 --- a/system.json +++ b/system.json @@ -3,7 +3,7 @@ "title": "Rolemaster FRP System", "description": "The Rolemaster FRP system for FoundryVTT.", "manifest": "https://www.uberwald.me/gitea/public/fvtt-rolemaster-frp/raw/branch/develop/system.json", - "download": "https://www.uberwald.me/gitea/public/fvtt-rolemaster-frp/archive/v12.0.5.zip", + "download": "https://www.uberwald.me/gitea/public/fvtt-rolemaster-frp/archive/v12.0.6.zip", "authors": [ { "name": "Cynicide", @@ -14,7 +14,7 @@ "email": "" } ], - "version": "12.0.5", + "version": "12.0.6", "compatibility": { "minimum": "12", "verified": "12" diff --git a/templates/sheets/skills/rmss-skill-sheet.html b/templates/sheets/skills/rmss-skill-sheet.html index 84b0584..fb7c1d1 100644 --- a/templates/sheets/skills/rmss-skill-sheet.html +++ b/templates/sheets/skills/rmss-skill-sheet.html @@ -11,8 +11,8 @@
Skill Category - + {{selectOptions owned_skillcats selected=selected_skillcat nameAttr="name" valueAttr="name" labelAttr="name"}}