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] Geiger Counter

1452462485
Ada L.
Marketplace Creator
Sheet Author
API Scripter
This script allows GMs to set up tokens on maps' GM layer to create radioactive areas. Characters can be given a 'hasGeigerCounter' attribute to alert them how many rads/s they're taking when they enter a radioactive area. If they don't have a Geiger Counter, only the GM is alerted. /** * This script allows the GM to dynamically create radioactive areas in their * maps. Characters that have Geiger counters will be alerted how many rads * they are taking. * * To create a radioactive source object: * 1) Create a token representing the source on the GM layer. * 2) Set that token's 'radioactive' status marker to on. * 3) Set its aura1 radius to the distance at which characters will start * taking rads from it. * 4) Set the bar1 value to amount of rads/s characters will take at the edge * of its aura. * 5) Set the bar1 max value to the maximum amount of rads/s characters can take * from it. * * To give a player a Geiger counter: * 1) Give them a 'hasGeigerCounter' attribute. * 2) Set the attribute to 'true'. * * If a character moves in a radioactive area and they have a Geiger counter, * their Geiger counter will alert everyone how many rads/s they are taking. * If a character moves in a radioactive area and they don't have a Geiger * counter, only the GM will be alerted how many rads/s they are taking. */ var GeigerCounter = (function() { /** * Computes the apparent brightness of some object, given distance from it * and the object's luminosity. * @param {number} distance * @param {number} luminosity * @return {number} */ function getBrightness(distance, luminosity) { return luminosity/(4*Math.PI*distance*distance); } /** * Computes the luminosity of some object, given distance from it and the * apparent brightness of that object at that distance. * @param {number} distance * @param {number} brightness * @return {number} */ function getLuminosity(distance, brightness) { return brightness*4*Math.PI*distance*distance; } /** * Gets the unit scale for an object's page. * @param {graphic} The graphic whose page to get the scale for. * @return {number} */ function _getPageScale(obj) { var page = findObjs({ _type: 'page', _id: obj.get('_pageid') })[0]; return page.get('scale_number'); } /** * Gets all the tokens representing radioactive sources on the same map * that some other graphic is on. * @param {graphic} The graphic whose page to use. * @return {graphic[]} */ function getRadioactiveTokens(obj) { return findObjs({ _pageid: obj.get('_pageid'), _type: 'graphic', layer: 'gmlayer', status_radioactive: true }); } /** * Gets the amount of rads an object is taking from a radioactive token. * @param {graphic} A graphic representing a character * @param {graphic} A gmlayer graphic representing a radioactive source. * @return {int} */ function getRads(obj, radToken) { var maxDist = parseInt(radToken.get('aura1_radius')); var minRads = parseInt(radToken.get('bar1_value')); var maxRads = parseInt(radToken.get('bar1_max')); if(!maxDist || !minRads || !maxRads) return 0; var x1 = obj.get('left'); var y1 = obj.get('top'); var x2 = radToken.get('left'); var y2 = radToken.get('top'); var distance = Math.sqrt((x1-x2)*(x1-x2) + (y1-y2)*(y1-y2)); distance = distance/70*_getPageScale(obj); if(distance === 0) return parseInt(maxRads); if(distance &gt; maxDist) return 0; var luminosity = getLuminosity(maxDist, minRads); var brightness = getBrightness(distance, luminosity); return Math.min(maxRads, brightness); } /** * Checks if a character token has a geiger counter. * @param {graphic} A graphic representing a character. * @return {boolean} */ function hasGeigerCounter(obj) { var charId = obj.get('represents'); if(!charId) return false; var geigerAttr = findObjs({ _type: 'attribute', _characterid: charId, name: 'hasGeigerCounter' })[0]; return geigerAttr && geigerAttr.get('current'); } on('change:graphic', function(obj) { // Only handle this script if the moved object represents a // player character. if(obj.get('represents')) { var character = findObjs({ _type: 'character', _id: obj.get('represents') })[0].get('name'); var radTokens = getRadioactiveTokens(obj); var rads = 0; // Get the total number of rads/s the character is taking on their // page from all radioactive sources. _.each(radTokens, function(radToken) { if(obj === radToken) return; rads += getRads(obj, radToken); }); // Round the total up for display. rads = Math.ceil(rads); if(rads) { // If the player has a Geiger counter, let everyone know that // they are taking rads. if(hasGeigerCounter(obj)) sendChat('☢', character + '\'s Geiger counter is ' + 'clicking at ' + rads + ' rads/s.'); // Otherwise, let only the GM know that they are taking rads. else sendChat('☢', '/w GM ' + character + 'is taking ' + rads + ' rads/s.'); } } }); // Expose the public functions as an API of this module. return { getBrightness: getBrightness, getLuminosity: getLuminosity, getRadioactiveTokens: getRadioactiveTokens, getRads: getRads, hasGeigerCounter: hasGeigerCounter }; })(); Until it is merged into the upstream repo, you can check out the script from my fork here: <a href="https://github.com/Cazra/roll20-api-scripts/tree/m" rel="nofollow">https://github.com/Cazra/roll20-api-scripts/tree/m</a>... Demo:
1452462895
Ziechael
Forum Champion
Sheet Author
API Scripter
Nice idea, I'm probably going to tweak this to make some dangerous magic zones in my high fantasy games, those with sensitivity to the weave can be assumed to have 'geiger counters' =D Thanks for the script and the new ideas it has given me to torture my players!
1452463148
Ada L.
Marketplace Creator
Sheet Author
API Scripter
Yes, the radioactivity concept of this script could easily be adapted to various other kinds of hazards that grow more intense with proximity.
1453913867

Edited 1453913897
Ziechael
Forum Champion
Sheet Author
API Scripter
Loving this script, thanks. Let the Wild Magic commence (home brew rules): (ignore the double output for the hasWeaveSense = true, just testing the range of DC's i can generate based on distance from the source), and a space is needed in the first example too... D'oh
1453915996
Stephen S.
Pro
Marketplace Creator
Sheet Author
API Scripter
fun idea
1453916055

Edited 1453916120
Stephen S.
Pro
Marketplace Creator
Sheet Author
API Scripter
unsafe floor..... or carpoolling with Vince...
1453918039
Gold
Forum Champion
I could use this in the AD&D Dragon Magazine module, Citadel By The Sea . There is a fetid smell in the dungeon that gradually chokes and suffocates the characters as they move deeper in the levels.
1453918080
vÍnce
Pro
Sheet Author
Time to break out my Gamma World box from the attic... Stephen, you get to ride on the hood... &nbsp;}:-)
1453918841

Edited 1453918848
Stephen S.
Pro
Marketplace Creator
Sheet Author
API Scripter
Vince said: Time to break out my Gamma World box from the attic... a great game!
1453935890
chris b.
Pro
Sheet Author
API Scripter
This is awesome, thanks! I am going to be running the Pathfinder module From Shore to Sea in a month or so and this will be a cool way to implement it. I wonder can we call sound files from the API? Such as if we found an appropriate sound from the library?
1453936027
The Aaron
Pro
API Scripter
You can! &nbsp; <a href="https://wiki.roll20.net/API:Utility_Functions#Juke" rel="nofollow">https://wiki.roll20.net/API:Utility_Functions#Juke</a>... I was thinking there was a way to play just a single sound file.. might be missing from the docs...
1453936113

Edited 1454005991
The Aaron
Pro
API Scripter
Found it: API Jukebox Support allows you to have basic control over the Jukebox using API Scripts. Here's what's changed: New object type, "jukeboxtrack". You can use this just like any other object with findObjs(), get(), set(), etc. To play a Jukebox Track, just get the track object (for example using findObjs) and then set the "playing" property to "true". You can have multiple tracks playing at the same time. New property on the Campaign object, "_jukeboxfolder", which allows you to view information about the folders (playlists) in the Jukebox, just like the "_journalfolder" property allows you to view information on the folders in the Journal tab. Two new functions, "playJukeboxPlaylist(id)" and "stopJukeboxPlaylist()". The play function takes in the Folder ID (get it from the "_jukeboxfolder" property in the Campaign object) of a playlist, and will begin playing that playlist for everyone in the game. The stop function does not require any arguments, and will stop any playlist that is currently playing.
1453946016
chris b.
Pro
Sheet Author
API Scripter
That would be cool to add little pings or clicks automatically. A lot easier than trying to remember to play tracks.
I hope this moves to production server in the next update. The new servers are more stable than the old ones, I have moved back to the main server with my games. For a while I ran my weekend games on dev to avoid the frightening lag times, my players are on three continents, so sometimes things got really slow, especially for Australians.
1454005963

Edited 1454006007
The Aaron
Pro
API Scripter
Al e.: that's on the live servers already. &nbsp;I copied the text from the Pro announcement and didn't realize it had that in it... (Edited that post to remove confusion)
Aaron the Scriptomancer to the rescue. Thanks!
1454106284
Stephen S.
Pro
Marketplace Creator
Sheet Author
API Scripter
My favorite part of this script..... sendChat('☢'