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

Looking for help with script to roll HP

I'd appreciate any help I could get with this as my Java skills are limited to put it mildly. I'm looking for a script I could use to roll the hit dice of a creature and set corresponding HP attributes and token bars equal to the die roll result. I have a character sheet with the attributes HP and HitDice and a token tied to the character sheet that maps Bar2 to the HP attribute. Is it possible to write a script that would roll the dice equation in the HitDice attribute (ie. 1d8+2) and set the HP attribute's Min and Max to equal the roll result and update the token's Bar2 Min and Max to the roll result as well? Again, any help I could get with this will be greatly appreciated. Thanks.
1403019812
The Aaron
Roll20 Production Team
API Scripter
That's definitely possible. I'm not sure if anyone has written anything like that (possibly?). I will point out that you probably don't want to have bar2 tied to the character sheet. If you do, changing bar2 of the token will change bar2 of the character sheet, and thus change bar2 for every copy of the creature you have in play. It should be possible to setup a script so that on add of a token to the board, if the token is tied to a character, but does not have bar2 linked or a value in bar2_value or bar2_max, and the character has HitDice as an attribute, that it rolls the expression in HitDice and sets bar2_value and bar2_max to the result. Then you could drag orcs onto the field like mad and they would all have hit points rolled and assigned to them. That sound like what you want?
That's exactly what I'm looking for Aaron! Would that be hard to do?
1403021690
The Aaron
Roll20 Production Team
API Scripter
Nope. Enjoy! =D <a href="https://gist.github.com/shdwjk/7377de58100f4e813432" rel="nofollow">https://gist.github.com/shdwjk/7377de58100f4e813432</a>
Holy cow! ... is that phrase dating myself :-) Thanks tons Aaron! I'll let you know how it goes.
1403022098

Edited 1403023616
Naz
Pro
It works like a charm Aaron! Thanks again. I must say I wasn't expecting to get this in less than an hour. Now I'm spoiled....even more so than before :-)
1403022207
The Aaron
Roll20 Production Team
API Scripter
=D Nope, I get the feeling from your profile we're probably in the same boat there. ( Rad! =D ) No problem on the script, it strikes me as something the guy running my Monday night DnD Next game would want. ( Maybe if HE likes it, he'll lower the cost of lightning bugs... =D ) Let me know if you run into any issues with it, or any ways you'd like to expand it. I'll probably come back and update it to allow selection of which bar to use, etc.
The only issue I had were the tokens with bars I mistakenly tied to the sheet. Once I fixed that everything was fine. I've already updated the dozen or so mobs I had created for my 5e game. I always liked rolling the mobs HP to vary their toughness. It sometimes makes unexpected one shots possible and sometimes get the player saying, "You're kidding, he still has a half bar of health left?". Thanks again, cheers!
1403023646
The Aaron
Roll20 Production Team
API Scripter
Glad to hear it! =D My Monday DM is the same way (but has a more complicated way of rolling hit dice which I'll be adding at some point.. =D ).
1403025737
Chad
Plus
Sheet Author
Try this script below. It's what I use as part of my combat efficiency. It allows for a few more options, and uses the API for dice rolls which is more efficient. Note: You need to unlink journal HP from the Token otherwise all tokens of the same type will share hitpoints. This is very beta, but it's been working nicely for me. Feel free to report any issues. var CM = CM || {}; CM.CAMPAIGN_MANAGER_VERSION = ".3 BETA"; /* Commands: !CM range = Find range between two selected tokens. !CM kill = Kill the selected tokens. !CM rollhp = Roll hitpoints for selected tokens. !CM xp = Find total XP for selected tokens. */ /* Setup: Commands require the following attributes and abilities: (It is easiest to add these to a NPC Template journal entry, and then simply duplicate that journal entry whenever adding a new NPC.) The following ability must exist to identify NPC MOBS: "CMIsMOBYES" (This keeps the game from rolling new HP for a player, if you accidentally select one.) The following attributes must exist for HP rolls: HPDieNum = Number of dice to be rolled HPDieSides = Number of sides on each die HPBonus = Bonus to be added after roll completed The following attributes must exist for XP rolls: XP = The number of experience points one of these mobs is worth Hitpoints will be rolled and added to Bar 2 Value. It is intended that Bar 2 NOT be attached to the HP value on the journal entry so that each selected MOB can have a different number of hitpoints, even if they are all linked to the same entry. */ /* Setup: Other options: */ CM.LOG_ON = true; //Default is true CM.PUBLIC_MESSAGES = true; //Default is true on("chat:message", function (msg) { var response = ""; if (msg.type=="api") { response = CM.ChatParse(msg); sendChat("CampaignManager",response); } }); CM.Log = function (logtext) { if (CM.LOG_ON) log(logtext); return; } CM.Chat = function (chattext) { if (CM.PUBLIC_MESSAGES) sendChat("CampaignManager", chattext); return; } CM.IsGM = function (msg){ if (CM.GM_CHAT_TAG == msg.who) return true; return false; } CM.AttributeValue = function (attributename,token) { if (token.get('represents') !== "") { var charid=token.get('represents'); } else { return false; //It doesn't have a journal so it can't have the attribute. } var obj = findObjs({ _characterid: charid, _type: "attribute", name: attributename, }, { caseInsensitive: true }); // End findObjs var value=-1; if (obj.length != 1) { return false; } else { _.each(obj, function(attribute) { value = attribute.get("current"); }); return Number(value); } //End if more than 1 attribute found } CM.HasAbility = function (abilityname, token) { if (token.get('represents') !== "") { var charid=token.get('represents'); } else { return false; //It doesn't have a journal so it can't have the ability. } var foundabilities = findObjs({ _characterid: charid, _type: "ability", name: abilityname, }, { caseInsensitive: true }); // End findObjs if (foundabilities.length == 0) { return false; } else { return true; }; //End isnull localabilties }; CM.Roll = function(rolls,die) { roll=0; for (x=0;x&lt;rolls;x++) { this_roll=randomInteger(die); roll += this_roll; } //End die roll FOR loop return roll; } CM.ChatParse = function(msg) { if (msg.type !== "api") return; //Ignore any message that isn't an API call (Starts with !) var message = msg.content; message = message.trim(); message = message.toLowerCase(); if (!(message.indexOf("!cm") == 0)) return; //We only listen for commands that start with CM message_from_gm = CM.IsGM(msg); message = message.substr(4,message.length-4); var response_text = "/w " + msg.who + " "; response_text = response_text.replace(" (GM)",""); var token = new Array(); //Now we setup selected tokens as a lot of commands require tokens selected var counter=0; _.each(msg.selected, function (obj) { if (obj._type == 'graphic') { token[counter] = getObj('graphic', obj._id); counter++; } }); var selected_objects = counter; switch (message) { case "range": if (selected_objects!=2) { response_text += "Please select two tokens for a range calculation."; } else { response_text += "The range from " + token[0].get("name") + " to " + token[1].get("name") + " is " + CM.TokenRange(token[0],token[1]); } break; case "rollhp": var selectedObjs = msg.selected; response_text += "HP Rolls: "; _.each(selectedObjs, function (obj) { if (obj._type == 'graphic') { var token = getObj('graphic', obj._id); if (CM.HasAbility("CMIsMOBYES",token)) { var die_num = CM.AttributeValue("HPDieNum", token); var die_sides = CM.AttributeValue("HPDieSides", token); var hp = 0; hp += CM.Roll(die_num,die_sides); hp += CM.AttributeValue("HPBonus",token); response_text += hp + ","; token.set("bar2_value",hp); token.set("bar2_max",hp); //Now set the default view permissions so the players can see what we want them to. token.set("showplayers_bar1",false); token.set("showplayers_bar2",true); token.set("showplayers_bar3",true); } //End CMIsMOBYES } //End if Graphic });// End each SelectedObjs break; case "kill": var selectedObjs = msg.selected; response_text += "HP Zeroed: "; _.each(selectedObjs, function (obj) { if (obj._type == 'graphic') { var token = getObj('graphic', obj._id); if (CM.HasAbility("CMIsMOBYES",token)) { response_text += 0 + ","; token.set("bar2_value",""); token.set("bar2_max",""); token.set("status_dead",true); } //End CMIsMOBYES } //End if Graphic });// End each SelectedObjs break; case "xp": var selectedObjs = msg.selected; response_text += "XP Total: "; var xp = 0; _.each(selectedObjs, function (obj) { if (obj._type == 'graphic') { var token = getObj('graphic', obj._id); if (CM.HasAbility("CMIsMOBYES",token)) { xp += CM.AttributeValue("XP",token); } //End CMIsMOBYES } //End if Graphic });// End each SelectedObjs response_text += xp; break; default: response_text += "Command not understood."; }//End switch content return response_text; } CM.TokenRange = function (token1,token2) { var page=getObj("page", token1.get("_pageid")); var scale=page.get("scale_number"); var scale_unit=page.get("scale_units"); var range=CM.GetDistance(token1.get('left'),token1.get('top'),token2.get('left'),token2.get('top')); range = range - (( ((token1.get("width")+token1.get("height"))/2) + ((token2.get("width")+token2.get("height"))/2) )/2); range=range / (70 / scale); range=range*100; range=Math.round(range); range=range/100; var range_txt=range + " " + scale_unit; return range_txt; } CM.GetDistance = function (x1, y1, x2, y2) { var dist = 0; dist = Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2)); return dist; };
1403026703
The Aaron
Roll20 Production Team
API Scripter
Nice looking script. I'm curious about your CM.isGM() function. I notice it compares to CM.GM_CHAT_TAG, which doesn't seem to be defined. What is it intended to be set to?
1403028435
Chad
Plus
Sheet Author
I decided not to implement that, so the code doesn't actually check for the GM yet. But if you wanted to, it would look like this (or whatever you set your chat tag to.) CM.GM_CHAT_TAG = "Chad (GM)"; Also, a bug I just found while trying out another script: if you use some other scripts that parse chat for their own API commands, you might need to make a small modification to avoid errors. Modify the sendchat command In the vicinity of line 48: if (response) sendChat("CampaignManager",response) And insert the following as the first command in chatparse in the vicinity of line 126: var response_text=null; Chad
1403028829
The Aaron
Roll20 Production Team
API Scripter
Ah. That's what I figured. The problem with simply checking for the ' (GM)' is that it is not sent on api messages, so far as I can tell, and can be spoofed by enterprising characters. I have a script that solves this problem and automatically accumulates GMs. You may be interested in it, you simply call the function isGM(&lt;playerid&gt;) and it tells you if they have been identified as a GM. Here's the script forum post: <a href="https://app.roll20.net/forum/post/920764/script-isgm-id-function-auto-populated#post-925675" rel="nofollow">https://app.roll20.net/forum/post/920764/script-isgm-id-function-auto-populated#post-925675</a>
1403035385
Lithl
Pro
Sheet Author
API Scripter
Aaron said: Ah. That's what I figured. The problem with simply checking for the ' (GM)' is that it is not sent on api messages, so far as I can tell, and can be spoofed by enterprising characters. " (GM)" is appended to msg.who if the user who sent the message has GM privileges and is speaking as themselves. If they're speaking as a character (or if they've re-joined as a player), it's not appended. It doesn't matter what msg.type is. Even beyond the possibility of players changing their name to spoof the system, the fact that it's not included when the GM is speaking as a character is probably enough reason to use a different indicator for GM privileges in scripts.
1403036236
The Aaron
Roll20 Production Team
API Scripter
Based on my testing, it's not present on api messages. I think this is a vaguely recent change to the API. { . "content": "!msg", . "playerid": "-JKhPSioQGMeqvGpGRkJ", . "type": "api", . "who": "Aaron" } { . "_d20userid": "104025", . "_displayname": "Aaron", . "speakingas": "", . "_online": true, . "color": "#ff00ff", . "_macrobar": "-JKhPSioQGMeqvGpGRkJ|-JOr8JLgeC_epl9N0xDd,-JKhPSioQGMeqvGpGRkJ|-JNH0jwEGwmuMD8Awjp4,-JKhPSioQGMeqvGpGRkJ|-JO7FkxmDBcaWkeeCqy2", . "showmacrobar": true, . "_id": "-JKhPSioQGMeqvGpGRkJ", . "_type": "player" }