From fa536a14bee487b5e5a2e5839e34aa56b7cef59f Mon Sep 17 00:00:00 2001 From: Diana Owrey Date: Mon, 13 Nov 2023 21:09:58 -0500 Subject: [PATCH] V11 Update --- README.md | 6 ++--- module.json | 25 +++++++++++-------- npcchatter.js | 68 +++++++++++++++++++++++++++++---------------------- 3 files changed, 57 insertions(+), 42 deletions(-) diff --git a/README.md b/README.md index 58646f8..07a7816 100644 --- a/README.md +++ b/README.md @@ -48,13 +48,13 @@ The easiest macro is the "Timed Global Chatter" macro - just slap it when a Scen [Trigger Happy](https://github.com/kakaroto/fvtt-module-trigger-happy) can trigger NPC chatter as well. Here's an example to get you started: -When an Actor walks into a Room (defined by an invisble actor), have a specific Token chatter: `@Actor[TriggerA] @Macro[OXyjmVhEGo3eTaJz]{Specific Token Chatter}` +When an Actor walks into a Room (defined by an invisible actor), have a specific Token chatter: `@Actor[TriggerA] @Macro[OXyjmVhEGo3eTaJz]{Specific Token Chatter}` # API ## Global Chatter -Picks a random Chatter Table belonging to a random Actor on the first active scene and displays a ChatBubble with rolled Text off of the random Chatter Table. +Picks a random Chatter Table belonging to a random Actor on the first active Scene and displays a ChatBubble with rolled Text off of the random Chatter Table. ```js async globalChatter() @@ -87,7 +87,7 @@ async tokenChatter(token) ## Selected Chatter -Grabs the currently selected Tokens and tries to find matching Chatter Tables. If none, exits. If one or more, randomly picks one and an elibable Token and displays a rolled result from the Table as a ChatBubble. +Grabs the currently selected Tokens and tries to find matching Chatter Tables. If none, exits. If one or more, randomly picks one and an eligible Token and displays a rolled result from the Table as a ChatBubble. ```js async selectedChatter() diff --git a/module.json b/module.json index 4651ea4..918f3cc 100644 --- a/module.json +++ b/module.json @@ -1,26 +1,31 @@ { - "name": "npc-chatter", + "id": "npc-chatter", "title": "NPC Chatter", "description": "Your NPCs have things to say", - "semanticVersion": "2.2.0", - "version": "2.2.0", - "minimumCoreVersion": "9", - "compatibleCoreVersion": "9", - "author": "Cody Swendrowski ", + "version": "2.3.0", + + "compatibility": { + "minimum": 11, + "verified": "11" + }, "scripts": [ "./npcchatter.js" ], - "socket": true, - "styles": [], - "languages": [], "packs": [ { "name": "npcchatter", "label": "NPC Chatter", "path": "./packs/npc-chatter.db", - "entity": "Macro" + "type": "Macro" } ], + "authors": [ + { + "id": "Cody Swendrowski", + "email": "cody@swendrowski.us" + } + ], + "socket": true, "url": "https://github.com/cswendrowski/FoundryVtt-Npc-Chatter", "manifest": "https://raw.githubusercontent.com/cswendrowski/FoundryVtt-Npc-Chatter/master/module.json", "download": "https://github.com/cswendrowski/FoundryVtt-Npc-Chatter/releases/download/v2.2.0/npcchatter.zip" diff --git a/npcchatter.js b/npcchatter.js index e400bbf..3f8e68e 100644 --- a/npcchatter.js +++ b/npcchatter.js @@ -2,14 +2,20 @@ class NpcChatter { static timer; + getRandomIndex(iterable) { + return Math.floor((Math.random() * iterable.length)) + } + getChatterTables() { const chatterFolder = game.folders.contents.find(x => x.type == "RollTable" && x.name.toLowerCase() == "npc chatter"); + if ( !chatterFolder ) { ui.notifications.warn("Could not find the 'NPC Chatter' Folder"); + return []; } - const tables = game.tables.contents.filter(x => x.name.toLowerCase().endsWith("chatter") || x.data.folder == chatterFolder.id); - return tables; + + return chatterFolder.contents; } randomGlobalChatterEvery(milliseconds, options={}) { @@ -18,44 +24,44 @@ class NpcChatter { static _getChatterScene() { const sceneType = game.settings.get("npc-chatter", "scenetype"); + switch (sceneType) { - case "active": return game.scenes.find(x => x.active); - case "viewed": return game.scenes.find(x => x.id === game.user.viewedScene); + case "active": return game.scenes.active; + case "viewed": return game.scenes.get(game.user.viewedScene); } } async globalChatter(options={}) { - const tables = this.getChatterTables(); - - const userCharacterActorIds = game.users.contents.filter(x => x.character).map(x => x.character.id); + const chatterTables = this.getChatterTables(); const scene = NpcChatter._getChatterScene(); - const npcTokens = scene.data.tokens.filter(x => !userCharacterActorIds.includes(x.actorId)); + const npcTokenNames = new Set(Object.values(scene.tokens.contents).map(t => t.name.toLowerCase())); + const eligibleTables = chatterTables.filter(t => npcTokenNames.has(t.name.toLowerCase().replace("chatter", "").trim())); - const eligibleTables = tables.filter(x => npcTokens.filter(t => x.name.toLowerCase().includes(t.name.toLowerCase().replace("chatter", "").trim()) > 0)); if ( eligibleTables.length === 0 ) { - ui.notifications.warn("You have no NPC Chatter tables setup for these tokens"); + ui.notifications.warn("You have no NPC Chatter tables set up for these tokens"); + return; } - const tableIndex = Math.floor((Math.random() * eligibleTables.length) + 0); - const table = eligibleTables[tableIndex]; - - const eligableTokens = npcTokens.filter(x => x.name.toLowerCase().includes(table.name.toLowerCase().replace("chatter", "").trim())); - - const tokenIndex = Math.floor((Math.random() * eligableTokens.length) + 0); - const token = eligableTokens[tokenIndex]; + const table = eligibleTables[this.getRandomIndex(eligibleTables)]; + const eligibleTokens = scene.tokens.contents.filter( + x => x.name.toLowerCase().includes(table.name.toLowerCase().replace("chatter", "").trim()) + ); + const token = eligibleTokens[this.getRandomIndex(eligibleTokens)]; if (token == undefined) return; + const roll = await table.roll(); + const result = roll.results[0].text; - let roll = await table.roll(); - const result = roll.results[0].data.text; game.socket.emit("module.npc-chatter", { - tokenId: token.data._id, + tokenId: token.id, msg: result }); + const emote = Object.keys(options).length ? {emote: options} : false; - await canvas.hud.bubbles.say(token.data, result, emote); + + await canvas.hud.bubbles.say(token, result, emote); } async tokenChatter(token, options={}) { @@ -63,9 +69,10 @@ class NpcChatter { ui.notifications.error("No Token passed in"); return; } - const tables = this.getChatterTables(); + const tables = this.getChatterTables(); const eligibleTables = tables.filter(x => token.name.toLowerCase().includes(x.name.toLowerCase().replace("chatter", "").trim())); + if ( eligibleTables.length === 0 ) { ui.notifications.warn("You have no NPC Chatter tables setup for this token"); return; @@ -74,19 +81,23 @@ class NpcChatter { const tableIndex = Math.floor((Math.random() * eligibleTables.length) + 0); const table = eligibleTables[tableIndex]; let roll = await table.roll(); - const result = roll.results[0].data.text; + const result = roll.results[0].text; + game.socket.emit("module.npc-chatter", { - tokenId: token.data._id, + tokenId: token.id, msg: result }); + const emote = Object.keys(options).length ? {emote: options} : false; + await canvas.hud.bubbles.say(token.data, result, emote); } async selectedChatter(options={}) { const npcTokens = canvas.tokens.controlled; - const tokenIndex = Math.floor((Math.random() * npcTokens.length) + 0); - const token = npcTokens[tokenIndex]; + const tokenIndex = Math.floor((Math.random() * npcTokens.length)); + const token = canvas.tokens.controlled[tokenIndex]; + return this.tokenChatter(token, options); } @@ -98,7 +109,7 @@ class NpcChatter { Hooks.once('init', async () => { game.settings.register("npc-chatter", "scenetype", { - name: "Should Tokens Chatter on the active scene, or the viewed scene?", + name: "Should Tokens chatter on the active scene, or the viewed scene?", type: String, config: true, scope: "world", @@ -114,9 +125,8 @@ Hooks.once('ready', async () => { game.npcChatter = new NpcChatter(); game.socket.on("module.npc-chatter", async (toShow) => { - //console.log("Got token " + toShow.tokenId + " with text " + toShow.msg); let token = canvas.tokens.get(toShow.tokenId); - //console.log(token); + canvas.hud.bubbles.say(token, toShow.msg, false); }); });