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] Combat System First Iteration

1420493162

Edited 1420547184
This is a relatively large script that incorporates some other peoples work with my own and helps DM's to run combat. There might of been others like it befor but this is mine. If anyone thinks theres something I should add i'll be happy to give it a try. //API script designed to aid in combat situations //--------------------------------------------------------// //Features: // 4 Command with configaruble right so playes may use them: // !HIT // !HITCHECK // !DMG // !HEAL // Configrable combat states //--------------------------------------------------------// //For the !HIT fucntion 4 veribls need to be passed in this order // 1. Defender Token_id // 2. Defence type used (ac/fort/ref/will) // 3. The moderfier to hit // 4. The attack roll (xdx+mod : 2d8+5) //This is the macro I use: // !HIT @{target|token_id} ?{Defence|ac} ?{mod|0} ?{Attack|xdx+mod} //Example of what this translats // 12 vs AC, damage: 1d8+6 //--------------------------------------------------------// //For the !HITCHECK fucntion 3 veribls need to be passed in this order //The diffrence between HIT and HITCHECK, HITCHECK will announce to everyone if they hit or miss // 1. Defender Token_id // 2. Defence type used (ac/fort/ref/will) // 3. The moderfier to hit //This is the macro I use: // !HIT @{target|token_id} ?{Defence|ac} ?{mod|0} //Example of what this translats // 12 vs AC, damage: 1d8+6 //--------------------------------------------------------// //For the !DMG function 2 veribles need to be passed in this order // 1. Token_id // 2. Damage to be delt //This is the macro i use: // !DMG @{target|token_id} ?{damage?} //--------------------------------------------------------// //For the !HEAL function 2 veribles need to be passed in this order // 1. Token_id // 2. Damage to be delt //This is the macro i use: // !HEAL @{target|token_id} ?{healing?} //--------------------------------------------------------// // // Set various token markers based on bar cur/max ratios // // The CONFIG array can have any number of configuration objects. These objects // are processed in order. // // barId - The ID of the bar to look at the values for [1, 2, 3] // barRatio - The ratio of bar value to max value that triggers setting the status marker [0 - 1] // status - The name of the status marker to toggle [redmarker, bluemarker, greenmarker, brownmarker, purplemarker, dead] // whenLow - The state of the marker when the bar value is <= the ratio [true, false] //--------------------------------------------------------// var combat = combat || { version: 1.1, //message to be loggad at the start of the log (%count is replased for logCount) logLabel: "Combat event %count: ", logCount: 0, //controls who has the rights to use the commands (I leave them as gm only) useRights: true, //set to true if you want right to be checked commandHitRights: [ {command: "HIT", rights: "Jacob "}, /*Your name must be added hear*/ {command: "DMG", rights: "Jacob "}, {command: "HEAL", rights: "Jacob "}, ], hasRights: false, //internal verible informGM: true, //true if you want the gm to be informed when players try and use a command announceHitCheck: true, //hold infomatoin about player using the mothod playerObject: "", playerName: "", //array used to cofig states stateConfig: [ {barId: 1, barRatio: .5, status: "redmarker", whenLow: true}, {barId: 1, barRatio: 0, status: "dead", whenLow: true}, ], //method to log an event and count the mesages sent logEvent: function(event,DMchatLog,announce) { //set default values if not value sent event = event || "No event sent"; DMchatLog = DMchatLog || false; announce = announce || false; //set current value var label = combat.logLabel.replace("%count", combat.logCount); combat.logCount++; log(label+event); //send event to GM if chatlog is true defalts as false and to players if anounnce is true if(DMchatLog == true && announce == true) { sendChat(label, event); } else if (DMchatLog == true) { label = label.replace(":", ""); sendChat(label, "/w gm "+event); } }, //cheacks if the player sending the command has the rights to use it checkRights: function(command) { //reset has rights to defalt combat.hasRights = false; if (combat.useRights == false) return; //set command hit rights to combat.commandHitRights.forEach(function(opts) { if(opts.command == command) { if(opts.rights.search(combat.playerName) != -1) { combat.hasRights = true; } } }) if(combat.hasRights == false) { combat.logEvent(combat.playerName+" tryed to use command "+command , combat.informGM); return; } }, //use the playerID to get the players object and name and log them in the veribles findPlayer: function(playerID) { combat.playerObject = getObj('player', playerID); combat.playerName = combat.playerObject.get("_displayname") }, //checks if health has changed to be above or below threshold state setState: function(obj) { //log state changeing combat.logEvent("Setting state") combat.stateConfig.forEach(function(opts) { var maxValue = parseInt(obj.get("bar" + opts.barId + "_max")); var curValue = parseInt(obj.get("bar" + opts.barId + "_value")); //log(opts.barId + ": " + curValue + "/" + maxValue); if (!isNaN(maxValue) && !isNaN(curValue)) { var markerName = "status_" + opts.status; if (curValue <= (maxValue * opts.barRatio)) { obj.set(markerName, opts.whenLow); } else { obj.set(markerName, !opts.whenLow); } } }); }, //find the command and determin if the player has rights then run with nesery infomation findCommand: function(obj) { // Exit if not an api command if (obj.type != "api") return; // Get the API Chat Command and split up message var command = obj.content.split(" "); //get player ID and log name combat.findPlayer(obj.playerid); combat.logEvent("Command Reseaved from "+combat.playerName+" : "+command) if(command[0] == '!HIT') { //check player have the rights to use the command combat.checkRights('HIT') if(combat.hasRights == false) return; //run the command combat.HIT(command); return; } else if(command[0] == '!DMG') { combat.checkRights('DMG') if(combat.hasRights == false) return; //run the command combat.DMG(command); } else if(command[0] == '!HEAL') { combat.checkRights('HEAL') if(combat.hasRights == false) return; //run the command combat.HEAL(command); } else if(command[0] == '!HITCHECK') { //run the command combat.HITCHECK(command); } else { combat.logEvent("No command found for "+command[0]) } }, //evaluate an attribute and return the value for this, the functoin must have the correct characterID or will return incorect value evaluateAttribute: function(characterID,attribute) { //get array form attribute used var attributeValue = 0; //get the string with for the attribute wanted var attributeString = getAttrByName(characterID, attribute); combat.logEvent("Attribute: "+attribute+" string: "+attributeString) attributeString = attributeString.split("+"); do { var buffer = ""; var i = 0; attributeString.forEach(function(opts) { //eseption to find half level if(attributeString[i].search("@{halflevel}") != -1) { attributeValue += Math.floor(Number(getAttrByName(characterID, "level"))/2); } //eseption to find def-highest ((dex/con/char/dex) - 10)/2 else if(attributeString[i].search("highest}") != -1) { if(attributeString[i].search("ac") != -1) attributeValue += Math.floor(Number(getAttrByName(characterID, "dexterity") - 10)/2); else if(attributeString[i].search("fort") != -1) attributeValue += Math.floor(Number(getAttrByName(characterID, "constitution") - 10)/2); else if(attributeString[i].search("will") != -1) attributeValue += Math.floor(Number(getAttrByName(characterID, "charisma") - 10)/2); else if(attributeString[i].search("ref") != -1) attributeValue += Math.floor(Number(getAttrByName(characterID, "dexterity") - 10)/2); else log("unusual value for 'highest'} :"+attributeString[i]); //catchs invaled input } //check if an attribute needs to be found and find it else if(attributeString[i].search("@{") != -1) { attributeString[i] = attributeString[i].replace("@{", ""); attributeString[i] = attributeString[i].replace("}", ""); var temp = getAttrByName(characterID, attributeString[i]); //if temp is another attrabut store it in buffer if(temp.search("@{") != -1) { buffer += temp; buffer += " "; } else // if temp is a value add it to defence { //only add it to defence if the valse is grater then 0 this also cathes null values if(temp > 0) { attributeValue += Number(temp); } } } else //if the target is anything else it must be a number so add it to defence { attributeValue += Number(attributeString[i]); } i++; }); //seperate buffer into an array then save it the defence buffer = buffer.replace("+", " "); buffer = buffer.split(" "); attributeString = buffer; } while(buffer.length > 1) return attributeValue }, //method to find roll value from a string ie 2d20+10 roll: function(string) { var roll = string.replace(" ", ""); combat.logEvent("rolling: "+roll) var rollTotal = 0; roll = roll.split("+"); var i = 0; roll.forEach(function(opts) { //if there is a dice roll the dice and add to total if(roll[i].search("d") != -1) { //This splits xdx into x * dx where dx is the dice rolled and x in the number of dice var buffer = roll[i].split("d"); for(i = 0; i < buffer[0]; i++) rollTotal += randomInteger(Number(buffer[1])); } //else add the value on to the total else { rollTotal += Number(roll[i]); } }); return rollTotal }, //method to check if a character has hit this will find the attack then roll for the damage in this form damage is just returnet in the chat //you can at the !DMG command to take the damage off although I wouldn't recomend this because somethins you might want to smuge a roll //you can just use the !DMG command to take the damage you want HIT: function(command) { combat.logEvent("Hit began") //target character var token = getObj("graphic", command[1]); var character = token.get("represents"); //evaluate the attribute for defence and roll for attack var defence = combat.evaluateAttribute(character,command[2]); var attack = randomInteger(20) + Number(command[3]); if(attack > defence) { combat.logEvent("Attack hit: "+attack+">"+defence+"("+command[2]+")", true); //calculate damage done var damage = combat.roll(command[4]); combat.logEvent("Damage: "+damage, true); } else { combat.logEvent("Attack missed: "+attack+"<"+defence); combat.logEvent("Attack missed", true) } }, //Hit check is the same as hit but dose not roll for damage automoticly and anouns to everyone if they hit or miss //this is instnded for player use and not just GM use HITCHECK: function(command) { combat.logEvent("Hit Check began") //target character var token = getObj("graphic", command[1]); var character = token.get("represents"); //evaluate the attribute for defence and roll for attack var defence = combat.evaluateAttribute(character,command[2]); var attack = randomInteger(20) + Number(command[3]); if(attack > defence) { combat.logEvent("Attack hit: "+attack+">"+defence+"("+command[2]+")", true, combat.announceHitCheck); } else { combat.logEvent("Attack missed: "+attack+"<"+defence); combat.logEvent("Attack missed", true, combat.announceHitCheck) } }, DMG: function(command) { var current_token = getObj("graphic", command[1]); //read max hp and current hp along with damage need var maxValue = Number(current_token.get("bar1_max")); var curValue = Number(current_token.get("bar1_value")); var damage = Number(command[2]); var damageDone; //deside damage to be delt and if below 0-max/2 ie blooded set to 0; var newValue = curValue - damage; if(newValue <= 0-maxValue/2){newValue = 0-maxValue/2;}; damageDone = curValue - newValue; sendChat("GM", "/desc "+damageDone+"("+damage+") damage was delt"); current_token.set({ "bar1_value": newValue }); //set state with new values combat.setState(current_token); }, HEAL: function(command) { var current_token = getObj("graphic", command[1]); //read max hp and current hp along with damage need var maxValue = current_token.get("bar1_max"); var curValue = Number(current_token.get("bar1_value")); var healing = Number(command[2]); var healingDone; //heal from 0 if(curValue < 0) curValue = 0; var newValue = curValue + healing; if(newValue > maxValue){newValue = maxValue;}; healingDone = newValue - curValue; sendChat("GM", "/desc "+healingDone+"("+healing+") healing done"); current_token.set({ "bar1_value": newValue }); //set state with new values combat.setState(current_token); }, //regesters event handalers this must be run on ready registerEventHandlers: function() { combat.logEvent("Events Registered", true); on('chat:message', combat.findCommand); on("change:token", combat.setState); }, }; on('ready',function() { combat.logEvent("API Running version: "+combat.version); combat.registerEventHandlers(); }); If anyone has noticed there work thankyou, I probably used it to learn javascript
I must say. I saw a similar script within a script of Alex L. The beauty of this baby is its simplicity. My players have been looking for simple scripts like this. As so have I as a GM. Thank you Jacob. :)
Though it does not seem to work i'm afraid. At least not in my campaign :3
ye sorry about that I messed up the rights. The version up now will work, and ye I pretty much took other people's code changed it around to all work together and added some more functionality. If you want anything adding I'll be more then happy I allways love programming
also the version up there now will ignore all the rights so anyone can use the commands
I have not checked yet but im just wondering how the atk part works. If it does not beat AC or such defense will it not deduct anything or will it deduct regardless?
the version thats up there right now won't take the damage automaticly instes will tell the DM if the person hit of miss, then if they hit it will roll the damage and tell the DM what the damage done is and then you can drduct the damage.