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

LightningFX script

August 11 (4 years ago)

Edited August 22 (4 years ago)
David M.
Pro
API Scripter

This has probably been done before, but here's a fun little script to add lightning effects to a map. We don't use sound in our games, so no soundFX in the current script, but maybe later.

EDIT - Note: currently only supports Legacy Dynamic Lighting

Click for animated gif of our hero about to realize he's in a dire situation (11s loop)

Same FX settings with DL layer trees (7s loop).


Setup:

1) Place a handful of tokens across the map with the following settings:

        name: "Lightning"

        All Players See Light: checked

        image: transparent png

        Aura1: 0ft (so the GM can see the square of the source)

2) Call !lightning on (+optional params?) to start the light show

3) Call !Lightning off to stop.

Only lightning tokens on the player page are affected

Optional parameters in bold below:

!lightning <on/off> <minInterval> <maxInterval> <maxDuration>

    minInterval = minimum time between flashes (in milliseconds) -- DEFAULT = 200

    minInterval = maximum time between flashes (in milliseconds) -- DEFAULT = 10000

    maxDuration= maximum duration of each flash (in milliseconds) -- DEFAULT = 400

Examples of valid calls:

!lightning on    //uses default values
!lightning off    //turns off FX (there may be one more cycle that has to finish after command is given)
!lightning on 400    //overrides the minInterval, rest are default values
!lightning on 400 8000    //overrides the min & max Intervals, with default value used for maxDuration
!lightning on 400 8000 200    //overrides all timer values

For the animated gif example above, I used 5 lightning tokens (red highlight) and drew tree trunks in the DL layer. I thought it created a pretty spooky effect.


Here's the script!

   const LightningFX = (() => {
    
    const scriptName = "LightningFX";
    const version = '0.1';
    
    var globalKill = true;
    const LIGHT_NAME = 'Lightning';
    
    const checkInstall = function() {
        log(scriptName + ' v' + version + ' initialized.');
    };
    
    const flashOff = function(src) {
        src.set('light_radius', 0);
    }
    
    const flashOn = function(src, dim, timeout) {
        let rand = Math.random() * timeout;
        
        if (dim) {
            src.set('light_dimradius', -15);
            src.set('light_radius', 200);
        } else {
            src.set('light_radius', 200);
        }
        setTimeout(flashOff, rand, src);
    }
    
    const handleFX = function(sources, minInterval, maxInterval, maxDuration, active) {
        let dim = false;
        
        if (active) {
            let rand = Math.floor(Math.random() * (maxInterval - minInterval + 1) + minInterval);
            
            if ( randomInteger(2) === 2 ) {
                dim = true;
            } else {
                dim = false;
            }
            
            setTimeout(function() {
                    sources.forEach((src) => {
                        flashOn(src, dim, maxDuration);
                    });
                    if (!globalKill) { handleFX(sources, minInterval, maxInterval, maxDuration, true); }
            }, rand);
        } else {
            sources.forEach((src) => {
                flashOff(src);
            });
        }
    }

    const handleInput = function(msg) {
        //set defaults
        let minInterval = 200;
        let maxInterval = 10000;
        let maxDuration = 400;
        
        try {
            if(msg.type=="api" && msg.content.indexOf("!lightning") === 0 && playerIsGM(msg.playerid)) {
                who = getObj('player',msg.playerid).get('_displayname');
                
                let cmd = msg.content.split((/\s+/));
                cmd.shift();
                
                switch (cmd.length) {
                    case 0:
                        //no commands, do nothing
                        sendChat('Lightning',`/w "${who}" `+ 'No commands given to !Lightning script');
                        break;
                    case 1:
                        //on or off
                        break;
                    case 2:
                        //minInterval
                        minInterval = parseInt(cmd[1])
                        break;
                    case 3:
                        //minInterval maxInterval
                        minInterval = parseInt(cmd[1])
                        maxInterval = parseInt(cmd[2])
                        break;
                    case 4:
                    default:
                        //minInterval maxInterval maxDuration
                        minInterval = parseInt(cmd[1])
                        maxInterval = parseInt(cmd[2])
                        maxDuration = parseInt(cmd[3])
                        break;
                }
                
                if ( isNaN(minInterval) || isNaN(maxInterval) || isNaN(maxDuration) ) {
                    sendChat('Lightning',`/w "${who}" `+ 'Error. Non-Numeric timer settings detected');
                    return;
                }
                
                var sources = findObjs({
                    _pageid: Campaign().get("playerpageid"),    
                    _type: "graphic",
                    name: LIGHT_NAME
                });
                
                if (!sources) {
                    sendChat('Lightning',`/w "${who}" `+ 'No Lightning Sources on Player Page!');
                    globalKill = true;
                    return;
                }
                
                switch (cmd[0].toLowerCase()) {
                    case "on":
                        //TURN ON FX
                        globalKill = false;
                        handleFX(sources, minInterval, maxInterval, maxDuration, true);
                        break;
                    case "off":
                        //TURN OFF FX
                        globalKill = true;
                        handleFX(sources, minInterval, maxInterval, maxDuration, false);
                        break;
                    default:
                        sendChat('Lightning',`/w "${who}" `+ 'Unrecognized command. Expected Lighting \"on\" or \"off\"');
                        return;
                }
            }   
        }
        catch(err) {
          sendChat('Lightning',`/w "${who}" `+ 'Unhandled exception: ' + err.message);
        }
    };
    
    const registerEventHandlers = function() {
        on('chat:message', handleInput);
    };

    on("ready",() => {
        checkInstall();
        registerEventHandlers();
    });
})();






Nice script I used it in my past session and with the thunder crash sound track it worked out nice, too bad when I use a weather overlay from the marketplace the sound gets all screwy. Your script worked like a charm though thanks !!

August 18 (4 years ago)
David M.
Pro
API Scripter

Great, thanks for the feedback!