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] [Video] Darkness Helper - Handles Magical Darkness & Devil's Sight

1708651305

Edited 1708884806
Nick O.
Forum Champion
UPDATE Feb 25 2024: This script does not work as originally advertised. While it will allow you to create a circle of darkness, and allow characters with Devil's Sight who are within the darkness to see normally, it does not allow them to see through the circle of darkness to what's on the other side of that darkness. When I created the video, I didn't realize that there were other light sources on the dynamic lighting layer, and that was what allowed characters to see what was on the other side of the darkness. As such, I am de-listing the video. I apologize for the confusion this caused. The code is still available for anyone who wants to tinker with it, and I will keep experimenting to see if there's a way to make it work as I originally intended.&nbsp; Hi Everyone Darkness Helper lets you spawn a a moveable area of darkness onto the battlefield, and also allows players who have Devil's Sight to see through that darkness. The code for the mod is here - <a href="https://gist.github.com/nolivo/5cbfb99046fb5de95bc5154d7a8302e9" rel="nofollow">https://gist.github.com/nolivo/5cbfb99046fb5de95bc5154d7a8302e9</a> Once installed, use !darkness to spawn a token with 15 ft sphere of darkness onto the map. When the darkness token appears, it also creates a circle on the dynamic lighting layer that moves with the token. When a PC's token (or say a familiar) moves into the area of darkness, the mod turns that token's vision off, effectively putting them in the dark. If the character has Devil's Sight listed in the features &amp; traits section of their character sheet, their vision is left on. It also gives that darkness token vision, and grants control of the darkness token to anyone with Devil's Sight, so they can see through the darkness.&nbsp; You can change the radius by entering !darkness --NEW_RADIUS_HERE (e.g., !darkness --20 will give you a 20 ft radius sphere of darkness). You can move the sphere around by moving the token, and deleting the token will also delete the circle on the dynamic lighting layer. I had a ton of help with this mod, so a huge thank you to KeithCurtis, David M, Oosh, Kurt J, Scott C, and of course, the Arcane Scriptomancer himself, the Aaron. I couldn't have built this without you all. Happy gaming!
1708652884
keithcurtis
Forum Champion
Marketplace Creator
API Scripter
Makes me wish I was sitting in the DM chair. This will have to wait for my turn to come around again. But this is a cool script with an elegant solution to handling darkness.
1708660061
The Aaron
Roll20 Production Team
API Scripter
Good stuff!&nbsp; Always happy to help.&nbsp; =D
Hi. Awesome script, thank you so much. Minor question, if I am creating a DMNPC and using the NPC template, how can I ensure Devil's Sight works? I can work around by dragging a devil to the desktop and editing its sheet, but if starting from scratch I can't make it work. I have edited to ensure vision is on, night vision on, range 120' ,no tint and the Player's Journals reads all players as does controlled and edited by. Added an ability to the sheet in exactly the same place as a devil NPC, I even cut n pasted the text rather than type it in, but it doesn't work, whereas it is perfect on the devil token. Side by side the devil token and the NPC look identical in setup. I ran through abilities tab on the devil but didn't see a flag, could have missed it though. Thanks in advance
1708690068
Nick O.
Forum Champion
@Simon G - I've heard something similar from another player - they said that entering Devils Sight (no apostrophe) resolved it for them. Please try that and let me know how it goes.
1708691100

Edited 1708691203
Hi @Nick, this is fantastic, thank you! I've installed the script but have a problem where my character with 'Devils Sight' can only see through the darkness they control if they are within the area of darkness, they can't see through it from the outside. Any thoughts? This is occurring when I'm trying to preview their vision with CTRL+L.
1708692137
Nick O.
Forum Champion
Hi Mantas - When you use CTRL+L, you're only looking through that specific token's eyes, rather than through the eyes of all the tokens that a given player controls. The character token's vision is blocked by the dynamic lighting wall, but because the player has control of the darkness token, too, they see through both the character token's eyes AND the darkness token's "eyes." I used a dummy account to illustrate that in the video, because CTRL+L wouldn't give the whole picture. So if you create a dummy account, log in, and give control of your Devil's Sight character to that dummy account, you should be able to see things properly. Thanks for watching, and happy gaming!
Makes sense, thank you! However, would this cause problems where the player may be able to 'see around corners' as the darkness token? Can I somehow limit the vision of the darkness token to only include what's contained within the aura - if so?
1708692770

Edited 1708692832
Could there be some clearer documentation for the commands? As it is, it's not clear from reading what the relevant commands are and it's not good to have to rewatch the video every time one needs to be reminded of the commands. As deleting the token does not seem to delete the darkness, clear instructions need to be there in order to prevent a lot of frustration. This is a great idea, but it would be nice if we could combine it with a permanent character token that we could drag, drop, and delete.
Have been trying to create something like this for a long time. Do you know if there is something similar to allow characters with dark vision to see into heavily obscured areas ? (assuming I have the game mechanics of this right)
1708693685
Nick O.
Forum Champion
Mantas said: Makes sense, thank you! However, would this cause problems where the player may be able to 'see around corners' as the darkness token? Can I somehow limit the vision of the darkness token to only include what's contained within the aura - if so? Technically, yes, this could allow a player to see around a corner. I'm not aware of a way to limit the token's vision to just the player's line of sight, but it's something I can look into for a future release.&nbsp;
1708694042
Nick O.
Forum Champion
Dr DM said: Could there be some clearer documentation for the commands? As it is, it's not clear from reading what the relevant commands are and it's not good to have to rewatch the video every time one needs to be reminded of the commands. As deleting the token does not seem to delete the darkness, clear instructions need to be there in order to prevent a lot of frustration. This is a great idea, but it would be nice if we could combine it with a permanent character token that we could drag, drop, and delete. The darkness circle on the DL layer should be deleted when you delete the token. Are there any errors in the API console?
1708694085
Nick O.
Forum Champion
FFR said: Have been trying to create something like this for a long time. Do you know if there is something similar to allow characters with dark vision to see into heavily obscured areas ? (assuming I have the game mechanics of this right) I'm not aware of anything that does that, but that's something I can look into for a future version of the script.
Hi Nick, changing to Devils Sight rather than Devil's Sight did not fix it.&nbsp; I also transmogrified a warlock in from another game and launched as a player, that token cannot see in to the darkness but can see if moved within it (Eldritch...Devil's Sight defintely in the right place).&nbsp; The devil token I mentioned earlier has the same thing going on, cannot see in to it but can see when within it.&nbsp; It's almost like a halfway situation, their sight doesn't get cancelled going in, but does not penetrate from outside
1708696817
Nick O.
Forum Champion
Simon G. said: Hi Nick, changing to Devils Sight rather than Devil's Sight did not fix it.&nbsp; I also transmogrified a warlock in from another game and launched as a player, that token cannot see in to the darkness but can see if moved within it (Eldritch...Devil's Sight defintely in the right place).&nbsp; The devil token I mentioned earlier has the same thing going on, cannot see in to it but can see when within it.&nbsp; It's almost like a halfway situation, their sight doesn't get cancelled going in, but does not penetrate from outside Hi Simon - is this happening with Ctrl+L?
With CTRL +L but also if I click "log in as player", which gives me restricted access to token options
1708697140
Nick O.
Forum Champion
Ah, ok.&nbsp; When you use CTRL+L, you're only looking through that specific token's eyes, rather than through the eyes of all the tokens that a given player controls (I think tejoin as player does something similar) The character token's vision is blocked by the dynamic lighting wall, but because the player has control of the darkness token, too, they see through both the character token's eyes AND the darkness token's "eyes." I used a dummy account to illustrate that in the video, because CTRL+L wouldn't give the whole picture. So if you create a dummy account, log in, and give control of your Devil's Sight character to that dummy account, you should be able to see things properly. &nbsp;
1708699676
keithcurtis
Forum Champion
Marketplace Creator
API Scripter
Here is some information and guidance on&nbsp; Dummy Accounts .
1708701993

Edited 1708702036
i have a dummy account but am not finding any difference.&nbsp; I logged in to dummy on Chrome whereas GM was on Firefox, gave permissions to warlock token for Camera (dummy) and made sure token had name etc, still no joy.&nbsp; There was a commoner token at the bottom that I could control, hence the weird shape in this shot, I have also removed Simon G from permissions on the warlock just to be sure.
token vision settings
1708706661

Edited 1708706743
So that darkness token did not have a controlled by, I had clicked a random token when dropping it, so that's on me, sorry.&nbsp; I then used the warlock to drop a new one, defintely says "Controlled by Camera" and I get this, which still looks wrong
This sounds like a great script. I haven't tried it yet, (no time,) but I am wondering - are other players able to move through the darkness?
1708729747

Edited 1708729785
This is supremely cool. I don't play 5e (I'm a 3.5e/PF1e guy), but there are many instances in which this script would be useful to me. So I'm wondering. Is the following section, lines 282-303 in your Git repo, the section where the script looks at the character's sheet to see if it has Devil's Sight, and caches the appropriate Character ID if the answer is yes? &nbsp; const hasDevilsSight = (()=&gt;{ &nbsp; &nbsp; let devilsSightCache = new Set(); &nbsp; &nbsp; const isDevilsSightAttr = (t) =&gt; /.*devil.*sight/i.test(t); &nbsp; &nbsp; const cacheForChar = (cid) =&gt; { &nbsp; &nbsp; &nbsp; let attrs = findObjs({type: "attribute", characterid: cid}); &nbsp; &nbsp; &nbsp; const burndown = () =&gt;{ &nbsp; &nbsp; &nbsp; &nbsp; let a = attrs.shift(); &nbsp; &nbsp; &nbsp; &nbsp; if(a){ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if(isDevilsSightAttr(a.get('current'))){ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; devilsSightCache.add(cid); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } else { &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; setTimeout(burndown,0); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } &nbsp; &nbsp; &nbsp; &nbsp; } else { &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; devilsSightCache.delete(cid); &nbsp; &nbsp; &nbsp; &nbsp; } &nbsp; &nbsp; &nbsp; }; &nbsp; &nbsp; &nbsp; burndown(); &nbsp; &nbsp; }; And if that's what's happening, then I have three questions. What is the name of the attribute as it appears on the character? What value does the attribute need to contain in order for a character to be cached? Would this caching process still be carried out if the character were not set up to use the 5e character sheet? For example, if I were not set up to use the 5e sheet, and I did the following: Create two characters, named Alice and Bob Give both an attribute called HasDevilsSight (or whatever the attribute is actually called) Set it Alice's attribute to 0 or null Set Bob's attribute to 1+ Can Bob can now see through darkness? I am asking because it would be a relatively simple matter for me to add the aforesaid attribute. All I need is to know what it is named.
1708732566
Nick O.
Forum Champion
Simon G. said: So that darkness token did not have a controlled by, I had clicked a random token when dropping it, so that's on me, sorry.&nbsp; I then used the warlock to drop a new one, defintely says "Controlled by Camera" and I get this, which still looks wrong Can you invite me to the game this is happening in? I can try to take a look later this weekend.
1708732660
Nick O.
Forum Champion
Hultz (Keeper of Secrets) said: This sounds like a great script. I haven't tried it yet, (no time,) but I am wondering - are other players able to move through the darkness? Thanks! As long as you don't have Dynamic Lighting Barriers Restrict Movement turned on, yes. If you do have that setting on, they can move in the area of darkness, but won't be able to move out of it.&nbsp;
1708737937
Nick O.
Forum Champion
Edward R. said: This is supremely cool. I don't play 5e (I'm a 3.5e/PF1e guy), but there are many instances in which this script would be useful to me. So I'm wondering. Is the following section, lines 282-303 in your Git repo, the section where the script looks at the character's sheet to see if it has Devil's Sight, and caches the appropriate Character ID if the answer is yes? &nbsp; const hasDevilsSight = (()=&gt;{ &nbsp; &nbsp; let devilsSightCache = new Set(); &nbsp; &nbsp; const isDevilsSightAttr = (t) =&gt; /.*devil.*sight/i.test(t); &nbsp; &nbsp; const cacheForChar = (cid) =&gt; { &nbsp; &nbsp; &nbsp; let attrs = findObjs({type: "attribute", characterid: cid}); &nbsp; &nbsp; &nbsp; const burndown = () =&gt;{ &nbsp; &nbsp; &nbsp; &nbsp; let a = attrs.shift(); &nbsp; &nbsp; &nbsp; &nbsp; if(a){ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if(isDevilsSightAttr(a.get('current'))){ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; devilsSightCache.add(cid); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } else { &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; setTimeout(burndown,0); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } &nbsp; &nbsp; &nbsp; &nbsp; } else { &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; devilsSightCache.delete(cid); &nbsp; &nbsp; &nbsp; &nbsp; } &nbsp; &nbsp; &nbsp; }; &nbsp; &nbsp; &nbsp; burndown(); &nbsp; &nbsp; }; And if that's what's happening, then I have three questions. What is the name of the attribute as it appears on the character? What value does the attribute need to contain in order for a character to be cached? Would this caching process still be carried out if the character were not set up to use the 5e character sheet? For example, if I were not set up to use the 5e sheet, and I did the following: Create two characters, named Alice and Bob Give both an attribute called HasDevilsSight (or whatever the attribute is actually called) Set it Alice's attribute to 0 or null Set Bob's attribute to 1+ Can Bob can now see through darkness? I am asking because it would be a relatively simple matter for me to add the aforesaid attribute. All I need is to know what it is named. Glad you liked it! The script is using a regular expression to search for an attribute whose "current" property contains Devil's Sight. I'm not sure of the structure of the other character sheets, so I can't say if this will work for non-5e sheets. But if those sheets contain attribute objects that have a "current" property then it should work. Or, you could modify the code so it looks for whatever the 3.5/PF equivalent to "current" is - it's line 292 in the code. Hope that helps!
1708829508

Edited 1708871162
Nick (and all), Fantastic script.&nbsp; I'm a Pathfinder guy and can confirm that the darkness script works.&nbsp; I would like to adapt it so that it works for Fog Cloud, Cloudkill, Stinking Cloud and the like.&nbsp;&nbsp; The rules for this say that your vision is reduced to 5' in these clouds.&nbsp; I would like set the token that is in the cloud to dim-light 5 and turn off any bright light or darkvision. &nbsp; As I try to adapt the script, I missing something that would allow this to happen. I'm trying to understand what parameters I would need to save, and restore when the token left the radius, or the token was destroyed. &nbsp; Right now, I have something that sort of works.&nbsp; I changed this section to look like this.&nbsp; Line 190 and 200 changes to "emits_bright_light"&nbsp; (Code changed at the bottom of this post)&nbsp;&nbsp; The token starts with bright light 20' and Low Light 5'.&nbsp;&nbsp; When the "fog" token appears, it changes the token's emits_bright_light to 0.&nbsp;&nbsp; So, that works.... sort of.&nbsp;&nbsp; I refresh both the GM's game and then the dummy player's game.&nbsp; The SightTest1 token's vision seems to be the same until I change his Low Light's Brightness value.&nbsp; Also, I have to move one of the tokens for the effect to start.&nbsp; If I remove the token, he regains emits_bright_light, but, I have to go back into the token and change the brightness value again to get the full bright light radius. I want to show this to see if it is something I'm doing to the code, or something else for my particular game.&nbsp; I'm using Pathfinder by Roll20. This is what the player sees: Step 0 - Starting state: Step 1 - Fog Token called in: Step 2 - Fog Token Moved 5' to the right. Step 3 - Move Player token 5' to the right. Step 4 - Move Player left 5' - Open Player's Token as GM and change Brightness level.&nbsp; This is what I want to see! Step 5 - Delete Fog Token. Step 6 - Open Player's Token as GM and change Brightness level again.&nbsp; Emit_Bright_Light back to 20' If I move the SightTest1 Token outside of the Fog radius, it performs as required (though I would like to be able to see 5' into the radius.... I'll play with that later. Hope the pictures help. --------------- Here are my questions/issues. 1) What other changes would I need to add to put in Darkvision to off and set Dim Light to 5'?&nbsp;&nbsp; 2) Finally, I would like to change the Darkness token.&nbsp; I can't seem to figure out how to do that.&nbsp; If I change the script from anything other than your token, I end up with errors.&nbsp; How do I use a different token to represent the Darkness token? Figured 2) out.&nbsp;&nbsp; Used The Aaron's script from here to use a transparent token, then changed the script to give it a small aura_2 so the GM can see it but the players cannot. 3) Cannot figure out the brightness level resetting (in step 4 and 6) to get proper functioning.&nbsp;&nbsp; Figured 3) out.&nbsp; I reset the dim_light_opacity which forces a change which causes the screen to reset. Code I changed: function updatePlayerVision(obj){ let fogObjects = findObjs({type:"graphic",layer:"objects",name:"fog",pageid:obj.get("_pageid")}); //get a list of all character tokens &amp; determine who's within the effect of the spell let scale_number = getObj("page", obj.get("_pageid")).get("scale_number"); let playerTokenList = getCharacterTokens(obj); for (let playerToken of playerTokenList){ playerToken.set("emits_bright_light",1); if (hasDevilsSight(playerToken.get("represents")) || playerToken.get("name") === "fog" ){ //log("skipping" + playerToken.get("name")); continue; } for (let fogObject of fogObjects){ let fogTokenAuraRadius = fogObject.get("aura1_radius"); let fogRadius = fogTokenAuraRadius/scale_number; let eDist = calculateEuclidianDistance(fogObject,playerToken); if (eDist&lt;=fogRadius){ playerToken.set("emits_bright_light",0); } } } }
Okay, I figured out a few more things out and now I'm very close to modding the original script so that it will do Fogs/Clouds I changed the code at lines 193 to set the token to what I wanted it to be.&nbsp;&nbsp; The issue is when you revert after the trigger. function updatePlayerVision(obj){ let fogObjects = findObjs({type:"graphic",layer:"objects",name:"fog",pageid:obj.get("_pageid")}); //get a list of all character tokens &amp; determine who's within the effect of the spell let scale_number = getObj("page", obj.get("_pageid")).get("scale_number"); let playerTokenList = getCharacterTokens(obj); for (let playerToken of playerTokenList){ playerToken.set("emits_bright_light",true); playerToken.set("has_night_vision",true); playerToken.set("low_light_distance",20); playerToken.set("dim_light_opacity",0.5); if (hasDevilsSight(playerToken.get("represents")) || playerToken.get("name") === "fog" ){ //log("skipping" + playerToken.get("name")); continue; } for (let fogObject of fogObjects){ let fogTokenAuraRadius = fogObject.get("aura1_radius"); let fogRadius = fogTokenAuraRadius/scale_number; let eDist = calculateEuclidianDistance(fogObject,playerToken); if (eDist&lt;=fogRadius){ playerToken.set("emits_bright_light",false); playerToken.set("emits_low_light",true); playerToken.set("low_light_distance",5); playerToken.set("dim_light_opacity",0.4); playerToken.set("has_night_vision",false); } } } } So I'm learning.&nbsp; Clearly the original code is resetting the overall vision as on, but does not set other original values.&nbsp; I can set certain values as well, such as dim_light_opacity, which is generally started at 50% for all tokens.&nbsp; I turned has_night_vision to true, and low_light_distance to 20, but I don't really want that for each token when the trigger token is removed. Changing the dim_light_opacity from 0.5 to 0.4 with the triggering event fixed a lot of the step issues I was having before.&nbsp; For instance, I'm at starting state 0, and jumping right to step 4!&nbsp; Success!&nbsp;&nbsp; When the fog token is removed, I'm back to Step 6.&nbsp; Great!&nbsp; Resetting the dim_light_opacity changes the "redraw/reset?" of the lighting for that token. So, my question now:&nbsp; Is there a way to capture the exact value of each token's light settings before the trigger, and then revert to that exact value when the trigger (the darkness/fog token) is removed? I can see how elegant the Darkness is, because it only turns on/off vision.&nbsp; Perfect for darkness.&nbsp; For Fog/Cloud effects, you would need the ability to capture each lighting setting for each token, to be able to revert back to those values.&nbsp; Correct? Is this possible?
You could use State memory, and create an array keyed to the TokenIds, with attributes for each of the vision/light attributes. &nbsp;Just make sure to have good logic to push and pop entries into the array, so that it doesn’t keep growing over time. &nbsp;Might consider adding a command to clear the cache, removing all entries from the array. &nbsp;