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] Spellcasting and Spell Definitions (for 3rd edition D&D)

1402757500

Edited 1402758952
Good morning! &lt;3 I'd like to share with you the code for the first two spells I have coded into my Campaign so far: Bless and Color Spray . To begin with, the casting of spells is accomplished through the API chat message, using the command "!cast" in an Ability. It is assumed in this code that a Token representing a Character is currently Selected (all spell casting Abilities should be Token Actions). The syntax for my API call is such that the first parameter is ALWAYS "!cast", the second parameter is ALWAYS a string representing a spell's name, the third parameter is ALWAYS the Token ID of the selected Token (who is the spell caster), and the fourth parameter is ALWAYS a STRING matching the name of an Attribute defined for the Character that the selected Token represents. Certain spells may require additional parameters, such as the ID of the Targeted token, etc. Bless: This is the first spell I coded. It is pretty simple. The spell turns on a bluish-white aura around the caster, at a radius equal to the spell's range (in this case, 50 feet). Then, the code searches all the Tokens on the caster's Page, and if the Token represents a Character controlled by a Player, AND that token is within the spell's range, the Script marks that Token with a BLUE status marker, if it does not already have one. (The functionality that applies the +1 morale bonus to attacks and fear saves has not been written yet... for now, just remember that a BLUE status marker represents a Bless effect. In the future, I will expand this to allow NPCs to cast Bless affecting the player characters' enemies.) I chose not to set a numeric value on the status marker since the Bless spell's duration is measured in minutes, not rounds. /me holds aloft Selûne's moon mote pendant. The radiant white light of the Moonmaiden illuminates you all. "Blessed Be!" !cast Bless @{selected|token_id} Wisdom Color Spray: This spell is a fair bit more complicated. The macro will prompt the caster to enter an angle measurement, from 0 to 359 degrees. Once that is entered, the Scrpit creates a graphic Token with the Color Spray image, rotates it according to the angle measurement entered, and moves it to the front of its Layer. THEN, the Script loops through all the other tokens on the page, selecting those that are within the spell's effect. Note that the code does NOT check for an intersection between the graphic Tokens; rather, it uses the JavaScript Math library's arctangent function to calculate the distance AND angle from the point of origin, i.e. the caster's coordinates. The values for the spell's range (spellEffectiveDistance) and the cone's angle (spellEffectiveAngle) are currently hard-coded into the spell_ColorSpray function, although eventually, the spell's range will be level dependent. The dimensions of the Color Spray rainbow graphic are calculated based on the spellEffectiveDistance. /me extends her arm and shouts, "KALLISTI!" A kaleidoscopic flash bursts from her outstretched hand. !cast ColorSpray @{selected|token_id} Charisma ?{Enter an angle rotation from 0-359 degrees: 0 = up, 90 = right, 180 = down, and 270 = left.|0} Once a Token has been determined to be within the spell's area of effect, that Token's Character is allowed a Will saving throw against the spell's Difficulty Class (which is calculated in the API event and passed as an Integer to the spell_ColorSpray function). (If the Token in question is NOT represented by a Character, the Will save bonus should default to 0.) If the target fails its Will save, the spell effect is applied. Since the spell's effect varies based on the target's level or Hit Dice, the function checks that and uses a /desc chat message to describe the effect. Finally, affected targets who fail their save are given a RED status marker with a number on it equal to the number of rounds they are unconscious, blinded, or whatever. Here is the PNG image file for the rainbow-colored 60° cone. You have to load it into your graphic library in order for it to work, and then you will have to change the imgsrc parameter for the createObj() function inside of spell_ColorSpray() to match the URL for the graphic in your library. Note that it is porportioned so that the apex of the cone falls exactly in the center of the file. This is important because the image will be given the caster's top and left coordinates, and then rotated around its center. I created this in Adobe Photoshop using the gradient tool, with opacity set to 65%. Finally, here is a link to the Gist which contains the source for the case: "cast" portion of my on ('chat:message') API routine, followed by my (separate) Script file containing the spell definition functions for Bless and Color Spray. &lt;script src=" <a href="https://gist.github.com/Aeristan/e3214ec8c0b18b6e35b8.js&quot;&gt;&lt;/script" rel="nofollow">https://gist.github.com/Aeristan/e3214ec8c0b18b6e35b8.js"&gt;&lt;/script</a> &gt; Thank you very much, I hope you enjoy this and find it useful in all of your Campaigns. Blessed Be!
1402775517
The Aaron
Roll20 Production Team
API Scripter
Very cool script! I can't wait to try it out! People should be able to use your graphic just fine, so long as it stays in your library. This is certainly the case for a script I'm working on. (see <a href="https://wiki.roll20.net/API:Objects#imgsrc_and_av" rel="nofollow">https://wiki.roll20.net/API:Objects#imgsrc_and_av</a>... ) Also, you don't need to pass the selected token in with @{selected|token_id}, as you get a list of all selected tokens as part of the msg object passed to your chat handler: { . "content": "!cast Bless Wisdom", . "playerid": "-JKhPSioQGMeqvGpGRkJ", . "selected": [ . . { . . . "_id": "-JPMdb9bJlWkC8DwMwqR", . . . "_type": "graphic" . . } . ], . "type": "api", . "who": "Aaron" } That would let you do something like: var selectedId = (_.has(msg,'selected') ? msg.selected[0]._id : undefined); if(undefined == selectedId) { var who=getObj('player',msg.playerid).get('_displayname').split(' ')[0]; sendChat('','/w '+who+' Please select a character to cast '+spellID'); return; }
1402777964
The Aaron
Roll20 Production Team
API Scripter
Reading your script, I can't help but think that there will be many spells with similar mechanics: Get all &lt;pcs, npcs, monsters&gt; within &lt;distance&gt; of &lt;point&gt;. Get all &lt;pcs, npcs, monsters&gt; in an arc &lt;point, angle, direction&gt; within &lt;distance&gt; Get all &lt;pcs, npcs, monsters&gt; in a path &lt;width&gt; wide at some &lt;angle&gt; within some &lt;distance&gt; It would probably be really useful to the community as a whole to write a library of functions to do just that, and you're off to a great start. You could be your own first client. =D
Oh, Awesome! Yes I will work on that for the next couple of days. Thank you Everybody!
Well, I have been busy and AFK the last few days. I had time today so far to revise the code so that the token that is selected is determined from the msg objct of the chat:message event, rather than being passed as a parameter in the content of the chat message. It took a while to debug, but it works now. Thank you! Revised API chat:message "!cast" command The only problem I am having is that for some API macros, I use the @{target} call to ask the player to select a target (for a melee attack, for example.) For some reason the @{target} call de-selects the token that was originally selected when the token action was clicked, which causes an error with the API. This wasn't happening when I was passing @{selected|token_id} as a parameter. I will try working on the 3 general-purpose function suggestions above. Can I assume, then, that characters have some kind of Attribute that shows whether they are PCs, NPCs, or Monsters? (Wouldn't that also be assuming that all tokens that represent creatures are necessarily representing a Character?) I was thinking of doing that for my own campaign regardless, in the form of an Attitude variable. ("PC", "helpful", "friendly", "indifferent", "unfriendly", "hostile", or "monster"). That way, the Bless spell can simultaneously target PCs and all Helpful or Friendly NPCs.
1403208988
The Aaron
Roll20 Production Team
API Scripter
Hi Sarienka, The @{target} de-selecting is a know issue, I'm sorry I didn't mention it. =( There isn't a field that determines if a token is a PC or NPC, but you can infer that relationship based on who can control it. I like the idea of an attribute that indicates relationships as you suggest. I use characters for monsters in my own campaigns. The key to doing this effectively is to set the token so it represents that (monster) character, but do not set the bar on the token to represent the hit points of the character. That way, when you drag in multiple copies of the monster, you have access to any token macros for them, but changing the hit points on one does not change them on all of them simultaneously. (If you prefer rolling the hit points for the monster when it is added, I wrote a little script for that for a poster earlier this week: <a href="https://gist.github.com/shdwjk/7377de58100f4e813432" rel="nofollow">https://gist.github.com/shdwjk/7377de58100f4e813432</a>)
Can a player be prompted to click on target(s) from within the API?
1403216950
Lithl
Pro
Sheet Author
API Scripter
No. The API cannot interact with the user interface.
Oh cool, so if you just write a script with functions it makes them global and you can use their callbacks in other scripts? This entire time I was on the impression that you had to start a script using an on () function. Learn something everyday. This is going to be so useful.
1403226772
The Aaron
Roll20 Production Team
API Scripter
Michael, conceptually, each script is just appended into a single file and the whole thing executed. This is also why it's important not to polute the global namespace with variables. It's great because you don't have to reinvent the wheel. If someone writes a generic function everyone can benefit from, you don't need multiple copies. I have an isGM() function in a script that I've used this way quite a bit. (I used it just a few hours ago to fix the status tracker and initiative scripts for Charles A.)
OK it's early and I'm having a 'noob moment'. Aaron, What does the method 'has' do in the code below? What is the significance of using the '_', is that a special operator? (Are we just making sure the object 'msg' has a property named 'selected'? Can we use that syntax to find Attributes of Characters, or do we need to use getAttrByName?) var selectedId = (_.has(msg,'selected') ? msg.selected[0]._id : undefined); if(undefined == selectedId) { var who=getObj('player',msg.playerid).get('_displayname').split(' ')[0]; sendChat('','/w '+who+' Please select a character to cast '+spellID'); return;}
1403362608
The Aaron
Roll20 Production Team
API Scripter
_ is the object for accessing the underscore library. They talk about it on the wiki ( <a href="https://wiki.roll20.net/API:Utility_Functions" rel="nofollow">https://wiki.roll20.net/API:Utility_Functions</a>). The underscore library has lots of handy utility functions that are optimized to the underlying JS engine and tend to shorten code and make it clearer. _.has() is almost identical to object .hasOwnProperty(): has _.has(object, key) Does the object contain the given key? Identical toobject.hasOwnProperty(key), but uses a safe reference to the hasOwnProperty function, in case it's been overridden accidentally . _.has({a: 1, b: 2, c: 3}, "b"); =&gt; true