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]Ammunition tracker

1418035934

Edited 1418417225
This is my first ever script, so... Yeah. The Aaron has made one, though I cannot find the link HOW TO USE: !bthelp - This will display a quick help section !setgun *SLOT* *NAME* *AMMUNITION* - Example "!setgun 1 revolver 200". !bullets *SLOT* - This decreases one point of ammunition from X slot !btdel *SLOT* - Deletes the contents of a slot !btedit *SLOT* *NEW_AMMUNITION_VALUE* - Changes the ammunition value of an already existing slot !btmyslots - Displays a list of all slots you own. ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Version .1 Introduced! ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Version .2 Added ownership protection With the help of Aaron, I have made the arrays be stored in "state". Basically, it saves fooorrrreeeeevvvveeeeerrrrrrr... Until you overwrite it or change the script or something like that... ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Version .3 Fixed everything that was broken. Or... Should have. Introduced a way of deleting used slots. ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Version .4 Introduced way to edit your ammunition. Slots are now not restricted to 0-9. Special thanks to Aaron! A bunch of other random not necessary to know about stuff. if( !_.has(state,'bullet') ) { state.bullet= { bulletarray: [], namearray: [], slotarray: [], ownershiparray: []} } on("chat:message", function(msg) { if(msg.type == "api" && msg.content.indexOf("!bullets ") !== -1) //This will unload all of the arrays, put them through the process of firing and finally re-package them again { var mainstring = msg.content.split(/\s+/); var slotlocator = parseInt(mainstring[1]) var unloader = state.bullet.slotarray.indexOf(slotlocator) log(slotlocator) log(unloader) if (state.bullet.slotarray[unloader] == null) { sendChat("Ammunition tracker", "/w " + msg.who + " This slot seems to be empty...") } else if(state.bullet.ownershiparray[unloader] != msg.who) { sendChat("Ammunition tracker", "/w " + msg.who + " This slot is owned by " + state.bullet.ownershiparray[unloader]) } else { state.bullet.bulletarray[unloader]--; log(msg.who + " uses one unit of ammunition from their " + state.bullet.namearray[unloader] + ", they now have " + state.bullet.bulletarray[unloader] + " units of ammunition remaining!") sendChat("Ammunition tracker", "/w " + msg.who + " you use one unit of ammo, and now have " + state.bullet.bulletarray[unloader] + " remaining!") } } else if (msg.type == "api" && msg.content.indexOf("!btedit ") !== -1) { var splitt = msg.content.split(/\s+/), slotselected = splitt[1]; if (splitt[1] != null) { slotselected = parseInt(slotselected); var newbullets = parseInt(splitt[2]); if (newbullets != null) { var checkforslots = parseInt(splitt[1]); checkforslots = state.bullet.slotarray.indexOf(slotselected); if (checkforslots != -1) { state.bullet.bulletarray[checkforslots] = newbullets; sendChat("Ammunition Tracker", "/w " + msg.who + "The weapon now has " + newbullets + " units of ammunition!"); } else { sendChat("Ammunition Tracker", "/w " + msg.who + "Slot " + splitt[1] + " is currently empty"); log(splitt[1]) } } else { sendChat("Ammunition Tracker", "/w " + msg.who + "You must enter a new ammunition value for the slot!") } } else { sendChat("Ammunition Tracker", "You must enter a slot number!") } } else if (msg.type == "api" && msg.content == "!btmyslots") { var counter; for (counter = 0; state.bullet.slotarray[counter] != null; counter++) { if (state.bullet.ownershiparray[counter] == msg.who) { sendChat("Ammunition Tracker", "/w " + msg.who + "Slot " + state.bullet.slotarray[counter] + ", " + state.bullet.namearray[counter] + ", " + state.bullet.bulletarray[counter] + " units of ammunition") } } } else if (msg.type == "api" && msg.content == "!bthelp") { var messagesent = msg.content.replace("!bthelp", "") sendChat("Ammunition tracker", "/w " + msg.who + " Hello! This is the help message! To declare a new weapon type use !setgun *SLOT* *WEAPON_NAME* *AMMUNITION*. There can be no spaces. If a slot is occupied by another player, you will not be able to use that slot. Whenever you fire, type !bullets *SLOT*.Use !btdel *SLOT* to delete a slot.Use !btedit *SLOT* *NEW_AMMO_VALUE to edit the ammunition of a weapon. It is 100% necessary to have slots correctly written. ENJOY!") } else if (msg.type == "api" && msg.content.indexOf("!btdel ") !== -1) { splitthestring = msg.content.split(/\s+/); var theslotselected = splitthestring[1]; var parsedslot = parseInt(splitthestring[1]) log(parsedslot); var indexedslot = state.bullet.slotarray.indexOf(parsedslot) log(indexedslot) if (state.bullet.ownershiparray[indexedslot] != msg.who) { sendChat("Ammunition Tracker", "/w " + msg.who + "This slot does not belong to you!") } else { log(msg.who + " Deleted slot " + state.bullet.slotarray[indexedslot]) state.bullet.slotarray.splice(indexedslot, 1); state.bullet.bulletarray.splice(indexedslot, 1); state.bullet.namearray.splice(indexedslot, 1); state.bullet.ownershiparray.splice(indexedslot, 1); sendChat("Ammunition Tracker", "/w " + msg.who + "You have successfully deleted the contents of slot " + parsedslot) log(state.bullet.ownershiparray[indexedslot]) log(state.bullet.bulletarray[indexedslot]) log(state.bullet.slotarray[indexedslot]) log(state.bullet.ownershiparray[indexedslot]) } } else if (msg.type == "api" && msg.content.indexOf("!setgun ") !== -1) { var splitstring = msg.content.split(/\s+/) , slots = parseInt(splitstring[1],10) || 0 , weaponname = splitstring[2] || 'Gun' , maximumbullets = parseInt(splitstring[3],10) || 10 ; var checkifslotisoccupied = state.bullet.slotarray.indexOf(slots); log(checkifslotisoccupied) if (checkifslotisoccupied == -1) { findifslotisoccupied = state.bullet.slotarray.indexOf(slots); state.bullet.slotarray.push(slots) state.bullet.bulletarray.push(maximumbullets); state.bullet.namearray.push(weaponname); state.bullet.ownershiparray.push(msg.who); log(msg.who) log("The ammunition of " + weaponname + " in slot " + slots + " is currently " + maximumbullets) sendChat("Ammunition Tracker", "/w " + msg.who + " Slot assignment completed successfully!") } else { sendChat("Ammunition Tracker", "/w " + msg.who + "Slot " + slots + " is currently occupied by " + state.bullet.ownershiparray[checkifslotisoccupied]) } } //This ends !setgun }) //Code is really abstract at the moment. I might fix it up later if I feel the need. Basically, if you were to write !setgun 1 Revolver, it will set slot 1 as "Revolver" Suggestions, feedback ect. are welcome!
1418054719
The Aaron
Roll20 Production Team
API Scripter
Welcome to the API! The other ammo script is lacking some nice features you've added (named sources). That other developer is a real slacker about updating it though. =D This is a really nice first script. It exhibits some of the features that I try to include in my scripts: A help screen, in chat configuration (I abhor forcing my users to edit a script to configure it!). That said, I do have a few suggestions: You've written a very impressive string parsing routine for breaking up the arguments of !setgun (No easy feat!!). However, you could just split on spaces: msg.content.split(' '), or whitespace in general: msg.content.split(/\s+/). That will greatly simplify your code and make it easier to maintain later. Here is what it would look like (I added defaults for each of the parsed items). else if (msg.type == "api" && msg.content.indexOf("!setgun ") !== -1) { var splitstring = msg.content.split(/\s+/) , slots = parseInt(splitstring[1],10) || 0 , weaponname = splitstring[2] || 'Gun' , maximumbullets = parseInt(splitstring[3],10) || 10 ; findifslotisoccupied = slotarray.indexOf(slots); slotarray.push(slots) bulletarray.push(maximumbullets); namearray.push(weaponname); ownershiparray.push(msg.player) log("The ammunition of " + weaponname + " in slot " + slots + " is currently " + maximumbullets) sendChat("Ammunition tracker", "/w " + msg.who + " Slot assignment completed successfully!") } //This ends !setgun You're currently storing everything in global arrays. This works great, but when you restart the API (or if it crashed), you lose the data. Consider storing information in the state object. Be warned, the state object is shared between all scripts, so you have to be careful not to corrupt it for others. It's pretty straight forward, here is a short tutorial I wrote for Josh C.: <a href="https://app.roll20.net/forum/post/1385717/#post-13" rel="nofollow">https://app.roll20.net/forum/post/1385717/#post-13</a>... I love that your script addresses the players by name! There are a few places you need a space in your output. After bullets in the !bullets output, after who in the !setgun output. You could reference the array directly in !bullets. What you have is perfectly valid and in many languages would be how you have to do this, but Javascript lets you use and adjust the value directly. Using msg.content.split(/\s+/) will also clear up your issue with single digit slot numbers. Here's how it would look (including defaulting to slot 0 if there wasn't a valid slot given): if(msg.type == "api" && msg.content.indexOf("!bullets ") !== -1) //This will unload all of the arrays, put them through the process of firing and finally re-package them again { var mainstring = msg.content.split(/\s+/), slot = parseInt(mainstring[1],10) || 0; bulletarray[slot]--; log(msg.who + " uses one unit of ammunition from their " + namearray[slot] + ", they now have " + bulletarray[slot] + " units of ammunition remaining!") sendChat("Ammunition tracker", "/w " + msg.who + " you use one unit of ammo, and now have " + bulletarray[slot] + " remaining!") } You could probably benefit from adding some checks around the inputs. For example, if a slot isn't filled, you probably want to tell them they can't shoot from it. Anyway, I hope that helps you out! I don't want to come across as criticizing, so I want to be sure you know that I think you've done a great job for a first script in a new language. You've obviously put a bunch of though behind what this is doing and you are only lacking deeper understanding of the eccentricities of the language. If you want to get deeper into Javascript, I highly recommend Javascript: The Good Parts by Douglas Crockford . It's a fast easy read if you already know a bit about programming and it will really open your eyes to what is possible in Javascript and the API in general. Let me know if you need any help!
Oh cool! Thanks heaps, I'll probably work on adding my own twisted versions of what you said in!
1418071085
The Aaron
Roll20 Production Team
API Scripter
No worries, I'm here to help! =D
Updated it now! I was stuffing up ownership beforehand because I put "msg.player" rather than "msg.who" in one part somewhere...
1418072573
The Aaron
Roll20 Production Team
API Scripter
Actually... var bulletarray; state.bulletarray = new Array(); var namearray; state.namearray = new Array(); var slotarray; state.slotarray = new Array(); var ownershiparray; state.ownershiparray = new Array(); Will overwrite the state property each time the script starts up. You really need to check if they exist already before setting them. Also, I recommend having an object as a property of state that all your properties are off of. if( !_.has(state,'Bullet') ) { state.Bullet= { bulletarray: [], namearray: [], slotarray: [], ownershiparray: [] }; } Then reference them as state.Bullet.bulletarray, state.Bullet.namearray, state.Bullet.slotarray, state.Bullet.ownershiparray.
1418072682
The Aaron
Roll20 Production Team
API Scripter
state is a variable in the global scope which is automatically created for the API. The Wiki doesn't do a great job of explaining it, but here is where you can find it: <a href="https://wiki.roll20.net/API:Objects#Global_Objects" rel="nofollow">https://wiki.roll20.net/API:Objects#Global_Objects</a> Like everything in Javascript, it is an object. In this case, it is an object that starts out with nothing in it, but anything in it will be persisted in a database across restarts of the API. It is a shared resource, so every API script running in the same campaign uses the same object. This is why you need to be extra careful not to stomp on other scripts toes and pick your names carefully. Additionally, since it is persisted every second or so, you need to be mindful not to put too much into it. You should strive to store the absolute minimum amount of information in it. A while back, there was a script that stored all of the spells from Pathfinder in the state, which caused a big issue. Don't do that. =D How I use state For each of my scripts, I create a property in the state object: state.MyScript = {}; However, you can't write that to the state object every time or you would overwrite whatever you have that you were intending to persist. So, you need to wrap this in a check: if( !_.has(state,'MyScript')) { state.MyScript = {}; } _.has() is basically the same as Object.hasOwnProperty(). This will see if state already has a property named 'MyScript', and will only add one if it isn't there already. You can also setup your property with properties of its own: if( !_.has(state,'MyScript')) { state.MyScript = { hour: 0, minute: 0, second: 0 }; } All that is left then is to do this at a point that makes sense. I do this in the on('ready') event, so it only gets run once per restart of the api: on('ready',function(){ if( !_.has(state,'MyScript')) { state.MyScript = { hour: 0, minute: 0, second: 0 }; } }); Now in your script you can be assured that you can access these properties with impunity: state.MyScript.minute += 20; state.MyScript.hour += Math.floor(state.MyScript.minute / 60); state.MyScript.minute %= 60;
Ah, yeah... Thank you. Welp.
1418076380
The Aaron
Roll20 Production Team
API Scripter
no prob. =D
Alright! Fixed that issue. Also introduced a new way to delete an occupied slot. So far looks like it all works :D
Hey Tristan, this may be a stupid question but how do you go about adding ammunition to an already "slotted" weapon?
1418230028
The Aaron
Roll20 Production Team
API Scripter
Certainly running your original !setgun command would have that effect.
Ah... You cannot edit with the !setgun command... Currently, if you wanted to change the ammunition of an item, you would need delete the slot and then use the !setgun command again. I'll work on adding some of the previous things Aaron mentioned as well as a !btedit command.
Alright, updated it.