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

Fodderator Clone Debug issue

I have modified the fodderator API to generate NPCs for The Silence of Hollowind (5e setting). I have debugged as far as I can see, but I keep getting a&nbsp; SyntaxError: Unexpected token ';' &nbsp;message. Can anybody see where the problem is? /** * Generates NPCs for The Silence of Hollowind 5E. * * Syntax: !fodder option * * option determines which set of rollable tables will be used for Background, * equipment, and options such as Heritage or physical makeup */ var Fodder = Fodder || { defaultAvatar: "<a href="https://s3.amazonaws.com/files.d20.io/images/7165064/VtQt1TimmSc8rxdHH4daxg/med.jpg?1421350799" rel="nofollow">https://s3.amazonaws.com/files.d20.io/images/7165064/VtQt1TimmSc8rxdHH4daxg/med.jpg?1421350799</a>", output: [], listen: function () { on('chat:message', function (msg) { // Exit if not an api command if (msg.type != "api") { return; } if (msg.content.indexOf("!fodder ") != -1) { var input = msg.content.split(" "); if (input[1] == "help") { Fodder.showHelp(); } else { Fodder.setTables(input[1]); sendChat('API', "/direct &lt;h6&gt;Generating character&lt;/h6&gt;"); Fodder.generate(msg, Fodder.printSheet, Fodder.save); } } else if (msg.content.indexOf("!fodder") != -1) { Fodder.showHelp(); } }); }, setTables: function (ruleset) { var defaultTable = { Background: "Backgrounds", Heritage: "Heritage", equipment: "Equipment" }; switch (ruleset) { case "brokenmoon": Fodder.HeritageTable = 'Heritages-CUaBM'; Fodder.BackgroundTable = 'Backgrounds-CUaBM'; Fodder.HeritageTable = defaultTable.Heritage; Fodder.EquipmentTable = 'Equipment-CUaBM'; break; case "crawl": Fodder.BackgroundTable = 'Backgrounds-Crawl'; Fodder.HeritageTable = defaultTable.Heritage; Fodder.EquipmentTable = defaultTable.equipment; break; case "nowhere": Fodder.BackgroundTable = 'Backgrounds-NCN'; Fodder.HeritageTable = defaultTable.Heritage; Fodder.EquipmentTable = 'Equipment-NCN'; break; case "core": default: Fodder.BackgroundTable = defaultTable.Background; Fodder.HeritageTable = defaultTable.Heritage; Fodder.EquipmentTable = defaultTable.equipment; } }, showHelp: function () { sendChat("API", "/direct &lt;table style='background: #DCD9D5; border-radius: 20px; font-size: 10px;'&gt;" + "&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Help&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;" + "&lt;tbody&gt;" + "&lt;tr&gt;&lt;td&gt;&lt;strong&gt;!fodder&lt;/strong&gt;&lt;br&gt;&lt;strong&gt;!fodder help&lt;/strong&gt;&lt;br&gt;Show this help screen.&lt;/td&gt;&lt;/tr&gt;" + "&lt;tr&gt;&lt;td&gt;&lt;strong&gt;!fodder core&lt;/strong&gt;&lt;br&gt;Use default core DCC tables.&lt;/td&gt;&lt;/tr&gt;" + "&lt;tr&gt;&lt;td&gt;&lt;strong&gt;!fodder brokenmoon&lt;/strong&gt;&lt;br&gt;Use Crawling Under A Broken Moon tables, including mutants and robots.&lt;/td&gt;&lt;/tr&gt;" + "&lt;tr&gt;&lt;td&gt;&lt;strong&gt;!fodder crawl&lt;/strong&gt;&lt;br&gt;Use Crawl! tables for zero-level character generation, including gnomes and physical characteristics.&lt;/td&gt;&lt;/tr&gt;" + "&lt;tr&gt;&lt;td&gt; &lt;/td&gt;&lt;/tr&gt;" + "&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;"); }, generate: function (msg, outputCallback, saveCallback) { Fodder.id = msg.playerid; Fodder.player = msg.who; Fodder.name = msg.who + " #" + (findObjs({_type: "character", controlledby: msg.playerid}).length + 1) Fodder.gender = Fodder.rollGender(); Fodder.strength = Fodder.rollAbility(); Fodder.strengthMod = Fodder.calcMod(Fodder.strength); Fodder.Dexterity = Fodder.rollAbility(); Fodder.DexterityMod = Fodder.calcMod(Fodder.Dexterity); Fodder.Constitution = Fodder.rollAbility(); Fodder.ConstitutionMod = Fodder.calcMod(Fodder.Constitution); Fodder.Wisdom = Fodder.rollAbility(); Fodder.WisdomMod = Fodder.calcMod(Fodder.Wisdom); Fodder.Intelligence = Fodder.rollAbility(); Fodder.IntelligenceMod = Fodder.calcMod(Fodder.Intelligence); Fodder.Charisma = Fodder.rollAbility(); Fodder.CharismaMod = Fodder.calcMod(Fodder.Charisma); Fodder.hp = Fodder.rollHP(Fodder.ConstitutionMod); if (typeof Fodder.HeritageTable != 'undefined') { Fodder.rollHeritage(); } if (typeof Fodder.BackgroundTable != 'undefined') { Fodder.rollBackground(); } if (typeof Fodder.EquipmentTable != 'undefined') { Fodder.rollEquipment(); } if (typeof outputCallback === "function") { setTimeout(outputCallback, 2500, msg, saveCallback); } }, /* Should account for more than male and female? */ rollGender: function () { var coinFlip = randomInteger(100); if (coinFlip &lt;= 50) { return "Male"; } else { return "Female"; } }, rollAbility: function () { return randomInteger(6) + randomInteger(6) + 6; }, calcMod: function (ability) { return Math.floor((0.0009 * ability * ability * ability) + (-0.029 * ability * ability) + (0.6 * ability) + 0.41) - 4; }, rollHeritageRoll: function () { Fodder.HeritageRoll = {}; sendChat("API", "/roll 1t[" + Fodder.HeritageTable + "]", function (result) { var content = JSON.parse(result[0].content); var values = content.rolls[0].results[0].tableItem.name.split(':'); Fodder.HeritageRoll.Heritage = values[0]; Fodder.HeritageRoll.detail = values[1]; }); }, rollHP: function (ConstitutionMod) { var hp = randomInteger(4) + ConstitutionMod; if (hp &lt;= 0) { hp = 1; } return hp; }, rollHeritage: function () { Fodder.Heritage = ''; sendChat("API", "/roll 1t[" + Fodder.HeritageTable + "]", function (result) { var content = JSON.parse(result[0].content); Fodder.Heritage = content.rolls[0].results[0].tableItem.name; }); }, rollBackground: function () { var Background = ""; sendChat("API", "/roll 1t[" + Fodder.BackgroundTable + "]", function (result, Background) { var content = JSON.parse(result[0].content); var values = content.rolls[0].results[0].tableItem.name.split(':'); Fodder.Background = values[0]; Background = values[0]; var weapon = values[1].split('|'); var handedness = 1; if (weapon[4] == 2) { handedness = 1.1; } Fodder.weapon = { name: weapon[1], damage: weapon[2], damageType: weapon[3], attackType: weapon[0], handedness: handedness }; if (weapon[0] === 'Ranged') { Fodder.weapon.ammo = randomInteger(6); Fodder.weapon.rangedType = '@{DEX}'; if (weapon[5] == 'Thrown') { Fodder.weapon.rangedType = '@{STR}'; } Fodder.weapon.rangedDistance = weapon[4] } Fodder.trade = values[2]; }); }, rollEquipment: function () { sendChat("API", "/roll 1t[" + Fodder.EquipmentTable + "]", function (result) { var content = JSON.parse(result[0].content); Fodder.equipment = content.rolls[0].results[0].tableItem.name; }); }, printSheet: function (msg, saveCallback) { var styleLabel = "style='font-weight: bold; padding: 5px;'"; var styleVal = "style='padding: 5px;'"; Fodder.output['name'] = "&lt;thead&gt;&lt;tr&gt;&lt;th colspan='2' style='background: #8C8173; padding: 5px;'&gt;" + Fodder.name + "&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;"; Fodder.output['gender'] = "&lt;tr&gt;&lt;td " + styleLabel + "&gt;Gender&lt;/td&gt;&lt;td " + styleVal + "&gt;" + Fodder.gender + "&lt;/td&gt;&lt;/tr&gt;"; if (Fodder.Heritage != undefined) { Fodder.output['Heritage'] = "&lt;tr&gt;&lt;td " + styleLabel + "&gt;Heritage&lt;/td&gt;&lt;td " + styleVal + "&gt;" + Fodder.Heritage + "&lt;/td&gt;&lt;/tr&gt;"; } else { Fodder.output['Heritage'] = ""; } if (Fodder.Background != undefined) { Fodder.output['Background'] = "&lt;tr&gt;&lt;td " + styleLabel + "&gt;Background&lt;/td&gt;&lt;td " + styleVal + "&gt;" + Fodder.Background + "&lt;/td&gt;&lt;/tr&gt;"; } else { Fodder.output['Background'] = ""; } Fodder.output['abilities'] = "&lt;tr&gt;&lt;td " + styleLabel + "&gt;Strength&lt;/td&gt;&lt;td " + styleVal + "&gt;" + Fodder.strength + ' (' + Fodder.strengthMod + ')' + "&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td " + styleLabel + "&gt;Dexterity&lt;/td&gt;&lt;td " + styleVal + "&gt;" + Fodder.Dexterity + ' (' + Fodder.DexterityMod + ')' + "&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td " + styleLabel + "&gt;Constitution&lt;/td&gt;&lt;td " + styleVal + "&gt;" + Fodder.Constitution + ' (' + Fodder.ConstitutionMod + ')' + "&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td " + styleLabel + "&gt;Wisdom&lt;/td&gt;&lt;td " + styleVal + "&gt;" + Fodder.Wisdom + ' (' + Fodder.WisdomMod + ')' + "&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td " + styleLabel + "&gt;Intelligence&lt;/td&gt;&lt;td " + styleVal + "&gt;" + Fodder.Intelligence + ' (' + Fodder.IntelligenceMod + ')' + "&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td " + styleLabel + "&gt;Charisma&lt;/td&gt;&lt;td " + styleVal + "&gt;" + Fodder.Charisma + ' (' + Fodder.CharismaMod + ')' + "&lt;/td&gt;&lt;/tr&gt;"; Fodder.output['hitpoints'] = "&lt;tr&gt;&lt;td " + styleLabel + "&gt;Hit Points&lt;/td&gt;&lt;td " + styleVal + "&gt;" + Fodder.hp + "&lt;/td&gt;&lt;/tr&gt;"; if (Fodder.weapon != undefined) { Fodder.output['weapon'] = "&lt;tr&gt;&lt;td style='font-weight: bold; padding: 5px;'&gt;Weapon&lt;/td&gt;&lt;td style='padding: 5px;'&gt;" + Fodder.weapon.name + " (" + Fodder.weapon.damage + ")&lt;/td&gt;&lt;/tr&gt;"; } else { Fodder.output['weapon'] = ""; } if (Fodder.equipment != undefined) { Fodder.output['equipment'] = "&lt;tr&gt;&lt;td style='font-weight: bold; padding: 5px;'&gt;Equipment&lt;/td&gt;&lt;td style='padding: 5px;'&gt;" + Fodder.equipment + "&lt;/td&gt;&lt;/tr&gt;"; } else { Fodder.output['equipment'] = ""; } sendChat(msg.who, "/direct &lt;table style='background: #DCD9D5; border-radius: 20px; font-size: 10px;'&gt;" + Fodder.output['name'] + "&lt;tbody&gt;" + Fodder.output['gender'] + Fodder.output['Heritage'] + Fodder.output['Background'] + Fodder.output['abilities'] + Fodder.output['hitpoints'] + Fodder.output['Charisma'] + Fodder.output['weapon'] + Fodder.output['trade'] + Fodder.output['equipment'] + Fodder.output['copper'] + "&lt;/tbody&gt;&lt;/table&gt;"); if (typeof saveCallback === "function") { saveCallback(); } }, save: function() { var character = createObj("character", { avatar: Fodder.defaultAvatar, name: Fodder.name, bio: "", gmnotes: "", archived: false, inplayerjournals: "all", controlledby: Fodder.id }); createObj('attribute', { name: 'player_name', current: Fodder.player, _characterid: character.id }); createObj('attribute', { name: 'Name', current: Fodder.name, _characterid: character.id }); createObj('attribute', { name: 'gender', current: Fodder.gender, _characterid: character.id }); createObj('attribute', { name: 'Level', current: '0', max: '10', _characterid: character.id }); createObj('attribute', { name: 'XP', current: 0, max: 10, _characterid: character.id }); createObj('attribute', { name: 'Strength', current: Fodder.strength, max: Fodder.strength, _characterid: character.id }); createObj('attribute', { name: 'Dexterity', current: Fodder.Dexterity, max: Fodder.Dexterity, _characterid: character.id }); createObj('attribute', { name: 'Constitution', current: Fodder.Constitution, max: Fodder.Constitution, _characterid: character.id }); createObj('attribute', { name: 'Wisdom', current: Fodder.Wisdom, max: Fodder.Wisdom, _characterid: character.id }); createObj('attribute', { name: 'Intelligence', current: Fodder.Intelligence, max: Fodder.Intelligence, _characterid: character.id }); createObj('attribute', { name: 'Charisma', current: Fodder.Charisma, max: Fodder.Charisma, _characterid: character.id }); createObj('attribute', { name: 'Charisma_Starting', current: Fodder.Charisma, max: Fodder.Charisma, _characterid: character.id }); if (typeof Fodder.Heritage != "undefined") { createObj('attribute', { name: 'Heritage', current: Fodder.Heritage, _characterid: character.id }); createObj('attribute', { name: 'Background', current: Fodder.Background, _characterid: character.id }); if (Fodder.weapon.attackType === 'Melee') { createObj('attribute', { name: 'MeleeWeaponName1', current: Fodder.weapon.name, _characterid: character.id }); createObj('attribute', { name: 'MeleeDmg1', current: Fodder.weapon.damage, _characterid: character.id }); createObj('attribute', { name: 'MeleeDmgType1', current: Fodder.weapon.damageType, _characterid: character.id }); createObj('attribute', { name: 'MeleeAttackWielded1_Zero', current: Fodder.weapon.handedness, _characterid: character.id }); } else { createObj('attribute', { name: "RangedAmmo1", current: Fodder.weapon.ammo, _characterid: character.id }); createObj('attribute', { name: 'RangedWeaponName1', current: Fodder.weapon.name, _characterid: character.id }); createObj('attribute', { name: 'RangedDistance1', current: Fodder.weapon.rangedDistance, _characterid: character.id }); createObj('attribute', { name: 'RangedType1', current: Fodder.weapon.rangedType, _characterid: character.id }); createObj('attribute', { name: 'RangedDmg1', current: Fodder.weapon.damage, _characterid: character.id }); } createObj('attribute', { name: 'Equipment', current: Fodder.trade + "\n" + Fodder.equipment, _characterid: character.id }); } }; on("ready", function () { Fodder.listen(); });
1649376605

Edited 1649376628
Oosh
Sheet Author
API Scripter
The whole Fodder singleton is missing its closing brace (or the last function inside it, save() is, depending on how you look at it). 6th line from the end, add another '}' and you should be good.
That worked, but now I'm getting the following from Airbag: Airbag: SRC: ScriptCards:4613 ==================== MSG: Firebase.set failed: First argument contains undefined in property 'current' ==================== Airbag: STK: Error: Firebase.set failed: First argument contains undefined in property 'current' at Ba (/home/node/d20-api-server/node_modules/firebase/lib/firebase-node.js:9:49) at Ba (/home/node/d20-api-server/node_modules/firebase/lib/firebase-node.js:10:207) at Aa (/home/node/d20-api-server/node_modules/firebase/lib/firebase-node.js:8:462) at J.set (/home/node/d20-api-server/node_modules/firebase/lib/firebase-node.js:146:98) at createObj (/home/node/d20-api-server/api.js:2818:26) Airbag: &nbsp;at save (apiscript.js:11795:8) at printSheet (apiscript.js:11671:9) at Timeout.airDelayHandler (apiscript.js:158:14) at listOnTimeout (internal/timers.js:556:17) at processTimers (internal/timers.js:497:7) Airbag: ==================== I don't see where current is defined, but it isn't defined in fodderator either. Suggestions?
1649390783

Edited 1649391313
Oosh
Sheet Author
API Scripter
Joab said: I don't see where current is defined, but it isn't defined in fodderator either. Suggestions? It's used 24 times in fodderator - 'current' is the main value key for Roll20 attributes (the other value is 'max', used significantly less). One of those 24 instances of 'current' in your script is trying to pass undefined to Roll20, which it doesn't like very much. If you have no idea which one, a very hacky workaround would be to replace all of your variables with template literals. So this: createObj('attribute', { name: 'MeleeWeaponName1', current: Fodder.weapon.name, _characterid: character.id }); ... would become this: createObj('attribute', { name: 'MeleeWeaponName1', current: `${Fodder.weapon.name}`, // IMPORTANT: these are backticks, not apostrophes _characterid: character.id }); This essentially casts the values to a String. It should get around this particular error, and the value of any attribute with a bad reference is going to be 'undefined' the String . That should make it easy enough to identify which attributes are being passed garbage. Note that this method isn't generally a great choice in final code - it's essentially moving a problem from a crash, to a potentially silent issue that can cause harder-to-find bugs down the line. I'd only use it for debugging, or if you're handling cases where you get 'null' or 'undefined' strings (not to mention the results of trying to cast objects to strings....) Even then, I'd probably only do this if you don't know which attributes are working and which aren't - this method should allow you to check the whole lot to see which ones are problematic. A better pattern is to always provide an empty string as a fallback parameter: createObj('attribute', { name: 'MeleeWeaponName1', current: Fodder.weapon.name || '', _characterid: character.id }); This might be less useful to you for debugging, as this won't tell you whether Fodder.weapon.name was 0, false, null, undefined, or an empty string.
Had an extra "s" at the end of a variable. Dangit!