fvtt-module-narrator-tools
fvtt-module-narrator-tools copied to clipboard
Calling scenery() and narrate() in one macro only executes one not both.
I tried to make a simple macro with two lines:
NarratorTools.scenery(); NarratorTools.chatMessage.narrate("test");
But it does either one or the other, not both. Usually on first try, it does the scenery but no narration and every try after that it only does the narration. I assumed race conditions and added a timeout, but that does not help.
Am I doing something wrong or is this a bug?
It is a race condition because everything is shared in the same state in the module.
I should've made those methods async and in separate states, I will fix that in the future, but in the meantime you can try:
function(scenery, message) {
const sharedState = { ...(game.settings.get('narrator-tools', 'sharedState')), scenery };
await game.settings.set('narrator-tools', 'sharedState', sharedState);
NarratorTools.chatMessage.narrate(message);
}
Really sorry about that, I should probably rewrite the module from scratch.
Thanks for the response! That helped a lot!
Making your functions async should absolutely make things a lot easier indeed. Rewriting from scratch is probably best saved for when the next big Foundry update breaks everything ;-)
Thanks to your help, I managed to achieve my goal of using it to display a videogame-like loading screen with hints on the press of a hotkey. I'm going to use this when I have to look up rules, we talk out of character, take a bathroom break or the like. I'm not very good at javascript so this is probably pretty badly cobbled together, but it works for now. I'll post it here if anyone needs something like that, wants to improve on it or add it to some macro compendium or whatnot:
* Uses Narrator Tools module to show or hide a loading screen.
*
* Loading screen is made of random image from folder /loading_screens and message rolled from a random table
*/
//first pause or unpause the game
game.togglePause();
loading_screen("Loading Screen","loading_screens");
/**
* Toggles a loading screen with the specified scenery and a random quote from a table.
* @async
* @param {string} scenery The scenery title
* @param {string} directory The path to the image folder
*/
async function loading_screen(scenery, directory) {
//if loading screen is already show, disable it by setting scenery to false
if(game.settings.get('narrator-tools','sharedState').scenery){
game.settings.set('narrator-tools', 'sharedState').scenery=false;
}else {
//otherwise, set the scenery image and show it
await set_scenery(directory);
const sharedState = {...(game.settings.get('narrator-tools', 'sharedState')), scenery};
await game.settings.set('narrator-tools', 'sharedState', sharedState);
//roll on quotes table and use the narrate function to display it mid-screen
game.tables.get("8DeXdIqCmhSH9ZGC").roll()
.then((value) => {
let textval = value.results[0].data.text;
NarratorTools.chatMessage.narrate(textval);
});
}
}
///////////////////////////
/* HELPER FUNCTIONS */
///////////////////////////
/**
* Sets the background image to a random image from the specified directory.
* @async
*/
async function set_scenery(directory) {
const image= await pick_random_image(directory);
const result = await new Promise(resolve => {
resolve(NarratorTools._updateBGImage(image)); // resolve the Promise with the result of nonAsyncFunction
});
return result;
}
/**
* Picks a random file from the specified directory.
* @async
* @param {string} directory The directory to pick a file from.
* @returns {Promise} A Promise that resolves with the randomly selected file.
*/
async function pick_random_image(directory) {
const {files} = await FilePicker.browse("data", directory);
const randomIndex = Math.floor(Math.random() * files.length);
return files[randomIndex];
}```