jalensailin / bottlecap

MIT License
0 stars 0 forks source link

Feature: System setting to create preset caps for quick awarding #2

Open DeviousHearts opened 8 months ago

DeviousHearts commented 8 months ago

NO ISSUES! Love IT! But... is there a way to write a macro to award common awards?

Is there a way to write a macro to quickly reward a player for MVP, or Good Role-Play, or Chuckles! Showstopper! or other frequently awarded bottle caps?

jalensailin commented 8 months ago

Hello! Glad to hear you are enjoying it. Thanks for the suggestion. It would certainly be possible. Currently the basic API is exposed in game.bottlecap. So you would do something like:

const userName = "Player2" // Fill in the user's name between the double quotes.
const customReason = "poop" // Fill in your reason between the double quotes.

// Don't change anything below this line.
const userID = game.users.getName(userName).id; // Get the user's ID from the name.
const BottleCap = game.bottlecap; // Get the bottle cap API
const newCap = new BottleCap(); // Create an ephemeral bottlecap with all the default values.
newCap.context = customReason; // Assigns the above reason to this bottle cap.
await BottleCap.createBottleCap(userID, newCap) // Actually make the new bottle cap (save to the database)

// Rerender the app if open
const bottleCapApp = Object.values(ui.windows).find((w) => w.id === "bottlecap-list-app"); 
if (bottleCapApp) bottleCapApp.render(true);

There are some issues with this. One, unfortunately I haven't exposed to the ChatMessage API yet, so it would be difficult for you to send this creation to chat (like what happens when you use the + button to create a cap). Also, you'd have to create a bunch of macros for different reasons and different users, which would get messy quickly. You could create a dropdown menu completely within the macro to select the user with preconfigured reasons, but that is complicated. If you have familiarity with javascript, I encourage you to try though :).

Your idea has given me some thoughts to make this more user-friendly, perhaps in the settings you can create your own common "bottle caps" which can then be selected right from the menu. Also to expose the creation of chat messages in the API for the system.

jalensailin commented 8 months ago

I am going to change the title of this to help me track this feature request better

jalensailin commented 8 months ago

Hopefully this will work for your needs! I gave the option to give your own custom name and icon as well. This will assign a cap to any user who owns a selected token, except the GM as the GM always owns every token.

As far as graphics, I'd love to see what you got! I can't make any promises to include them but would absolutely consider it :). Thanks for the offer. If I do end up including them, of course I would give you credit.

Let me know if you have issues with the macro. It was working on my end.

// Replace between the quotes with your own values.
const customName = "Bottle Cap!";
const customReason = "Great Roleplay";
const customImage = "icons/commodities/tech/cog-large-steel-white.webp";

//////////////////////////////////////////
// Don't change anything below this box //
// (unless you know what you're doing)  //
//////////////////////////////////////////

const selectedTokens = canvas.tokens.controlled; // Find selected tokens.
let userIDs = [];
const gmID = game.users.activeGM.id;
// If one of these tokens has a default ownership of 3, then every user owns it.
if (selectedTokens.some((t) => t.actor.ownership.default >= 3)) {
  userIDs = game.users.map((u) => u.id).filter((id) => id !== gmID); // Filter out GM ID (GM owns everything)
} else {
  // Otherwise, for each selected token, check the permissions and find the player owners.
  selectedTokens.forEach((t) => {
    Object.entries(t.actor.ownership).forEach(([k, v]) => {
      // Don't do anything for default or GM ID.
      if (k === "default" || k === gmID) return;
      // If permission is greater than 3, add ID to the list (if not already there)
      if (v >= 3 && !userIDs.includes(k)) userIDs.push(k);
    });
  });
}

const BottleCap = game.bottlecap; // Get the bottle cap API
const newCap = new BottleCap(); // Create an ephemeral bottlecap with all the default values.
newCap.name = customName; // Assigns the above name to this bottle cap.
newCap.context = customReason; // Assigns the above reason to this bottle cap.
newCap.img = customImage; // Assigns the above image to this bottle cap.

// For each selected user, give them a bottle cap.
for (const userID of userIDs) {
  await BottleCap.createBottleCap(userID, newCap);
}

// Rerender the app if open
const bottleCapApp = Object.values(ui.windows).find((w) => w.id === "bottlecap-list-app");
if (bottleCapApp) bottleCapApp.render(true);

const userNames = userIDs.map((id) => game.users.get(id).name).reduce((accumulator, name) => `${accumulator}, ${name}`);
ui.notifications.notify(`Bottle Cap given to the following users: ${userNames}`);
jalensailin commented 8 months ago

Hey there! My apologies for the delayed response. I have been busy over these last few days. How is the macro working out for you? Working as intended?

Those bottlecap images are pretty cool. Can I ask, do you do all the art yourself? What program do you use?

jalensailin commented 8 months ago

Glad to hear it. I do love the bottle caps you put together but at this time I am refraining from using AI art in my own modules. I do understand completely that it's more work than simply prompting the AI and using its results. You clearly did a lot of work to make them look as good as they do. I am all for using them at home, though!

I am working with an artist to hopefully get some bottlecap icons for the module going. Hopefully the next release of the system will have a better way to preload bottlecaps in the first place. Thanks for all your input!

DeviousHearts commented 8 months ago

best of luck