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] Champions / Hero System Damage Roller

1516908726

Edited 1590394982
GiGs
Pro
Sheet Author
API Scripter
I was inspired by Mark L over another thread (see below) to make a champions damage roller. I'll assume you know how damage works in that system, so I can get straight to the syntax. Example output (the last line only shows if using location rolls): Dice Rolls must start with !herodc [[a valid roll]] so for instance: !herodc [[4d6]] There are a bunch of parameters, which must be in one of these form: parameter:value parameter|value Parameters: damagetype Alternate: type Values: killing, martial, stun, normal Can use just the first letter of each.  If no Type is supplied, it is a normal attack. Killing: roll is for body damage, a multiple is applied for stun. Knockback gains +1 die. Martial: as normal damage, but knockback gains 1 extra die. Stun: no body or knockback is inflicted knockback Alternate: kb By default, attacks get 2 dice of knockback. use this parameter to add extra or fewer dice. Note: Martial and Killing attacks get +1 KB automatically; this is included, you dont need to add extra. So, assuming a normal attack, kb:1 would roll 3 dice, kb|-2 would roll 0 dice. knockdown Alt: kd HERO system has two different knockback systems. If this parameter is false, or omitted, the standard knockback rules are used. if kd:true, the alternate knockdown rules are used.  False is default, so only need to include this if using knockdown.. examples: kd:true, knockdown|true stunmod Alt: stunx, sm Some killing attacks do more stun, and have a bonus to the stun multiplier. That's what this is for, valid entries: stunx|1, sm:2, etc stund3 alt: hero6e If using hero 6e, killing attacks roll 1d3 stun multipliers instead of d6-1. if omitted, or false, the 5e and earlier rules will be used. examples: stund3:true, StunD3|true, Hero6e:true, etc location Alternate: loc, hit, placed If this parameter is present, the location effects will be used. If omitted, standard damage is used.  This accepts singular locations ( head, arm, shoulder, hand, vitals, chest, thigh leg, foot ) as well as roll types ( roll, headshot, lowroll, bodyshot, etc) you can also enter one of several rolls: roll: will make a standard 3d6 roll headshot, highshot, bodyshot, lowshot, legshot each use the variant location rolls (headrshot is 1d6+3 for example) headroll, highroll, bodyroll, lowroll, legroll are alternate values. Specific locations are also acceptable:  head, hand, arm, shoulder, chest, stomach, vitals, thigh leg, foot . Note all but vitals use the singular term. If the parameter location exists, and the value is not recognised, a standard 3d6 roll will be made, allowing you to use loc:any, loc:general, and so on. Examples  location:chest, placed|head, hit:highshot, loc:roll, location:any skipside Alternate: skip, side This is ignored if not using hit locations. When appropriate, the script will report right or left. So if you get a hit in the hand, it might report Right Hand. If skip:true, this behaviour is suppressed, and no side will be reported. when using hit locations, if this is omitted or false, it will roll for a left / right side. This is a pretty marginal parameter, but if in game you have aimed for the target's right leg, it might break your immersion slightly when it reports a hit in the left leg.  Examples: !herodc [[12d6]] a 12d6 normal attack !herodc [[2d6+2]] type:k a 2d6+2 killing attack !herodc [[7d6]] type:s hit:head a 7d6 stun only attack that hits the head !herodc [[6d6]] type|k loc|headshot kb|-1 6d6 killing attack, that will roll 1d6+3 for location, and roll 1 die less for knockback (cancelling the usual +1 for killing attacks) !herodc [[4d6]] type|k stund3:true stunx:2 a 4d6 killing attack, that rolls d3 for stun, and adds a +2 modifier to the stun multiplier !herodc [[7d6]] type:n loc|roll kd:true a 7d6 normal attack, using the knockdown system instead of knockback, that will roll a random location for the hit. Credits and script Mark L's work over in  this thread was a great inspiration (and the pretty css layout was his Scott's work, thank's Scott!), and The Aaron's dice scripts provided some important code snippets. Grab the script from  gist or from the next post. Please let me know about any bugs!
1516908744

Edited 1517190919
GiGs
Pro
Sheet Author
API Scripter
var herodc = herodc || (function() { 'use strict', /* when given an array of numbers will return an object with the numbers as the properties and the number of times it occurs as the value of each. */ getDiceCounts = function(rolls) { return ( _.reduce(rolls || [], function(m,r){ m[r]=(m[r]||0)+1; log('Parent Scope - Before call to asynchronous function.'); return m; },{})); }, /* takes an object with numbers as the properties and counts as the values and returns an array with the numbers repeated as many times as their count. */ getDiceArray = function(c) { return _.reduce(c,function(m,v,k){ _.times(v,function(){m.push(k);}); return m; },[]); }, getSpeaker = function(msg) { var characters = findObjs({_type: 'character'}); var speaking; characters.forEach(function(chr) { if(chr.get('name') == msg.who) speaking = chr; }); if(speaking) return 'character|'+speaking.id; else return'player|'+msg.playerid; }, // update the stun and body multiples of the // for killing attacks, armour applies to body before multiple // for normal attacks, defences apply before multiple for both stun & body // armour applies before multiples getLocation = function(roll) { let hit; if(roll <6) hit = "head"; else if(roll ===6) hit = "hand" else if(roll < 9) hit = "arm"; else if(roll ===9) hit = "shoulder" else if(roll <12) hit = "chest"; else if(roll === 12) hit = "stomach"; else if(roll === 13) hit = "vitals"; else if(roll === 14) hit = "thigh"; else if(roll < 17) hit = "leg"; else hit = "foot"; return hit; }, rollLocation = function(whichRoll) { let roll; switch(whichRoll) { case "headroll": case "headshot": roll = randomInteger(6) +3; break; case "highroll": case "highshot": roll = randomInteger(6) + randomInteger(6) + 1; break; case "bodyroll": case "bodyshot": roll = randomInteger(6) + randomInteger(6) + 4; break; case "lowroll": case "lowshot": roll = Math.min(18,randomInteger(6) + randomInteger(6) + 7); break; case "legroll": case "legshot": roll = randomInteger(6) + 12; break; default: roll = randomInteger(6) + randomInteger(6) + randomInteger(6); } return roll; }, applyLocation = function(where) { let locations = { head: { stunX: 5, NStun: 2, BodyX: 2, roll: '3-5'}, hand: { stunX: 1, NStun: 0.5, BodyX: 0.5, roll: '6'}, arm: { stunX: 2, NStun: 0.5, BodyX: 0.5, roll: '7-8'}, shoulder: { stunX: 3, NStun: 1, BodyX: 1, roll: '9'}, chest: { stunX: 3, NStun: 1, BodyX: 1, roll: '10-11'}, stomach: { stunX: 4, NStun: 1.5, BodyX: 1, roll: '12'}, vitals: { stunX: 4, NStun: 1.5, BodyX: 2, roll: '13'}, thigh: { stunX: 2, NStun: 1, BodyX: 1, roll: '14'}, leg: { stunX: 2, NStun: 0.5, BodyX: 0.5, roll: '15-16'}, foot: { stunX: 1, NStun: 0.5, BodyX: 0.5, roll: '17-18'}, }; if(herodc.parameters.type === "k") { herodc.damage.stunmult = locations[where]["stunX"]; herodc.damage.bodymult = locations[where]["BodyX"]; } else if(herodc.parameters.type === "s") { herodc.damage.stunmult = locations[where]["NStun"]; herodc.damage.bodymult = 0; } else { herodc.damage.stunmult = locations[where]["NStun"]; herodc.damage.bodymult = locations[where]["BodyX"]; } herodc.damage.hitrange = locations[where]["roll"] }, calcDamage = function(msg) { // rDice is an array of d6s, from the damage roll. herodc.damage = { // initialise defaults for the damage output dice: [], // the array that will hold the dice. total: 0, // initial dice roll, whether body or stun. body: 0, stun: 0, kb: "-", kblabel: "KB: ", loclabel: "-", stunmult: 1.0, // used on normal attacks when hit locations in use bodymult: 1.0, // used for both normal and killing attacks when hit locations in use expression: "-", hitlocation: "-", hitroll:0, hitrange:"3-18", }; herodc.damage.dice = _.pluck( (msg.inlinerolls && msg.inlinerolls[0].results.rolls[0].results) || [], 'v'); herodc.damage.dice.sort(); herodc.damage.dice.reverse(); herodc.damage.total = msg.inlinerolls[0].results.total; herodc.damage.expression = msg.inlinerolls[0].expression; // calculate damage roll switch(herodc.parameters.type) { case "k": herodc.damage.body = herodc.damage.total; herodc.damage.stun = herodc.damage.total * herodc.damage.stunmult; herodc.damage.expression += " Killing"; break; case "s": herodc.damage.stun = herodc.damage.total; herodc.damage.body = 0; herodc.damage.expression += " Stun"; break; default: let normal = getDiceCounts(herodc.damage.dice); herodc.damage.body = (normal[2] || 0) + (normal[3] || 0) + (normal[4] || 0) + (normal[5] || 0) + ((normal[6] *2) || 0); herodc.damage.stun = herodc.damage.total; herodc.damage.expression += " Normal"; } //if(herodc.parameters.hasOwnProperty("descriptor")) // herodc.damage.expression = herodc.damage.expression + " " + herodc.parameters.descriptor; // calculate knockback if(herodc.parameters.knockdown) { // this uses the knockdown rules. if(herodc.parameters.type === "s") { herodc.damage.kb = 0; herodc.damage.kblabel = "KD: "; } else { herodc.damage.kb = herodc.damage.body * 2; herodc.damage.kblabel = "KD: 1-"; } } else { herodc.damage.kblabel = "KB: "; if(herodc.parameters.type === "s") { herodc.damage.kb = "-"; } else { let kbDice = 2 + herodc.parameters.knockback; if(herodc.parameters.type === "k" || herodc.parameters.type === "m") kbDice +=1; let kb = herodc.damage.body; for (i = 0; i < kbDice; i++) { kb = kb - randomInteger(6); } if (kb >= 0) herodc.damage.kb = kb; } } // head shot 1d6+3, high shot 2d6+1 body shot 2d6+4, low show = 2d6+7, leg shot 1d6+12 // need to apply location modifiers, and killing damage stun multiple. if(!herodc.parameters.uselocation) { if(herodc.parameters.type === "k") { let stunX = 0; if(herodc.parameters.stund3) stunX = randomInteger(3); else stunX = Math.max(randomInteger(6)-1,1); stunX += herodc.parameters.stunmod; herodc.damage.stun = herodc.damage.body * stunX; } } else { // two possibilities: location is set, or use a location roll. // the logic here is tricky since location might also be a roll. // but location trumps locationroll. const rollTypes = ["headroll", "highroll", "bodyroll", "lowroll", "legroll","roll", "headshot", "highshot", "bodyshot", "lowshot", "legshot","shot"]; const locations = ["head","hand","arm","shoulder","chest", "stomach", "vitals", "thigh", "leg", "foot"]; if(herodc.parameters.hasOwnProperty("hitlocation")) { if(rollTypes.indexOf(herodc.parameters.hitlocation) !== -1) { herodc.damage.hitroll = rollLocation(herodc.parameters.hitlocation); herodc.damage.hitlocation = getLocation(herodc.damage.hitroll); } else if(locations.indexOf(herodc.parameters.hitlocation) !== -1) { herodc.damage.hitlocation = herodc.parameters.hitlocation; } else { herodc.damage.hitroll = rollLocation("roll"); herodc.damage.hitlocation = getLocation(herodc.damage.hitroll); } /* } else { herodc.damage.hitlocation = getLocation(herodc.parameters.locationroll); */ } // at this point we have a defined location. // when using location, add another row on the output for reporting location hit and any stun/body multiple. // update stun.x and bodyx applyLocation(herodc.damage.hitlocation); if(herodc.parameters.type === "k") { herodc.damage.stun = herodc.damage.body * (herodc.damage.stunmult + herodc.parameters.stunmod); } log("Location: " + herodc.damage.hitlocation); } }, errInput = function(input,test) { let errFound = false; let errText = ""; const isBoolean = (val)=>'boolean' === typeof val; switch(test) { case "inlineRoll": if(input.inlinerolls === undefined) { //msg.inlinerolls errText = "No Valid Damage Roll"; errFound=true; }; break; case "knockdown": case "stund3": case "skipside": if(isBoolean(input)) { errText = "No Valid " + test + " Value"; errFound= true; } break; case "kind": if(input !== "k" && input !== "n" && input !== "m" && input !== "s") { errText = "No Valid Damage Type"; errFound= true; } break; case "stunmod": case "knockback": if(isNaN(input)) { errText = test + " is not a Number"; errFound= true; } break; case "location": const valid = [ "head","hand","arm","shoulder","chest", "stomach", "vitals", "thigh", "leg", "foot", "headroll", "highroll", "bodyroll", "lowroll", "legroll","roll","any","random", ]; if(valid.indexOf(input) === -1) { errText = input + " is not a Valid Location"; errFound= true; } } if(errFound) { sendChat("HERO DC", errText); return errFound; } } handleInput = function(msg) { if(msg.type === "api" && msg.content.indexOf("!herodc") !== -1) { let args = msg.content.split(/\s+/); log("Args: " + args.join(", ")); herodc.parameters = { // initialise defaults type: "n", stund3: false, stunmod: 0, uselocation: false, knockdown: false, knockback: 0 }; for(i= 1; i < args.length; i++) { if(args[i].indexOf("|") > -1 || args[i].indexOf(":") > -1) { let item = []; if(args[i].indexOf("|") > -1) item = args[i].split("|"); else item = args[i].split(":"); log(item[0] + ": " + item[1]); // might check for valid parameters here, and discard those not used if(errInput(msg,"inlineRoll")) return; switch(item[0].toLowerCase()) { case "type": // if not included, it's a normal damage roll. Can be K, N, M, S, Martial, Killing, Normal. for nnd, use StunOnly. Use first letter. case "damagetype": herodc.parameters["type"] = item[1].slice(0,1).toLowerCase(); if(errInput(herodc.parameters.type,"kind")) return; // need to check it is n, m, k, or s break; case "knockdown": // if exists, ignore knockback caclulation. KB is reported as double Body-1 (so 7 body roll = 13), using KD instead of KB. case "kd": if(errInput(item[1],"knockdown")) return; herodc.parameters["knockdown"] = item[1]; //should be boolean break; case "knockback": // this is KB bonus. If not included, use 2d6. case "kb": if(errInput(item[1],"knockback")) return; herodc.parameters["knockback"] = parseInt(item[1])||0; break; case "location": // if this exists, ignore locationroll and stun multiplier case "loc": case "hit": case "placed": herodc.parameters["hitlocation"] = item[1].toLowerCase(); if(errInput(herodc.parameters.hitlocation,"location")) return; herodc.parameters["uselocation"] = true; break; case "stunmod": // this adds to any stun multiple, whether from a roll, or case "stunx": case "stunmodifier": if(errInput(item[1],"stunmod")) return; herodc.parameters["stunmod"] = parseInt(item[1])||0; break; case "hero6": //true or false; if hero6, stun multiple is 1d3, not d6-1. case "stund3": if(errInput(item[1],"stund3")) return; herodc.parameters["stund3"] = item[1]; //should be boolean break; case "side": //true or false; if true, hit location roll will NOT determine right or left. irrelevant if location rolls not used case "skipside": case "skip": if(errInput(item[1],"boolean")) return; herodc.parameters["skipside"] = item[1]; //should be boolean break; //case "descriptor": // used for building the output title //case "desc": // can include error checking here to make sure item[1] is the right kind of data // herodc.parameters["descriptor"] = item[1]; // break; default: // can i include a chat message here that the input is badly formed? add an error parameter... ; } } } log("Params: " + JSON.stringify(herodc.parameters)); calcDamage(msg); send2Chat(msg); } else { return; } }, send2Chat = function(msg) { let css = { containerLeft: '<div style="width: 227px; ', containerRight: 'border: 1px solid black; padding: 1px 1px; color: black; font-weight: bold;"align=center>', containerM: 'background: #d8ffdb; ', containerK: 'background: #f9ffba; ', containerN: 'background: #e6f2ff;', diceLeft: '<div style="width: 209px; ', diceRight: 'border: 1px solid #999999;border-radius: 1px;font-weight:bold;padding:5px 5px; margin:3px 3px;', diceEnd: '"align=center>', fontSize12: 'font-size: 12pt;', fontSize15: 'font-size: 15pt;', titleRight: 'border: 1px solid #999999;border-radius: 1px;font-weight:bold;padding:5px 5px; margin:3px 3px;font-size: 12pt"align=center>', diceM: 'background: #c3aa28; color: #ffffff; ', diceK: 'background: #cc0000; color: #ffffff; ', diceN: 'background: green; color: #ffffff; ', diceS: 'background: blue; color: #ffffff; ', damageContainerLeft: '<div style="', damageContainerRight: 'font-weight: bold; color: black; line-height: 20px; padding-top: 1px; padding-left: 3px; padding-bottom: 3px; padding-right: 0px;" align=center>', damageContainerM: 'background-color: eeeeee', damageContainerK: '', damageContainerN: 'background-color: eeeeee', damageBoxLeft: '<div style="float: left; width: 31%; background: #f7f7f9; border: 1px solid #999999; padding: 1px 1px; ', damageBoxRight: 'font-weight: bold;"align=center>', locationBox: '<div style="float: left; width: 97%; background: #f7f7f9; border: 1px solid #999999; padding: 1px 1px; color: black; font-weight: bold;"align=center>', div: '<div>', divClose: '</div>', lineBreak: '<br>', divClear: '<div style="clear:both;"></div>', colorBlue: 'color: blue; ', colorRed: 'color: red; ', colorGreen: 'color: green; ', }; let chatString = css.div + css.containerLeft + css['container' + 'K'] + css.containerRight + css.diceLeft + css['dice' + herodc.parameters.type.toUpperCase()] + css.diceRight + css.fontSize12 + css.diceEnd + herodc.damage.expression + css.lineBreak + css.divClose+ css.diceLeft + css['dice' + herodc.parameters.type.toUpperCase()] + css.diceRight + css.fontSize15 + css.diceEnd + herodc.damage.dice.join(", ")+ css.lineBreak + css.divClose+ css.damageContainerLeft + css.damageContainerN + css.damageContainerRight + css.damageBoxLeft + css.colorBlue + css.damageBoxRight + 'Stun: '+ herodc.damage.stun+ css.divClose + css.damageBoxLeft + css.colorRed + css.damageBoxRight + 'Body: '+ herodc.damage.body+ css.divClose + css.damageBoxLeft + css.colorGreen + css.damageBoxRight + herodc.damage.kblabel + herodc.damage.kb + css.divClose + css.divClear + css.divClose; if (herodc.parameters.uselocation) { let titleLocation = herodc.damage.hitlocation.substr(0,1).toUpperCase() + herodc.damage.hitlocation.substr(1,herodc.damage.hitlocation.length -1); if(!herodc.parameters.skipside) { switch(titleLocation) { case "Chest": case "Head": titleLocation = titleLocation if (herodc.damage.hitroll !== 0) titleLocation += " (" + herodc.damage.hitroll + ")"; //else titleLocation += ": " + herodc.damage.hitrange // + ")"; //LOCATION RANGE break; case "Vitals": case "Stomach": break; case "Shoulder": if (randomInteger(2)===1) titleLocation = "R " + titleLocation; else titleLocation = "L " + titleLocation; break; default: if (randomInteger(2)===1) titleLocation = "R " + titleLocation; else titleLocation = "L " + titleLocation; if (herodc.damage.hitroll !== 0) titleLocation += " (" + herodc.damage.hitroll + ")"; //else titleLocation += ": " + herodc.damage.hitrange //+ ")"; //LOCATION RANGE } } let output = titleLocation; let stunX = 'x' + herodc.damage.stunmult; let bodyX = 'x' + herodc.damage.bodymult; switch(herodc.parameters.type) { case "s": bodyX = "---"; break; case "k": stunX = "---"; } chatString = chatString + css.damageContainerLeft + css.damageContainerN + css.damageContainerRight + css.damageBoxLeft + css.colorBlue + css.damageBoxRight + stunX + css.divClose + css.damageBoxLeft + css.colorRed + css.damageBoxRight + bodyX + css.divClose + css.damageBoxLeft + css.colorGreen + css.damageBoxRight + titleLocation + css.divClose + css.divClear + css.divClose; } chatString = chatString + css.divClose + css.divClose; sendChat( getSpeaker(msg),chatString); return; }, registerEventHandlers = function() { on('chat:message', handleInput); }; return { RegisterEventHandlers: registerEventHandlers }; }()); on("ready",function(){ 'use strict'; herodc.RegisterEventHandlers(); });
This is awesome. I love the HERO system and have always believed it to be the best RPG system created. But due to the lack of useful code and support for the system on Roll20 - or any other VTT - I have shied away from using or playing it. I may now have to rethink that. Please keep up the great work.
The CCS was sorted by Scott. I took what Aaron had done for his Wd script, but was struggling with the CSS. Scott stepped in and sorted it out :-)
Whilst We have your attention, here a shameless plug for our Champions Podcast. <a href="http://www.Chimpions.co.uk" rel="nofollow">www.Chimpions.co.uk</a> (Chimpions, is not a typo)
Great re-work of our script G G! (and thanks Mark for the name check, my part in the original was only minor - albeit pleasing on the eye!) What would be good would be for someone to turn their attention to the character sheets, the existing Champions one is very lacking and could be made far more useful with the inclusion of skill and power functions (alas, I don't have the time to fumble through creating a better version)
1516980592

Edited 1516980709
GiGs
Pro
Sheet Author
API Scripter
Thanks guys! I did feel worried about how you two would react to me writing this script while you were still working on yours, so it's a relief you appreciate it. I did submit one minor fix for the character sheet, but I'm going to try to find time to have a bigger look at it in the next couple weeks. It did seem to have a bunch of issues. lols, at the name Chimpions: perfect.
Yeah, the character sheet is not very useful. The fields for powers need backing up and check boxes adding. that way you could select how many ranks of an ability your using, and then do the calculations. There so much that could be done. Don't even know where to start!
I'm being lazy here. Have you factored in the status of the opponent, for Knockback effects. e.g flying is - 1d6? If not I have some code for that.
1517068174
GiGs
Pro
Sheet Author
API Scripter
What I have done is include a knockback modifer, so if attacking a flying target, you'd add "kb:-1"&nbsp; to the string. Are there other statuses you are thinking of? One thing I'm thinking of adding, is to print an API button that allows the GM to click it, which will prompt for the target and the relevant defences, and then apply the damage directly. HERO having such complex systems for attacks and defences, that's a bit tricky and wont be appropriate for some targets, which is why I'd be making it an optional button the GM can ignore. That said, one advantage of the current script is its completely independent of character sheets.
I was hoping that macros could call the API from deep with them - I know you can call an API on a single line of a macro, but I was experimenting with macro dropdowns to then call a specific API - however, it's not possible. That way you could set a specific attack with say an emote, the attack macro ask you if your target was flying, in water etc..&nbsp; then it would work out the rest and display some blurb and the results - instead of having to input the API string in full each time (we have players that are not regular computer users, so wanted to make it player proof)&nbsp; So it looks like the character sheet is the only way to make life easier / foolproof for them
1517161990
GiGs
Pro
Sheet Author
API Scripter
Coming up with a quick-and-dirty macro to integrate with this script would be quicker than waiting for the character sheet to be writtern and be a good interim workaround. Can you post the code you tried, we might be able to get it to work? One approach that might work is a 2 line macro: The first has the dropdowns, asking questions, and storing answers in queries. Then the second line is the API script code, which reuses those queries. It should be just a matter of building the queries in a format the script understands, and working around roll20's frustrating html replacement issues. Failing that, I can add an interpreter to the script, to make it easier to work with those dropdowns. But either way, I'd need a full description of what you want to do, to know exactly what you need.
1517166247

Edited 1517167538
GiGs
Pro
Sheet Author
API Scripter
Here's a working macro that shows how to build the script: !herodc [[?{Damage|6d6}]] Type:?{Type|Normal|Killing|Martial|Stun} kb:?{Knockback Status|On Ground,0|Flying,-1|Underwater,1|Clinging,1|ZeroG,-1} This will prompt for damage amount (you must include the d6., because killing attacks might be in the form 3d6+1), damage type, and knockback status. You can replace queries with stat calls (@{attackDamage} for example, if you have the power's attack listed as a stat). Players would be well advised to create a few Abilities on the character sheets with the most common values, like /me uses Energy Blast! !herodc [[11d6]] Type:normal kb:?{Knockback Status|On Ground,0|Flying,-1|Underwater,1|Clinging,1|ZeroG,-1} And have one general use macro like the first one above, with all the queries you need to build an attack. Also, if you want to double check the player's inputs you can do this: /me makes an Attack! ?{Damage|4d6} ?{Type|Normal|Killing|Martial|Stun} kb:?{Knockback Status|On Ground,0|Flying,-1|Underwater,1|Clinging,1|ZeroG,-1} !herodc [[?{Damage}]] Type:?{Type} KB:?{Knockback Status} This will print out the results of the queries on a line before the API prints the script output. This wont be very pretty&nbsp; - it would be something like unformatted text that reads: "4d6 Normal 0" but it lets you see exactly what they entered.
1517172151
keithcurtis
Forum Champion
Marketplace Creator
API Scripter
Is there a provision in the roller to use knockdown instead of knockback for heroic level?
1517174909

Edited 1517175019
GiGs
Pro
Sheet Author
API Scripter
yes, Keith: just include kd:true or knockdown:true in the statement. One of the reasons I wanted to do my version of the script was specifically to support heroic level campaigns, which I play more often than superheroes. For example, a 2d6+1 Killing attack that uses the knockdown rules: !herodc [[2d6+1]] type:k kd:true And location rolls are supported too (you can specificy a bunch of different location options, see the first post): !herodc [[2d6+1]] type:k kd:true loc:roll
1517178803
keithcurtis
Forum Champion
Marketplace Creator
API Scripter
Cool. This is almost making me want to dust off the Hero System shelf...
1517190899
GiGs
Pro
Sheet Author
API Scripter
Good to know :) I just added some error checking code, so that entering invalid dice rolls, for isntance, shouldn't crash the sandbox. link in post 1 and code in post 2 have been updated.
cool thanks, didn't realise you could pass values down through a macro or you could write macro's like you have demonstrated - awesome stuff!
1517431686
GiGs
Pro
Sheet Author
API Scripter
That's great, Scott :) In this macro, i mentioned you could have it print out the paremeters. /me makes an Attack! ?{Damage|4d6} ?{Type|Normal|Killing|Martial|Stun} kb:?{Knockback Status|On Ground,0|Flying,-1|Underwater,1|Clinging,1|ZeroG,-1} !herodc [[?{Damage}]] Type:?{Type} KB:?{Knockback Status} I just realised, of course you can avoid making it unpretty for the PCs, by just posting the parameters to the gm, like so: /me makes an Attack! /w GM ?{Damage|4d6} ?{Type|Normal|Killing|Martial|Stun} kb:?{Knockback Status|On Ground,0|Flying,-1|Underwater,1|Clinging,1|ZeroG,-1} !herodc [[?{Damage}]] Type:?{Type} KB:?{Knockback Status}