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

Dedicated Custom Token Markers Tied to Attributes on Character Sheets

1714630671

Edited 1714630961
So this is something that I don't know if it already exists or not, but is there an API or Macro that I can use to set up dedicated custom Token Markers to appear on character tokens that are tied to a specific attribute from a character sheet? For example, say I'm running a game about zombies and there's a dedicated token marker and a custom attribute to track the infection status on an character's sheet. In this case, I would want to mark their sheet that they're at Stage 3 infection and have their token automatically update to include the appropriate token marker. Ideally without removing any other token markers that aren't tied to attributes. If there is something that exists for doing this sort of thing, what is it called and where can I find it? If there isn't, does anyone know how might I go about making it? Or, better yet, would anyone be willing to help me make it? For the record, I'm 99% sure this is possible as there are APIs that auto-apply token auras based on relative attribute values, macros that can adjust the sight for tokens based on attribute values, and APIs that can auto-apply a specific default token marker to a character sheet.
Also, does anyone know how I could edit the title of this post? I made it a bit too long, lol
1714668863
GiGs
Pro
Sheet Author
API Scripter
What your asking for is firmly in the arena of the APi and can't be done with macros alone. Editing the title is something only roll20 devs can do, but theyhave edited titles on request beforem so saying what you want it changed to might get it done. I don't know if you need to make a support request or can just ask within the thread.
1714673386
timmaugh
Pro
API Scripter
I would suggest a combination of Condefinition, perhaps TokenMod, and the Metascript Toolbox. Condefinition can apply markers-that-represent-conditions to tokens (and TokenMod can supplement this as necessary). Then the MST can read markers on a token... for example: @(selected.is.Bloodied) If you go this route, all of the authors of those scripts are active in the forums (keithcurtis for Condefinition, The Aaron for TokenMod, and me for the Metascript Toolbox), so between us we could get you sorted.
1714676428
keithcurtis
Forum Champion
Marketplace Creator
API Scripter
Hi RJGrayLight! The easiest way to change the title of your thread is to press the Report button on your top post (you won't get in trouble). Explain that you are the author of the thread and you are requesting the title change. This will flag it to be seen by a moderator, and give them a handy link to navigate directly there. I don't know what the moderator schedule is, so it may take a while for it to get noticed and acted on.
1714676701
keithcurtis
Forum Champion
Marketplace Creator
API Scripter
If you want an example of a script that does exactly what you are talking about (just a bit specialized), this one auto-applies bloodied or dead markers on tokens based on their current HP. If you are comfortable scripting, that might be a good jumping off place. Oh, and since I am the author and have the link handy: Condefinition . It's not in the repo, since it requires user editing to put in the token marker names.
1714865281

Edited 1714866202
Thanks everyone! At this point, I think I'll just keep the title as is. Not a big deal really. As for the tying of token markers, I'm specifically looking to tie 43 different status conditions to different token markers based on variable factors. 6 of which are health-based (>75%, 50-75%, 25-49%, 0.1-24%, -99-0%, -100%), 13 are checkbox based, and the remaining are based on variable numeric values. In short, here's an example scenario. When checkbox A is checked, Marker A appears on the token. When checkbox A is unchecked and Value A is lower than or equal to X, no marker. When checkbox A is unchecked and Value A is great than X but lower than Y, then it's marker B. When checkbox A is unchecked and Value A is greater than or equal to Y, then it's marker C. I'll admit, I'm not the best script-writer though. I'm better at editing existing script than writing it. Also this is for a custom character sheet that was coded by a combination of myself and another for a game that I designed myself and am still working to finalize for the Marketplace. So with that in mind, would Condefinition still work, granted with some major edits, with the custom sheet I designed? Regarding the MTS, I presume that's necessary to reverse-tie the markers back to the character sheet? For example, on marker change, attribute will change, while with Condefinition, on attribute change, marker changes? Does it work something like that? Just trying to understand.
1714881142
keithcurtis
Forum Champion
Marketplace Creator
API Scripter
No, condefinition doesn't  work like that. It listens for text coming through chat in roll templates and provides buttons for the quick setting of token markers. Example:, a spell or ability causes blindness on a DC 13 Wis save. It will provide buttons for rolling the save, applying the token marker and defining the condition for GM and/or players. It does not read a character sheet. The other script I linked is closer to the mechanic you are looking for.
Okay, so I found this script. Is there a way I might be able to adapt it to do what I am wanting it to do? As I understand, this script has one type a command into the chat, and it provides a marker for the token. But I want it to also adjust an attribute or check/uncheck a box in the token's sheet too. How might I adjust this to do that? var bshields = bshields || {}; bshields.flight = (function() { 'use strict'; var version = 3.5, commands = { fly: function(args, msg) { var height = parseInt(args[0]) || 0; markStatus('fluffy-wing', height, msg.selected); }, hide: function(args, msg) { var stealth = parseInt(args[0]) || 0; markStatus('ninja-mask', stealth, msg.selected); }, prone: function(args, msg) { var prone = parseInt(args[0]) || 0; markStatus('back-pain', prone, msg.selected); }, /** * To add new command, use this template: commandname: function(args, msg) { var num = parseInt(args[0]) || 0; markStatus('statusmarker-name', num, msg.selected); }, * commandname should be ALL LOWER-CASE and CANNOT contain spaces. If commandname includes anything other than a-z0-9_ * or if it begins with a number, it must be enclosed in quotes, eg: 'command-name': function... */ help: function(command, args, msg) { if (_.isFunction(commands[`help_${command}`])) { commands[`help_${command}`](args, msg); } }, help_fly: function(args, msg) { sendChat(`Flight v${version}`, 'Specify !fly &'+'lt;number&'+'gt; to add that number as wings on the selected token.'); } }; function markStatus(marker, num, selected) { var markerStr = '', token, markers; if (!selected) return; selected = _.reject(selected, (o) => o._type !== 'graphic'); if (!selected.length) return; if(num) { markerStr = _.chain(num.toString().split('')) .map((d) => `${marker}@${d}`) .value() .join(','); } _.each(selected, (obj) => { token = getObj('graphic', obj._id); if (token && token.get('subtype') === 'token') { token.set(`status_${marker}`, false); markers = token.get('statusmarkers'); markers = markers ? markers.trim() : ''; markers += (markers.length ? ',' : '') + markerStr; token.set('statusmarkers', markers); } }); } function handleInput(msg) { var isApi = msg.type === 'api', args = msg.content.trim().splitArgs(), command, arg0, isHelp; if (isApi) { command = args.shift().substring(1).toLowerCase(); arg0 = args.shift() || ''; isHelp = arg0.toLowerCase() === 'help' || arg0.toLowerCase() === 'h' || command === 'help'; if (!isHelp) { if (arg0 && arg0.length > 0) { args.unshift(arg0); } if (_.isFunction(commands[command])) { commands[command](args, msg); } } else if (_.isFunction(commands.help)) { commands.help(command === 'help' ? arg0 : command, args, msg); } } else if (_.isFunction(commands['msg_' + msg.type])) { commands['msg_' + msg.type](args, msg); } } function registerEventHandlers() { on('chat:message', handleInput); } return { registerEventHandlers: registerEventHandlers }; }()); on('ready', function() { 'use strict'; bshields.flight.registerEventHandlers(); });
1715005299
keithcurtis
Forum Champion
Marketplace Creator
API Scripter
If your goal is to issue a command and have it set a sheet value and add a token marker, you can do this "out of the box" with Token-mod and ChatSetAttr macros. These sorts of macros are pretty common. For example, this Action (macro): Sets the raging token marker posts a message to chat Sets the universal damage modifier on the sheet Whispers to the user how many rages are left. !token-mod --set statusmarkers|Raging /em flies into a terrifying rage! !setattr --modb --sel  --silent --class_resource|-1 /w @{selected|token_name} Number of rages left: [[@{class_resource}-1]] Doing this sort of thing with a command is very straightforward. It was my understanding however that you were looking for a script that would trigger the token marker when a sheet value was changed, which is a different event.
1715025045

Edited 1715025067
timmaugh
Pro
API Scripter
Not sure about that script, but here is a simple example of how it might look using the MetaScript Toolbox and TokenMod. This will approximate this use case you previously detailed: When checkbox A is checked, Marker A appears on the token. When checkbox A is unchecked and Value A is lower than or equal to X, no marker. When checkbox A is unchecked and Value A is great than X but lower than Y, then it's marker B. When checkbox A is unchecked and Value A is greater than or equal to Y, then it's marker C. First, this will assume that the checkbox you are utilizing is available to you (not all of them are). Some checkboxes represent attributes that are only available to sheet-processes (not scripts). If checkboxA is available to scripts, this will work. If it isn't, then no script will work. {&if @(selected|checkboxA[0]) = 1}   !token-mod --set statusmarkers|MarkerA|-MarkerB|-MarkerC {&else}   {&if @(selected|ValueA[0]) <= X}     !token-mod --set statusmarkers|-MarkerA|-MarkerB|-MarkerC   {&elseif @(selected|ValueA) > X && @(selected|ValueA) < Y}     !token-mod --set statusmarkers|-MarkerA|MarkerB|-MarkerC   {&else}     !token-mod --set statusmarkers|-MarkerA|-MarkerB|MarkerC   {&end} {&end} (The above written on separate lines for readability, and because that's how we'll use it later in this message. To run independently of the further work I will do, below, this would need to be on a single line.) Now... the problem with the above approach is that it requires you to trigger it in some way. That is, it isn't silently monitoring the checkbox and reacting to every change. We can work around this -- which I'll do, below. But first, consider the alternative (a dedicated script that would monitor the checkbox): Even if you had a dedicated script that could monitor the checkbox, you'd still have a problem in that the way Roll20 structures (and emits) their events... a script won't catch all changes to the checkbox (for instance, if the change to the checkbox was triggered by another script  that change will not register). If you don't use another script to make character sheet changes, you might be OK. So you're really in the business of finding the solution that can best satisfy what you are trying to do. With that said, back to the metascript solution... If you want to broaden the command to check all player tokens (running the above command series), you can use SelectManager criteria, ZeroFrame batching, and utilize 2 abilities. I will assume that the abilities will be on a character named "MuleCharacter." The first ability can have any name (I'll call mine InitiateMarkerCheck ). The second ability I'm calling MarkerCheck ; this name and the name of the character it resides on appear in the first ability text, so if you change either, you will have to update the command line accordingly. Here is InitiateMarkerCheck : !forselected %(MuleCharacter.MarkerCheck) {&select *, +pc} That will select all player character tokens on the board and run the command that is in MarkerCheck. Here is MarkerCheck : !{{   {&if @(selected|checkboxA[0]) = 1}     !token-mod --set statusmarkers|MarkerA|-MarkerB|-MarkerC   {&else}     {&if @(selected|ValueA[0]) <= X}       !token-mod --set statusmarkers|-MarkerA|-MarkerB|-MarkerC     {&elseif @(selected|ValueA) > X && @(selected|ValueA) < Y}       !token-mod --set statusmarkers|-MarkerA|MarkerB|-MarkerC     {&else}       !token-mod --set statusmarkers|-MarkerA|-MarkerB|MarkerC     {&end}   {&end} }} You can see how the MarkerCheck command could be expanded to incorporate more checks. In fact, since it's happening at this level,  you'd have easier control than having a script hard-coded to checking specific values. In any case, this will work to run. How to trigger it automatically? You could use The Aaron's "OnMyTurn" script with a combination of abilities on combat token/characters... although I did suggest to him the possibility of putting together an "OnEveryTurn" script, which would be a much easier setup for you: a single character with a single ability, and changing the Turn Tracker would cause the command to run. In that case, the "OnEveryTurn" command line would be the text of the "InitiateMarkerCheck" ability. Watch for that from him, if you want to go this route (you can do the rest of the prep, building the conditionals, etc., so you're ready when it's available).
1715029230

Edited 1715029459
timmaugh said: First, this will assume that the checkbox you are utilizing is available to you (not all of them are). Some checkboxes represent attributes that are only available to sheet-processes (not scripts). If checkboxA is available to scripts, this will work. If it isn't, then no script will work. I'd have to double check, but as far as I'm aware all statuses that are editable or have checkboxes represent attributes and are not sheet-processes. Here's a screenshot of what they look like on the character sheets btw. They trigger sheet-processes, but as I'm aware are not sheet-processes themselves as anyone with access to edit the sheet can adjust them. Also, only the script for Unconsious is triggered by a sheet process, but I'd tie that status to their health, not the unconscious status. timmaugh said: {&if @(selected|checkboxA[0]) = 1}   !token-mod --set statusmarkers|MarkerA|-MarkerB|-MarkerC {&else}   {&if @(selected|ValueA[0]) <= X}     !token-mod --set statusmarkers|-MarkerA|-MarkerB|-MarkerC   {&elseif @(selected|ValueA) > X && @(selected|ValueA) < Y}     !token-mod --set statusmarkers|-MarkerA|MarkerB|-MarkerC   {&else}     !token-mod --set statusmarkers|-MarkerA|-MarkerB|MarkerC   {&end} {&end} Now... the problem with the above approach is that it requires you to trigger it in some way. That is, it isn't silently monitoring the checkbox and reacting to every change. ... Even if you had a dedicated script that could monitor the checkbox, you'd still have a problem in that the way Roll20 structures (and emits) their events... a script won't catch all changes to the checkbox (for instance, if the change to the checkbox was triggered by another script  that change will not register). If you don't use another script to make character sheet changes, you might be OK. I assume this would be as an API? Also, I'm not interested in running a manual check on all tokens to check for the changes, especially not through the initiative tracker. This game is more RP and Survival focused, with an emphasis on avoiding combat instead of pursuing it. So I don't really use the initiative tracker unless they're in combat, I'm keeping track of the time of day for them, or they're being particularly unruly and I need to put them in turn order for anything to get done. Which means that any "onMyTurn" or "OnEveryTurn" check wouldn't work well. Ideally, whatever I set up would automatically monitor the checkbox and values, reacting to every change so that the moment I check the checkbox, the tied token gets the appropriate marker added to it. That said, if I can set up a macro or script to adjust those values, I wouldn't be opposed to that as that means there's one less thing for my players to manually track and adjust. That said, the only potential issue is that their health is both user-edited and effected by a sheet-process. More specifically, there's a process that auto-adds temp health onto current health, and when current health is reduced by any means, it auto-removes from the temp health before removing from the current health. It also prevents current health from surpassing the Max Health unless there is Temp Health in play. Essentially... Temp Health, Temp Max, Current Health are editable attribute values Temp Health + Current Health = Current Health Temp Max + Max = Current Max Temp Health cannot be lower than 0 Current Health cannot be higher than Current Max If Temp Health >0, on Current Health change reduce Temp Health BEFORE reducing Current Health If Temp Health =0, on Current Health change, reduce Current Health With all of that said, is your first script the one I should work with to have attribute values adjust token markers upon change? And will there be an issue with the health since it's affected by Sheet Processes but is still an editable attribute value? (I'm honestly not as concerned with the health as I am with the other status effects.) keithcurtis said: If your goal is to issue a command and have it set a sheet value and add a token marker, you can do this "out of the box" with Token-mod and ChatSetAttr macros. ... Doing this sort of thing with a command is very straightforward. It was my understanding however that you were looking for a script that would trigger the token marker when a sheet value was changed, which is a different event. Technically you're right. I want the sheet to change the marker and the marker to change the sheet. But I also wouldn't mind setting up a macro to manually add or remove both at the same time. For the record, if there's a way to do what I'm looking to do on the custom sheet's end, I would not be opposed to doing it that way either.
1715029966
GiGs
Pro
Sheet Author
API Scripter
RJGrayLight said: I'd have to double check, but as far as I'm aware all statuses that are editable or have checkboxes represent attributes and are not sheet-processes. IIRC its not possible to store the values of checkboxes (or any other data) unless you save them to an attribute.
1715030695
timmaugh
Pro
API Scripter
RJGrayLight said: timmaugh said: {&if @(selected|checkboxA[0]) = 1}   !token-mod --set statusmarkers|MarkerA|-MarkerB|-MarkerC {&else}   {&if @(selected|ValueA[0]) <= X}     !token-mod --set statusmarkers|-MarkerA|-MarkerB|-MarkerC   {&elseif @(selected|ValueA) > X && @(selected|ValueA) < Y}     !token-mod --set statusmarkers|-MarkerA|MarkerB|-MarkerC   {&else}     !token-mod --set statusmarkers|-MarkerA|-MarkerB|MarkerC   {&end} {&end} I assume this would be as an API? The above is the text you could put in a character ability to have it run, check the conditional cases you mentioned, and depending on the situation, issue the correct TokenMod command. That is, this is not the skeleton of something you would write in javascript, this is the exact verbiage you could run in your game using the Metascript Toolbox (and TokenMod). But you don't want to manually check (clicking a button), and you don't want to use the tracker. In that case, you're in the realm of a new script OR custom sheet work. Here is how you can tell which direction you need to go... 1) In your game, open a character sheet (like in the image from your previous post) 2) Right-click on a checkbox that you want to monitor, and choose "Inspect" 3) Examine the properties of the HTML element, looking for the name; it should say something like "attr_slapability" 4) Drop the "attr_" and remember the rest of the name; you're going to see if a script can locate this attribute 5) Install the Inspector script into your game 6) Run this command: !inspect --Character Name ...where you replace "Character Name" with the name of your character... unless Character Name IS the name of your character, in which case I bet they have a very, VERY high "slapability" score. 7) In the resulting panel, click on the entry for that character under the CHARACTERS section. 8) In the resulting panel (now looking at the Character Name character -- you heathen), choose the button at the bottom that represents Attributes (should be the @ symbol). 9) Hover over each ID in the resulting list and you'll get a pop-up with info; scan for one named whatever name you're remembering (ie, "slapability") If you don't find that attribute listed, then scripts can't see it; it's a "hot attribute" made just for the presentation of data and only accessible from the sheetworker side. So, if you don't see the attribute you're looking for (representing that checkbox), then you're going to have to use custom sheetwork to do what you're trying to do. If you DO see the attribute, then scripts can see it, and you can just write a script mod to handle it.
timmaugh said: Here is how you can tell which direction you need to go... 1) In your game, open a character sheet (like in the image from your previous post) 2) Right-click on a checkbox that you want to monitor, and choose "Inspect" 3) Examine the properties of the HTML element, looking for the name; it should say something like "attr_slapability" 4) Drop the "attr_" and remember the rest of the name; you're going to see if a script can locate this attribute 5) Install the Inspector script into your game 6) Run this command: !inspect --Character Name ...where you replace "Character Name" with the name of your character... unless Character Name IS the name of your character, in which case I bet they have a very, VERY high "slapability" score. 7) In the resulting panel, click on the entry for that character under the CHARACTERS section. 8) In the resulting panel (now looking at the Character Name character -- you heathen), choose the button at the bottom that represents Attributes (should be the @ symbol). 9) Hover over each ID in the resulting list and you'll get a pop-up with info; scan for one named whatever name you're remembering (ie, "slapability") If you don't find that attribute listed, then scripts can't see it; it's a "hot attribute" made just for the presentation of data and only accessible from the sheetworker side. So, if you don't see the attribute you're looking for (representing that checkbox), then you're going to have to use custom sheetwork to do what you're trying to do. If you DO see the attribute, then scripts can see it, and you can just write a script mod to handle it. Thanks for the detailed instructions! Turns out that they're all attributes that are showing up in the Inspector script. Apparently the custom sheet that I and my friend made set literally everything that can change in the sheet to be attributes. So it's extremely script friendly. Great to know! Also, that trick to inspect the sheet itself to find the attributes, I honestly feel a bit silly for not remembering that QoL trick ages ago. I used to do that all the time! lol I'm curious though. You mentioned that it's possible to hard-code it into the character sheet itself, yes? If that's the case, would it be as simple as adding 3 lines to the following Broken Leg function?     on('change:conLeg', function() {         getAttrs(['conLeg'], function(v) {             let a = parseInt(v.conLeg||0);             let tmpStr = "";             if (a>0) {                 tmpStr += "AGI -" + a * 2 + ", END -" + a + ", SPD -" + a * 2 + ", ENC +" + a * 2 + ", Healthy -" + a * 1.5;             };             setAttrs({                 conLeg_max: tmpStr             });             setWarning();         });     });              setMarker({                 'Broken_Leg_Marker'             }); Is it as simple as adding that or similar into the code?
1715093598
timmaugh
Pro
API Scripter
Glad the Inspector script helped! If you're going to approach it from the sheet side (and if this is a custom sheet you wrote already, why not?)... you're going to be out of my wheelhouse as a mod scripter. I'll try to direct sheet-author eyes this way to get their input.
timmaugh said: If you're going to approach it from the sheet side (and if this is a custom sheet you wrote already, why not?)... you're going to be out of my wheelhouse as a mod scripter. I'll try to direct sheet-author eyes this way to get their input. Fair, and thanks again! That said, I do intend to one day market this game once it's finished and thoroughly tested, so perhaps making an API for attributes providing token markers is the better route to take in the long-run. Otherwise I'd have to bundle the token markers that I made if I do ever ultimately market my game system and sheet. And considering that the markers that I'm using are ones that I bought on the Marketplace but added a black background to, I suspect that would be frowned upon. lol I'm not gonna lie though, I'm a bit apprehensive on writing an API, since this would be the first API I write, and I suspect what I'm aiming for isn't exactly simple from the coding side of things. Otherwise, I'm fairly sure that it'd already be a thing. lol
1715098605
timmaugh
Pro
API Scripter
If you're going to investigate a custom script for it, here's some info to get you started. Also, if you're going to do things with token markers, I'd suggest using Aaron's libTokenMarkers library script, as it already does a bunch of the heavy lifting for around markers. Fetch provides an example of using that library to get marker info from a token, if you want an example.