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 .
×

TokenController specific token/character macro

Hey all! I am BRAND new to scripting macros and working in js, but I am quickly finding my way in. I LOVE this script because I can make NPCs that travel with my group follow their "masters". I have dug into the syntax on guthub and tried EVERYTHING but I can't seem to figure something out.... Currently, the script to start a follow is !tc Follow @{selected|token_id} @{target|token_id}. The stop call is !tc stop. I want to change it so a SPECIFIC character is the character doing the following. I have tried different syntaxes (I won't list them all here) using the character_ID, the name|Charactername, just charactername and I can't get it to work. No matter what I try, either invalid ID selected or it "works" and the target character ends up following themselves. I even went on github and pulled the source and tried changing the selected|token_id to  name|charactername and character_id. Can anyone help me turn the two above macros into a macro that moves a specific character by their name or ID (don't care which), so when the macro is selected, the character is automatically the "selected|token_id" (follower) and the player just has to click on the target (person being followed)? 
1771430185
timmaugh
Roll20 Production Team
API Scripter
Hey, Ischkiara... welcome to scripting and JS! It's a bit of a rabbit hole. =D You don't have to modify the script (at least, in the way you are trying to modify it) to do what you want -- though, if you want to continue down that path to learn more, say the word and we'll figure it out. Instead, the script just needs to be adjusted to work with metascripts (a simple change), then all you have to do is install the Metascript Toolbox in your game. The Toolbox is a set of metascripts that expand the sort of things you can do in other scripts. The small adjustment that is needed in TokenController is just to run the chat event listener registration during the "ready" event. This is an on-the-order-of-cosmetic change that is necessary for metascripts to consistently function, and would affect potentially any other GM trying to implement TokenController, so I've reached out to the script author to see if they can make that change and push it to the repo. If they aren't willing to do that I can talk you through changing your copy. Once that change is in your game (from one-click code merge or by you making the change), and once you've installed the Metascript Toolbox, you can use a Fetch* construction to get the token_id of a token by name: @(Bob the Hirsute.token_id) ...or, in your full example command line: !tc Follow @(Bob the Hirsute.token_id) @{target|token_id} ...which will return the ID of the first token it finds on the current page named "Bob the Hirsute", without the user having to have that token selected. By the time TokenController sees the command line, the Fetch construction, like the Roll20 targeting construction, will have resolved to the requested token IDs. * Fetch is one of the metascripts in the Toolbox, offering ways to get data points like token properties, character properties, etc.
OK I understood MOST of that. I can't use character_id because the original code doesn't allow for that because it uses "token_id" everywhere. I can't just force it by doing !tc follow @{Bob the hirsute} or @{name | Bob} or @{character_id} because that doesn't pull in the token_id (I THINK I figured this much out on my own which is why I posted here). So the original code has to be changed and I can do that using Metascript Tools...Got you that far... you completely lose me at "The small adjustment that is needed in TokenController is just to run the chat event listener registration during the "ready" event" and "you can use a Fetch* construction". I know this is a vocabulary issue because, as I said, I am SO new, I am literally learning how to do this by going "ok, I want a macro/script that does this." Then going and finding something one of the "API wizards" made or some other user posted somewhere, then I script kitty my way through it and see what works or what changes until it does what I want. So... ZERO terminology and ZERO understanding of the stuff surrounding the stuff I am changing. I literally just pulled the code from github and started mass replacing "token_id" with everything else I had found from other macros I was using.. TBH, I don't really even understand the difference between the words "script" and "macro"! That's the "problem" with autodidacts... I learned how to write macros for WoW like 16 years ago, then never touched it again and now here I am trying to jump in in the middle of something without a foundation. So I appreciate the help! So, if the creator changes the code, I just have to reinstall the API? And if he doesn't... you'll walk me through it?
Another thing I wish I could change... Spawn Default Token requires the name and I would WAY rather use a token id! So that one is backwards. I don't create a character sheet for every little monster, especially custom monsters and I tried for like 4 hours to figure out a way to get Spawn to take tokens I had placed on the GM layer at a random spot to move, switch to the GM layer and surround a character who had tripped a trap. Since I have 10 traps surrounding a village and I want the warriors to appear around whichever trap the player happens to trigger, I don't know where they need to be and I don't really feel like creating character sheets for 20 warriors I am going to use once or creating "blanks" to be reused because I have to change the token pictures every time. I would rather be able to drop a token on the board and have spawn's functionality reference those. Couldn't figure it out. I assume that also has to do with the fact that the base code wants  "name | [character name]" and I can't do anything about that either...
1771459035
Scotty
Pro
API Scripter
I should have an update checked in tonight or tomorrow. Then I will think about how better to map across Character IDs and Token IDs. There are some one-to-many complications that need to be safeguarded against.
Sweet! I am also good with the idea of pulling the current token ID of the current version of the character on the page. Doesn't really matter which it is if that is to avoid replication across maps. So cool that you guys actually respond to people and so quickly! 
1771513072
timmaugh
Roll20 Production Team
API Scripter
Hooray! Thanks, Scott! BTW...           All the pets. All of 'em. Ischkiara said: ... you completely lose me at "The small adjustment that is needed in TokenController is just to run the chat event listener registration during the "ready" event" and "you can use a Fetch* construction". So this is the change that Scott will be making, but just to explain... Roll20 provides for script interaction by issuing events to the API sandbox (where all of the user-provided code runs). When you take some action in your game, the appropriate event is dispatched to the sandbox to notify your installed scripts. Any script that wants to "listen" for that event will run. There are events for the creation of an object, for changing an object, for deleting an object... changing the Turn Order... lots of different events. You can see what events a script wants to "listen" for by looking in the code for usage of the "on()" function: on('change:graphic', ... ) Which you could read as "on changing a graphic object, run ...this... code". That "on" function alerts the Roll20 backend that when the "change:graphic" event is dispatched, our code needs to be "registered" as a listener. Something changes in the game, the event is triggered, and the sandbox alerts any registered scripts with the relevant information, allowing the script to do what it does. We could refer to our answering code (what is executed when the event is dispatched) as our "handler" or our "listener" for that event. So in the example, we could say we are registering our "graphic change handler"... or that we are registering our "graphic change listener". Two important events are the "ready" event, which is dispatched after the sandbox has finished its startup initialization (signaling that it is ready for whatever code you need to run), and the "chat" event (which is really denoted as "chat:message"), which is dispatched any time someone sends text through the game's chat interface. ANY script that wants to respond to a command line coming through the chat is going to register to listen for the chat event. The question is *when* the registration happens. Consider these two scenarios of pseudo-code: == Scenario 1: on(ready, ...do these things); on(chat:message, ...do these other things); == Scenario 2: on(ready, ...do these things... including... on(chat:message, ...do these other things)); In the first scenario, our chat handler is separate from the ready handler. In this case, both the registration for the "ready" event AND the registration for the "chat:message" event will happen AS the sandbox boots up, but before the actual "ready" event is dispatched (we're just registering at this point). The order goes: Sandbox reads JS of scripts   ...register "...do these things" for the "ready" event   ...register "...do these other things" for the "chat:message" event Sandbox finishes reading all scripts Sandbox issues "ready" event   ..."...do these things" code runs In the second scenario, our "ready" registration will run at the same time as in scenario 1, but the answering code (our actual handler) won't run until the "ready" event is dispatched. In that case, the order goes: Sandbox reads JS of scripts   ...register "...do these things" for the "ready" event Sandbox finishes reading all scripts Sandbox issues "ready" event   ..."...do these things" code runs, including...   ...register "...do these other things" for the "chat:message" event In order for the metascripts to do what they do, they need "standard" scripts (like TokenController) to be built in the second pattern... where the chat registration is done in the "ready" handler. Now, Fetch Constructions When I say "construction" I just mean a syntax pattern that gets recognized to trigger an action. Roll20 offers constructions like: @{Character Name|attributeName} %{Character Name|abilityName} #MacroName Roll20 recognizes those and they get expanded to the appropriate data (either pulling out of the attribute, or getting the "action" text from a Character Ability Macro or from a Collection Tab Macro. Fetch, a metascript that has provides ways of getting game information, offers similar constructions: @(Character Name.attributeName) %(Character Name.abilityName) #(MacroName) That get expanded to the appropriate data, just the same. It also offers constructions for repeating attributes: *(Character Name.listName.[pattern].subAttributeName) *(Character Name.listName.$0.subAttributeName) And it can also return properties that aren't exposed by Roll20 constructions. For instance, the left and top properties of a token: @(Token Name.left) @(Token Name.top) Or the properties of a TOKEN based on the character name: @(Character Name.token_id) ...though, to Scott's point, there are considerations of the possibility of many tokens representing the same character on a page, so Fetch just defaults to returning the first -- in those cases, you'd have to use different methods to arrive at the appropriate, disambiguated token that you want.
1771523068

Edited 1771523156
timmaugh
Roll20 Production Team
API Scripter
Ischkiara said: Another thing I wish I could change... Spawn Default Token requires the name and I would WAY rather use a token id! So that one is backwards. I don't create a character sheet for every little monster, especially custom monsters and I tried for like 4 hours to figure out a way to get Spawn to take tokens I had placed on the GM layer at a random spot to move, switch to the GM layer and surround a character who had tripped a trap. Since I have 10 traps surrounding a village and I want the warriors to appear around whichever trap the player happens to trigger, I don't know where they need to be and I don't really feel like creating character sheets for 20 warriors I am going to use once or creating "blanks" to be reused because I have to change the token pictures every time. I would rather be able to drop a token on the board and have spawn's functionality reference those. Couldn't figure it out. I assume that also has to do with the fact that the base code wants  "name | [character name]" and I can't do anything about that either... OK, in this case, I'd suggest TokenMod plus the Metascript Toolbox. What if you had tokens set up to be your 10 traps, and the responding "goon" tokens responding to a triggered trap on the GM Layer. Then you could... ...use Roll20 Reactions (on the traps) that would   ...run a forselected command that would     ...use a metascript construction to select the goon tokens by generalized name on the GM Layer, and     ...iterate over each, issuing       ...a TokenMod command that would         ...use a Fetch construction to get the left/top of some reference point (either the reaction-Instigator or the trap), and         ...move that goon token to some locational relationship/offset with the referent         ...move that goon token to the objects layer ? The net effect of all of that is that the goons would appear around your trap (or trap-triggering token) in a pre-defined pattern... and that the same goons/mooks could be used for every one of the traps. If that's something that sounds like it could solve your need, you can check out the Send To Chat Reaction announcement thread. I have a few posts in there showing how to use the Toolbox to do various things, including some of the basic TokenMod command you would need... that's in this post . If you want more help with it, post back with some of the specifics of your setup (like the name of your goon tokens, what system you're in, etc.).
response to first message, you're dog is f-ing adorable. Do you teach coding for a living? I am still even a bit too beginner to have understood ALL of your explanation, but i did understand quite a bit and I 100% understood it conceptually, but I am still learning all the vocabulary, naming conventions and basic syntax. You are a VERY good teacher! Despite not understanding all of it, I understand the "conflicts" it could cause. If I want to use it for something with multiple instances of the same character, like a monster, I can use the token_ids. I am talking about followers (I play 2nd edition, so I am not sure if those still exist as they used to, but based on Charisma, people could have a certain number of followers). So, my fighter has a buddy he picked up along the way because my group needed another fighter. His character sheet is held by the player, but... a lot of the time, the group splits and they split the fighters up so one goes with the mage, the other with the priest. When that happens, I pass control of the follower to whomever he is exploring with. That means, I click on Grunt, then click on whomever he is supposed to follow. What I want is a button the players can push that says "I control Grunt now". And since there will only ever be one instance of Grunt (unless I doing a Doppelganger or mirror thing)  on a map. So it would be nice to just have the player push a macro button and 1) token mod passes control to that player (I have this working already) and he follows that character on the map (only works with the clicking). If it could hard select Grunt without all the clicking. My drood also has a fox for whom I would also create that button, for instance, when she goes hunting with the fighters. I just think it would be an EXTRA layer of specificity that would be great in this API script so we have BOTH of those functionalities. Of course then people have to know, "this only works if you only have one instance of Grunt on the page" or whatever, but the choice would be nice so that function can be global. Wherever Grunt exists, he can be controlled with one click instead of three or four.   Message 2 regarding spawn. Again, conceptually, totall understood. And yes, that is what I want to do. I want to have a "pile of monsters" that don't have character sheets (the exact scnario is I have monsters that will only EVER appear in this adventuer because they are location-specific and I don't feel like creating 30 character sheets for a clan of druids) and when one trap in their perimeter is triggered, they all appear from the trees and surround the players to take them captive. Since I can't know in advance on my open play map which trap exactly they will trip, I want the druids "waiting at every trap" so they spawn at whichever they happen to trigger. Then I can just jump to the GM layer and delete extras or, if I am understanding you correctly, what you are suggesting would grab them from the GM layer, put them on the token layer and move them to surround the trap at whatever offset I want so I wouldn't have to even do that. So, conceptually, I think I got it. Practically, ummm, huh what? I wouldn't begin to know the syntax or construction to build that macro code. Like I said, I pull a SIMPLE piece of code like a LITTLE tiny macro like: !token-mod --set bar3_current|-[[?{Damage|0}]] or !Spawn {{--name|Goblin --offset|0,0}}. When I first saw these two macros (the first roll20 macros I played around with), I immediately understood what they were saying more or les. The only thing I couldn't "translate" right away was the question mark in front of the "Damage". That was very quickly clear when I ran the macro.. It makes the system ask you a question with whatever is in the {}. The rest was obvious. What I have ZERO clue about is, how is "damage" defined in the underlying code? How is the "set" command coded in that, the "!token-mod" call, "name", etc.? I can run the front end stuff so to say and I can LOOK at the underlying JS in github, but I can't really translate all of it and there are like a billion other folders with little files in them that I have NO idea what they are or what they do, etc. That is why Token Contoller is a good piece of code for me to look at because the JS is pretty small, but I am not far enough along that I could change that successfully in any meaningful way.  However, since he has all the versions and I have been staring at the most recent for several days now, if he DOES implement this change, I will pull the new code and put them side-by-side and go look for all the changes he just added. That is how I learn. Since I know EXACTLY what he was adding, since I asked for it, I can go in and see, "ok, here is where he added a new line to define the character.id stuff and it's behavior," check the other pages of code in the package folder and other folders and see if there are changes there, etc. and what those changes do within the code.  I am a linguist in real life, so learning coding is just like any other language, but I have to learn the vocabulary and "grammar" and syntax first.  But this is a little like discovering an ancient language that no one speaks (because no one in my environment speaks it!) so I have to refer to a "Rosetta Stone" and I only have like a quarter of that stone... I can glean a lot just from a mix of instinct, having learned Apple Basic when I was like 8 (yes, apple basic, does anyone else remember the turtle?, so I guess that would be ancient Sumerian) and I stayed up with it until around, I think C? C++ (Hellenic Greek), can't remember. Then I learned some HTML in the early 2000s (Auld English). Then my first encounters with js was WoW in the 2010s (That weird movie way people spoke in the 1940s). So, I can sort of muck around reading it, but it's like reading a language I only partly understand, sometimes whole sentences, then I won't understand two paragraphs, so the next fragment or sentence I do understand makes no sense because I have no context from the stuff between. So I have to have little tiny snippets of code to play with or a finished code that works and I understand and then I break it and fix it so I can see what happens. I am VERY bad at learning forward. I need to backward engineer something so I can understand it properly first, THEN go try to build my own thing. Is there a way we can connect on this platform outside of this post? This is probably SUPER boring for anyone else who might read it.  
1771646559
timmaugh
Roll20 Production Team
API Scripter
Ahh! That wasn't my dog! That was Scott's (from his avatar) which I had to acknowledge before the cuteness aggression took over. =D I appreciate the kind words, btw. I am not an instructor, but... I guess I am in tech communications, where I have to make sure I get my point across to all levels of experience, so maybe it's just that coming through. Really quick, let me answer a few of the things you brought up: 1) You don't just have to learn what the scripts do and why from reading the code from github. TokenMod, for example, offers an in-game help handout (or the same info output to chat. Run: !token-mod --rebuild-help And you'll get an output like: Click the link to open the handout, then I typically pop the handout out of the game so I can use search functions to look for what I need. Other scripts have help, as well, or a dedicated thread. 2) The extra directories and files in a script's repo are typically back-versions of it. They don't have anything to do with the installation or execution of a script in your game. They're supposed to be so that you can choose to downgrade your script if the current version is not working for some reason. There is a version selector in your Mod Panel in your game settings when you're looking at a script you got from the one-click. That dropdown is supposed to let you select what version of the script you want... but it hasn't worked for a while. Most scripters these days just maintain the extra versions in the repo as a way, themselves to have a backup of what versions have been released into production... that way they can go back and understand something they did that broken functionality between versions (even if they happen to delete a local copy of a previous version). 3) Learning JavaScript and how to write for Roll20 is a ton of fun. If you're wanting to learn more, I keep this post  bookmarked where I gathered helpful links with a ton of good info that can help de-mysticize the whole operation. But, of course, reach out if you have questions -- either here on the forums or in a private message (you can click on a user to go to their profile page, then select "Send Message". 4) Regarding your two needs... (assigning a follower to a target, and having minions pop into view when a trap is triggered )... Your Token Controller command line should be the one I provided, above, though that was built on what you had initially supplied (just making the changes that needed to happen). If for whatever reason that command doesn't work after a) Token Controller gets updated (the script merge is typically Monday or Tuesday of the week), b) you install the Metascript Toolbox, post back with the original command line you're trying to modify and the name of the tokens you need to assign to follow other characters. I do think you're going to have to configure part of the Toolbox to let your players utilize the command, but we can get to that after we confirm that you (as GM) can run the command provided. Then we have the tokens popping into view from the GM layer. Let me mock this up in my game, then I'll post back with the solution.
Then @Scotty, cute dog! Timmaugh, I will ping you privately to continue this :)
Scotty said: I should have an update checked in tonight or tomorrow. Then I will think about how better to map across Character IDs and Token IDs. There are some one-to-many complications that need to be safeguarded against. All of the sudden, I am getting out of bounds errors... Screenshot 1 is an overview of the map. If I put the token in the upper right (screenshot 2) and several other areas of the map , it won't exceute even a basic pre-programmed square and I get the error message in screenshot 3 when it tries to move right and left, so it just moves up and down. If I move that same token down to where the other two tokens are (screenshot 4), it moves find. There are no walls or anything there that might cause it. The map extends WAY beyond where they are (60 x 60 map, screenshot 5). So... why am I getting that error?