From 417acacfe4b47146f79d2316dbb737516cee4543 Mon Sep 17 00:00:00 2001 From: Martin Jencka Date: Mon, 23 Nov 2020 10:27:43 -0700 Subject: [PATCH] Item Macros + Reload Popup 0.1.0 -You can now drag items and weapons on your sheet. -If you drag an item/weapon/skill to your macro bar it will create a rollable macro. Reloading Changes -When you try to fire a weapon that is either out of shots, or out of ammo, it will popup saying you need to reload. --- module/actor/actor-sheet.js | 13 +++++ module/actor/actor.js | 86 +++++++++++++++++++++++++++-- module/actor/creature-sheet.js | 11 ++++ module/actor/ship-sheet.js | 19 +++++-- module/mosh.js | 76 ++++++++++++++++++++++++- system.json | 2 +- templates/actor/actor-sheet.html | 10 ++-- templates/actor/creature-sheet.html | 6 +- templates/actor/ship-sheet.html | 8 +-- 9 files changed, 206 insertions(+), 25 deletions(-) diff --git a/module/actor/actor-sheet.js b/module/actor/actor-sheet.js index 5238e18..a7c5016 100644 --- a/module/actor/actor-sheet.js +++ b/module/actor/actor-sheet.js @@ -170,6 +170,7 @@ export class MothershipActorSheet extends ActorSheet { // Rollable Weapon html.find('.weapon-roll').click(ev => { const li = ev.currentTarget.closest(".item"); + this.actor.rollWeapon(li.dataset.itemId, { event: ev }); @@ -243,6 +244,18 @@ export class MothershipActorSheet extends ActorSheet { attribute.label = "Stress"; this.actor.rollStress(attribute); }); + + // Drag events for macros. + if (this.actor.owner) { + let handler = ev => this._onDragStart(ev); + + html.find('li.dropitem').each((i, li) => { + if (li.classList.contains("inventory-header")) return; + li.setAttribute("draggable", true); + li.addEventListener("dragstart", handler, false); + }); + } + } /* -------------------------------------------- */ diff --git a/module/actor/actor.js b/module/actor/actor.js index 42cbc50..3aeb605 100644 --- a/module/actor/actor.js +++ b/module/actor/actor.js @@ -91,7 +91,7 @@ export class MothershipActor extends Actor { rollStress(attribute) { //this.rollAttribute(attribute, "none"); let rollOver = true; - if(attribute.label == "Calm") + if (attribute.label == "Calm") rollOver = false; let attLabel = attribute.label?.charAt(0).toUpperCase() + attribute.label?.toLowerCase().slice(1); @@ -130,16 +130,71 @@ export class MothershipActor extends Actor { item.data.ammo -= 1; this.updateEmbeddedEntity('OwnedItem', item); } else { + + //Select the stat of the roll. + let t = new Dialog({ + title: "Reload", + content: "

Out of Ammo


", + buttons: { + cancel: { + icon: '', + label: "Cancel", + callback: () => { } + } + }, + default: "roll", + close: () => { } + }); + t.render(true); return; } } else { if (item.data.curShots > 0) { let subAmount = Math.max(item.data.shotsPerFire, 1); - item.data.curShots = Math.max(item.data.curShots-subAmount, 0); + item.data.curShots = Math.max(item.data.curShots - subAmount, 0); console.log("Unloading Shots"); this.updateEmbeddedEntity('OwnedItem', item); } else { + if (item.data.ammo > 0 || !item.data.useAmmo) { + //Select the stat of the roll. + let t = new Dialog({ + title: "Reload", + content: "

Reload?


", + buttons: { + roll: { + icon: '', + label: "Reload", + callback: (html) => this.reloadWeapon(itemId) + }, + cancel: { + icon: '', + label: "Cancel", + callback: () => { } + } + }, + default: "roll", + close: () => { } + }); + t.render(true); + } else { + //Select the stat of the roll. + let t = new Dialog({ + title: "Reload", + content: "

Out of Ammo


", + buttons: { + cancel: { + icon: '', + label: "Cancel", + callback: () => { } + } + }, + default: "roll", + close: () => { } + }); + t.render(true); + } + // let actor = this; // let speaker = ChatMessage.getSpeaker({ actor }); // ChatMessage.create({ @@ -178,6 +233,25 @@ export class MothershipActor extends Actor { t.render(true); } + reloadWeapon(itemId, options = { event: null }) { + let item = duplicate(this.getEmbeddedEntity("OwnedItem", itemId)); + + if (event.button == 0) { + if (!item.data.useAmmo) { + item.data.curShots = item.data.shots; + } else { + item.data.ammo += item.data.curShots; + let reloadAmount = Math.min(item.data.ammo, item.data.shots); + item.data.curShots = reloadAmount; + + item.data.ammo -= reloadAmount; + } + } + + this.updateEmbeddedEntity('OwnedItem', item); + } + + printDescription(itemId, options = { event: null }) { let item = duplicate(this.getEmbeddedEntity("OwnedItem", itemId)); this.chatDesc(item); @@ -247,12 +321,12 @@ export class MothershipActor extends Actor { let a = new Roll(diceformular, {}); a.roll(); - if(a._total == 100){ + if (a._total == 100) { r.results[0] = 0; r._total = 0; } - if(a._total == 100){ + if (a._total == 100) { r.results[0] = 0; a._total = 0; } @@ -274,7 +348,7 @@ export class MothershipActor extends Actor { //Here's where we handle the result text. let resultText = (r._total < targetValue ? "Success" : "Failure"); - if(rollOver == true) + if (rollOver == true) resultText = (r._total > targetValue ? "Success" : "Failure"); console.log(attribute.value + attribute.mod); @@ -412,7 +486,7 @@ export class MothershipActor extends Actor { chatDesc(item) { let itemName = item.name?.charAt(0).toUpperCase() + item.name?.toLowerCase().slice(1); if (!item.name && isNaN(itemName)) - itemName = item.charAt(0)?.toUpperCase() + item.toLowerCase().slice(1); + itemName = item.charAt(0)?.toUpperCase() + item.toLowerCase().slice(1); var templateData = { actor: this, diff --git a/module/actor/creature-sheet.js b/module/actor/creature-sheet.js index 8f50e4e..c1b86b4 100644 --- a/module/actor/creature-sheet.js +++ b/module/actor/creature-sheet.js @@ -211,6 +211,17 @@ export class MothershipCreatureSheet extends ActorSheet { }); }); + // Drag events for macros. + if (this.actor.owner) { + let handler = ev => this._onDragStart(ev); + + html.find('li.dropitem').each((i, li) => { + if (li.classList.contains("inventory-header")) return; + li.setAttribute("draggable", true); + li.addEventListener("dragstart", handler, false); + }); + } + } /* -------------------------------------------- */ diff --git a/module/actor/ship-sheet.js b/module/actor/ship-sheet.js index e20f2d4..5b92fa5 100644 --- a/module/actor/ship-sheet.js +++ b/module/actor/ship-sheet.js @@ -103,8 +103,8 @@ export class MothershipShipSheet extends ActorSheet { const item = this.actor.getOwnedItem(li.data("itemId")); item.sheet.render(true); - if(item.type == "module"){ - item.data.totalHull = amount*item.data.hull; + if (item.type == "module") { + item.data.totalHull = amount * item.data.hull; } }); @@ -120,8 +120,8 @@ export class MothershipShipSheet extends ActorSheet { item.data.quantity = Number(amount) - 1; } - if(item.type == "module"){ - item.data.totalHull = item.data.quantity*item.data.hull; + if (item.type == "module") { + item.data.totalHull = item.data.quantity * item.data.hull; } this.actor.updateEmbeddedEntity('OwnedItem', item); @@ -198,6 +198,17 @@ export class MothershipShipSheet extends ActorSheet { }); }); + + // Drag events for macros. + if (this.actor.owner) { + let handler = ev => this._onDragStart(ev); + + html.find('li.dropitem').each((i, li) => { + if (li.classList.contains("inventory-header")) return; + li.setAttribute("draggable", true); + li.addEventListener("dragstart", handler, false); + }); + } } /* -------------------------------------------- */ diff --git a/module/mosh.js b/module/mosh.js index 1877908..7bab8c4 100644 --- a/module/mosh.js +++ b/module/mosh.js @@ -13,7 +13,8 @@ Hooks.once('init', async function () { game.mosh = { MothershipActor, - MothershipItem + MothershipItem, + rollItemMacro }; /** @@ -75,4 +76,75 @@ Hooks.once('init', async function () { Handlebars.registerHelper('toLowerCase', function (str) { return str.toLowerCase(); }); -}); \ No newline at end of file +}); + +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) => createMothershipMacro(data, slot)); +}); + + +/* -------------------------------------------- */ +/* Hotbar Macros */ +/* -------------------------------------------- */ + +/** + * Create a Macro from an Item drop. + * Get an existing item macro if one exists, otherwise create a new one. + * @param {Object} data The dropped data + * @param {number} slot The hotbar slot to use + * @returns {Promise} + */ +async function createMothershipMacro(data, slot) { + if (data.type !== "Item") return; + if (!("data" in data)) return ui.notifications.warn("You can only create macro buttons for owned Items"); + const item = data.data; + + console.log(item); + + // Create the macro command + let command = `game.mosh.rollItemMacro("${item.name}");`; + + + let macro = game.macros.entities.find(m => (m.name === item.name) && (m.command === command)); + if (!macro) { + macro = await Macro.create({ + name: item.name, + type: "script", + img: item.img, + command: command, + flags: { + "mosh.itemMacro": true + } + }); + } + game.user.assignHotbarMacro(macro, slot); + return false; +} + + +/** + * Roll Macro from a Weapon. + * @param {string} itemName + * @return {Promise} + */ +function rollItemMacro(itemName) { + const speaker = ChatMessage.getSpeaker(); + let actor; + if (speaker.token) actor = game.actors.tokens[speaker.token]; + if (!actor) actor = game.actors.get(speaker.actor); + const item = actor ? actor.items.find(i => i.name === itemName) : null; + if (!item) return ui.notifications.warn(`Your controlled Actor does not have an item with the id ${itemId}`); + + console.log(); + + if(item.type == "weapon"){ + return actor.rollWeapon(item.id); + } else if(item.type == "item" || item.type == "armor" || item.type == "ability"){ + return actor.printDescription(item.id); + } else if(item.type == "skill"){ + return actor.rollSkill(item.id); + } + + console.error("No item type found: " + item); +} diff --git a/system.json b/system.json index 0340b16..e560981 100644 --- a/system.json +++ b/system.json @@ -2,7 +2,7 @@ "name": "mosh", "title": "Mothership", "description": "The unofficial Mothership system for FoundryVTT", - "version": "0.0.9", + "version": "0.1.0", "minimumCoreVersion": "0.5.5", "compatibleCoreVersion": "0.5.5", "templateVersion": 2, diff --git a/templates/actor/actor-sheet.html b/templates/actor/actor-sheet.html index 26c4b56..2fc0678 100644 --- a/templates/actor/actor-sheet.html +++ b/templates/actor/actor-sheet.html @@ -308,7 +308,7 @@ {{#each actor.armors as |armor id|}} -
  • +
  • {{armor.name}}

    {{armor.data.bonus}}
    @@ -340,7 +340,7 @@
  • {{#if actor.data.settings.hideWeight}} {{#each actor.gear as |item id|}} -
  • +
  • {{item.name}}

    {{item.data.quantity}}
    @@ -353,7 +353,7 @@ {{/each}} {{else}} {{#each actor.gear as |item id|}} -
  • +
  • {{item.name}}

    {{item.data.quantity}}
    @@ -384,7 +384,7 @@
  • {{#each actor.skills as |skill id|}} -
  • +
  • {{skill.name}}
    {{skill.data.rank}}
    @@ -414,7 +414,7 @@
  • {{#each actor.weapons as |weapon id|}} -
  • +
  • {{weapon.name}}
    diff --git a/templates/actor/creature-sheet.html b/templates/actor/creature-sheet.html index 712a807..e1b25e6 100644 --- a/templates/actor/creature-sheet.html +++ b/templates/actor/creature-sheet.html @@ -131,14 +131,14 @@
    Special Abilities
    {{#each actor.abilities as |ability id|}} -
    +
  • {{ability.name}}
    {{{ability.data.description}}}
    - +
  • {{/each}} {{#each actor.weapons as |weapon id|}} -
  • +
  • {{weapon.name}}
    diff --git a/templates/actor/ship-sheet.html b/templates/actor/ship-sheet.html index 50e910b..4f2824b 100644 --- a/templates/actor/ship-sheet.html +++ b/templates/actor/ship-sheet.html @@ -159,7 +159,7 @@
    -
    Special Abilities
    +
    Notes
    {{#each actor.abilities as |ability id|}}
    @@ -217,7 +217,7 @@
  • {{#each actor.weapons as |weapon id|}} -
  • +
  • {{weapon.name}}
    @@ -264,7 +264,7 @@
  • {{#each actor.modules as |module id|}} -
  • +
  • {{module.name}}

    @@ -295,7 +295,7 @@
  • {{#each actor.cargo as |item id|}} -
  • +
  • {{item.name}}