Roll20 uses cookies to improve your experience on our site. Cookies enable you to enjoy certain features, social sharing functionality, and tailor message and display ads to your interests on our site and others. They also help us understand how our site is being used. By continuing to use our site, you consent to our use of cookies. Update your cookie preferences .
×
Create a free account

Script Generates the Same Result Each Time

I have created a script to roll the indicated number of times on a table and save the results to a handout. The problem is, it comes up with the same result each time. The code is: /** * Generates Hard Light Tombs for Stars Without Numbers Revised * * Syntax: !TG number of rooms * * option determines which set of rollable tables will be used for Background, * equipment, and options such as Heritage or physical makeup */ var TG = TG || { output: [], listen: function () { on('chat:message', function (msg) { // Exit if not an api command if (msg.type != "api") { return; } if (msg.content.indexOf("!TG ") != -1) { var input = msg.content.split(" "); TombText = ''; switch (input[1]) { case "help": TG.showHelp; default: NumRooms = input[1]; for (let i = 0; i < NumRooms; i++) { TG.genRoom(msg, TG.printRoom, TG.save); sendChat('API', "/w gm <h6>Generating Tomb Location</h6>"); } } } else if (msg.content.indexOf("!TG") != -1) { TG.showHelp(); } }); }, showHelp: function () { sendChat("API", "/direct <table style='background: #DCD9D5; border-radius: 20px; font-size: 10px;'>" + "<thead><tr><th>Help</th></tr></thead>" + "<tbody>" + "<tr><td><strong>!TG [Number of Rooms]</strong><br>Generate the indicated number of tomb rooms.</td></tr>" + "<tr><td><strong>!TG help</strong><br>Display this Help.</td></tr>" + "<tr><td> </td></tr>" + "</td></tr></tbody></table>"); }, genRoom: function (msg, outputCallback, saveCallback) { TG.id = msg.playerid; TG.name = "Room #" TG.player = msg.who; TG.rollRoom(); if (typeof outputCallback === "function") { setTimeout(outputCallback, 2500, msg, saveCallback); } }, rollRoom: function () { TG.TO = ''; sendChat("API", "/roll 1t[TombGen]", function (result) { var content = JSON.parse(result[0].content); TG.TO = content.rolls[0].results[0].tableItem.name; }); }, printRoom: function (msg, saveCallback) { var styleLabel = "style='font-weight: bold; padding: 5px;'"; var styleVal = "style='padding: 5px;'"; TombText = TombText + "<p><p>" + TG.TO; // sendChat(msg.who, "/w gm " + TG.TO); if (typeof saveCallback === "function") { saveCallback(); } }, save: function () { var handout = createObj("handout", { }); handoutId = handout.id; handoutName = TG.name +' '+ handoutId.toString(16).toUpperCase(); handout.set('gmnotes', TombText); handout.set('name', handoutName); sendChat('API','/w gm <h6>Created '+ handoutName +'</h6>'); } }; on("ready", function () { TG.listen(); }); The other issue is that I want all the results in a single handout. What happens now is that a handout is saved after each iteration such that the first handout has the first result, the second has the first and second results, etc. How can I get a single handout with all the results? Suggestions?
1652610459
Julexar
Pro
API Scripter
You create a handout each time you use the save function. Try defining the Handout outside of that function and have it generated once on 'ready'
Thanks. I'm not sure how to do that. And that doesn't address the issue of getting the same result every time. Any thoughts?
1652725545
timmaugh
Pro
API Scripter
Your function flow is linear... listen => genRoom => rollRoom => printRoom => save But you're trying to manage async operations through stacking your callbacks, while writing a variable to your outer scope. I think that's contributing to both of your issues... ...same result because you're getting a race condition between your rollRoom and printRoom (the linear progression of code continues in genRoom once rollRoom goes async with the sendChat). You're trying to manage that through a setTimeout... but that's not guaranteed to work. ...AND... ...your progression from one function to the next precludes you aggregating the results of the various rolls into a single handout output. I think you can get all of the table results in a single return by structuring your function with recursion, appending your results to the prior set and decrementing the cycles to run each time... much like breaking a reduce() operation over subsequent async calls. You'd make it work by calling the function from within the sendChat callback and memo-izing the return into a single object you passed along from call to call. Which is, of course, ugly as sin. I think you can do better by utilizing the libInline library and extracting all of the table returns in one go (using libInline you can do 2t[TombGen] and get both results, rather than just the "top" one). That way you don't have multiple async calls going on. With all the results at your fingertips, you can structure the rest of the calls as functions that return information, aggregate that, that write it to a single handout. Of course, you could get rid of the async callback altogether and just give your script a secondary handle to listen for... it listens for "!TG " as the user-executed command, and when it is ready to generate the rooms, it sends a secondary command line through chat: !TG-api [[4t[TombGen]]]... That won't ever hit the chat window (since it's another API call), but you'd give your script the logic to catch it and process it. On the outbound sendChat that generates the message, append to the command line the issuing player's ID or the speaker (as necessary) to track information about the rooms you've generated, and then parse it off on the secondary catch: !TG-api [[4t[TombGen]]] --pid#-M1234567890abcdef --speaker#The Speaker
1652729242
Kurt J.
Pro
API Scripter
Don't know if it is helpful to you at all, but here is the function I use in ScriptCards to make a weighted roll on a rollable table so I don't have to rely on the chat server to do it: function rollOnRollableTable(tableName) { var theTable = findObjs({ type: "rollabletable", name: tableName })[0]; if (theTable !== undefined) { var tableItems = findObjs({ type: "tableitem", _rollabletableid: theTable.id }); if (tableItems !== undefined) { var rollResults = {}; var rollIndex = 0; var lastRollIndex = 0; var itemCount = 0; var maxRoll = 0; tableItems.forEach(function (item) { var thisWeight = parseInt(item.get("weight")); rollIndex += thisWeight; for (var x = lastRollIndex + 1; x <= rollIndex; x++) { rollResults[x] = itemCount; } itemCount += 1; maxRoll += thisWeight; lastRollIndex += thisWeight; }); var tableRollResult = randomInteger(maxRoll); return [tableItems[rollResults[tableRollResult]].get("name"), tableItems[rollResults[tableRollResult]].get("avatar")]; } else { return ["", ""]; } } } It returns a two item array with the text of the roll and the image source of the associated image without the complication of callbacks while still taking the weight entries for the items into account. I'm sure there is a faster/more clever way to take the weighting into account, but given that table rolling is fairly infrequent I didn't worry too much about it.