Skip to content

Commit

Permalink
Merge branch 'main' into xp_spending
Browse files Browse the repository at this point in the history
  • Loading branch information
wrycu authored Apr 6, 2024
2 parents 24f3c7d + 09eb95b commit 4e5ea13
Show file tree
Hide file tree
Showing 23 changed files with 329 additions and 68 deletions.
5 changes: 5 additions & 0 deletions lang/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,10 @@
"SWFFG.Cost": "COST:",
"SWFFG.EnableSoakCalc": "Enable Soak Auto-Calculation",
"SWFFG.EnableSoakCalcHint": "Enable soak auto-calculation and unload field for manual entry",
"SWFFG.SheetOptions2.EnablePrice.Name": "Enable Price",
"SWFFG.SheetOptions2.EnablePrice.Hint": "Shows price on item sheets",
"SWFFG.SheetOptions2.enableRarity.Name": "Enable Rarity",
"SWFFG.SheetOptions2.enableRarity.Hint": "Shows rarity on item sheets",
"SWFFG.DefaultMedicalItemName": "Stimpacks",
"SWFFG.MedicalItemName": "Healing Item Name",
"SWFFG.MedicalItemNameHint": "Name of the item characters use to heal.",
Expand All @@ -343,6 +347,7 @@
"SWFFG.Delete": "Delete",
"SWFFG.SheetOptions": "Sheet Options",
"SWFFG.CharacterSheet": "Character Sheet",
"SWFFG.ItemSheet": "Item Sheet",
"SWFFG.Options": "Options",
"SWFFG.TalentSource": "Talent Rank Sources for",
"SWFFG.EnableStrainThreshold": "Enable Strain Threshold",
Expand Down
32 changes: 26 additions & 6 deletions modules/actors/actor-sheet-ffg.js
Original file line number Diff line number Diff line change
Expand Up @@ -543,13 +543,33 @@ export class ActorSheetFFG extends ActorSheet {
html.find("li.item-pill").on("click", async (event) => {
event.preventDefault();
event.stopPropagation();
const li = event.currentTarget;

let itemId = li.dataset.itemId;
let modifierType = li.dataset.modifierType;
let modifierId = li.dataset.modifierId;
const li = $(event.currentTarget);
const itemType = li.attr("data-item-embed-type");
let itemData = {};
const newEmbed = li.attr("data-item-embed");

if (newEmbed === "true" && itemType === "itemmodifier") {
itemData = {
img: li.attr('data-item-embed-img'),
name: li.attr('data-item-embed-name'),
type: li.attr('data-item-embed-type'),
system: {
description: unescape(li.attr('data-item-embed-description')),
attributes: JSON.parse(li.attr('data-item-embed-modifiers')),
rank: li.attr('data-item-embed-rank'),
rank_current: li.attr('data-item-embed-rank'),
},
};
const tempItem = await Item.create(itemData, {temporary: true});
tempItem.sheet.render(true);
} else {
CONFIG.logger.debug(`Unknown item type: ${itemType}, or lacking new embed system`);
let itemId = li.dataset.itemId;
let modifierType = li.dataset.modifierType;
let modifierId = li.dataset.modifierId;

await EmbeddedItemHelpers.displayOwnedItemItemModifiersAsJournal(itemId, modifierType, modifierId, this.actor.id, this.actor.compendium);
await EmbeddedItemHelpers.displayOwnedItemItemModifiersAsJournal(itemId, modifierType, modifierId, this.actor.id, this.actor.compendium);
}
});
}
});
Expand Down
2 changes: 1 addition & 1 deletion modules/helpers/crew.js
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ export function build_crew_roll(vehicle, crew_id, crew_role) {
}
// check if the pool uses handling
if (role_info[0].use_handling) {
const handling = vehicle?.system?.stats?.handling?.value;
const handling = vehicle_actor?.system?.stats?.handling?.value;
// add modifiers from the vehicle handling
if (handling > 0) {
starting_pool['boost'] = handling;
Expand Down
1 change: 1 addition & 0 deletions modules/helpers/dice-helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,7 @@ export function get_dice_pool(actor_id, skill_name, incoming_roll) {
triumph: skill.triumph + incoming_roll.triumph,
despair: skill.despair + incoming_roll.despair,
upgrades: skill.upgrades + incoming_roll.upgrades,
remsetback: skill.remsetback + incoming_roll.remsetback,
difficulty: +incoming_roll.difficulty,
});
return dicePool;
Expand Down
104 changes: 78 additions & 26 deletions modules/helpers/macros.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,44 +8,96 @@ const createMacroItem = async (macro) => {
};

// Simple function for handling the creation of rollable weapon macros on hotbarDrop event.
export async function createFFGMacro(data, slot) {
if (data.type !== "Transfer" && data.type !== "CreateMacro") return;
if (data.data.type !== "weapon" && data.data.type !== "skill") return;

export async function createFFGMacro(bar, data, slot) {
let macro;
if (data.data.type === "weapon") {
if (!("data" in data)) return ui.notifications.warn("You can only create macro buttons for owned weapon items.");
const item = data.data;
// Create the macro command
const command = `
// game.ffg.DiceHelpers.rollItem(itemid, actorid, flavortext, sound);
if (["Item", "Actor"].includes(data.type)) {
const entity = await fromUuid(data.uuid);
if (!entity) {
return;
}
if (entity.type === "weapon") {
let command;
if (!entity?.flags?.starwarsffg?.ffgIsOwned) {
command = `await Hotbar.toggleDocumentSheet("${data.uuid}");`;
} else {
command = `
game.ffg.DiceHelpers.rollItem(\"${item._id}\", \"${entity.actorId}\");
`;
}
macro = await createMacroItem({
name: entity.name,
type: "script",
img: entity.img,
command: command,
});
} else if (entity.type === "skill") {
const actor = game.actors.get(data.actorId);
const command = `
const ffgactor = game.actors.get("${data.actorId}");
const skill = ffgactor.data.data.skills["${data.data.skill}"];
const characteristic = ffgactor.data.data.characteristics["${data.data.characteristic}"];
const actorSheet = ffgactor.sheet.getData();
game.ffg.DiceHelpers.rollSkillDirect(skill, characteristic, 2, actorSheet);`;
macro = await createMacroItem({
name: `${actor.name}-${data.data.skill}`,
type: "script",
command: command,
});
}


} else if (data.type === "Transfer") {
if (data.data.type !== "weapon" && data.data.type !== "skill") {
return;
}
if (data.data.type === "weapon") {
if (!("data" in data)) return ui.notifications.warn("You can only create macro buttons for owned weapon items.");
const item = data.data;
// Create the macro command
const command = `
game.ffg.DiceHelpers.rollItem(\"${item._id}\", \"${data.actorId}\");
`;
macro = await createMacroItem({
name: item.name,
type: "script",
img: item.img,
command: command,
});
} else if (data.data.type === "skill") {
const actor = game.actors.get(data.actorId);
const command = `
macro = await createMacroItem({
name: `Attack with ${item.name}`,
type: "script",
img: item.img,
command: command,
});
} else if (data.data.type === "skill") {
const actor = game.actors.get(data.actorId);
const command = `
// game.ffg.DiceHelpers.rollSkillDirect(skill, characteristic, difficulty, actorSheet, flavortext, sound);
const ffgactor = game.actors.get("${data.actorId}");
const skill = ffgactor.data.data.skills["${data.data.skill}"];
const characteristic = ffgactor.data.data.characteristics["${data.data.characteristic}"];
const actorSheet = ffgactor.sheet.getData();
game.ffg.DiceHelpers.rollSkillDirect(skill, characteristic, 2, actorSheet);`;
macro = await createMacroItem({
name: `${actor.name}-${data.data.skill}`,
type: "script",
command: command,
});
macro = await createMacroItem({
name: `${actor.name}-${data.data.skill}`,
type: "script",
command: command,
});
}
}

if (macro) {
game.user.assignHotbarMacro(macro, slot);
}

return false;
}

/**
* Update a macro with the image of the entity in the macro
* @param macro
* @returns {Promise<*>}
*/
export async function updateMacro(macro) {
let uuid = macro.command.split("\"");
if (uuid.length >= 1) {
const document = await fromUuid(uuid[1]);
if (document?.img) {
macro.img = document?.img;
await macro.update({img: document.img});
}
}
return macro;
}
93 changes: 93 additions & 0 deletions modules/items/item-ffg-options.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
export default class ItemOptions {
constructor(data, html) {
this.data = data;
this.options = {};
this.init(html);
}

init(html) {
const options = $(`.starwarsffg.sheet.item[data-appid='${this.data.appId}'] .ffg-sheet-options`);
if (options.length === 0) {
const button = $(`<a class="ffg-sheet-options"><i class="fas fa-wrench"></i>${game.i18n.localize("SWFFG.SheetOptions")}</a>`);
button.insertBefore(`.starwarsffg.sheet.item[data-appid='${this.data.appId}'] header a:first`);
button.on("click", this.handler.bind(this));
}
}

handler(event) {
const title = `${game.i18n.localize("SWFFG.ItemSheet")} ${game.i18n.localize("SWFFG.Options")}: ${this.data.item.name}`;

new Dialog(
{
title,
content: {
options: this.options,
},
buttons: {
one: {
icon: '<i class="fas fa-check"></i>',
label: game.i18n.localize("SWFFG.ButtonAccept"),
callback: (html) => {
const controls = html.find("input, select");

let updateObject = {};

for (let i = 0; i < controls.length; i += 1) {
const control = controls[i];
let value;
if (control.dataset["dtype"] === "Boolean") {
value = control.checked;
} else {
value = control.value;
}

updateObject[control.name] = value;
this.options[control.id].value = value;
}

this.data.object.update(updateObject);
this.data.object.sheet.render(true);
},
},
two: {
icon: '<i class="fas fa-times"></i>',
label: game.i18n.localize("SWFFG.Cancel"),
},
},
},
{
classes: ["dialog", "starwarsffg"],
template: "systems/starwarsffg/templates/dialogs/ffg-sheet-options.html",
}
).render(true);
}

async register(optionName, options) {
if (!this.options[optionName]) {
this.options[optionName] = { ...options };
}
if (typeof this.data.object.flags?.starwarsffg?.config == "undefined") {
await this.data.object.setFlag("starwarsffg", "config", {});
}

if (typeof this.data.object.flags?.starwarsffg?.config[optionName] !== "undefined") {
this.options[optionName].value = this.data.object.flags?.starwarsffg?.config[optionName];
} else {
this.options[optionName].value = this.options[optionName].default;
}
}

registerMany(optionsArray) {
optionsArray.forEach((option) => {
this.register(option.name, option.options);
});
}

unregister(optionName) {
delete this.options[optionName];
}

clear() {
this.options = {};
}
}
3 changes: 2 additions & 1 deletion modules/items/item-ffg.js
Original file line number Diff line number Diff line change
Expand Up @@ -491,7 +491,8 @@ export class ItemFFG extends ItemBaseFFG {
// General equipment properties
else if (this.type !== "talent") {
if (data.hasOwnProperty("adjusteditemmodifier")) {
const qualities = data.adjusteditemmodifier?.map((m) => `<li class='item-pill ${m.adjusted ? "adjusted hover" : ""}' data-item-embed-type='itemmodifier' data-item-embed-name='${m.name}' data-item-embed-img='${m.img}' data-item-embed-description='${m.system.description}' data-item-embed-modifiers='${JSON.stringify(m.system.attributes)}' data-item-embed-rank='${m.system.rank_current}' data-item-embed='true'>${m.name} ${m.system?.rank_current > 0 ? m.system.rank_current : ""} ${m.adjusted ? "<div class='tooltip2'>" + game.i18n.localize("SWFFG.FromAttachment") + "</div>" : ""}</li>`);
const modifiers = data.adjusteditemmodifier?.filter(i => Object.keys(i).length > 0);
const qualities = modifiers?.map((m) => `<li class='item-pill ${m.adjusted ? "adjusted hover" : ""}' data-item-embed-type='itemmodifier' data-item-embed-name='${m.name}' data-item-embed-img='${m.img}' data-item-embed-description='${escape(m.system.description)}' data-item-embed-modifiers='${JSON.stringify(m.system.attributes)}' data-item-embed-rank='${m.system.rank_current}' data-item-embed='true'>${m.name} ${m.system?.rank_current > 0 ? m.system.rank_current : ""} ${m.adjusted ? "<div class='tooltip2'>" + game.i18n.localize("SWFFG.FromAttachment") + "</div>" : ""}</li>`);

props.push(`<div>${game.i18n.localize("SWFFG.ItemDescriptors")}: <ul>${qualities.join("")}<ul></div>`);
}
Expand Down
23 changes: 22 additions & 1 deletion modules/items/item-sheet-ffg.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import DiceHelpers from "../helpers/dice-helpers.js";
import item from "../helpers/embeddeditem-helpers.js";
import EmbeddedItemHelpers from "../helpers/embeddeditem-helpers.js";
import {xpLogSpend} from "../helpers/actor-helpers.js";
import ItemOptions from "./item-ffg-options.js";

/**
* Extend the basic ItemSheet with some very simple modifications
Expand Down Expand Up @@ -108,8 +109,11 @@ export class ItemSheetFFG extends ItemSheet {
this.position.height = 350;
break;
case "armour":
case "ability":
case "gear":
this.position.width = 385;
this.position.height = 750;
break;
case "ability":
case "shipattachment":
case "homesteadupgrade":
this.position.width = 385;
Expand Down Expand Up @@ -306,6 +310,23 @@ export class ItemSheetFFG extends ItemSheet {
},
]);

// register sheet options
if (["gear", "weapon", "armour"].includes(this.object.type)) {
this.sheetoptions = new ItemOptions(this, html);
this.sheetoptions.register("enablePrice", {
name: game.i18n.localize("SWFFG.SheetOptions2.EnablePrice.Name"),
hint: game.i18n.localize("SWFFG.SheetOptions2.EnablePrice.Hint"),
type: "Boolean",
default: true,
});
this.sheetoptions.register("enableRarity", {
name: game.i18n.localize("SWFFG.SheetOptions2.enableRarity.Name"),
hint: game.i18n.localize("SWFFG.SheetOptions2.enableRarity.Hint"),
type: "Boolean",
default: true,
});
}

// TODO: This is not needed in Foundry 0.6.0
// Activate tabs
let tabs = html.find(".tabs");
Expand Down
12 changes: 8 additions & 4 deletions modules/swffg-main.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ import {register_crew} from "./helpers/crew.js";

// Import Dice Types
import { AbilityDie, BoostDie, ChallengeDie, DifficultyDie, ForceDie, ProficiencyDie, SetbackDie } from "./dice-pool-ffg.js";
import { createFFGMacro } from "./helpers/macros.js";
import { createFFGMacro, updateMacro } from "./helpers/macros.js";
import EmbeddedItemHelpers from "./helpers/embeddeditem-helpers.js";
import DataImporter from "./importer/data-importer.js";
import PauseFFG from "./apps/pause-ffg.js";
Expand Down Expand Up @@ -574,7 +574,7 @@ Hooks.on("renderChatMessage", (app, html, messageData) => {
name: li.attr('data-item-embed-name'),
type: li.attr('data-item-embed-type'),
system: {
description: li.attr('data-item-embed-description'),
description: unescape(li.attr('data-item-embed-description')),
attributes: JSON.parse(li.attr('data-item-embed-modifiers')),
rank: li.attr('data-item-embed-rank'),
rank_current: li.attr('data-item-embed-rank'),
Expand Down Expand Up @@ -868,7 +868,11 @@ Hooks.once("ready", async () => {
}

// Wait to register hotbar drop hook on ready so that modules could register earlier if they want to
Hooks.on("hotbarDrop", (bar, data, slot) => createFFGMacro(data, slot));
Hooks.on("hotbarDrop", async (bar, data, slot) => await createFFGMacro(bar, data, slot));
Hooks.on("createMacro", async function (...args) {
args[0] = await updateMacro(args[0]);
return args;
});

Hooks.on("closeItemSheetFFG", (item) => {
Hooks.call(`closeAssociatedTalent_${item.object._id}`, item);
Expand Down Expand Up @@ -918,7 +922,7 @@ Hooks.once("ready", async () => {

game.socket.on("system.starwarsffg", async (...args) => {
const event_type = args[0].event;
if (game.user.id === game.users.find(i => i.isGM)?.id) {
if (game.user.id === game.users.activeGM?.id) {
if (event_type === "combat") {
CONFIG.logger.debug("Processing combat event from player");
const data = args[0]?.data;
Expand Down
Loading

0 comments on commit 4e5ea13

Please sign in to comment.