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

Looking for help: "Encroaching Token following a Player Token."

I'm looking for something that will allow me to place a Token (let's call it the "Shadow" token) onto the Token Layer and then link it to a Players character token. When the player moves, the Shadow mirrors or rather copies its movement at a distance, but also encroaches by 1 grid unit, so every time the player moves the Shadow will essentially hunt it down.  I'm not sure how to go about any of this, imagining the difficulties with having the Shadow pass through Light walls will be one problem, and then the encroaching aspect will present its own set of problems... (but would potentially work off a similar principle to the "Reveal on Drop" aspect of Dynamic Lighting) but first off, I have no idea how to even get the Shadow to link to, and follow the movement of the Player token. Is this even possible? Any help with this would be greatly appreciated.
So I don't know of any already built Mod or API script that would do this. Conceptually, for a blank page, this could be done by having something trigger off of a change:graphic  and respond to a token moving across the board, checking the token is the token_id or character_id to follow, and mimic that token's lastmove property . But those steps would get much more complicated trying to mirror movement around obstacles, walls, and through doors. I don't think it's impossible to do programmatically but I'm also not sure it would be easy enough to justify a script when the GM can just move the token manually in a more responsive and realistic way that doesn't run into weirdness of a token just floating through rocks and trees and walls.
Thanks for replying. It does seem as complicated as I thought it might. The moving through walls and rocks is actually part of the effect, rather than something like having a hunter follow a trail set by the player token. The idea is taht there are a group of ghostly hunters tracking the characters, which can move through walls and doors all the while just getting closer. I'll have another think about a better way to do it.
1704040120

Edited 1704040708
Well if moving through walls and obstacles is part of the effect, then that might be simple enough to do with  ScriptCards triggers . If you would like, I can probably take a look at something like this tomorrow. Can you describe any more requirements? Are you looking to have each ghostly hunter tied to a specific player token? Do you play on the default page size with 70 pixels per square? Hex maps? Also what token sizes are you wanting, 1 square? Larger tokens?
Ideally, there would be 4 "Shadows" each one attached to a different  Player Token. One would be set to the north of it's player, one would be set east, and so on The map will be large, with the actual mapped "playing" area being a sqaure in the middle, allowing freedom for the players to move to extremes of the play area without the shadows risking disappearing off the edge. When a player picks up its token, and moves when it is dropped the Shadow would effectively mirror that movement, then move one sqaure/unit/70p closer to its prey. My players couldn;t stick togther if they were roped and glued, particularly if I give them something like a "Haunted House" to explore... so they WILL see these shadows floating through walls and doors and so on. I use regulation 5' square/70p with the Tokens typically set to 1 unit rather than 70p, but that's easily changeable if it would impact the design. Thank you for the help, but i f this is going to be a ballache, and require MOD scripting please don't worry about devoting time to it. I was kind of hoping an existing API/MOD would cover the stuff and someone could help me with getting the syntax/construction right on a couple fo macros. I don;t want anyone to go to any trouble on this
Have you looked at the Marching Order script in the one-click? It will do the first part (have a token follow another), and you can create ad-hoc following or formations, but it won't make them come any closer. However, a possible work around is to use a macro that sets the ad-hoc follow but asks for input for the distance, effectively, resetting the follow each time. You would have to limit movement to turn-based. It might be more trouble than it's worth.
So here is the first attempt at a ScriptCard Trigger that will do this: !scriptcard {{ --/|VARIABLES TO SET --~|array;define;trackedTokens;PlayerTokenID1;PlayerTokenID2 --~|array;define;hunterTokens;HunterTokenID1;HunterTokenID2 --&pixels|70 --&debugOutput|false --#hidecard|1 --/|TRIGGER_REPLACEMENTS --/|Check if the page where the graphics changed is the active player page --/|If not the current player page, then stop processing --?"[&GraphicNew_pageid]" -ne "[*C:playerpageid]"|[ --?"[&debugOutput]" -eq "true"|>DebugLog;PageID [&GraphicNew_pageid] doesn't match current player page ID: [*C:playerpageid] -->Done| --]| --/|Check if the graphic that moved is a tracked token and if not stop processing --~TrackedIndex|array;indexof;trackedTokens;[&GraphicNew_id] --?"[&TrackedIndex]" -eq "ArrayError"|[ --?"[&debugOutput]" -eq "true"|>DebugLog;Moved TokenID [&GraphicNew_id] not found in tracked tokens array -->Done| --]| --&HunterTID|[@hunterTokens([&TrackedIndex])] --?"[&debugOutput]" -eq "true"|>DebugLog;Moved TokenID [&GraphicNew_id] found in tracked tokens array --?"[&debugOutput]" -eq "true"|>DebugLog;Moved TokenID [&GraphicNew_id] tracked by [&HunterTID] --~LM|string;split;,;[*[&GraphicNew_id]:t-lastmove] --?"[&debugOutput]" -eq "true"|>DebugLog;Found [$LMCount] coordinates in tracked tokens last move --?[$LMCount] -lt 2|>Error;Invalid lastmove for [&GraphicNew_id]. Got [*[&GraphicNew_id]:t-lastmove] --~FinalDistance|distance;[&GraphicNew_id];[&HunterTID] -->DistanceByCoordinates|[&LM2];[&LM1];[*[&HunterTID]:t-top];[*[&HunterTID]:t-left];OriginalDistance --?"[&debugOutput]" -eq "true"|>DebugLog;Original distance:[$OriginalDistance] Final distance:[$FinalDistance] --?[$FinalDistance] -lt [$OriginalDistance]|MoveCloser --:MirrorMovement| --?"[&debugOutput]" -eq "true"|>DebugLog;Mirroring movement --%origLeftIndex|1;[$LMCount];2 --&origTopIndex|[= [&origLeftIndex] + 1] --?[$LMCount] -gt [&origTopIndex]|[ --&destLeftIndex|[= [&origTopIndex] + 1] --&destTopIndex|[= [&origTopIndex] + 2] --=LeftMovement|[&LM[&origLeftIndex]] - [&LM[&destLeftIndex]] {NEGATE} --=TopMovement|[&LM[&origTopIndex]] - [&LM[&destTopIndex]] {NEGATE} --]|[ --=LeftMovement|[&LM[&origLeftIndex]] - [*[&GraphicNew_id]:t-left] {NEGATE} --=TopMovement|[&LM[&origTopIndex]] - [*[&GraphicNew_id]:t-top] {NEGATE} --]| --=NewHunterLeft|[*[&HunterTID]:t-left] + [$LeftMovement] {FLOOR} --=NewHunterTop|[*[&HunterTID]:t-top] + [$TopMovement] {FLOOR} --?"[&debugOutput]" -eq "true"|>DebugLog;Original Hunter Coordinates:[*[&HunterTID]:t-left] [*[&HunterTID]:t-top] --?"[&debugOutput]" -eq "true"|>DebugLog;New Hunter Coordinates:[$NewHunterLeft.Total] [$NewHunterTop.Total] --!t:[&HunterTID]|left:[$NewHunterLeft.Total]|top:[$NewHunterTop.Total] --?[&origTopIndex] -ge [$LMCount]|%! --%| --:MoveCloser| --~NewGap|distance;[&GraphicNew_id];[&HunterTID] --?[$NewGap] -le 1|Done --/|Calculate top and left distances and move 1 square closer in whichever distance is greater --=LeftDistance|[*[&GraphicNew_id]:t-left] - [*[&HunterTID]:t-left] {ABS} --=TopDistance|[*[&GraphicNew_id]:t-top] - [*[&HunterTID]:t-top] {ABS} --?"[&debugOutput]" -eq "true"|>DebugLog;Horizontal distance:[$LeftDistance] Vertical distance:[$TopDistance] --?[$LeftDistance] -gt [$TopDistance]|[ --?"[&debugOutput]" -eq "true"|>DebugLog;Move closer 1 square left/right --=HorizontalDistance|[*[&GraphicNew_id]:t-left] - [*[&HunterTID]:t-left] --?[$HorizontalDistance] -gt 0|=NewLeft;[*[&HunterTID]:t-left] + [&pixels]|=NewLeft;[*[&HunterTID]:t-left] - [&pixels] --?"[&debugOutput]" -eq "true"|>DebugLog;Old left coor:[*[&HunterTID]:t-left] New left coor:[$NewLeft.Total] --!t:[&HunterTID]|left:[$NewLeft.Total] --]|[ --?"[&debugOutput]" -eq "true"|>DebugLog;Move closer 1 square up/down --=VerticalDistance|[*[&GraphicNew_id]:t-top] - [*[&HunterTID]:t-top] --?[$VerticalDistance] -gt 0|=NewTop;[*[&HunterTID]:t-top] + [&pixels]|=NewTop;[*[&HunterTID]:t-top] - [&pixels] --?"[&debugOutput]" -eq "true"|>DebugLog;Old top coor:[*[&HunterTID]:t-top] New top coor:[$NewTop.Total] --!t:[&HunterTID]|top:[$NewTop.Total] --]| --:Done| --X| --/|Emulates what the distance function in ScriptCards does with 2 tokens --:DistanceByCoordinates|X1;Y1;X2;Y2;RollVariableForResult --=x1|[%1%] / [&pixels] --=y1|[%2%] / [&pixels] --=x2|[%3%] / [&pixels] --=y2|[%4%] / [&pixels] --=XAB|[$x1] - [$x2] {ABS} {FLOOR} --=YAB|[$y1] - [$y2] {ABS} {FLOOR} --~[%5%]|math;max;[$XAB];[$YAB] --<| --:DebugLog|DebugMessage --\|SC change_graphic trigger DEBUG: [%1%] --<| --:Error|ErrorMessage --\|ERROR change:graphic trigger: [%1%] -->Done| --X| }} Setup : Requires  ScriptCards  mod to be installed Requires a character named ScriptCards_Triggers (may require a sandbox restart after creation) Requires the ScriptCards_Triggers character to have an ability named change:graphic Edit the above script to include the token ids for the players' tokens and the token ids for the hunter tokens --~|array;define;trackedTokens;PlayerTokenID1;PlayerTokenID2 --~|array;define;hunterTokens;HunterTokenID1;HunterTokenID2 Just separate each ID with a semi-colon ; and each player token will be tracked by the corresponding hunter token. Hunter1 tracking Player1 and so on. If you want to disable the trigger, rename the ability to something else like OFFchange:graphic  and it won't process the events any longer. Current Logic: When setup, the change:graphic  event will check if the graphic is on the same page as the current active player ribbon page and if not, then stop processing. If on the active player page, will check if the graphic changed is in the trackedTokens array, if not, will stop processing. If found in the trackedTokens array, will get the corresponding token id in the hunterTokens array. Checks if the tracked token is closer or farther away than it was originally. If farther, then the hunter token will mirror the lastmove property of the tracked token. If the tracked token moved closer, then the hunter will not mirror. Regardless of the mirrored movement result, the hunter token will move 1 square closer unless the hunter token is already within 1 square of the tracked token. The 1 square direction is chosen by which is the greater distance, horizontal or vertical, and then moves 1 square closer. If they are equal distance, the hunter will move 1 square closer vertically. More Info: If you want to see a bunch of cryptic messages in the Mod Sandbox Console, then set debugOutput to true --&debugOutput|true ScriptCards wiki on Triggers I had already been working on a trigger for change:graphic  for token movement anyway so a lot of this is similar to what I was working on already. Hopefully it works as you want and these instructions are clear enough. Let me know if you have any questions or feedback.
Doug E. said: Have you looked at the Marching Order script in the one-click? It will do the first part (have a token follow another), and you can create ad-hoc following or formations, but it won't make them come any closer. However, a possible work around is to use a macro that sets the ad-hoc follow but asks for input for the distance, effectively, resetting the follow each time. You would have to limit movement to turn-based. It might be more trouble than it's worth. HI Doug,  the intention isn't to follow but to mirror at a distance, so if the target token moves 6 squares left and 3 down, the shadow would move exactly the same, then encroach by a square. It would give the impression that the shadows are wandering/hunting rather than following. If the player gets giddy and starts moving too much out of order... it will make the shadow encroach faster. They'll get a warning to keep their order, and be careful... but they're players. Even the smartest people I know often morph into clay-mation Golems when they have a character sheet and dice in front of them...
Wow, thank you.  I will sit down with this this evening and get my head round as much as possible. I've only ever USED other peoples' script cards and never used a scriptcard trigger, so there will be a few things I probably get wrong first time round... But before I do, a quick question just so that I'm absolutely sure; that "change:graphic" ability ONLY goes on the "ScriptCards_Triggers" character, and that character's token does need to sit somewhere (out of sight) on the map? Right? Joshua N. said: So here is the first attempt at a ScriptCard Trigger that will do this: !scriptcard {{ --/|VARIABLES TO SET --~|array;define;trackedTokens;PlayerTokenID1;PlayerTokenID2 --~|array;define;hunterTokens;HunterTokenID1;HunterTokenID2 --&pixels|70 --&debugOutput|false --#hidecard|1 --/|TRIGGER_REPLACEMENTS --/|Check if the page where the graphics changed is the active player page --/|If not the current player page, then stop processing --?"[&GraphicNew_pageid]" -ne "[*C:playerpageid]"|[ --?"[&debugOutput]" -eq "true"|>DebugLog;PageID [&GraphicNew_pageid] doesn't match current player page ID: [*C:playerpageid] -->Done| --]| --/|Check if the graphic that moved is a tracked token and if not stop processing --~TrackedIndex|array;indexof;trackedTokens;[&GraphicNew_id] --?"[&TrackedIndex]" -eq "ArrayError"|[ --?"[&debugOutput]" -eq "true"|>DebugLog;Moved TokenID [&GraphicNew_id] not found in tracked tokens array -->Done| --]| --&HunterTID|[@hunterTokens([&TrackedIndex])] --?"[&debugOutput]" -eq "true"|>DebugLog;Moved TokenID [&GraphicNew_id] found in tracked tokens array --?"[&debugOutput]" -eq "true"|>DebugLog;Moved TokenID [&GraphicNew_id] tracked by [&HunterTID] --~LM|string;split;,;[*[&GraphicNew_id]:t-lastmove] --?"[&debugOutput]" -eq "true"|>DebugLog;Found [$LMCount] coordinates in tracked tokens last move --?[$LMCount] -lt 2|>Error;Invalid lastmove for [&GraphicNew_id]. Got [*[&GraphicNew_id]:t-lastmove] --~FinalDistance|distance;[&GraphicNew_id];[&HunterTID] -->DistanceByCoordinates|[&LM2];[&LM1];[*[&HunterTID]:t-top];[*[&HunterTID]:t-left];OriginalDistance --?"[&debugOutput]" -eq "true"|>DebugLog;Original distance:[$OriginalDistance] Final distance:[$FinalDistance] --?[$FinalDistance] -lt [$OriginalDistance]|MoveCloser --:MirrorMovement| --?"[&debugOutput]" -eq "true"|>DebugLog;Mirroring movement --%origLeftIndex|1;[$LMCount];2 --&origTopIndex|[= [&origLeftIndex] + 1] --?[$LMCount] -gt [&origTopIndex]|[ --&destLeftIndex|[= [&origTopIndex] + 1] --&destTopIndex|[= [&origTopIndex] + 2] --=LeftMovement|[&LM[&origLeftIndex]] - [&LM[&destLeftIndex]] {NEGATE} --=TopMovement|[&LM[&origTopIndex]] - [&LM[&destTopIndex]] {NEGATE} --]|[ --=LeftMovement|[&LM[&origLeftIndex]] - [*[&GraphicNew_id]:t-left] {NEGATE} --=TopMovement|[&LM[&origTopIndex]] - [*[&GraphicNew_id]:t-top] {NEGATE} --]| --=NewHunterLeft|[*[&HunterTID]:t-left] + [$LeftMovement] {FLOOR} --=NewHunterTop|[*[&HunterTID]:t-top] + [$TopMovement] {FLOOR} --?"[&debugOutput]" -eq "true"|>DebugLog;Original Hunter Coordinates:[*[&HunterTID]:t-left] [*[&HunterTID]:t-top] --?"[&debugOutput]" -eq "true"|>DebugLog;New Hunter Coordinates:[$NewHunterLeft.Total] [$NewHunterTop.Total] --!t:[&HunterTID]|left:[$NewHunterLeft.Total]|top:[$NewHunterTop.Total] --?[&origTopIndex] -ge [$LMCount]|%! --%| --:MoveCloser| --~NewGap|distance;[&GraphicNew_id];[&HunterTID] --?[$NewGap] -le 1|Done --/|Calculate top and left distances and move 1 square closer in whichever distance is greater --=LeftDistance|[*[&GraphicNew_id]:t-left] - [*[&HunterTID]:t-left] {ABS} --=TopDistance|[*[&GraphicNew_id]:t-top] - [*[&HunterTID]:t-top] {ABS} --?"[&debugOutput]" -eq "true"|>DebugLog;Horizontal distance:[$LeftDistance] Vertical distance:[$TopDistance] --?[$LeftDistance] -gt [$TopDistance]|[ --?"[&debugOutput]" -eq "true"|>DebugLog;Move closer 1 square left/right --=HorizontalDistance|[*[&GraphicNew_id]:t-left] - [*[&HunterTID]:t-left] --?[$HorizontalDistance] -gt 0|=NewLeft;[*[&HunterTID]:t-left] + [&pixels]|=NewLeft;[*[&HunterTID]:t-left] - [&pixels] --?"[&debugOutput]" -eq "true"|>DebugLog;Old left coor:[*[&HunterTID]:t-left] New left coor:[$NewLeft.Total] --!t:[&HunterTID]|left:[$NewLeft.Total] --]|[ --?"[&debugOutput]" -eq "true"|>DebugLog;Move closer 1 square up/down --=VerticalDistance|[*[&GraphicNew_id]:t-top] - [*[&HunterTID]:t-top] --?[$VerticalDistance] -gt 0|=NewTop;[*[&HunterTID]:t-top] + [&pixels]|=NewTop;[*[&HunterTID]:t-top] - [&pixels] --?"[&debugOutput]" -eq "true"|>DebugLog;Old top coor:[*[&HunterTID]:t-top] New top coor:[$NewTop.Total] --!t:[&HunterTID]|top:[$NewTop.Total] --]| --:Done| --X| --/|Emulates what the distance function in ScriptCards does with 2 tokens --:DistanceByCoordinates|X1;Y1;X2;Y2;RollVariableForResult --=x1|[%1%] / [&pixels] --=y1|[%2%] / [&pixels] --=x2|[%3%] / [&pixels] --=y2|[%4%] / [&pixels] --=XAB|[$x1] - [$x2] {ABS} {FLOOR} --=YAB|[$y1] - [$y2] {ABS} {FLOOR} --~[%5%]|math;max;[$XAB];[$YAB] --<| --:DebugLog|DebugMessage --\|SC change_graphic trigger DEBUG: [%1%] --<| --:Error|ErrorMessage --\|ERROR change:graphic trigger: [%1%] -->Done| --X| }} Setup : Requires  ScriptCards  mod to be installed Requires a character named ScriptCards_Triggers (may require a sandbox restart after creation) Requires the ScriptCards_Triggers character to have an ability named change:graphic Edit the above script to include the token ids for the players' tokens and the token ids for the hunter tokens --~|array;define;trackedTokens;PlayerTokenID1;PlayerTokenID2 --~|array;define;hunterTokens;HunterTokenID1;HunterTokenID2 Just separate each ID with a semi-colon ; and each player token will be tracked by the corresponding hunter token. Hunter1 tracking Player1 and so on. If you want to disable the trigger, rename the ability to something else like OFFchange:graphic  and it won't process the events any longer. Current Logic: When setup, the change:graphic  event will check if the graphic is on the same page as the current active player ribbon page and if not, then stop processing. If on the active player page, will check if the graphic changed is in the trackedTokens array, if not, will stop processing. If found in the trackedTokens array, will get the corresponding token id in the hunterTokens array. Checks if the tracked token is closer or farther away than it was originally. If farther, then the hunter token will mirror the lastmove property of the tracked token. If the tracked token moved closer, then the hunter will not mirror. Regardless of the mirrored movement result, the hunter token will move 1 square closer unless the hunter token is already within 1 square of the tracked token. The 1 square direction is chosen by which is the greater distance, horizontal or vertical, and then moves 1 square closer. If they are equal distance, the hunter will move 1 square closer vertically. More Info: If you want to see a bunch of cryptic messages in the Mod Sandbox Console, then set debugOutput to true --&debugOutput|true ScriptCards wiki on Triggers I had already been working on a trigger for change:graphic  for token movement anyway so a lot of this is similar to what I was working on already. Hopefully it works as you want and these instructions are clear enough. Let me know if you have any questions or feedback.
But before I do, a quick question just so that I'm absolutely sure; that "change:graphic" ability ONLY goes on the "ScriptCards_Triggers" character, and that character's token does need to sit somewhere (out of sight) on the map? Right? That's right. The ScriptCards_Triggers character does not need to have a token or anything. The character just needs to exist when the ScriptCards mod is loaded so that events can be checked for abilities on that character. That ScriptCard I pasted above only needs to be an ability on the ScriptCards_Triggers character and nowhere else.