332 lines
13 KiB
JavaScript
332 lines
13 KiB
JavaScript
// Import document classes.
|
|
import { KidsOnBroomsActor } from "./documents/actor.mjs";
|
|
|
|
// Import sheet classes.
|
|
import { KidsOnBroomsActorSheet } from "./sheets/actor-sheet.mjs";
|
|
|
|
// Import helper/utility classes and constants.
|
|
import { preloadHandlebarsTemplates } from "./helpers/templates.mjs";
|
|
import { KIDSONBROOMS } from "./helpers/config.mjs";
|
|
|
|
/* -------------------------------------------- */
|
|
/* Init Hook */
|
|
/* -------------------------------------------- */
|
|
|
|
Hooks.once('init', async function() {
|
|
|
|
// Register the helper
|
|
Handlebars.registerHelper('capitalizeFirst', function(string) {
|
|
if (typeof string === 'string') {
|
|
return string.charAt(0).toUpperCase() + string.slice(1);
|
|
}
|
|
return '';
|
|
});
|
|
|
|
// Add utility classes and functions to the global game object so that they're more easily
|
|
// accessible in global contexts.
|
|
game.kidsonbrooms = {
|
|
KidsOnBroomsActor,
|
|
_onTakeAdversityToken: _onTakeAdversityToken, // Add the function to the global object
|
|
_onSpendAdversityTokens: _onSpendAdversityTokens // Add the function to the global object
|
|
};
|
|
|
|
// Add custom constants for configuration.
|
|
CONFIG.KIDSONBROOMS = KIDSONBROOMS;
|
|
|
|
/**
|
|
* Set an initiative formula for the system
|
|
* @type {String}
|
|
*/
|
|
CONFIG.Combat.initiative = {
|
|
formula: "1d20",
|
|
decimals: 2
|
|
};
|
|
|
|
|
|
// Define custom Document classes
|
|
CONFIG.Actor.documentClass = KidsOnBroomsActor;
|
|
|
|
// Register sheet application classes
|
|
Actors.unregisterSheet("core", ActorSheet);
|
|
Actors.registerSheet("kidsonbrooms", KidsOnBroomsActorSheet, { makeDefault: true });
|
|
|
|
//If there is a new chat message that is a roll we add the adversity token controls
|
|
Hooks.on("renderChatMessage", (message, html, messageData) => {
|
|
const adversityControls = html.find('.adversity-controls');
|
|
if (adversityControls.length > 0) {
|
|
const messageToEdit = adversityControls.data("roll-id");
|
|
// Bind event listeners for the controls
|
|
adversityControls.find(".take-adversity").off("click").click((event) => {
|
|
|
|
const actorId = event.currentTarget.dataset.actorId;
|
|
const actor = game.actors.get(actorId);
|
|
|
|
// Check if the current user owns the actor - They can not claim if they are not
|
|
if (!actor.testUserPermission(game.user, "owner")) {
|
|
ui.notifications.warn("You don't own this character and cannot take adversity tokens.");
|
|
return;
|
|
}
|
|
|
|
// Check if the token has already been claimed -- Contigency if the button somehow activates again
|
|
if (message.getFlag("kidsonbrooms", "tokenClaimed")) {
|
|
ui.notifications.warn("This adversity token has already been claimed.");
|
|
return;
|
|
}
|
|
|
|
_onTakeAdversityToken(event, actor);
|
|
if (game.user.isGM) {
|
|
let tokenControls = game.messages.get(message.id);
|
|
console.log(tokenControls);
|
|
// Update the chat message content with the button disabled and text changed
|
|
const updatedContent = tokenControls.content.replace(
|
|
`<button class="take-adversity" data-actor-id="${actor.id}">Take Adversity Token</button>`,
|
|
`<button class="take-adversity" data-actor-id="${actor.id}" disabled>Token claimed</button>`
|
|
);
|
|
console.log("Removing Button");
|
|
// Update the message content
|
|
tokenControls.update({ content: updatedContent });
|
|
// Set the flag on the chat message to indicate that the token has been claimed
|
|
tokenControls.setFlag("kidsonbrooms", "tokenClaimed", true);
|
|
} else {
|
|
// Emit a socket request to update the message to show that the token has been claimed
|
|
game.socket.emit('system.kidsonbrooms', {
|
|
action: "takeToken",
|
|
messageID: message.id,
|
|
actorID: actor.id,
|
|
});
|
|
}
|
|
console.log("Send socket message for taking a token");
|
|
});
|
|
|
|
adversityControls.find(".spend-adversity").off("click").click((event) => {
|
|
//This entails a lot more, so I offloaded it to a new function
|
|
_onSpendAdversityTokens(event, messageToEdit);
|
|
});
|
|
}
|
|
});
|
|
|
|
// Preload Handlebars templates.
|
|
return preloadHandlebarsTemplates();
|
|
|
|
|
|
});
|
|
|
|
/***
|
|
* This handles the incoming socket requests.
|
|
* If a player wants to spend tokens on another players roll the gm has to approve first
|
|
* if a player wants to claim a token we will update the message since they do not have the permissions
|
|
*/
|
|
Hooks.once('ready', function() {
|
|
game.socket.on('system.kidsonbrooms', async (data) => {
|
|
console.log("Socket data received:", data);
|
|
|
|
if (data.action === "spendTokens") {
|
|
console.log(`Request to spend tokens: ${data.tokensToSpend} tokens for ${data.rollActorId} by ${data.spendingActorId}`);
|
|
|
|
// Only handle the request if the GM is logged in
|
|
if (!game.user.isGM) {
|
|
console.log("Not GM, ignoring the token spend request.");
|
|
return;
|
|
}
|
|
|
|
// The actor who made the roll
|
|
const rollActor = game.actors.get(data.rollActorId);
|
|
// The actor who is spending tokens
|
|
const spendingActor = game.actors.get(data.spendingActorId);
|
|
|
|
//If these for some reason do not exist
|
|
if (!rollActor || !spendingActor) {
|
|
console.warn("Actor not found:", data.rollActorId, data.spendingActorId);
|
|
return;
|
|
}
|
|
|
|
// Create a confirmation dialog for the GM
|
|
new Dialog({
|
|
title: "Approve Adversity Token Spending?",
|
|
content: `<p>${spendingActor.name} wants to spend ${data.tokenCost} adversity tokens on ${rollActor.name}'s roll to increase it by ${data.tokensToSpend}. Approve?</p>`,
|
|
buttons: {
|
|
yes: {
|
|
label: "Yes",
|
|
callback: async () => {
|
|
|
|
|
|
const currentTokens = spendingActor.system.adversityTokens || 0;
|
|
|
|
// Update the spending actor's adversity token count
|
|
await spendingActor.update({ "system.adversityTokens": currentTokens - data.tokenCost });
|
|
|
|
|
|
// Modify the roll message with the new total
|
|
await _updateRollMessage(data.rollMessageId, data.tokensToSpend, false);
|
|
|
|
console.log(`${spendingActor.name} spent ${data.tokensToSpend} tokens, updated roll total to ${roll.cumulativeTotal}`);
|
|
ui.notifications.info(`${spendingActor.name} successfully spent ${data.tokensToSpend} tokens.`);
|
|
}
|
|
},
|
|
no: {
|
|
label: "No",
|
|
callback: () => {
|
|
ui.notifications.info(`The GM denied ${spendingActor.name}'s request to spend tokens.`);
|
|
}
|
|
}
|
|
},
|
|
default: "yes"
|
|
}).render(true);
|
|
} else if (data.action === "takeToken") {
|
|
// Only handle the request if the GM is logged in
|
|
if (!game.user.isGM) {
|
|
console.log("Not GM, ignoring the token spend request.");
|
|
return;
|
|
}
|
|
let tokenControls = game.messages.get(data.messageID);
|
|
console.log(tokenControls);
|
|
// Update the chat message content with the button disabled and text changed
|
|
const updatedContent = tokenControls.content.replace(
|
|
`<button class="take-adversity" data-actor-id="${data.actorID}">Take Adversity Token</button>`,
|
|
`<button class="take-adversity" data-actor-id="${data.actorID}" disabled>Token claimed</button>`
|
|
);
|
|
console.log("Removing Button");
|
|
// Update the message content
|
|
tokenControls.update({ content: updatedContent });
|
|
// Set the flag on the chat message to indicate that the token has been claimed
|
|
tokenControls.setFlag("kidsonbrooms", "tokenClaimed", true);
|
|
}
|
|
});
|
|
});
|
|
|
|
/***
|
|
* This function adds the adversity token to the actor that made the roll and logs it
|
|
*
|
|
* @param {Event} e - The button click event
|
|
* @param {Actor} actor - The actor object that made the roll
|
|
*/
|
|
async function _onTakeAdversityToken(e, actor) {
|
|
e.preventDefault();
|
|
|
|
|
|
// Get the chat message ID (assuming it's stored in the dataset)
|
|
const messageId = e.currentTarget.closest('.message').dataset.messageId;
|
|
const message = game.messages.get(messageId);
|
|
|
|
// Add an adversity token to the actor
|
|
const currentTokens = actor.system.adversityTokens || 0;
|
|
await actor.update({ "system.adversityTokens": currentTokens + 1 });
|
|
|
|
|
|
// Notify the user
|
|
ui.notifications.info(`You gained 1 adversity token.`);
|
|
console.log(`Gave one adversity token to ${actor.id}`)
|
|
}
|
|
|
|
/***
|
|
* This function allows players to spend tokens to change a roll. This will automatically be calculated in their sheet
|
|
*
|
|
*/
|
|
async function _onSpendAdversityTokens(e, rollMessageId) {
|
|
e.preventDefault();
|
|
|
|
// The actor who made the roll
|
|
const rollActorId = e.currentTarget.dataset.actorId;
|
|
const rollActor = game.actors.get(rollActorId); //technically redundant since it is also done in the main hook, but perfomance is good enuff
|
|
|
|
// Get the actor of the player who is spending tokens
|
|
const spendingPlayerActor = game.actors.get(game.user.character?.id || game.actors.filter(actor => actor.testUserPermission(game.user, "owner"))[0]?.id);
|
|
|
|
if (!spendingPlayerActor) {
|
|
ui.notifications.warn("You don't control any actors.");
|
|
return;
|
|
}
|
|
|
|
//Get the tokens to be spend from the input field
|
|
const tokenInput = $(e.currentTarget).closest('.adversity-controls').find('.token-input').val();
|
|
const tokensToSpend = parseInt(tokenInput, 10);
|
|
|
|
if (isNaN(tokensToSpend) || tokensToSpend <= 0) {
|
|
ui.notifications.warn("Please enter a valid number of tokens.");
|
|
return;
|
|
}
|
|
|
|
let tokenCost = tokensToSpend;
|
|
|
|
// If the player spending tokens is not the owner of the actor who rolled, they spend double
|
|
//(note, this is a rule of mine, I have disabled it by default)
|
|
if ((!spendingPlayerActor.testUserPermission(game.user, "owner") || spendingPlayerActor.id !== rollActorId) && false) {
|
|
tokenCost = tokensToSpend * 2;
|
|
}
|
|
|
|
// Ensure the spending actor has enough adversity tokens
|
|
if (spendingPlayerActor.system.adversityTokens < tokenCost) {
|
|
ui.notifications.warn(`You do not have enough adversity tokens.`);
|
|
return;
|
|
}
|
|
|
|
// Check if the player owns the actor who made the roll
|
|
if (spendingPlayerActor.id === rollActorId) {
|
|
// The player owns the actor, so they can spend tokens directly without GM approval
|
|
const currentTokens = spendingPlayerActor.system.adversityTokens || 0;
|
|
|
|
// Deduct the tokens from the player
|
|
await spendingPlayerActor.update({ "system.adversityTokens": currentTokens - tokenCost });
|
|
|
|
// Modify the roll message with the new total
|
|
await _updateRollMessage(rollMessageId, tokensToSpend, true);
|
|
|
|
} else {
|
|
// The player does not own the actor, so request GM approval to spend the tokens
|
|
console.log(`Requesting to spend ${tokensToSpend} tokens for ${rollActor.name} by ${spendingPlayerActor.name} (cost: ${tokenCost})`);
|
|
|
|
// Emit a socket request to spend tokens
|
|
game.socket.emit('system.kidsonbrooms', {
|
|
action: "spendTokens",
|
|
rollActorId: rollActorId,
|
|
spendingActorId: spendingPlayerActor.id, // Send the player's actor who is spending the tokens
|
|
tokensToSpend: tokensToSpend,
|
|
tokenCost: tokenCost,
|
|
rollMessageId: rollMessageId // Pass message ID to update the roll result
|
|
});
|
|
|
|
ui.notifications.info(`Requested to spend ${tokenCost} tokens for ${rollActor.name}`);
|
|
}
|
|
}
|
|
|
|
// Helper function to send a new message with the updated roll result
|
|
async function _updateRollMessage(rollMessageId, tokensToSpend, isPlayerOfActor) {
|
|
const message = game.messages.get(rollMessageId);
|
|
|
|
if (!message) {
|
|
console.error("Message not found with ID:", rollMessageId);
|
|
return;
|
|
}
|
|
|
|
// Retrieve current tokens spent from flags, or initialize to 0 if not found
|
|
let cumulativeTokensSpent = message.getFlag("kidsonbrooms", "tokensSpent") || 0;
|
|
let newTotal = message.getFlag("kidsonbrooms", "newRollTotal") || message.rolls[0].total;
|
|
|
|
/*if(isPlayerOfActor)
|
|
{
|
|
// Add the new tokens to the cumulative total
|
|
cumulativeTokensSpent += tokensToSpend;
|
|
} else {
|
|
cumulativeTokensSpent += 2*tokensToSpend;
|
|
}*/
|
|
cumulativeTokensSpent += tokensToSpend;
|
|
newTotal += tokensToSpend;
|
|
await message.setFlag("kidsonbrooms", "newRollTotal", newTotal);
|
|
|
|
// Update the message's flags to store the cumulative tokens spent
|
|
await message.setFlag("kidsonbrooms", "tokensSpent", cumulativeTokensSpent);
|
|
let newContent = "";
|
|
if(cumulativeTokensSpent === 1)
|
|
{
|
|
newContent = `You have now spent ${cumulativeTokensSpent} token. The new roll total is ${newTotal}.`;
|
|
} else {
|
|
newContent = `You have now spent ${cumulativeTokensSpent} tokens. The new roll total is ${newTotal}.`;
|
|
}
|
|
|
|
// Create a new chat message to display the updated total
|
|
await ChatMessage.create({
|
|
speaker: ChatMessage.getSpeaker({ actor: message.speaker.actor }),
|
|
content: newContent,
|
|
type: CONST.CHAT_MESSAGE_STYLES.OTHER,
|
|
});
|
|
} |