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 .
×
May your rolls be merry + bright! 🎄
Create a free account

D&D 5E Barbarian Class Module issue

Hi, if anyone could help that would be much appreciated, i am trying to use the barbarian module for rage but all it is doing is causing an error every time. It will usually take the rage down by 1 as intended but doesn't add status, doesn't add damage modifier or put anything in chat etc. If use on character without rage or use when have not rage left correct message shows but still causes error. (i've got the paladin lay on hands one working fine, this one seems to be the only one having issues) Macro i am using is what was written by author of script- !dm-action barbarian rage @{selected|character_id} his Error showing- Your scripts are currently disabled due to an error that was detected. Please make appropriate changes to your script's code and click the "Save Script" button. We will then attempt to start running the scripts again.  More info...  If this script was installed from the Script Library, you might find help in the Community API Forum. For reference, the error message generated was:  TypeError: Cannot read property 'id' of null TypeError: Cannot read property 'id' of null at DungeonMasterToolsBarbarian.action_rage (apiscript.js:9743:48) at DungeonMasterTools.dispatchAction (apiscript.js:4052:23) at DungeonMasterTools.handleAction (apiscript.js:4066:10) at Object.dm-action (apiscript.js:3886:41) at apiscript.js:3958:33 at eval (eval at <anonymous> (/home/node/d20-api-server/api.js:161:1), <anonymous>:65:16) at Object.publish (eval at <anonymous> (/home/node/d20-api-server/api.js:161:1), <anonymous>:70:8) at /home/node/d20-api-server/api.js:1721:12 at /home/node/d20-api-server/node_modules/firebase/lib/firebase-node.js:93:560 at hc (/home/node/d20-api-server/node_modules/firebase/lib/firebase-node.js:39:147) all current API used - G  DryErase G  True Page Copy G  5th Edition OGL by Roll20 Companion G  5E Resting in Style G  Concentration G  D&D 5E - PaladinAura G  D&D 5E Dungeon Master Tools G  D&D 5E Difficulty Rating G  D&D 5E Paladin Class Module G  Aura/Tint HealthColors G  splitArgs G  Flight G  MonsterHitDice G  Calendar G  StatusInfo G  TableExport G  CombatTracker Big brother hit dice tracker G  D&D 5E Barbarian Class Module Thanks for any help.
1625281009

Edited 1625281456
Oosh
Sheet Author
API Scripter
You can give this a go instead - if it stops the crash, and you get an error message in chat, it's the getToken() method use in the base Class of the script that's causing the issue. The other option is a character.id call causing the crash - but that seems unlikely if the Rage counter is being subtracted properly sometimes. I've just added a line at the "// Add Event for Tracking" part to stop it trying to send an event with token.id if it hasn't found a token. If this fixes it, but you get a chat message error instead, it might be that you're not on the same page as the player ribbon. It currently searches for a token which is:     - representing the character id supplied     - on the page where the player ribbon is If your GM view is on a different page, this script won't find any of the tokens you're looking at. That can be changed if you'd like? edit - this is the modified Barbarian module, not the base script class DungeonMasterToolsBarbarian extends RatWorkshop_Module { static MODULE_NAME = 'Barbarian'; static VERSION = 0.1; static DEFAULT_STATE = { version: DungeonMasterToolsBarbarian.VERSION, gcUpdated: 0, }; /** END ACTIONS **/ /** * Ends the Rage Action, removes rage token icon, and unchecks the rage global modifier * @param event */ end_action_rage({ characterId }) { const character = getObj("character", characterId); // Set Rage Token Status const token = this.getToken(characterId); if (token) { const token_status = {}; token_status[`status_${this.tokenIcons.rage}`] = false; token.set(token_status); } // Clear Global Damage Modifier const global_rage_damage = this.getGlobalModifier(characterId, 'Rage Damage'); if (global_rage_damage) { global_rage_damage['active_flag'].set({ current: 0 }); } // Send Action Message this.sendActionMessage( character.get('name'), `**${character.get('name')}** is no longer raging.`, ); } /** ACTIONS **/ /** * Rage * @param options * @param playerId */ action_rage(options, { playerid: playerId }) { const character = getObj("character", options[0]); const possessivePronoun = options[1] || 'his'; // Validate the Character if (!character) { this.sendErrorMessage(playerId, 'Unable to find the selected character to perform **rage**'); return; } // Validate the Character has Rage const rageTrait = this.getTrait(character.id, 'Rage'); if (!rageTrait) { this.sendErrorMessage(playerId, 'The currently selected character can not perform **rage**'); return; } // Check how much rage available const rage = this.getResource(character.id, 'Rage'); if (!rage) { this.sendErrorMessage(playerId, 'The currently selected character is missing the Rage Resource'); return; } // Send exhausted message if (rage.get('current') <= 0) { this.sendActionMessage( character.get('name'), `**${character.get('name')}** has exhausted ${possessivePronoun} rage and will need a long rest before raging again.`, ); return; } // Update Character's Rage rage.set({ current: rage.get('current') - 1 }); // Toggle Rage Damage On const global_rage_damage = this.getGlobalModifier(character.id, 'Rage Damage'); if (global_rage_damage) { global_rage_damage['active_flag'].set({ current: 1 }); } else { this.sendErrorMessage(playerId, 'The currently selected character is missing the Rage Damage Modifier, you will have to activate it manually.'); } // Add Turn Order const eventId = this.addTurnOrder({ id: "-1", pr: 10, custom: `Rage: ${character.get('name')}`, formula: '-1' }); // Set Rage Token Status const token = this.getToken(character.id); if (token) { const tokenStatus = {}; tokenStatus[`status_${this.tokenIcons.rage}`] = true; token.set(tokenStatus); } // Add Event for Tracking, check token exists if (!token) this.sendErrorMessage(playerId, `Couldn't find token for current character`); else this.addEvent(eventId, character.id, token.id, 'rage', DungeonMasterToolsBarbarian.MODULE_NAME, 'end_action_rage'); // Send Action to the Chat Window this.sendActionMessage( character.get('name'), `**${character.get('name')}** enters a state of primal ferocity and is now raging`, ); // Send exhausted message if (rage.get('current') <= 0) { this.sendActionMessage( character.get('name'), `**${character.get('name')}** has exhausted ${possessivePronoun} rage and will need a long rest before raging again.`, ); } } /** SHORT REST **/ /** LONG REST **/ /** * Initialize Configurations and update from userOptions */ initialConfigurations() { if (!state.RatWorkShop_DungeonMasterTools_Roll20_5E.modules[DungeonMasterToolsBarbarian.MODULE_NAME] || !state.RatWorkShop_DungeonMasterTools_Roll20_5E.modules[DungeonMasterToolsBarbarian.MODULE_NAME].version || state.RatWorkShop_DungeonMasterTools_Roll20_5E.modules[DungeonMasterToolsBarbarian.MODULE_NAME].version !== DungeonMasterToolsBarbarian.VERSION) { state.RatWorkShop_DungeonMasterTools_Roll20_5E.modules[DungeonMasterToolsBarbarian.MODULE_NAME] = DungeonMasterToolsBarbarian.DEFAULT_STATE; state.RatWorkShop_DungeonMasterTools_Roll20_5E.tokenIcons['rage'] = 'strong'; } const gc = globalconfig && globalconfig.RatWorkShop_DungeonMasterTools_Roll20_5E; if (gc && gc.lastsaved && gc.lastsaved > state.RatWorkShop_DungeonMasterTools_Roll20_5E.modules[DungeonMasterToolsBarbarian.MODULE_NAME].gcUpdated) { state.RatWorkShop_DungeonMasterTools_Roll20_5E.modules[DungeonMasterToolsBarbarian.MODULE_NAME].gcUpdated = gc.lastsaved; if ('tokenIcon-rage' in gc) { state.RatWorkShop_DungeonMasterTools_Roll20_5E.tokenIcons['rage'] = gc['tokenIcon-rage']; } } } constructor() { super(); } } DungeonMasterToolsBarbarian.register();
Thanks heaps for that! seems to be all working well now without issue for the barbarian.  If another token is selected who isn't a barbarian when pressed it shows up they don't have rage in chat which is good but also then it causes an error, but i will tell my players not to and hopefully it will be all good. just for reference the error is below- For reference, the error message generated was:  TypeError: Cannot read property 'get' of undefined TypeError: Cannot read property 'get' of undefined at handleInput (apiscript.js:9552:23) at eval (eval at <anonymous> (/home/node/d20-api-server/api.js:161:1), <anonymous>:65:16) at Object.publish (eval at <anonymous> (/home/node/d20-api-server/api.js:161:1), <anonymous>:70:8) at /home/node/d20-api-server/api.js:1721:12 at /home/node/d20-api-server/node_modules/firebase/lib/firebase-node.js:93:560 at hc (/home/node/d20-api-server/node_modules/firebase/lib/firebase-node.js:39:147) at Kd (/home/node/d20-api-server/node_modules/firebase/lib/firebase-node.js:93:546) at Id.Mb (/home/node/d20-api-server/node_modules/firebase/lib/firebase-node.js:93:489) at Zd.Ld.Mb (/home/node/d20-api-server/node_modules/firebase/lib/firebase-node.js:94:425) at /home/node/d20-api-server/node_modules/firebase/lib/firebase-node.js:111:461
1625375391

Edited 1625375835
Oosh
Sheet Author
API Scripter
Hrmmm... it looks like that error is coming from another script. From your original error log, it looks like the Barbarian script starts around line 9640ish. What's that "hit dice tracker" script? Is it 100+ lines long? If it's not that it's probably "Big Brother" - thought I also have no idea what that script is. It seems like the Barbarian module chat error is triggering one of those, but hard to tell without knowing the content of the scripts. I'm assuming your script list above is in the same order as on your API scripts setting page. edit - oh wait, I'm assuming it's this one from Kyle G? It sure looks like the culprit - it assumes every message it sniffs has a valid Roll20 Player as the sender... this isn't necessarily the case with API-generated messages. Try this modified script, it's got an extra line in it to handle API generated messages with no sender " if (!sender || !sender.id) return; " ... that should hopefully cover all bases. /** * Big Brother by Kyle G. * Listens to any whispers sent to players/characters that are not gm and whispers the gm the contents * of the message. * * API Commands: * !bigBrother on/off - automatically whispers detected whispers to the gm * (will also store the whisper in the chat archive). * !bigBrother - displays the current status of the script (on/off). */ var BigBrother = BigBrother || (function(){ 'use strict'; var version = '0.1.0', scriptName = 'Big Brother', validOnOptions = ['1', 'on'], validOffOptions = ['0', 'off'], handleInput = function(msg) { if(msg.type === 'whisper' && msg.target_name !== 'GM' && msg.target !== 'gm' && state.BigBrother === 1) { var output = "<div><p>(Message to TARGET from SENDER)</p><p><b>CONTENT</b></p>"; var sender = getObj('player', msg.playerid); if (!sender || !sender.id) return; var speakingAs; if(sender.get('speakingas') && sender.get('speakingas').indexOf('character|') !== -1) { var character = getObj('character', sender.get('speakingas').split('|')[1]); speakingAs = character.get('name'); } else { speakingAs = sender.get('_displayname') } output = output.replace("TARGET", msg.target_name).replace("SENDER", speakingAs).replace("CONTENT", msg.content); sendChat(scriptName, "/w gm " + output); } else if (msg.type === 'api' && (msg.content.indexOf('!bigBrother') !== -1 || msg.content.indexOf('!bb') !== -1)) { if(validOffOptions.indexOf(msg.content.split(' ')[1]) !== -1) { state.BigBrother = 0; } else if(validOnOptions.indexOf(msg.content.split(' ')[1]) !== -1) { state.BigBrother = 1; } sendChat(scriptName, '/w gm ' + scriptName + ' - ' + (state.BigBrother? 'on' : 'off')); } }, checkInstall = function() { log('->' + scriptName + ' v' + version + '<- Ready'); state.BigBrother = state.BigBrother || 1; }, registerEventHandlers = function() { on('chat:message', handleInput); }; return { CheckInstall: checkInstall, RegisterEventHandlers: registerEventHandlers }; }()); on('ready', function(){ 'use strict'; BigBrother.CheckInstall(); BigBrother.RegisterEventHandlers(); });
1625376605
Oosh
Sheet Author
API Scripter
Ermmm... not really my place to judge, but that's a pretty unethical script. It should really notify players that their whispers are no longer private... but if your players are aware of it, all good I guess.
Wow, thanks heaps again wasn't expecting the extra help, that fixed it, thank you very much. In regards to the script it is so players can chat to each other without other players being aware of what they are saying but dm still aware so can get things ready for them if needed etc. They are aware if they want to talk amongst the players without the dm like making a group plan they don't want me to be aware of or whatever to use messanger or something. It came up originally in a campaign i was playing in because me and another player seemed to be ignoring everything others in the group were doing but were just discussing it in whispers making a plan that the others wouldn't have been able to hear because they were in a different area. and then the dm got annoyed because we didn't respond quick enough to an NPC and we almost got attacked by the whole town until we explained etc.  Anyway yeah it's a really useful script but players should be aware of it and have to trust that the DM will work with them not against.
1625472894
Oosh
Sheet Author
API Scripter
All good, it sounds like it's pretty useful in an RP environment! My unsanctioned judginess was more in relation to the script itself... I probably would've written a notification in there to remind players that their whispers aren't necessarily private, the first time they whisper in a session. It seems like it could be misused in certain circumstances, like in a game where players don't all know each other well, and are new to the platform.
oh yeah, fair enough, if i understood scripts enough to have written it myself i probably would have added something like gm is watching with funny eyes lol, and make it not send it to me again when they whisper to me.