diff --git a/module/actor/actor-sheet.js b/module/actor/actor-sheet.js index f520662..d8b7b0e 100644 --- a/module/actor/actor-sheet.js +++ b/module/actor/actor-sheet.js @@ -1,17 +1,16 @@ /* globals $ game Roll ChatMessage AudioHelper ActorSheet mergeObject Dialog TextEditor ActiveEffect ui duplicate fromUuidSync */ -import { +import { DGPercentileRoll, DGLethalityRoll, DGDamageRoll, DGSanityDamageRoll, -} from "../roll/roll.js" +} from "../roll/roll.js"; /** * Extend the basic ActorSheet with some very simple modifications * @extends {ActorSheet} */ export class DeltaGreenActorSheet extends ActorSheet { - /** @override */ static get defaultOptions() { return mergeObject(super.defaultOptions, { @@ -19,7 +18,13 @@ export class DeltaGreenActorSheet extends ActorSheet { template: "systems/deltagreen/templates/actor/actor-sheet.html", width: 700, height: 800, - tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "skills" }] + tabs: [ + { + navSelector: ".sheet-tabs", + contentSelector: ".sheet-body", + initial: "skills", + }, + ], }); } @@ -27,33 +32,29 @@ export class DeltaGreenActorSheet extends ActorSheet { /** @override */ get template() { - - if(this.actor !== null){ - if(this.actor.type === 'agent'){ - if ( !game.user.isGM && this.actor.limited ) { + if (this.actor !== null) { + if (this.actor.type === "agent") { + if (!game.user.isGM && this.actor.limited) { return "systems/deltagreen/templates/actor/limited-sheet.html"; } - else{ - //return `systems/deltagreen/templates/actor/${this.actor.data.type}-sheet.html`; - return `systems/deltagreen/templates/actor/actor-sheet.html`; - } + + // return `systems/deltagreen/templates/actor/${this.actor.data.type}-sheet.html`; + return `systems/deltagreen/templates/actor/actor-sheet.html`; } - else if(this.actor.type === 'unnatural'){ + if (this.actor.type === "unnatural") { return `systems/deltagreen/templates/actor/unnatural-sheet.html`; } - else if(this.actor.type === 'npc'){ + if (this.actor.type === "npc") { return `systems/deltagreen/templates/actor/npc-sheet.html`; } - else if(this.actor.type === 'vehicle'){ + if (this.actor.type === "vehicle") { return `systems/deltagreen/templates/actor/vehicle-sheet.html`; } - else{ - return "systems/deltagreen/templates/actor/limited-sheet.html"; - } - } - else{ + return "systems/deltagreen/templates/actor/limited-sheet.html"; } + + return "systems/deltagreen/templates/actor/limited-sheet.html"; } /** @override */ @@ -61,24 +62,33 @@ export class DeltaGreenActorSheet extends ActorSheet { const data = super.getData(); // Prepare items. - if (this.actor.type == 'agent') { + if (this.actor.type == "agent") { this._prepareCharacterItems(data); } switch (this.actor.type) { case "agent": - data.enrichedDescription = await TextEditor.enrichHTML(this.object.system.physicalDescription, {async: true}); + data.enrichedDescription = await TextEditor.enrichHTML( + this.object.system.physicalDescription, + { async: true }, + ); break; case "vehicle": - data.enrichedDescription = await TextEditor.enrichHTML(this.object.system.description, {async: true}); + data.enrichedDescription = await TextEditor.enrichHTML( + this.object.system.description, + { async: true }, + ); break; case "npc": case "unnatural": - data.enrichedDescription = await TextEditor.enrichHTML(this.object.system.notes, {async: true}); + data.enrichedDescription = await TextEditor.enrichHTML( + this.object.system.notes, + { async: true }, + ); break; default: } - + return data; } @@ -98,13 +108,13 @@ export class DeltaGreenActorSheet extends ActorSheet { // Iterate through items, allocating to containers // let totalWeight = 0; - for (let i of sheetData.items) { + for (const i of sheetData.items) { // Append to armor. - if (i.type === 'armor') { + if (i.type === "armor") { armor.push(i); } // Append to weapons. - else if (i.type === 'weapon') { + else if (i.type === "weapon") { weapons.push(i); } } @@ -113,35 +123,38 @@ export class DeltaGreenActorSheet extends ActorSheet { actorData.armor = armor; actorData.weapons = weapons; } - + // Can add extra buttons to form header here if necessary - _getHeaderButtons(){ + _getHeaderButtons() { let buttons = super._getHeaderButtons(); let label = "Roll Luck"; let label2 = "Luck"; - try{ + try { label = game.i18n.translations.DG.RollLuck; label2 = game.i18n.translations.DG.Luck; + } catch { + ui.notifications.warn( + "Missing translation key for either DG.RollLuck or DG.Luck key.", + ); } - catch{ - ui.notifications.warn('Missing translation key for either DG.RollLuck or DG.Luck key.') - } - - buttons = [{ - label: label, - class: "test-extra-icon", - icon: "fas fa-dice", - onclick: (ev) => this.luckRollOnClick(ev, this.actor, label2) - }].concat(buttons); + + buttons = [ + { + label, + class: "test-extra-icon", + icon: "fas fa-dice", + onclick: (ev) => this.luckRollOnClick(ev, this.actor, label2), + }, + ].concat(buttons); return buttons; } // This only exists to give a chance to activate the modifier dialogue if desired // Cannot seem to trigger the event on a right-click, so unfortunately only applies to a shift-click currently. - async luckRollOnClick(event){ - if(event && event.which === 2){ + async luckRollOnClick(event) { + if (event && event.which === 2) { // probably don't want rolls to trigger from a middle mouse click so just kill it here return; } @@ -149,10 +162,10 @@ export class DeltaGreenActorSheet extends ActorSheet { rollType: "luck", key: "luck", actor: this.actor, - } + }; // Create a default 1d100 roll just in case. - let roll = new DGPercentileRoll("1D100", {}, rollOptions); + const roll = new DGPercentileRoll("1D100", {}, rollOptions); // Open dialog if user requests it. if (event.shiftKey || event.which === 3) { const dialogData = await roll.showDialog(); @@ -163,27 +176,32 @@ export class DeltaGreenActorSheet extends ActorSheet { // Evaluate the roll. await roll.evaluate({ async: true }); // Send the roll to chat. - roll.toChat(); + roll.toChat(); } - activeEffectTest(sheet){ + activeEffectTest(sheet) { console.log(sheet.actor.uuid); - let owner = sheet.actor; + const owner = sheet.actor; - let effect = ActiveEffect.create({ + const effect = ActiveEffect.create( + { label: "Custom Effect", tint: "#008000", icon: "icons/svg/aura.svg", origin: owner.uuid, - //duration: {"rounds": 1, "seconds": null, "startTime": null, "turns": null, "startRound": null, "startTurn": null}, + // duration: {"rounds": 1, "seconds": null, "startTime": null, "turns": null, "startRound": null, "startTurn": null}, disabled: false, - changes: [{ - "key": "data.skills.firearms.proficiency", //"data.statistics.str.value", //"data.health.max", - "mode": 2, // 0 = custom, 1 = multiply, 2 = add, 3 = upgrade, 4 = downgrade, 5 = override - "value": -20, - "priority": "20" - }] - }, owner).create(); + changes: [ + { + key: "data.skills.firearms.proficiency", // "data.statistics.str.value", //"data.health.max", + mode: 2, // 0 = custom, 1 = multiply, 2 = add, 3 = upgrade, 4 = downgrade, 5 = override + value: -20, + priority: "20", + }, + ], + }, + owner, + ).create(); } /* -------------------------------------------- */ @@ -196,39 +214,45 @@ export class DeltaGreenActorSheet extends ActorSheet { if (!this.options.editable) return; // Add Inventory Item - html.find('.item-create').click(this._onItemCreate.bind(this)); + html.find(".item-create").click(this._onItemCreate.bind(this)); // Update Inventory Item - html.find('.item-edit').click(ev => { + html.find(".item-edit").click((ev) => { const li = $(ev.currentTarget).parents(".item"); - //const item = this.actor.getOwnedItem(li.data("itemId")); + // const item = this.actor.getOwnedItem(li.data("itemId")); const item = this.actor.items.get(li.data("itemId")); item.sheet.render(true); }); // Delete Inventory Item - html.find('.item-delete').click(ev => { + html.find(".item-delete").click((ev) => { const li = $(ev.currentTarget).parents(".item"); - //this.actor.deleteOwnedItem(li.data("itemId")); - let options = {}; + // this.actor.deleteOwnedItem(li.data("itemId")); + const options = {}; this.actor.deleteEmbeddedDocuments("Item", [li.data("itemId")], options); li.slideUp(200, () => this.render(false)); }); // Rollable abilities - bind to everything with the 'Rollable' class - html.find('.rollable').click(this._onRoll.bind(this)); + html.find(".rollable").click(this._onRoll.bind(this)); - html.find('.toggle-untrained').click(() => this.actor.update({"system.showUntrainedSkills": !this.actor.system.showUntrainedSkills})); + html.find(".toggle-untrained").click(() => + this.actor.update({ + "system.showUntrainedSkills": !this.actor.system.showUntrainedSkills, + }), + ); // Macro for toggling an item's equipped state - html.find('.equipped-item').mousedown(this._onEquippedStatusChange.bind(this)); + html + .find(".equipped-item") + .mousedown(this._onEquippedStatusChange.bind(this)); // Drag events for macros. if (this.actor.isOwner) { - let handler = ev => this._onDragStart(ev); - html.find('li.item').each((i, li) => { + const handler = (ev) => this._onDragStart(ev); + html.find("li.item").each((i, li) => { if (li.classList.contains("inventory-header")) return; li.setAttribute("draggable", true); li.addEventListener("dragstart", handler, false); @@ -236,56 +260,60 @@ export class DeltaGreenActorSheet extends ActorSheet { } // Custom Sheet Macros - html.find('.btn-reset-breaking-point').click(event => { + html.find(".btn-reset-breaking-point").click((event) => { event.preventDefault(); let currentBreakingPoint = 0; - - currentBreakingPoint = this.actor.system.sanity.value - this.actor.system.statistics.pow.value; - - let updatedData = duplicate(this.actor.system); + + currentBreakingPoint = + this.actor.system.sanity.value - this.actor.system.statistics.pow.value; + + const updatedData = duplicate(this.actor.system); updatedData.sanity.currentBreakingPoint = currentBreakingPoint; - this.actor.update({"data": updatedData}); + this.actor.update({ data: updatedData }); }); - html.find('.typed-skill-add').click(event => { + html.find(".typed-skill-add").click((event) => { event.preventDefault(); - let targetskill = event.target.getAttribute("data-typeskill"); + const targetskill = event.target.getAttribute("data-typeskill"); this._showNewTypeSkillDialog(targetskill); }); - html.find('.typed-skill-edit').click(event => { - + html.find(".typed-skill-edit").click((event) => { event.preventDefault(); - let targetskill = event.target.getAttribute("data-typedskill"); - let existingLabel = this.actor.system.typedSkills[targetskill].label; - let existingGroup = this.actor.system.typedSkills[targetskill].group; + const targetskill = event.target.getAttribute("data-typedskill"); + const existingLabel = this.actor.system.typedSkills[targetskill].label; + const existingGroup = this.actor.system.typedSkills[targetskill].group; - //this.actor.update({[`data.typedSkills.${targetskill}.label`]: 'test'}); - - this._showNewEditTypeSkillDialog(targetskill, existingLabel, existingGroup); + // this.actor.update({[`data.typedSkills.${targetskill}.label`]: 'test'}); + this._showNewEditTypeSkillDialog( + targetskill, + existingLabel, + existingGroup, + ); }); - html.find('.typed-skill-delete').click(event => { - + html.find(".typed-skill-delete").click((event) => { event.preventDefault(); - let targetskill = event.target.getAttribute("data-typedskill"); + const targetskill = event.target.getAttribute("data-typedskill"); // many bothans died to bring us this information on how to delete a property on an entity - this.actor.update({[`system.typedSkills.-=${targetskill}`]: null}); - + this.actor.update({ [`system.typedSkills.-=${targetskill}`]: null }); }); - html.find('.apply-skill-improvements').click(event => { - + html.find(".apply-skill-improvements").click((event) => { event.preventDefault(); - const failedSkills = Object.entries(this.actor.system.skills).filter((skill) => skill[1].failure); - const failedTypedSkills = Object.entries(this.actor.system.typedSkills).filter((skill) => skill[1].failure); + const failedSkills = Object.entries(this.actor.system.skills).filter( + (skill) => skill[1].failure, + ); + const failedTypedSkills = Object.entries( + this.actor.system.typedSkills, + ).filter((skill) => skill[1].failure); if (failedSkills.length === 0 && failedTypedSkills.length === 0) { - ui.notifications.warn('No Skills to Increase') + ui.notifications.warn("No Skills to Increase"); return; } @@ -293,95 +321,115 @@ export class DeltaGreenActorSheet extends ActorSheet { let failedSkillNames = ""; failedSkills.forEach(([skill], value) => { if (value === 0) { - failedSkillNames += (game.i18n.localize("DG.Skills." + skill)); + failedSkillNames += game.i18n.localize(`DG.Skills.${skill}`); } else { - failedSkillNames += `, ${(game.i18n.localize("DG.Skills." + skill))}`; + failedSkillNames += `, ${game.i18n.localize(`DG.Skills.${skill}`)}`; } - }) + }); failedTypedSkills.forEach(([skillName, skillData], value) => { if (value === 0 && failedSkillNames === "") { - failedSkillNames += `${game.i18n.localize("DG.TypeSkills." + skillData.group.split(" ").join(""))} (${skillData.label})`; + failedSkillNames += `${game.i18n.localize( + `DG.TypeSkills.${skillData.group.split(" ").join("")}`, + )} (${skillData.label})`; } else { - failedSkillNames += `, ${game.i18n.localize("DG.TypeSkills." + skillData.group.split(" ").join(""))} (${skillData.label})`; + failedSkillNames += `, ${game.i18n.localize( + `DG.TypeSkills.${skillData.group.split(" ").join("")}`, + )} (${skillData.label})`; } - }) + }); - const baseRollFormula = game.settings.get("deltagreen", "skillImprovementFormula"); + const baseRollFormula = game.settings.get( + "deltagreen", + "skillImprovementFormula", + ); htmlContent += `
`; - htmlContent += ` `; + htmlContent += ` `; htmlContent += `
`; - htmlContent += ` ${game.i18n.localize("DG.Skills.ApplySkillImprovementsDialogEffectsFollowing")} ${failedSkillNames} `; + htmlContent += ` ${game.i18n.localize( + "DG.Skills.ApplySkillImprovementsDialogEffectsFollowing", + )} ${failedSkillNames} `; htmlContent += `
`; - + new Dialog({ content: htmlContent, - title: game.i18n.translations.DG?.Skills?.ApplySkillImprovements ?? "Apply Skill Improvements", + title: + game.i18n.translations.DG?.Skills?.ApplySkillImprovements ?? + "Apply Skill Improvements", default: "add", buttons: { - apply:{ + apply: { label: game.i18n.translations.DG?.Skills?.Apply ?? "Apply", - callback: btn =>{ - this._applySkillImprovements(baseRollFormula, failedSkills, failedTypedSkills); + callback: (btn) => { + this._applySkillImprovements( + baseRollFormula, + failedSkills, + failedTypedSkills, + ); }, - } - } + }, + }, }).render(true); - }); // Browse Weapon Compendiums - html.find('.weapon-browse').click(ev => { + html.find(".weapon-browse").click((ev) => { const dialog = new Dialog({ title: "Select Compendium", - buttons:{ + buttons: { firearms: { icon: '', - callback: () => game.packs.find(k=>k.collection==="deltagreen.firearms").render(true) + callback: () => + game.packs + .find((k) => k.collection === "deltagreen.firearms") + .render(true), }, melee: { icon: '', - callback: () => game.packs.find(k=>k.collection==="deltagreen.hand-to-hand-weapons").render(true) - } - } + callback: () => + game.packs + .find((k) => k.collection === "deltagreen.hand-to-hand-weapons") + .render(true), + }, + }, }); dialog.render(true); }); - html.find('.armor-browse').click(ev => { - game.packs.find(k=>k.collection==="deltagreen.armor").render(true); + html.find(".armor-browse").click((ev) => { + game.packs.find((k) => k.collection === "deltagreen.armor").render(true); }); - html.find('.gear-browse').click(ev => { - //game.packs.find(k=>k.collection==="deltagreen.firearms").render(true); + html.find(".gear-browse").click((ev) => { + // game.packs.find(k=>k.collection==="deltagreen.firearms").render(true); }); - html.find('.toggle-lethality').click(event => { + html.find(".toggle-lethality").click((event) => { this._toggleLethality(event); }); // let user check off the 'bond damaged' checkbox right from the sheet - html.find('.bond-has-been-damaged-agent-sheet-checkbox').click(ev => { - + html.find(".bond-has-been-damaged-agent-sheet-checkbox").click((ev) => { const el = $(ev.currentTarget).parents(".item"); - const item = this.actor.items.get(el.data('item-id')); - let value = ev.target.checked; - - item.update({["system.hasBeenDamagedSinceLastHomeScene"]: value}); + const item = this.actor.items.get(el.data("item-id")); + const value = ev.target.checked; + item.update({ "system.hasBeenDamagedSinceLastHomeScene": value }); }); - html.find('.clear-all-bond-damage-checks').click(ev => { + html.find(".clear-all-bond-damage-checks").click((ev) => { this._updateBondsRemoveAllDamagedCheckmarks(); }); } // trigger an update on all bonds that have had their damaged flag checked off - async _updateBondsRemoveAllDamagedCheckmarks(){ - for(let i of this.actor.items){ - if(i.type === 'bond' && i.system.hasBeenDamagedSinceLastHomeScene){ - await i.update({["system.hasBeenDamagedSinceLastHomeScene"]: false}); + async _updateBondsRemoveAllDamagedCheckmarks() { + for (const i of this.actor.items) { + if (i.type === "bond" && i.system.hasBeenDamagedSinceLastHomeScene) { + await i.update({ "system.hasBeenDamagedSinceLastHomeScene": false }); } } } @@ -390,156 +438,250 @@ export class DeltaGreenActorSheet extends ActorSheet { const itemId = event.target.getAttribute("item-id"); const isLethal = event.target.getAttribute("is-lethal") === "true"; const item = this.actor.items.find((i) => i.id === itemId); - item.update({"data.isLethal": !isLethal}); - + item.update({ "data.isLethal": !isLethal }); } - _showNewEditTypeSkillDialog(targetSkill, currentLabel, currentGroup){ - + _showNewEditTypeSkillDialog(targetSkill, currentLabel, currentGroup) { // TO DO: BUILD DIALOG TO CAPTURE UPDATED DATA let htmlContent = `
`; - htmlContent += ` `; + htmlContent += ` `; htmlContent += ` `; htmlContent += `
`; htmlContent += `
`; - htmlContent += ` `; + htmlContent += ` `; htmlContent += ` `; htmlContent += `
`; new Dialog({ content: htmlContent, - title: game.i18n.translations.DG?.Skills?.EditTypedOrCustomSkill ?? "Edit Typed or Custom Skill", + title: + game.i18n.translations.DG?.Skills?.EditTypedOrCustomSkill ?? + "Edit Typed or Custom Skill", default: "add", buttons: { - add:{ + add: { label: game.i18n.translations.DG?.Skills?.EditSkill ?? "Edit Skill", - callback: btn =>{ - let newTypeSkillLabel = btn.find("[name='new-type-skill-label']").val(); - let newTypeSkillGroup = btn.find("[name='new-type-skill-group']").val(); - this._updateTypedSkill(targetSkill, newTypeSkillLabel, newTypeSkillGroup); - } - } - } + callback: (btn) => { + const newTypeSkillLabel = btn + .find("[name='new-type-skill-label']") + .val(); + const newTypeSkillGroup = btn + .find("[name='new-type-skill-group']") + .val(); + this._updateTypedSkill( + targetSkill, + newTypeSkillLabel, + newTypeSkillGroup, + ); + }, + }, + }, }).render(true); } - _showNewTypeSkillDialog(targetskill){ + _showNewTypeSkillDialog(targetskill) { let htmlContent = ""; htmlContent += `
`; - htmlContent += ` `; + htmlContent += ` `; htmlContent += ` `; htmlContent += `
`; htmlContent += `
`; - htmlContent += ` `; + htmlContent += ` `; htmlContent += ` `; htmlContent += `
`; new Dialog({ content: htmlContent, - title: game.i18n.translations.DG?.Skills?.AddTypedOrCustomSkill ?? "Add Typed or Custom Skill", + title: + game.i18n.translations.DG?.Skills?.AddTypedOrCustomSkill ?? + "Add Typed or Custom Skill", default: "add", buttons: { - add:{ + add: { label: game.i18n.translations.DG?.Skills?.AddSkill ?? "Add Skill", - callback: btn =>{ - let newTypeSkillLabel = btn.find("[name='new-type-skill-label']").val(); - let newTypeSkillGroup = btn.find("[name='new-type-skill-group']").val(); + callback: (btn) => { + const newTypeSkillLabel = btn + .find("[name='new-type-skill-label']") + .val(); + const newTypeSkillGroup = btn + .find("[name='new-type-skill-group']") + .val(); this._addNewTypedSkill(newTypeSkillLabel, newTypeSkillGroup); }, - } - } + }, + }, }).render(true); } - _addNewTypedSkill(newSkillLabel, newSkillGroup){ - let updatedData = duplicate(this.actor.system); - let typedSkills = updatedData.typedSkills; + _addNewTypedSkill(newSkillLabel, newSkillGroup) { + const updatedData = duplicate(this.actor.system); + const { typedSkills } = updatedData; - let d = new Date(); + const d = new Date(); - let newSkillPropertyName = d.getFullYear().toString() + (d.getMonth() + 1).toString() + d.getDate().toString() + d.getHours().toString() + d.getMinutes().toString() + d.getSeconds().toString(); - //console.log(newSkillPropertyName); - typedSkills[newSkillPropertyName] = {"label": newSkillLabel, "group": newSkillGroup, "proficiency": 10, "failure": false}; + const newSkillPropertyName = + d.getFullYear().toString() + + (d.getMonth() + 1).toString() + + d.getDate().toString() + + d.getHours().toString() + + d.getMinutes().toString() + + d.getSeconds().toString(); + // console.log(newSkillPropertyName); + typedSkills[newSkillPropertyName] = { + label: newSkillLabel, + group: newSkillGroup, + proficiency: 10, + failure: false, + }; updatedData.typedSkills = typedSkills; - this.actor.update({"data": updatedData}); + this.actor.update({ data: updatedData }); } - _updateTypedSkill(targetSkill, newSkillLabel, newSkillGroup){ + _updateTypedSkill(targetSkill, newSkillLabel, newSkillGroup) { + if ( + newSkillLabel !== null && + newSkillLabel !== "" && + (newSkillGroup !== null) & (newSkillGroup !== "") + ) { + const updatedData = duplicate(this.actor.system); - if(newSkillLabel !== null && newSkillLabel !== "" && newSkillGroup !== null & newSkillGroup !== ""){ - let updatedData = duplicate(this.actor.system); - updatedData.typedSkills[targetSkill].label = newSkillLabel; updatedData.typedSkills[targetSkill].group = newSkillGroup; - - this.actor.update({"data": updatedData}); + + this.actor.update({ data: updatedData }); } - } /** @@ -548,46 +690,45 @@ export class DeltaGreenActorSheet extends ActorSheet { * @private */ _onItemCreate(event) { - event.preventDefault(); const header = event.currentTarget; // Get the type of item to create. - const type = header.dataset.type; - + const { type } = header.dataset; + // Initialize a default name. - //const name = `New ${type.capitalize()}`; - const name = game.i18n.localize("DG.ItemTypes.NewPrefix") + game.i18n.localize("DG.ItemTypes." + type) + // const name = `New ${type.capitalize()}`; + const name = + game.i18n.localize("DG.ItemTypes.NewPrefix") + + game.i18n.localize(`DG.ItemTypes.${type}`); // Prepare the item object. const itemData = { - name: name, - type: type, - system: {} + name, + type, + system: {}, }; - if(type == "weapon"){ - //itemData.system.skill = "firearms"; //default skill to firearms, since that will be most common - //itemData.system.expense = "Standard"; - } - else if(type == "armor"){ - //itemData.system.armor = 3; - //itemData.system.expense = "Standard"; - } - else if(type == "bond"){ + if (type == "weapon") { + // itemData.system.skill = "firearms"; //default skill to firearms, since that will be most common + // itemData.system.expense = "Standard"; + } else if (type == "armor") { + // itemData.system.armor = 3; + // itemData.system.expense = "Standard"; + } else if (type == "bond") { // try to default bonds for an agent to their current CHA itemData.system.score = this.object.system.statistics.cha.value; // Can vary, but at character creation starting bond score is usually agent's charisma - //itemData.img = "icons/svg/mystery-man.svg" + // itemData.img = "icons/svg/mystery-man.svg" } - + // create the item return this.actor.createEmbeddedDocuments("Item", [itemData]); } /** * Handle clickable rolls. - * + * * @param {Event} event The originating click event * @async * @private @@ -597,7 +738,7 @@ export class DeltaGreenActorSheet extends ActorSheet { const element = event.currentTarget; const { dataset } = element; - if(event && event.which === 2) { + if (event && event.which === 2) { // probably don't want rolls to trigger from a middle mouse click so just kill it here return; } @@ -607,31 +748,35 @@ export class DeltaGreenActorSheet extends ActorSheet { rollType: dataset.rolltype, key: dataset.key, actor: this.actor, - item - } + item, + }; // Create a default 1d100 roll just in case. let roll = new Roll("1d100", {}); switch (dataset.rolltype) { case "stat": case "skill": - case "sanity": + case "sanity": case "weapon": roll = new DGPercentileRoll("1D100", {}, rollOptions); break; case "lethality": - roll = new DGLethalityRoll("1D100", {}, rollOptions) + roll = new DGLethalityRoll("1D100", {}, rollOptions); break; case "damage": { let diceFormula = item.system.damage; const { skill } = item.system; - if(this.actor.type === 'agent' && (skill === 'unarmed_combat' || skill === 'melee_weapons')){ - diceFormula += this.actor.system.statistics.str.meleeDamageBonusFormula; + if ( + this.actor.type === "agent" && + (skill === "unarmed_combat" || skill === "melee_weapons") + ) { + diceFormula += + this.actor.system.statistics.str.meleeDamageBonusFormula; } - roll = new DGDamageRoll(diceFormula, {}, rollOptions) + roll = new DGDamageRoll(diceFormula, {}, rollOptions); break; } - case "sanity-damage":{ + case "sanity-damage": { const { successLoss, failedLoss } = this.actor.system.sanity; const combinedFormula = `{${successLoss}, ${failedLoss}}`; roll = new DGSanityDamageRoll(combinedFormula, {}, rollOptions); @@ -640,25 +785,28 @@ export class DeltaGreenActorSheet extends ActorSheet { default: break; } - return this.processRoll(event, roll, rollOptions) + return this.processRoll(event, roll, rollOptions); } /** * Show a dialog for the roll and then send to chat. * Broke this logic out from `_onRoll()` so that other files can call it, * namely the macro logic. - * + * * @param {Event} event The originating click event * @param {Event} roll The roll to show a dialog for and then send to chat. * @async */ async processRoll(event, roll) { // Open dialog if user requests it (no dialog for Sanity Damage rolls) - if ((event.shiftKey || event.which === 3) && !(roll instanceof DGSanityDamageRoll)) { + if ( + (event.shiftKey || event.which === 3) && + !(roll instanceof DGSanityDamageRoll) + ) { const dialogData = await roll.showDialog(); if (!dialogData) return; if (dialogData.newFormula) { - roll = new DGDamageRoll(dialogData.newFormula, {}, roll.options) + roll = new DGDamageRoll(dialogData.newFormula, {}, roll.options); } roll.modifier += dialogData.targetModifier; roll.options.rollMode = dialogData.rollMode; @@ -669,47 +817,51 @@ export class DeltaGreenActorSheet extends ActorSheet { return roll.toChat(); } - _resetBreakingPoint(event){ + _resetBreakingPoint(event) { event.preventDefault(); let currentBreakingPoint = 0; - - currentBreakingPoint = this.actor.system.sanity.value - this.actor.system.statistics.pow.value; - if(currentBreakingPoint < 0){ + currentBreakingPoint = + this.actor.system.sanity.value - this.actor.system.statistics.pow.value; + + if (currentBreakingPoint < 0) { currentBreakingPoint = 0; } - - let updatedData = duplicate(this.actor.system); + + const updatedData = duplicate(this.actor.system); updatedData.sanity.currentBreakingPoint = currentBreakingPoint; - this.actor.update({"data": updatedData}); + this.actor.update({ data: updatedData }); } _onEquippedStatusChange(event) { event.preventDefault(); const element = event.currentTarget; - const dataset = element.dataset; + const { dataset } = element; - try{ - //const item = this.actor.getOwnedItem(dataset.id); + try { + // const item = this.actor.getOwnedItem(dataset.id); const item = this.actor.items.get(dataset.id); - var isEquipped = item.system.equipped; + let isEquipped = item.system.equipped; isEquipped = !isEquipped; - item.update({data:{equipped: isEquipped}}); - } - catch(ex){ + item.update({ data: { equipped: isEquipped } }); + } catch (ex) { console.log(ex); } } // For any skills a user has checked off as failed, roll the improvement and update the agent's skills to their new values - async _applySkillImprovements(baseRollFormula, failedSkills, failedTypedSkills) { + async _applySkillImprovements( + baseRollFormula, + failedSkills, + failedTypedSkills, + ) { const actorData = this.actor.system; const resultList = []; let rollFormula; - + // Define the amount of dice being rolled, if any. switch (baseRollFormula) { case "1": @@ -728,97 +880,122 @@ export class DeltaGreenActorSheet extends ActorSheet { let roll; if (rollFormula !== 1) { roll = new Roll(rollFormula, actorData); - roll.evaluate({async: true}); + roll.evaluate({ async: true }); // Put the results into a list. - roll.terms[0].results.forEach((result) => resultList.push(baseRollFormula === "1d4-1" ? result.result - 1 : result.result)); + roll.terms[0].results.forEach((result) => + resultList.push( + baseRollFormula === "1d4-1" ? result.result - 1 : result.result, + ), + ); } // This will be end up being a list of skills and how much each were improved by. It gets modified in the following loops. let improvedSkillList = ""; - + // Get copy of current system data, will update this and then apply all changes at once synchronously at the end. const updatedData = duplicate(actorData); failedSkills.forEach(([skill], value) => { - updatedData.skills[skill].proficiency += resultList[value] ?? 1; // Increase proficiency by die result or by 1 if there is no dice roll. updatedData.skills[skill].failure = false; // So we can record the regular skills improved and how much they were increased by in chat. // The if statement tells us whether to add a comma before the term or not. if (value === 0) { - improvedSkillList += `${game.i18n.localize("DG.Skills." + skill)}: +${resultList[value] ?? 1}%`; + improvedSkillList += `${game.i18n.localize( + `DG.Skills.${skill}`, + )}: +${resultList[value] ?? 1}%`; } else { - improvedSkillList += `, ${game.i18n.localize("DG.Skills." + skill)}: +${resultList[value] ?? 1}%`; + improvedSkillList += `, ${game.i18n.localize( + `DG.Skills.${skill}`, + )}: +${resultList[value] ?? 1}%`; } - }) + }); failedTypedSkills.forEach(([skillName, skillData], value) => { // We must increase value in the following line by the length of failedSkills, so that we index the entire resultList. // Otherwise we would be adding the same die results to regular skills and typed skills. - updatedData.typedSkills[skillName].proficiency += resultList[value + failedSkills.length] ?? 1; + updatedData.typedSkills[skillName].proficiency += + resultList[value + failedSkills.length] ?? 1; updatedData.typedSkills[skillName].failure = false; // So we can record the typed skills improved and how much they were increased by in chat. // The if statement tells us whether to add a comma before the term or not. if (value === 0 && improvedSkillList === "") { - improvedSkillList += `${game.i18n.localize("DG.TypeSkills." + skillData.group.split(" ").join(""))} (${skillData.label}): +${resultList[value + failedSkills.length] ?? 1}%`; + improvedSkillList += `${game.i18n.localize( + `DG.TypeSkills.${skillData.group.split(" ").join("")}`, + )} (${skillData.label}): +${ + resultList[value + failedSkills.length] ?? 1 + }%`; } else { - improvedSkillList += `, ${game.i18n.localize("DG.TypeSkills." + skillData.group.split(" ").join(""))} (${skillData.label}): +${resultList[value + failedSkills.length] ?? 1}%`; + improvedSkillList += `, ${game.i18n.localize( + `DG.TypeSkills.${skillData.group.split(" ").join("")}`, + )} (${skillData.label}): +${ + resultList[value + failedSkills.length] ?? 1 + }%`; } - }) + }); // Probably not worth triggering the update if the user didn't pick any skills - if (improvedSkillList !== ""){ - await this.actor.update({"system": updatedData}); - } + if (improvedSkillList !== "") { + await this.actor.update({ system: updatedData }); + } let html; - html = `
` - html += `
${improvedSkillList}
` - html += `
` + html = `
`; + html += `
${improvedSkillList}
`; + html += `
`; const chatData = { - speaker: ChatMessage.getSpeaker({actor: this.actor, token: this.token, alias: this.actor.name}), + speaker: ChatMessage.getSpeaker({ + actor: this.actor, + token: this.token, + alias: this.actor.name, + }), content: html, - flavor: `${game.i18n.localize("DG.Skills.ApplySkillImprovementsChatFlavor")} +${baseRollFormula}%:`, + flavor: `${game.i18n.localize( + "DG.Skills.ApplySkillImprovementsChatFlavor", + )} +${baseRollFormula}%:`, type: baseRollFormula === "1" ? 0 : 5, // 0 = CHAT_MESSAGE_TYPES.OTHER, 5 = CHAT_MESSAGE_TYPES.ROLL rolls: baseRollFormula === "1" ? [] : [roll], // If adding flat +1, there is no roll. - rollMode: game.settings.get("core", "rollMode") - }; - - // play the dice rolling sound, like a regular in-chat roll - if (roll) AudioHelper.play({src: "sounds/dice.wav", volume: 0.8, autoplay: true, loop: false}, true); - - ChatMessage.create(chatData, {}); + rollMode: game.settings.get("core", "rollMode"), + }; + // play the dice rolling sound, like a regular in-chat roll + if (roll) + AudioHelper.play( + { src: "sounds/dice.wav", volume: 0.8, autoplay: true, loop: false }, + true, + ); + + ChatMessage.create(chatData, {}); } /** @override */ _onDragStart(event) { // Most of this is the standard Foundry implementation of _onDragStart const li = event.currentTarget; - if ( event.target.classList.contains("content-link") ) return; + if (event.target.classList.contains("content-link")) return; // Create drag data let dragData; // Owned Items - if ( li.dataset.itemId ) { + if (li.dataset.itemId) { const item = this.actor.items.get(li.dataset.itemId); dragData = item.toDragData(); } // Active Effect - if ( li.dataset.effectId ) { + if (li.dataset.effectId) { const effect = this.actor.effects.get(li.dataset.effectId); dragData = effect.toDragData(); } - if ( !dragData ) return; + if (!dragData) return; // this is custom, grab item data for creating item macros on the hotbar - if ( li.dataset.itemId ) { + if (li.dataset.itemId) { const item = this.actor.items.get(li.dataset.itemId); dragData.itemData = item; } @@ -828,7 +1005,7 @@ export class DeltaGreenActorSheet extends ActorSheet { } /** @override */ - async _onDrop(event){ + async _onDrop(event) { super._onDrop(event); // If alt key is held down, we will delete the original document. if (event.altKey) { @@ -837,7 +1014,7 @@ export class DeltaGreenActorSheet extends ActorSheet { // Make sure that we are dragging an item, otherwise this doesn't make sense. if (dragData.type === "Item") { const item = fromUuidSync(dragData.uuid); - await item.delete() + await item.delete(); } } } @@ -847,4 +1024,3 @@ export class DeltaGreenActorSheet extends ActorSheet { return super.activateEditor(target, editorOptions, initialContent); } } - diff --git a/module/actor/actor.js b/module/actor/actor.js index 2efe8f9..ba84d40 100644 --- a/module/actor/actor.js +++ b/module/actor/actor.js @@ -3,7 +3,6 @@ * @extends {Actor} */ export class DeltaGreenActor extends Actor { - /** * Augment the basic actor data with additional dynamic data. */ @@ -11,41 +10,38 @@ export class DeltaGreenActor extends Actor { super.prepareData(); const actorData = this; - const system = actorData.system; - const flags = actorData.flags; + const { system } = actorData; + const { flags } = actorData; - //console.log('actor.js prepareData'); - //console.log(this); + // console.log('actor.js prepareData'); + // console.log(this); // Make separate methods for each Actor type (character, npc, etc.) to keep // things organized. - if (actorData.type === 'agent'){ + if (actorData.type === "agent") { this._prepareAgentData(this); - } - else if(actorData.type === 'unnatural'){ + } else if (actorData.type === "unnatural") { this._prepareUnnaturalData(this); - } - else if(actorData.type === 'npc'){ + } else if (actorData.type === "npc") { this._prepareNpcData(this); - } - else if(actorData.type === 'vehicle'){ + } else if (actorData.type === "vehicle") { this._prepareVehicleData(this); } } /** - * - * @param {*} agent + * + * @param {*} agent */ - _prepareVehicleData(actor){ - let actorData = actor; + _prepareVehicleData(actor) { + const actorData = actor; - // calculate total armor rating + // calculate total armor rating let protection = 0; - for (let i of actor.items) { - if (i.type === 'armor') { - if(i.system.equipped === true){ + for (const i of actor.items) { + if (i.type === "armor") { + if (i.system.equipped === true) { protection += i.system.protection; } } @@ -56,74 +52,76 @@ export class DeltaGreenActor extends Actor { console.log(actor); } - _prepareNpcData(actor){ - const { system } = actor; - - // Loop through ability scores, and add their modifiers to our sheet output. - for (let [key, statistic] of Object.entries(system.statistics)) { - // the x5 is just whatever the raw statistic is x 5 to turn it into a d100 percentile - statistic.x5 = statistic.value * 5; - } - - // initialize sanity, don't set these afterwards, as they need to be manually edited - if(system.sanity.value >= 100){ - system.sanity.value = system.statistics.pow.x5 - system.sanity.currentBreakingPoint = system.sanity.value - system.statistics.pow.value; - }; - - system.sanity.max = 99 - system.skills.unnatural.proficiency; - - system.wp.max = system.statistics.pow.value; - - system.health.max = Math.ceil((system.statistics.con.value + system.statistics.str.value) / 2); - - system.skills.ritual = { - label: "Ritual", - proficiency: 99 - system.sanity.value, - cannotBeImprovedByFailure: true, - failure: false - }; - - if(system.skills.ritual.proficiency > 99){ - system.skills.ritual.proficiency = 99 - } - else if(system.skills.ritual.proficiency < 1){ - system.skills.ritual.proficiency = 1 - } - - // calculate total armor rating - let protection = 0; - for (let i of actor.items) { - if (i.type === 'armor') { - if(i.system.equipped === true){ - protection += i.system.protection; - } - } - } - - system.health.protection = protection; - - console.log(actor); -} - - /** - * - * @param {*} agent - */ - _prepareUnnaturalData(actor){ + _prepareNpcData(actor) { const { system } = actor; // Loop through ability scores, and add their modifiers to our sheet output. - for (let [key, statistic] of Object.entries(system.statistics)) { + for (const [key, statistic] of Object.entries(system.statistics)) { + // the x5 is just whatever the raw statistic is x 5 to turn it into a d100 percentile + statistic.x5 = statistic.value * 5; + } + + // initialize sanity, don't set these afterwards, as they need to be manually edited + if (system.sanity.value >= 100) { + system.sanity.value = system.statistics.pow.x5; + system.sanity.currentBreakingPoint = + system.sanity.value - system.statistics.pow.value; + } + + system.sanity.max = 99 - system.skills.unnatural.proficiency; + + system.wp.max = system.statistics.pow.value; + + system.health.max = Math.ceil( + (system.statistics.con.value + system.statistics.str.value) / 2, + ); + + system.skills.ritual = { + label: "Ritual", + proficiency: 99 - system.sanity.value, + cannotBeImprovedByFailure: true, + failure: false, + }; + + if (system.skills.ritual.proficiency > 99) { + system.skills.ritual.proficiency = 99; + } else if (system.skills.ritual.proficiency < 1) { + system.skills.ritual.proficiency = 1; + } + + // calculate total armor rating + let protection = 0; + for (const i of actor.items) { + if (i.type === "armor") { + if (i.system.equipped === true) { + protection += i.system.protection; + } + } + } + + system.health.protection = protection; + + console.log(actor); + } + + /** + * + * @param {*} agent + */ + _prepareUnnaturalData(actor) { + const { system } = actor; + + // Loop through ability scores, and add their modifiers to our sheet output. + for (const [key, statistic] of Object.entries(system.statistics)) { // the x5 is just whatever the raw statistic is x 5 to turn it into a d100 percentile statistic.x5 = statistic.value * 5; } // calculate total armor rating let protection = 0; - for (let i of actor.items) { - if (i.type === 'armor') { - if(i.system.equipped === true){ + for (const i of actor.items) { + if (i.type === "armor") { + if (i.system.equipped === true) { protection += i.system.protection; } } @@ -138,94 +136,96 @@ export class DeltaGreenActor extends Actor { * Prepare Agent type specific data */ _prepareAgentData(agent) { - const { system } = agent; // Make modifications to data here. For example: // Loop through ability scores, and add their modifiers to our sheet output. - for (let [key, statistic] of Object.entries(system.statistics)) { + for (const [key, statistic] of Object.entries(system.statistics)) { // the x5 is just whatever the raw statistic is x 5 to turn it into a d100 percentile statistic.x5 = statistic.value * 5; } - + // The ritual skill is from the Handler's Guide, it is for activating a ritual and is always equal to 99 - current sanity. // The rules can be found on page 166, under 'Ritual Activation'. system.skills.ritual = { label: "Ritual", proficiency: 99 - system.sanity.value, cannotBeImprovedByFailure: true, - failure: false + failure: false, }; - if(system.skills.ritual.proficiency > 99){ - system.skills.ritual.proficiency = 99 - } - else if(system.skills.ritual.proficiency < 1){ - system.skills.ritual.proficiency = 1 + if (system.skills.ritual.proficiency > 99) { + system.skills.ritual.proficiency = 99; + } else if (system.skills.ritual.proficiency < 1) { + system.skills.ritual.proficiency = 1; } // The unnatural skill is sort of special // It cannot be improved via failure, so add in a special property to reflect this // Mostly to make it easy to deactivate the failure checkbox in the GUI - for (let [key, skill] of Object.entries(system.skills)){ - if(key === 'unnatural'){ + for (const [key, skill] of Object.entries(system.skills)) { + if (key === "unnatural") { skill.cannotBeImprovedByFailure = true; - } - else if(key === 'luck'){ + } else if (key === "luck") { skill.cannotBeImprovedByFailure = true; - } - else if(key === 'ritual'){ + } else if (key === "ritual") { skill.cannotBeImprovedByFailure = true; - } - else{ + } else { skill.cannotBeImprovedByFailure = false; } // For ritual skill, it's calculated, so add some logic to turn off changing that entirely. - if(key === 'ritual'){ + if (key === "ritual") { skill.isCalculatedValue = true; - } - else{ + } else { skill.isCalculatedValue = false; } } system.wp.max = system.statistics.pow.value; - system.health.max = Math.ceil((system.statistics.con.value + system.statistics.str.value) / 2); + system.health.max = Math.ceil( + (system.statistics.con.value + system.statistics.str.value) / 2, + ); // initialize sanity, don't set these afterwards, as they need to be manually edited - if(system.sanity.value >= 100){ - system.sanity.value = system.statistics.pow.x5 - system.sanity.currentBreakingPoint = system.sanity.value - system.statistics.pow.value; - }; + if (system.sanity.value >= 100) { + system.sanity.value = system.statistics.pow.x5; + system.sanity.currentBreakingPoint = + system.sanity.value - system.statistics.pow.value; + } system.sanity.max = 99 - system.skills.unnatural.proficiency; - // Sanity Loss Adaptations Logic - let adaptations = system.sanity.adaptations; + const { adaptations } = system.sanity; - if (adaptations.violence.incident1 && adaptations.violence.incident2 && adaptations.violence.incident3){ + if ( + adaptations.violence.incident1 && + adaptations.violence.incident2 && + adaptations.violence.incident3 + ) { system.sanity.adaptations.violence.isAdapted = true; - } - else{ + } else { system.sanity.adaptations.violence.isAdapted = false; } - if (adaptations.helplessness.incident1 && adaptations.helplessness.incident2 && adaptations.helplessness.incident3){ + if ( + adaptations.helplessness.incident1 && + adaptations.helplessness.incident2 && + adaptations.helplessness.incident3 + ) { system.sanity.adaptations.helplessness.isAdapted = true; - } - else{ + } else { system.sanity.adaptations.helplessness.isAdapted = false; } // calculate total armor rating let protection = 0; - for (let i of agent.items) { - if (i.type === 'armor') { - if(i.system.equipped === true){ + for (const i of agent.items) { + if (i.type === "armor") { + if (i.system.equipped === true) { protection += i.system.protection; } } @@ -236,25 +236,22 @@ export class DeltaGreenActor extends Actor { // Damage Bonus/Malus From Strength in Hand-to-hand Combat (melee/unarmed) let bonus = 0; let sbonus = ""; - let strength = system.statistics.str; + const strength = system.statistics.str; - if(strength.value < 5){ + if (strength.value < 5) { sbonus = "-2"; bonus = -2; - } - else if(strength.value < 9){ + } else if (strength.value < 9) { sbonus = "-1"; bonus = -1; - } - else if(strength.value > 12 && strength.value < 17){ + } else if (strength.value > 12 && strength.value < 17) { sbonus = "+1"; bonus = 1; - } - else if(strength.value > 16){ + } else if (strength.value > 16) { sbonus = "+2"; bonus = 2; } - + system.statistics.str.meleeDamageBonus = bonus; system.statistics.str.meleeDamageBonusFormula = sbonus; @@ -262,95 +259,98 @@ export class DeltaGreenActor extends Actor { } /** @override */ - static async create(data, options={}) { + static async create(data, options = {}) { data.prototypeToken = data.prototypeToken || {}; - if ( data.type === "agent" ) { - mergeObject(data.prototypeToken, { - actorLink: true // this will make the 'Link Actor Data' option for a token is checked by default. So changes to the token sheet will reflect to the actor sheet. - }, {overwrite: false}); + if (data.type === "agent") { + mergeObject( + data.prototypeToken, + { + actorLink: true, // this will make the 'Link Actor Data' option for a token is checked by default. So changes to the token sheet will reflect to the actor sheet. + }, + { overwrite: false }, + ); } return super.create(data, options); } - async AddUnarmedAttackItemIfMissing(){ - try{ - + async AddUnarmedAttackItemIfMissing() { + try { let alreadyAdded = false; - for(let item of this.items){ - - let flag = await item.getFlag('deltagreen', 'SystemName'); + for (const item of this.items) { + const flag = await item.getFlag("deltagreen", "SystemName"); - if(flag === 'unarmed-attack' || item.name === 'Unarmed Attack'){ + if (flag === "unarmed-attack" || item.name === "Unarmed Attack") { alreadyAdded = true; break; } - } - if(alreadyAdded === true){ return; }; + if (alreadyAdded === true) { + return; + } - let handToHandPack = await game.packs.get('deltagreen.hand-to-hand-weapons'); - let itemIndex = await handToHandPack.getIndex(); - let toAdd = []; // createEmbeddedDocument expects an array + const handToHandPack = await game.packs.get( + "deltagreen.hand-to-hand-weapons", + ); + const itemIndex = await handToHandPack.getIndex(); + const toAdd = []; // createEmbeddedDocument expects an array - for(let idx of itemIndex){ - let _temp = await handToHandPack.getDocument(idx._id); - - if(_temp.name === 'Unarmed Attack'){ + for (const idx of itemIndex) { + const _temp = await handToHandPack.getDocument(idx._id); + + if (_temp.name === "Unarmed Attack") { toAdd.push(_temp); - } - } - - let newItems = await this.createEmbeddedDocuments("Item", toAdd); - - for(let item of newItems){ - await item.setFlag('deltagreen','AutoAdded', true); - - if(item.name === 'Unarmed Attack'){ - await item.setFlag('deltagreen','SystemName', 'unarmed-attack'); } } - } - catch(ex){ - console.log('Error adding unarmed strike item to Actor.') + + const newItems = await this.createEmbeddedDocuments("Item", toAdd); + + for (const item of newItems) { + await item.setFlag("deltagreen", "AutoAdded", true); + + if (item.name === "Unarmed Attack") { + await item.setFlag("deltagreen", "SystemName", "unarmed-attack"); + } + } + } catch (ex) { + console.log("Error adding unarmed strike item to Actor."); console.log(ex); } } - async AddBaseVehicleItemsIfMissing(){ - try{ - let flag = await this.getFlag('deltagreen', 'DefaultVehicleArmorAdded'); + async AddBaseVehicleItemsIfMissing() { + try { + const flag = await this.getFlag("deltagreen", "DefaultVehicleArmorAdded"); - if(flag !== null && flag !== undefined && flag !== true){ - console.log('found a flag'); + if (flag !== null && flag !== undefined && flag !== true) { + console.log("found a flag"); console.log(flag); - } - else{ + } else { // mark the actor so that we don't accidently do this again later, or if we want to fix/change something on it in the future - this.setFlag('deltagreen', 'DefaultVehicleArmorAdded', true); - - let toAdd = []; // createEmbeddedDocument expects an array + this.setFlag("deltagreen", "DefaultVehicleArmorAdded", true); - let armor = await Item.create({type:"armor", name:"Vehicle Frame"}); + const toAdd = []; // createEmbeddedDocument expects an array + + const armor = await Item.create({ + type: "armor", + name: "Vehicle Frame", + }); // this is the current default, but set it anyways in case it gets changed later. armor.system.protection = 3; toAdd.push(armor); - - // create the item on the actor - let newItems = await this.createEmbeddedDocuments("Item", toAdd); - - for(let item of newItems){ - await item.setFlag('deltagreen','AutoAdded', true); - } + // create the item on the actor + const newItems = await this.createEmbeddedDocuments("Item", toAdd); + + for (const item of newItems) { + await item.setFlag("deltagreen", "AutoAdded", true); + } } - } - catch(ex){ + } catch (ex) { console.log(ex); } } - -} \ No newline at end of file +} diff --git a/module/deltagreen.js b/module/deltagreen.js index 4159a63..367b531 100644 --- a/module/deltagreen.js +++ b/module/deltagreen.js @@ -6,20 +6,19 @@ import { DeltaGreenActorSheet } from "./actor/actor-sheet.js"; import { DeltaGreenItem } from "./item/item.js"; import { DeltaGreenItemSheet } from "./item/item-sheet.js"; import * as DGRolls from "./roll/roll.js"; -import { registerSystemSettings } from "./settings.js" +import { registerSystemSettings } from "./settings.js"; import { preloadHandlebarsTemplates } from "./templates.js"; import { ParseDeltaGreenStatBlock } from "./other/stat-parser-macro.js"; import DGUtils from "./other/utility-functions.js"; -Hooks.once('init', async function() { - +Hooks.once("init", async function () { game.deltagreen = { DeltaGreenActor, DeltaGreenItem, rollItemMacro, rollItemSkillCheckMacro, rollSkillMacro, - ParseDeltaGreenStatBlock + ParseDeltaGreenStatBlock, }; /** @@ -28,11 +27,11 @@ Hooks.once('init', async function() { */ CONFIG.Combat.initiative = { formula: "@statistics.dex.value", - decimals: 0 + decimals: 0, }; // Register custom dice rolls - Object.values(DGRolls).forEach((cls) => CONFIG.Dice.rolls.push(cls)) + Object.values(DGRolls).forEach((cls) => CONFIG.Dice.rolls.push(cls)); // Register System Settings registerSystemSettings(); @@ -44,28 +43,33 @@ Hooks.once('init', async function() { // Register sheet application classes Actors.unregisterSheet("core", ActorSheet); Items.unregisterSheet("core", ItemSheet); - Actors.registerSheet("deltagreen", DeltaGreenActorSheet, { makeDefault: true }); + Actors.registerSheet("deltagreen", DeltaGreenActorSheet, { + makeDefault: true, + }); Items.registerSheet("deltagreen", DeltaGreenItemSheet, { makeDefault: true }); - + // Preload Handlebars Templates preloadHandlebarsTemplates(); // Add Handlebars helpers - Handlebars.registerHelper('localizeWithFallback', function(value, fallbackValue) { - return DGUtils.localizeWithFallback(value, fallbackValue); - }); + Handlebars.registerHelper( + "localizeWithFallback", + function (value, fallbackValue) { + return DGUtils.localizeWithFallback(value, fallbackValue); + }, + ); - Handlebars.registerHelper('concat', function() { - var outStr = ''; - for (var arg in arguments) { - if (typeof arguments[arg] != 'object') { + Handlebars.registerHelper("concat", function () { + let outStr = ""; + for (let arg in arguments) { + if (typeof arguments[arg] !== "object") { outStr += arguments[arg]; } } return outStr; }); - Handlebars.registerHelper('toLowerCase', function(str) { + Handlebars.registerHelper("toLowerCase", function (str) { try { return str.toLowerCase(); } catch (error) { @@ -73,7 +77,7 @@ Hooks.once('init', async function() { } }); - Handlebars.registerHelper('toUpperCase', function(str) { + Handlebars.registerHelper("toUpperCase", function (str) { try { return str.toUpperCase(); } catch (error) { @@ -81,62 +85,62 @@ Hooks.once('init', async function() { } }); - Handlebars.registerHelper('if_eq', function(a, b, opts) { + Handlebars.registerHelper("if_eq", function (a, b, opts) { if (a == b) { - return opts.fn(this); + return opts.fn(this); } else { - return opts.inverse(this); + return opts.inverse(this); } }); - Handlebars.registerHelper('if_not_eq', function(a, b, opts) { - if (a != b) { return opts.fn(this); } + Handlebars.registerHelper("if_not_eq", function (a, b, opts) { + if (a != b) { + return opts.fn(this); + } return opts.inverse(this); }); - Handlebars.registerHelper('if_gt', function(a, b, trueVal, falseVal) { + Handlebars.registerHelper("if_gt", function (a, b, trueVal, falseVal) { if (a > b) { - return trueVal; + return trueVal; } else { - return falseVal; + return falseVal; } }); - Handlebars.registerHelper('cite_ahb', function(page) { + Handlebars.registerHelper("cite_ahb", function (page) { return `See page ${page} of the Agent's Handbook.`; }); - Handlebars.registerHelper('formatLethality', function(lethality) { + Handlebars.registerHelper("formatLethality", function (lethality) { if (lethality > 0) { - return lethality.toString() + "%"; - } - else { + return `${lethality.toString() }%`; + } else { return ""; } }); - // Is this used anywhere? - Handlebars.registerHelper('getActorSkillProp', function(actorData, skillName, prop) { - try{ - if(skillName != "" && prop != ""){ - let skills = actorData.data.skills; - let skill = skills[skillName]; - let propVal = skill[prop]; - return propVal; - } - else{ + Handlebars.registerHelper( + "getActorSkillProp", + function (actorData, skillName, prop) { + try { + if (skillName != "" && prop != "") { + const skills = actorData.data.skills; + let skill = skills[skillName]; + const propVal = skill[prop]; + return propVal; + } else { + return ""; + } + } catch (ex) { + console.log(ex); return ""; } - } - catch(ex){ - console.log(ex); - return ""; - } - - }); + }, + ); - Handlebars.registerHelper('getAvailableRollModes', function() { + Handlebars.registerHelper("getAvailableRollModes", function () { try { return CONFIG.Dice.rollModes; } catch (error) { @@ -144,7 +148,7 @@ Hooks.once('init', async function() { } }); - Handlebars.registerHelper('getDefaultRollMode', function() { + Handlebars.registerHelper("getDefaultRollMode", function () { try { return game.settings.get("core", "rollMode"); } catch (error) { @@ -152,44 +156,41 @@ Hooks.once('init', async function() { } }); - Handlebars.registerHelper('calculateHandToHandCombatDamageFormulaBonus', function(strength) { - try { - let bonus = ""; + Handlebars.registerHelper( + "calculateHandToHandCombatDamageFormulaBonus", + function (strength) { + try { + let bonus = ""; - if(strength.value < 5){ - bonus = " - 2"; - } - else if(strength.value < 9){ - bonus = " - 1"; - } - else if(strength.value > 12 && strength < 17){ - bonus = " + 1"; - } - else if(strength.value > 16){ - bonus = " + 2"; - } - - return bonus; + if (strength.value < 5) { + bonus = " - 2"; + } else if (strength.value < 9) { + bonus = " - 1"; + } else if (strength.value > 12 && strength < 17) { + bonus = " + 1"; + } else if (strength.value > 16) { + bonus = " + 2"; + } - } catch (error) { - console.log(error); - } - }); + return bonus; + } catch (error) { + console.log(error); + } + }, + ); - Handlebars.registerHelper('localizeWeaponSkill', function(skill) { + Handlebars.registerHelper("localizeWeaponSkill", function (skill) { let label = skill; try { - - if(skill === 'dex'){ + if (skill === "dex") { label = game.i18n.localize("DG.Attributes.dex"); } - if(skill === 'DG.Skills.custom'){ - label = game.i18n.localize('DG.ItemWindow.Custom'); + if (skill === "DG.Skills.custom") { + label = game.i18n.localize("DG.ItemWindow.Custom"); + } else { + label = game.i18n.localize(`DG.Skills.${ skill}`); } - else{ - label = game.i18n.localize("DG.Skills." + skill); - } } catch (error) { console.log(error); } @@ -197,37 +198,37 @@ Hooks.once('init', async function() { return label; }); - Handlebars.registerHelper('hideSkillBasedOnProficiencyAndUserChoice', function(hideUntrainedSkills, proficiency) { - let showValue = true; + Handlebars.registerHelper( + "hideSkillBasedOnProficiencyAndUserChoice", + function (hideUntrainedSkills, proficiency) { + let showValue = true; - try { - - if(hideUntrainedSkills === false){ - showValue = true; - } - else{ - if(proficiency > 0){ + try { + if (hideUntrainedSkills === false) { showValue = true; + } else { + if (proficiency > 0) { + showValue = true; + } else { + showValue = false; + } } - else{ - showValue = false; - } - } - } catch (error) { - console.log(error); - } + } catch (error) { + console.log(error); + } - return showValue; + return showValue; + }, + ); - }); - - // looks at system setting for what font to use and returns the class that is then used in the handlebars template that + // looks at system setting for what font to use and returns the class that is then used in the handlebars template that // generates the character sheet. - Handlebars.registerHelper('getFontFamilySystemSettingClass', function() { - let setting = game.settings.get("deltagreen", "characterSheetFont"); + Handlebars.registerHelper("getFontFamilySystemSettingClass", function () { + const setting = game.settings.get("deltagreen", "characterSheetFont"); + + const characterSheetStyle = game.settings.get("deltagreen", "characterSheetStyle"); + ); - let characterSheetStyle = game.settings.get("deltagreen", "characterSheetStyle"); - /* if(setting === "TypeWriterCondensed"){ return "typewriter-condensed-font"; @@ -251,7 +252,7 @@ Hooks.once('init', async function() { return "martel-font"; } */ - + /* if(characterSheetStyle === "cowboy"){ return "special-elite-font"; @@ -262,35 +263,29 @@ Hooks.once('init', async function() { */ }); - Handlebars.registerHelper('getCharacterSheetStyle', function() { + Handlebars.registerHelper("getCharacterSheetStyle", function () { + const characterSheetStyle = game.settings.get("deltagreen", "characterSheetStyle"); + ); - let characterSheetStyle = game.settings.get("deltagreen", "characterSheetStyle"); - - if(characterSheetStyle === "cowboy"){ + if (characterSheetStyle === "cowboy") { return "cowboy-style"; - } - else if(characterSheetStyle === "outlaw"){ + } else if (characterSheetStyle === "outlaw") { return "outlaw-style"; - } - else{ + } else { return "program-style"; } - }); - Handlebars.registerHelper('keepSanityPrivate', function() { - + Handlebars.registerHelper("keepSanityPrivate", function () { let setting = false; - try{ + try { setting = game.settings.get("deltagreen", "keepSanityPrivate"); - if(game.user.isGM){ + if (game.user.isGM) { setting = false; } - - } - catch(ex){ + } catch (ex) { setting = false; } @@ -298,37 +293,34 @@ Hooks.once('init', async function() { }); }); -Handlebars.registerHelper('playerHasGamemasterPrivileges', function(){ +Handlebars.registerHelper("playerHasGamemasterPrivileges", function () { return game.user.isGM; }); -Handlebars.registerHelper('showImpossibleLandscapesContent', function() { - +Handlebars.registerHelper("showImpossibleLandscapesContent", function () { let result = false; - let setting = game.settings.get("deltagreen", "showImpossibleLandscapesContent"); + const setting = game.settings.get("deltagreen", "showImpossibleLandscapesContent"); - if(game.user.isGM === true && setting === true){ + if (game.user.isGM === true && setting === true) { result = true; } - - return result + + return result; }); -Hooks.once("ready", async function() { +Hooks.once("ready", async function () { // Wait to register hotbar drop hook on ready so that modules could register earlier if they want to - Hooks.on("hotbarDrop", (bar, data, slot) => createDeltaGreenMacro(data, slot)); + Hooks.on("hotbarDrop", (bar, data, slot) => + createDeltaGreenMacro(data, slot), + ); }); -Hooks.on("ready", ()=> { - - //let backgroundImageSetting = game.settings.get("deltagreen", "characterSheetBackgroundImageSetting"); - //let characterSheetStyle = game.settings.get("deltagreen", "characterSheetStyle"); - +Hooks.on("ready", () => { + // let backgroundImageSetting = game.settings.get("deltagreen", "characterSheetBackgroundImageSetting"); + // let characterSheetStyle = game.settings.get("deltagreen", "characterSheetStyle"); //let customCss = ""; - - //let customStyle = document.createElement("style"); - //customStyle.id = "dg-custom-css"; - + // let customStyle = document.createElement("style"); + // customStyle.id = "dg-custom-css"; /* if(backgroundImageSetting === "OldPaper1"){ customCss += `div.deltagreen.sheet.actor section.window-content{ @@ -341,7 +333,6 @@ Hooks.on("ready", ()=> { }`; } */ - /* if(characterSheetStyle === "cowboy"){ customCss += `div.deltagreen.sheet.actor section.window-content{ @@ -360,7 +351,6 @@ Hooks.on("ready", ()=> { //document.querySelector("head").appendChild(customStyle); } */ - }); Hooks.on("preCreateItem", (item) => { @@ -368,68 +358,62 @@ Hooks.on("preCreateItem", (item) => { console.log(item.img); console.log(item.type); - if(item.img === 'icons/svg/item-bag.svg'){ - - if(item.type === 'bond'){ - item.updateSource({ img: 'systems/deltagreen/assets/icons/person-black-bg.svg'}); - } - else{ - item.updateSource({ img: 'systems/deltagreen/assets/icons/swap-bag-black-bg.svg'}); + if (item.img === "icons/svg/item-bag.svg") { + if (item.type === "bond") { + item.updateSource({ + img: "systems/deltagreen/assets/icons/person-black-bg.svg", + }); + } else { + item.updateSource({ + img: "systems/deltagreen/assets/icons/swap-bag-black-bg.svg", + }); } } - }); Hooks.on("renderSidebarTab", async (app, html) => { if (app.options.id == "actors") { - let button = $("") + const button = $("") button.click(function () { - ParseDeltaGreenStatBlock() + ParseDeltaGreenStatBlock(); }); html.find(".directory-footer").append(button); } -}) +}); // Note - this event is fired on ALL connected clients... -Hooks.on('createActor', async function(actor, options, userId){ - try{ - +Hooks.on("createActor", async function (actor, options, userId) { + try { // use this to trap on if this hook is firing for the same user that triggered the create // can put logic specific to a particular user session below if (userId !== game.user.id) return; - if (actor !== null){ - - if(actor.type === 'agent'){ + if (actor !== null) { + if (actor.type === "agent") { // update the default type skill of Art - Painting's labels to try to be localized // since I really backed myself into a corner on this with my implementation of it... - console.log('createActor Hook'); + console.log("createActor Hook"); - let artLabel = game.i18n.translations.DG?.TypeSkills?.Art ?? "Art"; - let paintingLabel = game.i18n.translations.DG?.TypeSkills?.Subskills?.Painting ?? "Painting"; + const artLabel = game.i18n.translations.DG?.TypeSkills?.Art ?? "Art"; + const paintingLabel = game.i18n.translations.DG?.TypeSkills?.Subskills?.Painting ?? "Painting"; - let updatedData = duplicate(actor.system); + const updatedData = duplicate(actor.system); updatedData.typedSkills.tskill_01.group = artLabel; updatedData.typedSkills.tskill_01.label = paintingLabel; - - actor.update({"data": updatedData}); - + + actor.update({ data: updatedData }); + // throw on an unarmed strike item for convenience actor.AddUnarmedAttackItemIfMissing(); - } - else if(actor.type === 'unnatural'){ + } else if (actor.type === "unnatural") { // Do nothing. - } - else if(actor.type === 'vehicle'){ + } else if (actor.type === "vehicle") { actor.AddBaseVehicleItemsIfMissing(); } - } - - } - catch(ex){ + } catch (ex) { console.log(ex); } }); @@ -448,25 +432,25 @@ Hooks.on('createActor', async function(actor, options, userId){ async function createDeltaGreenMacro(data, slot) { // Definitely should not be doing assignments in conditionals but if we fix this, it breaks macro creation. // eslint-disable-next-line no-cond-assign - if (data.type = "Item" && data.itemData.type !== "weapon") return; - //if (!("data" in data)) return ui.notifications.warn("You can only create macro buttons for owned Items"); + if ((data.type = "Item" && data.itemData.type !== "weapon")) return; + // if (!("data" in data)) return ui.notifications.warn("You can only create macro buttons for owned Items"); const item = data.itemData; // Create the macro command - let command = '// Uncomment line below to also roll skill check if desired.' - command += '\n' + `//game.deltagreen.rollItemSkillCheckMacro("${item._id}");`; - command += '\n' + `game.deltagreen.rollItemMacro("${item._id}");`; + let command = "// Uncomment line below to also roll skill check if desired."; + command += "\n" + `//game.deltagreen.rollItemSkillCheckMacro("${item._id}");`; + command += "\n" + `game.deltagreen.rollItemMacro("${item._id}");`; - //let macro = game.macros.entities.find(m => (m.name === data.name) && (m.command === command)); - //if (!macro) { - let macro = await Macro.create({ + // let macro = game.macros.entities.find(m => (m.name === data.name) && (m.command === command)); + // if (!macro) { + const macro = await Macro.create({ name: data.itemData.name, type: "script", img: data.itemData.img, command: command, flags: { "deltagreen.itemMacro": true } }); - //} + // } game.user.assignHotbarMacro(macro, slot); return false; @@ -483,17 +467,21 @@ async function rollItemMacro(itemId) { let actor; if (speaker.token) actor = game.actors.tokens[speaker.token]; if (!actor) actor = game.actors.get(speaker.actor); - - if(!actor) return ui.notifications.warn('Must have an Actor selected first.'); - let item = actor ? actor.items.find(i => i._id === itemId) : null; + if (!actor) + return ui.notifications.warn("Must have an Actor selected first."); + + let item = actor ? actor.items.find((i) => i._id === itemId) : null; // for backwards compatibility with older macros, where I unwisely set it to use name instead of id - if(!item){ - item = actor ? actor.items.find(i => i.name === itemId) : null; - } + if (!item) { + item = actor ? actor.items.find((i) => i.name === itemId) : null; + } - if (!item) return ui.notifications.warn(`Your controlled Actor does not have an item named ${itemId}`); + if (!item) + return ui.notifications.warn( + `Your controlled Actor does not have an item named ${itemId}`, + ); // Trigger the item roll const r = await item.roll(); @@ -507,35 +495,49 @@ function rollItemSkillCheckMacro(itemId) { if (speaker.token) actor = game.actors.tokens[speaker.token]; if (!actor) actor = game.actors.get(speaker.actor); - if (!actor) return ui.notifications.warn('Must have an Actor selected first.'); + if (!actor) + return ui.notifications.warn("Must have an Actor selected first."); - let item = actor ? actor.items.find(i => i._id === itemId) : null; + let item = actor ? actor.items.find((i) => i._id === itemId) : null; // for backwards compatibility with older macros, where I unwisely set it to use name instead of id - if(!item){ - item = actor ? actor.items.find(i => i.name === itemId) : null; - } + if (!item) { + item = actor ? actor.items.find((i) => i.name === itemId) : null; + } - if (!item) return ui.notifications.warn(`Your controlled Actor does not have an item '${item.name}'`); + if (!item) + return ui.notifications.warn( + `Your controlled Actor does not have an item '${item.name}'`, + ); - let skillName = item.system.skill.toString(); + const skillName = item.system.skill.toString(); - const roll = new DGRolls.DGPercentileRoll("1D100", {}, { rollType: "weapon", key: skillName, actor, item }); - return actor.sheet.processRoll({}, roll)} + const roll = new DGRolls.DGPercentileRoll( + "1D100", + {}, + { rollType: "weapon", key: skillName, actor, item }, + ); + return actor.sheet.processRoll({}, roll); +} function rollSkillMacro(skillName) { const speaker = ChatMessage.getSpeaker(); let actor; if (speaker.token) actor = game.actors.tokens[speaker.token]; if (!actor) actor = game.actors.get(speaker.actor); - - if(!actor) return ui.notifications.warn('Must have an Actor selected first.'); - let skill = actor.system.skills[skillName]; + if (!actor) + return ui.notifications.warn("Must have an Actor selected first."); - if(!skill) return ui.notifications.warn('Bad skill name passed to macro.'); + const skill = actor.system.skills[skillName]; - const roll = new DGRolls.DGPercentileRoll("1D100", {}, { rollType: "skill", key: skillName, actor }); - actor.sheet.processRoll({}, roll) + if (!skill) return ui.notifications.warn("Bad skill name passed to macro."); + + const roll = new DGRolls.DGPercentileRoll( + "1D100", + {}, + { rollType: "skill", key: skillName, actor }, + ); + actor.sheet.processRoll({}, roll); // sendPercentileTestToChat(actor, translatedSkillLabel, skill.proficiency); -} \ No newline at end of file +} diff --git a/module/item/item-sheet.js b/module/item/item-sheet.js index 9cab3bd..771ed7d 100644 --- a/module/item/item-sheet.js +++ b/module/item/item-sheet.js @@ -3,21 +3,26 @@ * @extends {ItemSheet} */ export class DeltaGreenItemSheet extends ItemSheet { - /** @override */ static get defaultOptions() { return mergeObject(super.defaultOptions, { classes: ["deltagreen", "sheet", "item"], width: 520, height: 600, - tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "attributes" }] + tabs: [ + { + navSelector: ".sheet-tabs", + contentSelector: ".sheet-body", + initial: "attributes", + }, + ], }); } /** @override */ get template() { const path = "systems/deltagreen/templates/item"; - + // unique item sheet by type, like `weapon-sheet.html`. return `${path}/item-${this.item.type}-sheet.html`; } @@ -27,7 +32,10 @@ export class DeltaGreenItemSheet extends ItemSheet { /** @override */ async getData() { const data = super.getData(); - data.enrichedDescription = await TextEditor.enrichHTML(this.object.system.description, {async: true}); + data.enrichedDescription = await TextEditor.enrichHTML( + this.object.system.description, + { async: true }, + ); return data; } diff --git a/module/item/item.js b/module/item/item.js index 19cbed3..82527bf 100644 --- a/module/item/item.js +++ b/module/item/item.js @@ -16,7 +16,7 @@ export class DeltaGreenItem extends Item { // Get the Item's data const itemData = this; const actorData = this.actor || {}; - const system = itemData.system; + const { system } = itemData; } /** @@ -32,17 +32,25 @@ export class DeltaGreenItem extends Item { let roll; if (item.system.isLethal) { - roll = new DGLethalityRoll("1D100", {}, { rollType: "lethality", actor, item }) + roll = new DGLethalityRoll( + "1D100", + {}, + { rollType: "lethality", actor, item }, + ); } else { // regular damage roll let diceFormula = item.system.damage; - let skillType = item.system.skill; + const skillType = item.system.skill; - if (skillType === 'unarmed_combat' || skillType === 'melee_weapons') { + if (skillType === "unarmed_combat" || skillType === "melee_weapons") { diceFormula += actorSystemData.statistics.str.meleeDamageBonusFormula; } - roll = new DGDamageRoll(diceFormula, {}, { rollType: "damage", actor, item }) + roll = new DGDamageRoll( + diceFormula, + {}, + { rollType: "damage", actor, item }, + ); } return actor.sheet.processRoll({}, roll); } diff --git a/module/other/stat-parser-macro.js b/module/other/stat-parser-macro.js index cfb2633..63ee711 100644 --- a/module/other/stat-parser-macro.js +++ b/module/other/stat-parser-macro.js @@ -1,185 +1,372 @@ // call this within a world as: game.deltagreen.ParseDeltaGreenStatBlock() -function GetTypeSkillRatingsFromInput(inputText){ - - let matchStr = "(Art|Craft|Foreign Language|Native Language|Military Science|Pilot|Science)\\s?\\((\\w.*?)\\)\\s?(\\d?\\d)%"; +function GetTypeSkillRatingsFromInput(inputText) { + const matchStr = + "(Art|Craft|Foreign Language|Native Language|Military Science|Pilot|Science)\\s?\\((\\w.*?)\\)\\s?(\\d?\\d)%"; - inputText = inputText.replace(/[\n\r]/g, ' ') + inputText = inputText.replace(/[\n\r]/g, " "); - let re = new RegExp(matchStr, "gi"); - - let matches = []; - let match; - - try{ - while(match = re.exec(inputText)){ - matches.push({group: match[1], label: match[2], proficiency: parseInt(match[3]), failure: false}); - } + const re = new RegExp(matchStr, "gi"); + + const matches = []; + let match; + + try { + while ((match = re.exec(inputText))) { + matches.push({ + group: match[1], + label: match[2], + proficiency: parseInt(match[3]), + failure: false, + }); } - catch(ex){ - console.log('GetAttributeFromInput Error'); - console.log(ex); - } - - return matches; + } catch (ex) { + console.log("GetAttributeFromInput Error"); + console.log(ex); + } + + return matches; } -function GetAttributeFromInput(inputText, attribute){ - - let matchStr = "(?:" + attribute + "\\s)(\\d\\d?)"; - let re = new RegExp(matchStr, "i"); - let results = inputText.match(re); - let attributeScore = 10; - - try{ - if(results != null && results.length > 1){ - attributeScore = parseInt(results[1]); - } - else{ - attributeScore = 0; - } +function GetAttributeFromInput(inputText, attribute) { + const matchStr = `(?:${attribute}\\s)(\\d\\d?)`; + const re = new RegExp(matchStr, "i"); + const results = inputText.match(re); + let attributeScore = 10; + + try { + if (results != null && results.length > 1) { + attributeScore = parseInt(results[1]); + } else { + attributeScore = 0; } - catch(ex){ - console.log('GetAttributeFromInput Error'); - console.log(ex); - } - - return attributeScore; + } catch (ex) { + console.log("GetAttributeFromInput Error"); + console.log(ex); + } + + return attributeScore; } -function GetSkillRatingsFromInput(inputText, skill){ - - let matchStr = "(?:" + skill + "\\s)(\\d\\d?)"; - let re = new RegExp(matchStr, "i"); - let results = inputText.match(re); - let skillValue = 0; - - try{ - if(results != null && results.length > 1){ - skillValue = parseInt(results[1]); - } +function GetSkillRatingsFromInput(inputText, skill) { + const matchStr = `(?:${skill}\\s)(\\d\\d?)`; + const re = new RegExp(matchStr, "i"); + const results = inputText.match(re); + let skillValue = 0; + + try { + if (results != null && results.length > 1) { + skillValue = parseInt(results[1]); } - catch(ex){ - console.log('GetAttributeFromInput Error'); - console.log(ex); - } - - return skillValue; + } catch (ex) { + console.log("GetAttributeFromInput Error"); + console.log(ex); + } + + return skillValue; } -async function RegexParseNpcStatBlock(inputStr, actorType){ - let actorData = {}; +async function RegexParseNpcStatBlock(inputStr, actorType) { + const actorData = {}; - let shortDescription = ""; - - actorData.type = actorType; - actorData.data = {}; - actorData.data.statistics = {}; - actorData.data.skills = {}; - actorData.data.typedSkills = {}; - actorData.data.physical = {}; + let shortDescription = ""; - actorData.data.health = {value: 10, min: 0, max: 10}; - actorData.data.wp = {value: 10, min: 0, max: 10}; - - let tempStr = ""; - let arr = []; - - tempStr = inputStr.split(/\r?\n/); - - if(tempStr.length > 1){ - actorData.name = tempStr[0]; - shortDescription = tempStr[1]; - } - else{ - actorData.name = "Unknown"; - } + actorData.type = actorType; + actorData.data = {}; + actorData.data.statistics = {}; + actorData.data.skills = {}; + actorData.data.typedSkills = {}; + actorData.data.physical = {}; - if(actorType === 'agent'){ - actorData.data.physical = {description: shortDescription, wounds: "", firstAidAttempted: false} - } - else if(actorType === 'npc' || actorType === 'unnatural'){ - actorData.data.shortDescription = shortDescription; - } - - actorData.data.statistics.str = {value: GetAttributeFromInput(inputStr, "STR"), distinguishing_feature: ""}; - actorData.data.statistics.con = {value: GetAttributeFromInput(inputStr, "CON"), distinguishing_feature: ""}; - actorData.data.statistics.dex = {value: GetAttributeFromInput(inputStr, "DEX"), distinguishing_feature: ""}; - actorData.data.statistics.int = {value: GetAttributeFromInput(inputStr, "INT"), distinguishing_feature: ""}; - actorData.data.statistics.pow = {value: GetAttributeFromInput(inputStr, "POW"), distinguishing_feature: ""}; - actorData.data.statistics.cha = {value: GetAttributeFromInput(inputStr, "CHA"), distinguishing_feature: ""}; + actorData.data.health = { value: 10, min: 0, max: 10 }; + actorData.data.wp = { value: 10, min: 0, max: 10 }; - if(actorType === 'npc' || actorType === 'unnatural'){ - // don't want to try to set HP/SAN for player characters - actorData.data.health = {min: 0, max: GetAttributeFromInput(inputStr, "HP"), value: GetAttributeFromInput(inputStr, "HP")}; - actorData.data.sanity = {max: actorData.data.statistics.pow.value * 5, value: GetAttributeFromInput(inputStr, "SAN"), currentBreakingPoint: GetAttributeFromInput(inputStr, "BREAKING POINT")}; - actorData.data.wp = {max: actorData.data.statistics.pow.value, value: GetAttributeFromInput(inputStr, "WP"), min: 0}; - } + let tempStr = ""; + let arr = []; - actorData.data.skills.accounting = {"label": "Accounting", proficiency: GetSkillRatingsFromInput(inputStr, "ACCOUNTING"), failure: false}; - actorData.data.skills.alertness = {"label": "Alertness", proficiency: GetSkillRatingsFromInput(inputStr, "ALERTNESS"), failure: false}; - actorData.data.skills.anthropology = {"label": "Anthropology", proficiency: GetSkillRatingsFromInput(inputStr, "ANTHROPOLOGY"), failure: false}; - actorData.data.skills.archeology = {"label": "Archeology", proficiency: GetSkillRatingsFromInput(inputStr, "ARCHEOLOGY|ARCHAEOLOGY"), failure: false}; // damn you british spellings - actorData.data.skills.artillery = {"label": "Artillery", proficiency: GetSkillRatingsFromInput(inputStr, "ARTILLERY"), failure: false}; - actorData.data.skills.athletics = {"label": "Athletics", proficiency: GetSkillRatingsFromInput(inputStr, "ATHLETICS"), failure: false}; - actorData.data.skills.bureaucracy = {"label": "Bureaucracy", proficiency: GetSkillRatingsFromInput(inputStr, "BUREAUCRACY"), failure: false}; - actorData.data.skills.computer_science = {"label": "Computer Science", proficiency: GetSkillRatingsFromInput(inputStr, "COMPUTER SCIENCE"), failure: false}; - actorData.data.skills.criminology = {"label": "Criminology", proficiency: GetSkillRatingsFromInput(inputStr, "CRIMINOLOGY"), failure: false}; - actorData.data.skills.demolitions = {"label": "Demolitions", proficiency: GetSkillRatingsFromInput(inputStr, "DEMOLITIONS"), failure: false}; - actorData.data.skills.disguise = {"label": "Disguise", proficiency: GetSkillRatingsFromInput(inputStr, "DISGUISE"), failure: false}; - actorData.data.skills.dodge = {"label": "Dodge", proficiency: GetSkillRatingsFromInput(inputStr, "DODGE"), failure: false}; - actorData.data.skills.drive = {"label": "Drive", proficiency: GetSkillRatingsFromInput(inputStr, "DRIVE"), failure: false}; + tempStr = inputStr.split(/\r?\n/); - // Impossible Landscapes seems to favor 'Driving' as the name for this instead for some - if(actorData.data.skills.drive.proficiency === 0){ - actorData.data.skills.drive = {"label": "Drive", proficiency: GetSkillRatingsFromInput(inputStr, "DRIVING"), failure: false}; - } + if (tempStr.length > 1) { + actorData.name = tempStr[0]; + shortDescription = tempStr[1]; + } else { + actorData.name = "Unknown"; + } - actorData.data.skills.firearms = {"label": "Firearms", proficiency: GetSkillRatingsFromInput(inputStr, "FIREARMS"), failure: false}; - actorData.data.skills.first_aid = {"label": "First Adi", proficiency: GetSkillRatingsFromInput(inputStr, "FIRST AID"), failure: false}; - actorData.data.skills.forensics = {"label": "Forensics", proficiency: GetSkillRatingsFromInput(inputStr, "FORENSICS"), failure: false}; - actorData.data.skills.heavy_machinery = {"label": "Heavy Machinery", proficiency: GetSkillRatingsFromInput(inputStr, "HEAVY MACHINERY"), failure: false}; // template.json has typo on heavy machinery... - actorData.data.skills.heavy_weapons = {"label": "Heavy Weapons", proficiency: GetSkillRatingsFromInput(inputStr, "HEAVY WEAPONS"), failure: false}; - actorData.data.skills.history = {"label": "History", proficiency: GetSkillRatingsFromInput(inputStr, "HISTORY"), failure: false}; - actorData.data.skills.humint = {"label": "HUMINT", proficiency: GetSkillRatingsFromInput(inputStr, "HUMINT"), failure: false}; - actorData.data.skills.law = {"label": "Law", proficiency: GetSkillRatingsFromInput(inputStr, "LAW"), failure: false}; - actorData.data.skills.medicine = {"label": "Medicine", proficiency: GetSkillRatingsFromInput(inputStr, "MEDICINE"), failure: false}; - actorData.data.skills.melee_weapons = {"label": "Melee Weapons", proficiency: GetSkillRatingsFromInput(inputStr, "MELEE WEAPONS"), failure: false}; - actorData.data.skills.navigate = {"label": "Navigate", proficiency: GetSkillRatingsFromInput(inputStr, "NAVIGATE"), failure: false}; - actorData.data.skills.occult = {"label": "Occult", proficiency: GetSkillRatingsFromInput(inputStr, "OCCULT"), failure: false}; - actorData.data.skills.persuade = {"label": "Persuade", proficiency: GetSkillRatingsFromInput(inputStr, "PERSUADE"), failure: false}; - actorData.data.skills.pharmacy = {"label": "Pharmacy", proficiency: GetSkillRatingsFromInput(inputStr, "PHARMACY"), failure: false}; - actorData.data.skills.psychotherapy = {"label": "Psychotherapy", proficiency: GetSkillRatingsFromInput(inputStr, "PSYCHOTHERAPY"), failure: false}; - actorData.data.skills.ride = {"label": "Ride", proficiency: GetSkillRatingsFromInput(inputStr, "RIDE"), failure: false}; - actorData.data.skills.search = {"label": "Search", proficiency: GetSkillRatingsFromInput(inputStr, "SEARCH"), failure: false}; - actorData.data.skills.sigint = {"label": "SIGINT", proficiency: GetSkillRatingsFromInput(inputStr, "SIGINT"), failure: false}; - actorData.data.skills.stealth = {"label": "Stealth", proficiency: GetSkillRatingsFromInput(inputStr, "STEALTH"), failure: false}; - actorData.data.skills.surgery = {"label": "Surgery", proficiency: GetSkillRatingsFromInput(inputStr, "SURGERY"), failure: false}; - actorData.data.skills.survival = {"label": "Survival", proficiency: GetSkillRatingsFromInput(inputStr, "SURVIVAL"), failure: false}; - actorData.data.skills.swim = {"label": "Swim", proficiency: GetSkillRatingsFromInput(inputStr, "SWIM"), failure: false}; - actorData.data.skills.unarmed_combat = {"label": "Unarmed Combat", proficiency: GetSkillRatingsFromInput(inputStr, "UNARMED COMBAT"), failure: false}; - actorData.data.skills.unnatural = {"label": "Unnatural", proficiency: GetSkillRatingsFromInput(inputStr, "UNNATURAL"), failure: false}; + if (actorType === "agent") { + actorData.data.physical = { + description: shortDescription, + wounds: "", + firstAidAttempted: false, + }; + } else if (actorType === "npc" || actorType === "unnatural") { + actorData.data.shortDescription = shortDescription; + } - // some npcs/unnatural have other skills - if(GetSkillRatingsFromInput(inputStr, "FLIGHT") > 0){ - actorData.data.skills.flight = {"label": "Flight", proficiency: GetSkillRatingsFromInput(inputStr, "FLIGHT"), failure: false}; - } - - arr = GetTypeSkillRatingsFromInput(inputStr); + actorData.data.statistics.str = { + value: GetAttributeFromInput(inputStr, "STR"), + distinguishing_feature: "", + }; + actorData.data.statistics.con = { + value: GetAttributeFromInput(inputStr, "CON"), + distinguishing_feature: "", + }; + actorData.data.statistics.dex = { + value: GetAttributeFromInput(inputStr, "DEX"), + distinguishing_feature: "", + }; + actorData.data.statistics.int = { + value: GetAttributeFromInput(inputStr, "INT"), + distinguishing_feature: "", + }; + actorData.data.statistics.pow = { + value: GetAttributeFromInput(inputStr, "POW"), + distinguishing_feature: "", + }; + actorData.data.statistics.cha = { + value: GetAttributeFromInput(inputStr, "CHA"), + distinguishing_feature: "", + }; - for (let index = 0; index < arr.length; ++index) { - const element = arr[index]; - actorData.data.typedSkills['tskill_' + index.toString()] = element; - } - - console.log(actorData); + if (actorType === "npc" || actorType === "unnatural") { + // don't want to try to set HP/SAN for player characters + actorData.data.health = { + min: 0, + max: GetAttributeFromInput(inputStr, "HP"), + value: GetAttributeFromInput(inputStr, "HP"), + }; + actorData.data.sanity = { + max: actorData.data.statistics.pow.value * 5, + value: GetAttributeFromInput(inputStr, "SAN"), + currentBreakingPoint: GetAttributeFromInput(inputStr, "BREAKING POINT"), + }; + actorData.data.wp = { + max: actorData.data.statistics.pow.value, + value: GetAttributeFromInput(inputStr, "WP"), + min: 0, + }; + } - const newActors = await Actor.createDocuments([actorData]); + actorData.data.skills.accounting = { + label: "Accounting", + proficiency: GetSkillRatingsFromInput(inputStr, "ACCOUNTING"), + failure: false, + }; + actorData.data.skills.alertness = { + label: "Alertness", + proficiency: GetSkillRatingsFromInput(inputStr, "ALERTNESS"), + failure: false, + }; + actorData.data.skills.anthropology = { + label: "Anthropology", + proficiency: GetSkillRatingsFromInput(inputStr, "ANTHROPOLOGY"), + failure: false, + }; + actorData.data.skills.archeology = { + label: "Archeology", + proficiency: GetSkillRatingsFromInput(inputStr, "ARCHEOLOGY|ARCHAEOLOGY"), + failure: false, + }; // damn you british spellings + actorData.data.skills.artillery = { + label: "Artillery", + proficiency: GetSkillRatingsFromInput(inputStr, "ARTILLERY"), + failure: false, + }; + actorData.data.skills.athletics = { + label: "Athletics", + proficiency: GetSkillRatingsFromInput(inputStr, "ATHLETICS"), + failure: false, + }; + actorData.data.skills.bureaucracy = { + label: "Bureaucracy", + proficiency: GetSkillRatingsFromInput(inputStr, "BUREAUCRACY"), + failure: false, + }; + actorData.data.skills.computer_science = { + label: "Computer Science", + proficiency: GetSkillRatingsFromInput(inputStr, "COMPUTER SCIENCE"), + failure: false, + }; + actorData.data.skills.criminology = { + label: "Criminology", + proficiency: GetSkillRatingsFromInput(inputStr, "CRIMINOLOGY"), + failure: false, + }; + actorData.data.skills.demolitions = { + label: "Demolitions", + proficiency: GetSkillRatingsFromInput(inputStr, "DEMOLITIONS"), + failure: false, + }; + actorData.data.skills.disguise = { + label: "Disguise", + proficiency: GetSkillRatingsFromInput(inputStr, "DISGUISE"), + failure: false, + }; + actorData.data.skills.dodge = { + label: "Dodge", + proficiency: GetSkillRatingsFromInput(inputStr, "DODGE"), + failure: false, + }; + actorData.data.skills.drive = { + label: "Drive", + proficiency: GetSkillRatingsFromInput(inputStr, "DRIVE"), + failure: false, + }; - newActors[0].sheet.render(true); + // Impossible Landscapes seems to favor 'Driving' as the name for this instead for some + if (actorData.data.skills.drive.proficiency === 0) { + actorData.data.skills.drive = { + label: "Drive", + proficiency: GetSkillRatingsFromInput(inputStr, "DRIVING"), + failure: false, + }; + } + + actorData.data.skills.firearms = { + label: "Firearms", + proficiency: GetSkillRatingsFromInput(inputStr, "FIREARMS"), + failure: false, + }; + actorData.data.skills.first_aid = { + label: "First Adi", + proficiency: GetSkillRatingsFromInput(inputStr, "FIRST AID"), + failure: false, + }; + actorData.data.skills.forensics = { + label: "Forensics", + proficiency: GetSkillRatingsFromInput(inputStr, "FORENSICS"), + failure: false, + }; + actorData.data.skills.heavy_machinery = { + label: "Heavy Machinery", + proficiency: GetSkillRatingsFromInput(inputStr, "HEAVY MACHINERY"), + failure: false, + }; // template.json has typo on heavy machinery... + actorData.data.skills.heavy_weapons = { + label: "Heavy Weapons", + proficiency: GetSkillRatingsFromInput(inputStr, "HEAVY WEAPONS"), + failure: false, + }; + actorData.data.skills.history = { + label: "History", + proficiency: GetSkillRatingsFromInput(inputStr, "HISTORY"), + failure: false, + }; + actorData.data.skills.humint = { + label: "HUMINT", + proficiency: GetSkillRatingsFromInput(inputStr, "HUMINT"), + failure: false, + }; + actorData.data.skills.law = { + label: "Law", + proficiency: GetSkillRatingsFromInput(inputStr, "LAW"), + failure: false, + }; + actorData.data.skills.medicine = { + label: "Medicine", + proficiency: GetSkillRatingsFromInput(inputStr, "MEDICINE"), + failure: false, + }; + actorData.data.skills.melee_weapons = { + label: "Melee Weapons", + proficiency: GetSkillRatingsFromInput(inputStr, "MELEE WEAPONS"), + failure: false, + }; + actorData.data.skills.navigate = { + label: "Navigate", + proficiency: GetSkillRatingsFromInput(inputStr, "NAVIGATE"), + failure: false, + }; + actorData.data.skills.occult = { + label: "Occult", + proficiency: GetSkillRatingsFromInput(inputStr, "OCCULT"), + failure: false, + }; + actorData.data.skills.persuade = { + label: "Persuade", + proficiency: GetSkillRatingsFromInput(inputStr, "PERSUADE"), + failure: false, + }; + actorData.data.skills.pharmacy = { + label: "Pharmacy", + proficiency: GetSkillRatingsFromInput(inputStr, "PHARMACY"), + failure: false, + }; + actorData.data.skills.psychotherapy = { + label: "Psychotherapy", + proficiency: GetSkillRatingsFromInput(inputStr, "PSYCHOTHERAPY"), + failure: false, + }; + actorData.data.skills.ride = { + label: "Ride", + proficiency: GetSkillRatingsFromInput(inputStr, "RIDE"), + failure: false, + }; + actorData.data.skills.search = { + label: "Search", + proficiency: GetSkillRatingsFromInput(inputStr, "SEARCH"), + failure: false, + }; + actorData.data.skills.sigint = { + label: "SIGINT", + proficiency: GetSkillRatingsFromInput(inputStr, "SIGINT"), + failure: false, + }; + actorData.data.skills.stealth = { + label: "Stealth", + proficiency: GetSkillRatingsFromInput(inputStr, "STEALTH"), + failure: false, + }; + actorData.data.skills.surgery = { + label: "Surgery", + proficiency: GetSkillRatingsFromInput(inputStr, "SURGERY"), + failure: false, + }; + actorData.data.skills.survival = { + label: "Survival", + proficiency: GetSkillRatingsFromInput(inputStr, "SURVIVAL"), + failure: false, + }; + actorData.data.skills.swim = { + label: "Swim", + proficiency: GetSkillRatingsFromInput(inputStr, "SWIM"), + failure: false, + }; + actorData.data.skills.unarmed_combat = { + label: "Unarmed Combat", + proficiency: GetSkillRatingsFromInput(inputStr, "UNARMED COMBAT"), + failure: false, + }; + actorData.data.skills.unnatural = { + label: "Unnatural", + proficiency: GetSkillRatingsFromInput(inputStr, "UNNATURAL"), + failure: false, + }; + + // some npcs/unnatural have other skills + if (GetSkillRatingsFromInput(inputStr, "FLIGHT") > 0) { + actorData.data.skills.flight = { + label: "Flight", + proficiency: GetSkillRatingsFromInput(inputStr, "FLIGHT"), + failure: false, + }; + } + + arr = GetTypeSkillRatingsFromInput(inputStr); + + for (let index = 0; index < arr.length; ++index) { + const element = arr[index]; + actorData.data.typedSkills[`tskill_${index.toString()}`] = element; + } + + console.log(actorData); + + const newActors = await Actor.createDocuments([actorData]); + + newActors[0].sheet.render(true); } -async function GetUserInput(){ - const content = `
+async function GetUserInput() { + const content = `
@@ -197,25 +384,25 @@ async function GetUserInput(){
`; - - new Dialog({ - title: "Stat Block Parser", // Change the title if you want. - content, - buttons: { - roll: { - label: "PARSE", - callback: async (html) => { - const textInput = html.find("[name=parse-input]")[0].value; - - const actorType = html.find("[name=actor-type]")[0].value; - RegexParseNpcStatBlock(textInput, actorType); - } - } - } - }).render(true); + new Dialog({ + title: "Stat Block Parser", // Change the title if you want. + content, + buttons: { + roll: { + label: "PARSE", + callback: async (html) => { + const textInput = html.find("[name=parse-input]")[0].value; + + const actorType = html.find("[name=actor-type]")[0].value; + + RegexParseNpcStatBlock(textInput, actorType); + }, + }, + }, + }).render(true); } -export async function ParseDeltaGreenStatBlock(){ - GetUserInput(); -} \ No newline at end of file +export async function ParseDeltaGreenStatBlock() { + GetUserInput(); +} diff --git a/module/other/utility-functions.js b/module/other/utility-functions.js index ed13a60..e358f57 100644 --- a/module/other/utility-functions.js +++ b/module/other/utility-functions.js @@ -1,27 +1,25 @@ /* globals game */ - export default class DGUtils { /** * Attempt to localize a keyword, and gracefully fallback to something else if the key does not exist. * This way people using incomplete translations will not as many crashes or bugs when playing against a newly updated system. - * - * @param {String} key - localization key + * + * @param {String} key - localization key * @param {String} fallback - string to fall back to if translation does not exist for key - * @returns + * @returns */ - static localizeWithFallback(key, fallback){ + static localizeWithFallback(key, fallback) { try { - let translatedValue = game.i18n.localize(key); + const translatedValue = game.i18n.localize(key); if (translatedValue != key) { - return translatedValue; - } else { - console.warn(`Untranslated localization key '${key}'.`); - // can't have single quotes in a handlebars string literal input, so sort of hack in an escape character for them. - fallback = fallback.replace("'", "'"); - return fallback; + return translatedValue; } - } catch(ex) { + console.warn(`Untranslated localization key '${key}'.`); + // can't have single quotes in a handlebars string literal input, so sort of hack in an escape character for them. + fallback = fallback.replace("'", "'"); + return fallback; + } catch (ex) { console.warn(ex); return fallback; } @@ -29,12 +27,12 @@ export default class DGUtils { /** * Format a number with a leading plus. - * - * @param {Number} number + * + * @param {Number} number * @returns {String} - the stringified number with a leading plus if applicable - * + * */ - static formatStringWithLeadingPlus(number){ - return number > 0 ? `+${number}` : number.toString() ; + static formatStringWithLeadingPlus(number) { + return number > 0 ? `+${number}` : number.toString(); } -} \ No newline at end of file +} diff --git a/module/roll/roll.js b/module/roll/roll.js index f0cb1ac..169a6ba 100644 --- a/module/roll/roll.js +++ b/module/roll/roll.js @@ -1,13 +1,13 @@ /* globals game Roll ChatMessage AudioHelper renderTemplate Dialog */ -import DGUtils from "../other/utility-functions.js" +import DGUtils from "../other/utility-functions.js"; export class DGRoll extends Roll { /** * NOTE: This class will rarely be called on its own. It should generally be extended. Look to DGPercentileRoll as an example. - * + * * Customize our roll with some useful information, passed in the `options` Object. - * + * * @param {string} formula Unused - The string formula to parse (from Foundry) * @param {Object} data Unused - The data object against which to parse attributes within the formula * @param {Object} [options] Additional data which is preserved in the database @@ -27,24 +27,27 @@ export class DGRoll extends Roll { } /** - * Simple function that actually creates the message and sends it to chat. - * + * Simple function that actually creates the message and sends it to chat. + * * Broke this out so multiple functions can use it. - * + * * @returns {Promise} - the created chat message. */ async createMessage(content, flavor, rollMode) { - let chatData = { + const chatData = { speaker: ChatMessage.getSpeaker({ actor: this.actor }), content, flavor, - type: 5, //CHAT_MESSAGE_TYPES.ROLL, + type: 5, // CHAT_MESSAGE_TYPES.ROLL, roll: this, - rollMode + rollMode, }; - + // play the dice rolling sound, like a regular in-chat roll - AudioHelper.play({src: "sounds/dice.wav", volume: 0.8, autoplay: true, loop: false}, true); + AudioHelper.play( + { src: "sounds/dice.wav", volume: 0.8, autoplay: true, loop: false }, + true, + ); return ChatMessage.create(chatData); } } @@ -52,15 +55,15 @@ export class DGRoll extends Roll { export class DGPercentileRoll extends DGRoll { /** * Creates D100 rolls, the base die of the system. - * - * This constructor embeds the following info into the roll: - * 1. Target number that the roll needs to beat. - * 2. Localized name for the roll. - * + * + * This constructor embeds the following info into the roll: + * 1. Target number that the roll needs to beat. + * 2. Localized name for the roll. + * * Note: In order for all of our custom data to persist, our constructor must use the same parameters as its parent class. * So, even though percentile rolls will always have a formula of "1d100" and we don't use the `data` object, * we still have to keep them as parameters. - * + * * @param {string} formula Unused - The string formula to parse (from Foundry) - Always "1d100" for percentile rolls. * @param {Object} data Unused - The data object against which to parse attributes within the formula * @param {Object} [options] Additional data which is preserved in the database @@ -81,7 +84,7 @@ export class DGPercentileRoll extends DGRoll { this.target = this.actor.system.statistics[this.key].x5; this.localizedKey = game.i18n.localize(`DG.Attributes.${this.key}`); break; - case "skill": + case "skill": // Set up a target number and localized roll based on whether the skill is regular or typed. if (skillKeys.includes(this.key)) { this.target = this.actor.system.skills[this.key].proficiency; @@ -113,7 +116,7 @@ export class DGPercentileRoll extends DGRoll { // Add a the weapon's internal modifier. this.modifier += this.item.system.skillModifier; break; - case "luck": + case "luck": this.target = 50; this.localizedKey = game.i18n.localize("DG.Luck"); break; @@ -124,59 +127,64 @@ export class DGPercentileRoll extends DGRoll { /** * Shows a dialog that can modify the roll. - * + * * @returns {Promise} - the results of the dialog. */ - async showDialog() { + async showDialog() { let isSanCheck = false; - const hideSanTarget = !game.user.isGM && game.settings.get("deltagreen", "keepSanityPrivate"); - - if (this.key === 'sanity' || this.key === 'ritual') { + const hideSanTarget = + !game.user.isGM && game.settings.get("deltagreen", "keepSanityPrivate"); + + if (this.key === "sanity" || this.key === "ritual") { isSanCheck = true; } - - let backingData = { - data:{ + + const backingData = { + data: { label: this.localizedKey, originalTarget: this.target, targetModifier: 20, - isSanCheck: isSanCheck, - hideTarget: hideSanTarget + isSanCheck, + hideTarget: hideSanTarget, }, }; - - let template = "systems/deltagreen/templates/dialog/modify-percentile-roll.html"; - let html = await renderTemplate(template, backingData); + + const template = + "systems/deltagreen/templates/dialog/modify-percentile-roll.html"; + const html = await renderTemplate(template, backingData); return new Promise((resolve, reject) => { new Dialog({ content: html, - title: DGUtils.localizeWithFallback("DG.ModifySkillRollDialogue.Title", "Modify Roll"), + title: DGUtils.localizeWithFallback( + "DG.ModifySkillRollDialogue.Title", + "Modify Roll", + ), default: "roll", buttons: { - roll:{ + roll: { label: DGUtils.localizeWithFallback("DG.Roll.Roll", "Roll"), - callback: html => { + callback: (html) => { try { - let targetModifier = html.find("[name='targetModifier']").val(); // this is text as a heads up - - let rollMode = html.find("[name='rollMode']").val(); - - let plusMinus = html.find("[name='plusOrMinus']").val(); - - if (targetModifier.trim() != "" && !isNaN(targetModifier)){ + let targetModifier = html.find("[name='targetModifier']").val(); // this is text as a heads up + + const rollMode = html.find("[name='rollMode']").val(); + + const plusMinus = html.find("[name='plusOrMinus']").val(); + + if (targetModifier.trim() != "" && !isNaN(targetModifier)) { targetModifier = Math.abs(parseInt(targetModifier)); - - if(plusMinus === "-"){ + + if (plusMinus === "-") { targetModifier = -1 * targetModifier; } } - resolve({targetModifier, rollMode}) - } catch(ex) { + resolve({ targetModifier, rollMode }); + } catch (ex) { reject(console.log(ex)); } - } - } - } + }, + }, + }, }).render(true); }); } @@ -184,74 +192,93 @@ export class DGPercentileRoll extends DGRoll { /** * Prepares data for a chat message and then passes that data * to a method that actually creates a ChatMessage. - * + * * Lays out and styles message based on outcome of the roll. - * + * * @returns {Promise} - the created chat message. */ async toChat() { - let rollMode = this.options.rollMode || game.settings.get("core", "rollMode"); - + let rollMode = + this.options.rollMode || game.settings.get("core", "rollMode"); + // if using private san rolls, must hide any SAN roll unless user is a GM - const privateSanSetting = game.settings.get("deltagreen", "keepSanityPrivate"); - if (privateSanSetting && (this.key === 'sanity' || this.key === 'ritual') && !game.user.isGM){ - rollMode = 'blindroll'; + const privateSanSetting = game.settings.get( + "deltagreen", + "keepSanityPrivate", + ); + if ( + privateSanSetting && + (this.key === "sanity" || this.key === "ritual") && + !game.user.isGM + ) { + rollMode = "blindroll"; } - - let label = `${game.i18n.localize("DG.Roll.Rolling")} ${this.localizedKey} ${game.i18n.localize("DG.Roll.Target")} ${this.target + this.modifier}`; + + let label = `${game.i18n.localize("DG.Roll.Rolling")} ${ + this.localizedKey + } ${game.i18n.localize("DG.Roll.Target")} ${ + this.target + this.modifier + }`; // "Inhuman" stat being rolled. See function for details. if (this.isInhuman) { - label = `${game.i18n.localize("DG.Roll.Rolling")} ${this.localizedKey} [${game.i18n.localize("DG.Roll.Inhuman").toUpperCase()}] ${game.i18n.localize("DG.Roll.Target")} ${this.target + this.modifier}`; + label = `${game.i18n.localize("DG.Roll.Rolling")} ${ + this.localizedKey + } [${game.i18n + .localize("DG.Roll.Inhuman") + .toUpperCase()}] ${game.i18n.localize("DG.Roll.Target")} ${ + this.target + this.modifier + }`; } if (this.modifier) { - label += ` (${DGUtils.formatStringWithLeadingPlus(this.modifier)}%)` + label += ` (${DGUtils.formatStringWithLeadingPlus(this.modifier)}%)`; } - - let resultString = '', styleOverride = ''; + + let resultString = ""; + let styleOverride = ""; if (this.isCritical) { resultString = `${game.i18n.localize("DG.Roll.Critical")} `; } - + if (this.isSuccess) { resultString += `${game.i18n.localize("DG.Roll.Success")}`; - - if (this.isCritical){ - resultString = resultString.toUpperCase() + '!'; - styleOverride="color: green"; + + if (this.isCritical) { + resultString = `${resultString.toUpperCase()}!`; + styleOverride = "color: green"; } - } else { + } else { resultString += `${game.i18n.localize("DG.Roll.Failure")}`; - - if(this.isCritical){ - resultString = resultString.toUpperCase() + '!'; - styleOverride="color: red"; + + if (this.isCritical) { + resultString = `${resultString.toUpperCase()}!`; + styleOverride = "color: red"; } } - - let html = ''; - html += `
` - html += `
` - html += `
${resultString}
` - html += `
` - html += `
` - html += `
` - html += `
` - html += ` ` - html += ` ${this.formula}` - html += ` ` - html += ` ` - html += ` ${this.total}` - html += ` ` - html += `
` - html += `
    ` - html += `
  1. ${this.total}
  2. ` - html += `
` - html += `
` - html += `
` - html += `
` - html += `

${this.total}

` - html += `
` - + + let html = ""; + html += `
`; + html += `
`; + html += `
${resultString}
`; + html += `
`; + html += `
`; + html += `
`; + html += `
`; + html += ` `; + html += ` ${this.formula}`; + html += ` `; + html += ` `; + html += ` ${this.total}`; + html += ` `; + html += `
`; + html += `
    `; + html += `
  1. ${this.total}
  2. `; + html += `
`; + html += `
`; + html += `
`; + html += `
`; + html += `

${this.total}

`; + html += `
`; + return this.createMessage(html, label, rollMode); } @@ -261,28 +288,28 @@ export class DGPercentileRoll extends DGRoll { * 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. - * - * @returns {Boolean} + * + * @returns {Boolean} */ get isInhuman() { if (this.target + this.modifier > 99 && this.type === "stat") { return true; } - return false; + return false; } /** * Determines if a roll result is critical. * If roll has not been evaluated, return null. - * - * @returns {null|Boolean} + * + * @returns {null|Boolean} */ get isCritical() { // If roll isn't evaluated, return null. if (!this.total) { return null; } - let isCritical = false + 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) { @@ -290,9 +317,9 @@ export class DGPercentileRoll extends DGRoll { isCritical = true; } - // If inhuman and the roll is below the regular (non-x5) value of the stat, it is a critical. + // 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 + this.modifier) / 5)) { + if (this.isInhuman && this.total <= (this.target + this.modifier) / 5) { isCritical = true; } @@ -302,8 +329,8 @@ export class DGPercentileRoll extends DGRoll { /** * Determines if a roll succeeded. * If roll has not been evaluated, return null. - * - * @returns {null|Boolean} + * + * @returns {null|Boolean} */ get isSuccess() { // If roll isn't evaluated, return null. @@ -313,7 +340,7 @@ export class DGPercentileRoll extends DGRoll { // A roll of 100 always (critically) fails, even for inhuman rolls. if (this.total === 100) return false; - return this.total <= (this.target + this.modifier); + return this.total <= this.target + this.modifier; } } @@ -321,11 +348,11 @@ export class DGLethalityRoll extends DGPercentileRoll { /** * See constructor for DGPercentileRoll. This theoretically could be done in the parent class' * constructor, but since Lethality rolls needs its own class for custom methods anyway, - * we will set the target and localized key here. - * - * @param {String} formula - * @param {Object} data - * @param {Object} options + * we will set the target and localized key here. + * + * @param {String} formula + * @param {Object} data + * @param {Object} options */ constructor(formula, data, options) { super(formula, data, options); @@ -335,34 +362,40 @@ export class DGLethalityRoll extends DGPercentileRoll { /** * Prepares data for a chat message and then passes that data - * to a method that actually creates a ChatMessage. - * + * to a method that actually creates a ChatMessage. + * * Lays out and styles message based on outcome of the roll. - * + * * Overrides `DGPercentileRoll.toChat()` - * + * * @returns {Promise} - the created chat message. * @override */ - async toChat() { - const rollMode = this.options.rollMode || game.settings.get("core", "rollMode"); - let resultString = ''; - let styleOverride = ''; - if(this.total <= this.target){ + async toChat() { + const rollMode = + this.options.rollMode || game.settings.get("core", "rollMode"); + let resultString = ""; + let styleOverride = ""; + if (this.total <= this.target) { resultString = `${game.i18n.localize("DG.Roll.Lethal").toUpperCase()}`; - styleOverride="color: red"; - } - else{ + styleOverride = "color: red"; + } else { resultString = `${game.i18n.localize("DG.Roll.Failure")}`; } const { nonLethalDamage } = this; - let label = `${game.i18n.localize("DG.Roll.Rolling")} ${game.i18n.localize("DG.Roll.Lethality").toUpperCase()} ${game.i18n.localize("DG.Roll.For")} ${this.item.name.toUpperCase()} ${game.i18n.localize("DG.Roll.Target")} ${this.target + this.modifier}`; + let label = `${game.i18n.localize("DG.Roll.Rolling")} ${game.i18n + .localize("DG.Roll.Lethality") + .toUpperCase()} ${game.i18n.localize( + "DG.Roll.For", + )} ${this.item.name.toUpperCase()} ${game.i18n.localize( + "DG.Roll.Target", + )} ${this.target + this.modifier}`; if (this.modifier) { - label += ` (${DGUtils.formatStringWithLeadingPlus(this.modifier)}%)` + label += ` (${DGUtils.formatStringWithLeadingPlus(this.modifier)}%)`; } - - let html = ''; + + let html = ""; html += `
`; html += `
`; html += `
${resultString}
`; @@ -396,7 +429,9 @@ export class DGLethalityRoll extends DGPercentileRoll { html += `
`; html += ` `; html += `
`; - html += `

${this.total} (${nonLethalDamage.total} ${game.i18n.localize("DG.Roll.Damage")})

`; + html += `

${this.total} (${ + nonLethalDamage.total + } ${game.i18n.localize("DG.Roll.Damage")})

`; html += `
`; return this.createMessage(html, label, rollMode); @@ -405,12 +440,12 @@ export class DGLethalityRoll extends DGPercentileRoll { /** * Calculates the damage for when a lethality roll fails. * If roll has not been evaluated, return null. - * + * * See full rules on page 57 of agent's handbook. - * + * * Note, this getter does not actually care if the roll has failed. - * - * @returns {null|Object} - return data about the non-lethal damage. + * + * @returns {null|Object} - return data about the non-lethal damage. */ get nonLethalDamage() { if (!this.total) { @@ -420,7 +455,8 @@ export class DGLethalityRoll extends DGPercentileRoll { // Try to determine what the d100 result would be as if it was two d10's being rolled. const totalString = this.total.toString(); const digits = totalString.length; - let die1, die2; + let die1; + let die2; switch (digits) { case 1: // If one digit in the result, one die is a 10, and the other is the result. @@ -428,7 +464,10 @@ export class DGLethalityRoll extends DGPercentileRoll { break; case 2: // If two digits in the result, each die is the value of one of the digits. If one of those digits is 0, make it 10. - [die1, die2] = totalString.split("").map((digit) => parseInt(digit)).map((digit) => digit || 10); + [die1, die2] = totalString + .split("") + .map((digit) => parseInt(digit)) + .map((digit) => digit || 10); break; case 3: // If three digits in the result (aka result === 100), each die is a 10. @@ -439,7 +478,7 @@ export class DGLethalityRoll extends DGPercentileRoll { } const total = die1 + die2; - return { die1, die2, total } + return { die1, die2, total }; } } @@ -447,70 +486,77 @@ export class DGDamageRoll extends DGRoll { /** * Prepares data for a chat message and then passes that data * to a method that actually creates a ChatMessage. - * + * * @returns {Promise} - the created chat message. * @override */ async toChat() { - const rollMode = this.options.rollMode || game.settings.get("core", "rollMode"); + const rollMode = + this.options.rollMode || game.settings.get("core", "rollMode"); let label = this.formula; - try{ - label = `${this.item.name}: ${game.i18n.localize("DG.Roll.Rolling")} ${game.i18n.localize("DG.Roll.Damage").toUpperCase()} ${game.i18n.localize("DG.Roll.For")} ${label.toUpperCase()}`; - } - catch{ + try { + label = `${this.item.name}: ${game.i18n.localize( + "DG.Roll.Rolling", + )} ${game.i18n + .localize("DG.Roll.Damage") + .toUpperCase()} ${game.i18n.localize( + "DG.Roll.For", + )} ${label.toUpperCase()}`; + } catch { label = `Rolling DAMAGE for ${label.toUpperCase()}`; } return this.createMessage(this.total, label, rollMode); } async showDialog() { - let template = "systems/deltagreen/templates/dialog/modify-damage-roll.html"; - let backingData = { - data:{ + const template = + "systems/deltagreen/templates/dialog/modify-damage-roll.html"; + const backingData = { + data: { label: this.item?.name, originalFormula: this.formula, outerModifier: "2 * ", - innerModifier: "+ 0" + innerModifier: "+ 0", }, }; - let html = await renderTemplate(template, backingData); + const html = await renderTemplate(template, backingData); return new Promise((resolve, reject) => { new Dialog({ content: html, title: game.i18n.localize("DG.ModifySkillRollDialogue.Title"), default: "roll", buttons: { - roll:{ + roll: { label: game.i18n.translations.DG.Roll.Roll, - callback: html => { - try{ - let outerModifier = html.find("[name='outerModifier']").val(); // this is text as a heads up - let innerModifier = html.find("[name='innerModifier']").val(); // this is text as a heads up - let modifiedBaseRoll = html.find("[name='originalFormula']").val(); // this is text as a heads up - let rollMode = html.find("[name='targetRollMode']").val(); + callback: (html) => { + try { + const outerModifier = html.find("[name='outerModifier']").val(); // this is text as a heads up + let innerModifier = html.find("[name='innerModifier']").val(); // this is text as a heads up + const modifiedBaseRoll = html + .find("[name='originalFormula']") + .val(); // this is text as a heads up + const rollMode = html.find("[name='targetRollMode']").val(); - if(innerModifier.replace(" ", "") === "+0"){ + if (innerModifier.replace(" ", "") === "+0") { innerModifier = ""; } let newFormula = ""; - if(outerModifier.trim() != ""){ - newFormula += outerModifier + "(" + modifiedBaseRoll + innerModifier.trim() + ")"; - } - else{ + if (outerModifier.trim() != "") { + newFormula += `${outerModifier}(${modifiedBaseRoll}${innerModifier.trim()})`; + } else { newFormula += modifiedBaseRoll + innerModifier.trim(); } - resolve({newFormula, rollMode}) - } - catch(ex){ + resolve({ newFormula, rollMode }); + } catch (ex) { reject(console.log(ex)); } - } - } - } + }, + }, + }, }).render(true); }); } @@ -520,22 +566,26 @@ export class DGSanityDamageRoll extends DGRoll { /** * Prepares data for a chat message and then passes that data * to a method that actually creates a ChatMessage. - * + * * @returns {Promise} - the created chat message. * @override */ async toChat() { - const rollMode = this.options.rollMode || game.settings.get("core", "rollMode"); + const rollMode = + this.options.rollMode || game.settings.get("core", "rollMode"); const [lowDie, highDie] = this.terms[0].terms.map((formula) => { return Roll.parse(formula)[0] || { faces: parseInt(formula), number: 1 }; }); const [lowResult, highResult] = this.damageResults; - - const flavor = `Rolling ${DGUtils.localizeWithFallback('DG.Generic.SanDamage', 'SAN DAMAGE')} For ${lowDie.formula} / ${highDie.formula}`; - - let html = ''; + + const flavor = `Rolling ${DGUtils.localizeWithFallback( + "DG.Generic.SanDamage", + "SAN DAMAGE", + )} For ${lowDie.formula} / ${highDie.formula}`; + + let html = ""; html += `
`; html += `
`; html += `
${lowDie.formula} / ${highDie.formula}
`; @@ -568,22 +618,22 @@ export class DGSanityDamageRoll extends DGRoll { html += `
`; html += ` `; html += `
`; - html += `

${lowResult} / ${highResult}

` + html += `

${lowResult} / ${highResult}

`; html += `
`; return this.createMessage(html, flavor, rollMode); } /** * Returns the two results for a sanity damage roll. - * + * * Returns null if the roll has not been evaluated. - * + * * @returns {null|Array} - Array of result numbers */ get damageResults() { if (!this.total) return null; const [lowResult, highResult] = this.terms[0].results; - return [lowResult?.result, highResult?.result] + return [lowResult?.result, highResult?.result]; } -} \ No newline at end of file +} diff --git a/module/settings.js b/module/settings.js index 0a97cac..005e425 100644 --- a/module/settings.js +++ b/module/settings.js @@ -15,7 +15,7 @@ export const registerSystemSettings = function () { default: "program", // The default value for the setting onChange: (value) => { // A callback function which triggers when the setting is changed - //console.log(value) + // console.log(value) }, }); @@ -44,11 +44,10 @@ export const registerSystemSettings = function () { default: "1d4", // The default value for the setting, per the most recent errata. onChange: (value) => { // A callback function which triggers when the setting is changed - //console.log(value) + // console.log(value) }, }); - // These two settings are obsolete now game.settings.register("deltagreen", "showImpossibleLandscapesContent", { name: "Show Impossible Landscapes Content", @@ -73,12 +72,12 @@ export const registerSystemSettings = function () { TypeWriterCondensed: "Condensed Typewriter (Modern, Small Typewriter Font)", PublicSans: "Public Sans (US Government-style sans serif font)", - //"atwriter": "Another Typewriter (Alternate Old-style Typewriter Font)" + // "atwriter": "Another Typewriter (Alternate Old-style Typewriter Font)" }, default: "SpecialElite", // The default value for the setting onChange: (value) => { // A callback function which triggers when the setting is changed - //console.log(value) + // console.log(value) }, }); @@ -97,7 +96,7 @@ export const registerSystemSettings = function () { default: "OldPaper1", // The default value for the setting onChange: (value) => { // A callback function which triggers when the setting is changed - //console.log(value) + // console.log(value) }, }); }; diff --git a/module/templates.js b/module/templates.js index 0cde96b..9f479e2 100644 --- a/module/templates.js +++ b/module/templates.js @@ -3,15 +3,15 @@ * Pre-loaded templates are compiled and cached for fast access when rendering * @return {Promise} */ -export const preloadHandlebarsTemplates = async function() { - return loadTemplates([ - "systems/deltagreen/templates/actor/actor-sheet.html", - "systems/deltagreen/templates/actor/limited-sheet.html", - "systems/deltagreen/templates/actor/unnatural-sheet.html", - "systems/deltagreen/templates/actor/npc-sheet.html", - "systems/deltagreen/templates/actor/cv-partial.html", - "systems/deltagreen/templates/dialog/modify-percentile-roll.html", - "systems/deltagreen/templates/actor/vehicle-sheet.html", - "systems/deltagreen/templates/actor/help-and-licensing-partial.html" - ]); - }; \ No newline at end of file +export const preloadHandlebarsTemplates = async function () { + return loadTemplates([ + "systems/deltagreen/templates/actor/actor-sheet.html", + "systems/deltagreen/templates/actor/limited-sheet.html", + "systems/deltagreen/templates/actor/unnatural-sheet.html", + "systems/deltagreen/templates/actor/npc-sheet.html", + "systems/deltagreen/templates/actor/cv-partial.html", + "systems/deltagreen/templates/dialog/modify-percentile-roll.html", + "systems/deltagreen/templates/actor/vehicle-sheet.html", + "systems/deltagreen/templates/actor/help-and-licensing-partial.html", + ]); +};