Skip to content

Commit

Permalink
feat: Added button on token hud to Mystify/Unmystify a token.
Browse files Browse the repository at this point in the history
Fixed replacing rarity != Common with (by default) Unusual
Changed defaults to what I think are more sensible values.
  • Loading branch information
xdy committed Nov 27, 2021
1 parent 17a378d commit 20fb7c2
Show file tree
Hide file tree
Showing 4 changed files with 107 additions and 45 deletions.
63 changes: 63 additions & 0 deletions src/module/mystify-token.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { generateNameFromTraits } from "./traits-name-generator";
import { MODULENAME } from "./xdy-pf2e-workbench";
import { mystifyKey } from "./settings";

export async function mystifyToken(token: Token | null, mystified: boolean): Promise<string> {
if (token === null) return "";
let name = token?.name || "";
if (token) {
if (mystified) {
name = token.actor.name;
} else {
switch (game.settings.get(MODULENAME, "npcMystifierMethod")) {
default:
name = generateNameFromTraits(token);
}
}
}
// @ts-ignore
if (token.document) {
// @ts-ignore
await token.document.update({ name: name });
} else {
token.data.name = name;
// @ts-ignore
token.data.update(token.data);
}

return name;
}

export function preTokenCreateMystification(token: Token) {
// @ts-ignore Nope, game.keyboard is never *actually* undefined. Shut up, TypeScript.
if (game.keyboard.isDown(mystifyKey) && (!game.keyboard.isDown("V") || game.keyboard.isDown("Insert"))) {
mystifyToken(token, isMystified(token));
}
}

function isMystified(token: Token | null) {
return token?.data.name !== token?.actor.name || false;
}

export function renderNameHud(data: any, html: JQuery<HTMLElement>) {
let token: Token;
if (canvas instanceof Canvas && canvas && canvas["tokens"]) {
token = canvas["tokens"].get(data._id);

const title = isMystified(token) ? "Unmystify" : "Mystify";
const toggle = $(
`<div class="control-icon ${
isMystified(token) ? "active" : ""
}" > <i class="fas fa-eye-slash" title=${title}></i></div>`
);
toggle.on("click", async (e) => {
const hudElement = $(e.currentTarget);
const active = hudElement.hasClass("active");
if (isMystified(token) === active) {
await mystifyToken(token, active);
}
hudElement.toggleClass("active");
});
html.find("div.col.right").append(toggle);
}
}
8 changes: 4 additions & 4 deletions src/module/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export function registerSettings() {
//TODO Make a settings menu with the following settings that is set to be restricted to GMs
game.settings.register(MODULENAME, "npcMystifier", {
name: "Turn on npc mystifier.", // game.i18n.localize(`${MODULENAME}.settings.npcMystifierOn.Name`),
hint: "Turn on npc mystifier, renaming tokens based on their traits if Alt (configurable) is clicked when adding to scene.", // game.i18n.format(`${MODULENAME}.settings.npcMystifierOn.Hint`),
hint: "Turn on npc mystifier, renaming tokens based on their traits if Ctrl (configurable) is clicked when adding to scene.", // game.i18n.format(`${MODULENAME}.settings.npcMystifierOn.Hint`),
scope: "world",
config: true,
default: true,
Expand Down Expand Up @@ -49,15 +49,15 @@ export function registerSettings() {

game.settings.register(MODULENAME, "npcMystifierKey", {
name: "Key to mystify", //game.i18n.localize(`${MODULENAME}.settings.npcMystifier.key.Hint`),
hint: "Hold this to mystify npc as it's dragged out to the scene. Note that if you choose Alt (the default) it also hides the npc.", //game.i18n.localize(`${MODULENAME}.SETTINGS.npcMystifier.key.Name`),
hint: "Hold this to mystify npc as it's dragged out to the scene. Note that if you choose Alt (not the default) it also hides the npc.", //game.i18n.localize(`${MODULENAME}.SETTINGS.npcMystifier.key.Name`),
scope: "world",
config: true,
type: String,
choices: {
Alt: "Alt",
Control: "Ctrl",
},
default: "Alt",
default: "Control",
onChange: (key) => {
return (mystifyKey = <string>key);
},
Expand All @@ -78,7 +78,7 @@ export function registerSettings() {
hint: "Filter out rarities from the mystified name.", //game.i18n.localize(`${MODULENAME}.settings.npcMystifierFilterRarities.Hint`),
scope: "world",
config: true,
default: false,
default: true,
type: Boolean,
});

Expand Down
27 changes: 19 additions & 8 deletions src/module/traits-name-generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,16 @@ function filterTraitList(traitsList: any) {
let rarities: string[] = [];
if (!game.settings.get(MODULENAME, "npcMystifierFilterRarities")) {
rarities = traitsList.filter((trait: string) => TRAITS.RARITIES.includes(trait));
const replacement: string = <string>game.settings.get(MODULENAME, "npcMystifierFilterRaritiesReplacement");
const replacement: string = (<string>(
game.settings.get(MODULENAME, "npcMystifierFilterRaritiesReplacement")
)).toLocaleLowerCase();
if (replacement !== "") {
rarities = rarities.map((trait: string) => {
if (trait !== "common") {
return replacement;
} else {
return trait;
}
return trait;
});
}
}
Expand All @@ -47,10 +50,10 @@ function filterTraitList(traitsList: any) {
let others: string[] = [];
if (!game.settings.get(MODULENAME, "npcMystifierFilterOtherTraits")) {
others = traitsList
.filter((trait: string) => !eliteWeak.includes(trait))
.filter((trait: string) => !rarities.includes(trait))
.filter((trait: string) => !creatures.includes(trait))
.filter((trait: string) => !families.includes(trait));
.filter((trait: string) => !TRAITS.ELITE_WEAK.includes(trait))
.filter((trait: string) => !TRAITS.RARITIES.includes(trait))
.filter((trait: string) => !TRAITS.CREATURE_TYPES.includes(trait))
.filter((trait: string) => !TRAITS.CREATURE_FAMILIES.includes(trait));
}

return [<string>game.settings.get(MODULENAME, "npcMystifierPrefix")]
Expand All @@ -63,15 +66,23 @@ function filterTraitList(traitsList: any) {
}

export function generateNameFromTraits(token: Token) {
let traitsList = token?.actor?.data?.data["traits"]["traits"]?.value.filter(
let traitsList: string[] = token?.actor?.data?.data["traits"]["traits"]?.value.filter(
(trait: string, index: number, self: string[]) => self.indexOf(trait) === index
);
const customTraits = token?.actor?.data?.data["traits"]["traits"]["custom"];
if (customTraits) {
traitsList = traitsList.concat(customTraits.trim().split(","));
}
const tokenrarities = token?.actor?.data?.data["traits"]["rarity"]?.value;
if (tokenrarities) {
traitsList = traitsList.concat(tokenrarities);
}

traitsList = filterTraitList(traitsList);

let name = traitsList
.map((trait: string) => {
return trait.charAt(0).toUpperCase() + trait.slice(1);
return trait?.charAt(0).toUpperCase() + trait?.slice(1);
})
// .map((trait: string) => {
// return game.i18n.localize(`PF2E.TraitDescription.${trait}`);
Expand Down
54 changes: 21 additions & 33 deletions src/module/xdy-pf2e-workbench.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,20 @@
* Software License: Apache 2.0
*/

//TODO Move out to each separate app (once there are more than one...)
//TODO Start using the actual pf2e types
//TODO Make it so holding shift pops up a dialog where one can change the name
//TODO Fix localization
//TODO Can I use the pf2e localization strings?
//TODO Add the option to randomize a name from a list of names (kinda like token mold)
//TODO Add a way to disable the 'traits -> name' stuff but keep the rest. I.e. modularize the name generation.
//TODO Consider doing something to handle the actor name or the original token name being shown in abilities, etc.
//TODO Make issues out of the harder of the above todos...

// Import TypeScript modules
import { preloadTemplates } from "./preloadTemplates";
import { mystifyKey, registerSettings } from "./settings";
import { generateNameFromTraits } from "./traits-name-generator";
import { registerSettings } from "./settings";
import { preTokenCreateMystification, renderNameHud } from "./mystify-token";

export const MODULENAME = "xdy-pf2e-workbench";

Expand Down Expand Up @@ -41,38 +51,16 @@ Hooks.once("ready", async () => {
console.log(`${MODULENAME} | Ready`);
});

//TODO Move out to each separate app (once there are more than one...)
//TODO Start using the actual pf2e types
//TODO Make it so holding shift pops up a dialog where one can change the name
//TODO Fix localization
//TODO Can I use the pf2e localization strings?
//TODO Add a way to revert the name change from the sheet. (Hover over the name gives a context menu? Or inject a button on the sheet title bar? Maybe just a function that can be called from a macro?)
//TODO Add the option to randomize a name from a list of names (kinda like token mold)
//TODO Add a way to disable the 'traits -> name' stuff but keep the rest. I.e. modularize the name generation.
//TODO Consider doing something to handle the actor name or the original token name being shown in abilities, etc.
//TODO Make issues out of the harder of the above todos...
Hooks.on("preCreateToken", async (token: Token, data: any) => {
Hooks.on("preCreateToken", async (token: Token) => {
console.log(`${MODULENAME} | preCreateToken`);

if (game.settings.get(MODULENAME, "npcMystifier")) {
console.log(`${MODULENAME} | preCreateToken`);
preTokenCreateMystification(token);
}
});

const originalName = getProperty(token.data.flags, MODULENAME + ".OriginalName") || token.actor?.name;
console.log(originalName);
let name: string;
// @ts-ignore Nope, game.keyboard is never *actually* undefined. Shut up, TypeScript.
if (game.keyboard.isDown(mystifyKey) && !hasProperty(data.flags, MODULENAME + ".OriginalName")) {
switch (game.settings.get(MODULENAME, "npcMystifierMethod")) {
default:
name = generateNameFromTraits(token);
break;
}
} else {
name = originalName;
}
data.name = name;
setProperty(data.flags, MODULENAME + ".OriginalName", originalName);
// @ts-ignore
token.data.update(data);
// console.log(originalName + " changed to " + name);
// console.log(token.data);
Hooks.on("renderTokenHUD", (_app: TokenHUD, html: JQuery, data: Token.Data) => {
if (game.settings.get(MODULENAME, "npcMystifier")) {
renderNameHud(data, html);
}
});

0 comments on commit 20fb7c2

Please sign in to comment.