/*
* Version 0.1.8
* Made By Robin Kuiper
* Skype: RobinKuiper.eu
* Discord: Atheos#1095
* Roll20: https://app.roll20.net/users/1226016/robin
* Roll20 Wiki: https://wiki.roll20.net/Script:Concentration
* Github: https://github.com/RobinKuiper/Roll20APIScripts
* Reddit: https://www.reddit.com/user/robinkuiper/
* Patreon: https://patreon.com/robinkuiper
* Paypal.me: https://www.paypal.me/robinkuiper
*/
var Concentration = Concentration || (function() {
'use strict';
let checked = [];
// Styling for the chat responses.
const styles = {
reset: 'padding: 0; margin: 0;',
menu: 'background-color: #fff; border: 1px solid #000; padding: 5px; border-radius: 5px;',
button: 'background-color: #000; border: 1px solid #292929; border-radius: 3px; padding: 5px; color: #fff; text-align: center;',
list: 'list-style: none;',
float: {
right: 'float: right;',
left: 'float: left;'
},
overflow: 'overflow: hidden;',
fullWidth: 'width: 100%;'
},
script_name = 'Concentration',
state_name = 'CONCENTRATION',
markers = ['blue', 'brown', 'green', 'pink', 'purple', 'red', 'yellow', '-', 'all-for-one', 'angel-outfit', 'archery-target', 'arrowed', 'aura', 'back-pain', 'black-flag', 'bleeding-eye', 'bolt-shield', 'broken-heart', 'broken-shield', 'broken-skull', 'chained-heart', 'chemical-bolt', 'cobweb', 'dead', 'death-zone', 'drink-me', 'edge-crack', 'fishing-net', 'fist', 'fluffy-wing', 'flying-flag', 'frozen-orb', 'grab', 'grenade', 'half-haze', 'half-heart', 'interdiction', 'lightning-helix', 'ninja-mask', 'overdrive', 'padlock', 'pummeled', 'radioactive', 'rolling-tomb', 'screaming', 'sentry-gun', 'skull', 'sleepy', 'snail', 'spanner', 'stopwatch','strong', 'three-leaves', 'tread', 'trophy', 'white-tower'],
handleInput = (msg) => {
if(state[state_name].config.auto_add_concentration_marker && msg && msg.rolltemplate && msg.rolltemplate === 'spell' && (msg.content.includes("{{concentration=1}}"))){
let character_name = msg.content.match(/charname=([^\n{}]*[^"\n{}])/);
character_name = RegExp.$1;
let spell_name = msg.content.match(/name=([^\n{}]*[^"\n{}])/);
spell_name = RegExp.$1;
let player = getObj('player', msg.playerid),
characterid = findObjs({ name: character_name, _type: 'character' }).shift().get('id'),
represented_tokens = findObjs({ represents: characterid, _type: 'graphic' }),
marker = state[state_name].config.statusmarker,
message,
target = state[state_name].config.send_reminder_to;
if(!character_name || !spell_name || !player || !characterid) return;
let search_attributes = {
represents: characterid,
_type: 'graphic',
_pageid: player.get('lastpage')
}
search_attributes['status_'+marker] = true;
let is_concentrating = (findObjs(search_attributes).length > 0);
if(is_concentrating){
message = ''+character_name+' is concentrating already.';
}else{
represented_tokens.forEach(token => {
let attributes = {};
attributes['status_'+marker] = true;
token.set(attributes);
message = ''+character_name+' is now concentrating on '+spell_name+'.';
});
}
if(target === 'character'){
target = createWhisperName(character_name);
}else if(target === 'everyone'){
target = ''
}
makeAndSendMenu(message, '', target);
}
if (msg.type != 'api' || !playerIsGM(msg.playerid)) return;
// Split the message into command and argument(s)
let args = msg.content.split(' ');
let command = args.shift().substring(1);
let extracommand = args.shift();
let message;
if (command == state[state_name].config.command) {
switch(extracommand){
case 'reset':
state[state_name] = {};
setDefaults(true);
sendConfigMenu(false, 'The API Library needs to be restarted for this to take effect.');
break;
case 'config':
if(args.length > 0){
let setting = args.shift().split('|');
let key = setting.shift();
let value = (setting[0] === 'true') ? true : (setting[0] === 'false') ? false : setting[0];
state[state_name].config[key] = value;
if(key === 'bar'){
//registerEventHandlers();
message = 'The API Library needs to be restarted for this to take effect.';
}
}
sendConfigMenu(false, message);
break;
default:
sendConfigMenu();
break;
}
}
},
handleStatusMarkerChange = (obj, prev) => {
const marker = state[state_name].config.statusmarker
if(!obj.get('status_'+marker)){
findObjs({ type: obj.get('type'), represents: obj.get('represents') }).forEach(o => {
o.set('status_'+marker, false);
});
}
},
handleGraphicChange = (obj, prev) => {
if(checked.includes(obj.get('represents'))){ return false; }
let bar = 'bar'+state[state_name].config.bar+'_value',
target = state[state_name].config.send_reminder_to,
marker = state[state_name].config.statusmarker;
if(prev && obj.get('status_'+marker) && obj.get(bar) < prev[bar]){
let calc_DC = Math.floor((prev[bar] - obj.get(bar))/2),
DC = (calc_DC > 10) ? calc_DC : 10,
chat_text;
if(target === 'character'){
target = createWhisperName(obj.get('name'));
chat_text = "Make a Concentration Check - DC " + DC + ".";
}else if(target === 'everyone'){
target = ''
chat_text = ''+obj.get('name')+' must make a Concentration Check - DC ' + DC + '.';
}
makeAndSendMenu(chat_text, '', target);
let length = checked.push(obj.get('represents'));
setTimeout(() => {
checked.splice(length-1, 1);
}, 1000);
}
},
createWhisperName = (name) => {
return name.split(' ').shift();
},
ucFirst = (string) => {
return string.charAt(0).toUpperCase() + string.slice(1);
},
sendConfigMenu = (first, message) => {
let markerDropdown = '?{Marker';
markers.forEach((marker) => {
markerDropdown += '|'+ucFirst(marker).replace('-', ' ')+','+marker
})
markerDropdown += '}';
let markerButton = makeButton(state[state_name].config.statusmarker, '!' + state[state_name].config.command + ' config statusmarker|'+markerDropdown, styles.button + styles.float.right);
let commandButton = makeButton('!'+state[state_name].config.command, '!' + state[state_name].config.command + ' config command|?{Command (without !)}', styles.button + styles.float.right);
let barButton = makeButton('bar ' + state[state_name].config.bar, '!' + state[state_name].config.command + ' config bar|?{Bar|Bar 1 (green),1|Bar 2 (blue),2|Bar 3 (red),3}', styles.button + styles.float.right);
let sendToButton = makeButton(state[state_name].config.send_reminder_to, '!' + state[state_name].config.command + ' config send_reminder_to|?{Send To|Everyone,everyone|Character,character|GM,gm}', styles.button + styles.float.right);
let addConMarkerButton = makeButton(state[state_name].config.auto_add_concentration_marker, '!' + state[state_name].config.command + ' config auto_add_concentration_marker|'+!state[state_name].config.auto_add_concentration_marker, styles.button + styles.float.right);
let listItems = [
'Command: ' + commandButton,
'Statusmarker: ' + markerButton,
'HP Bar: ' + barButton,
'Send Reminder To: ' + sendToButton,
'Auto Add Con. Marker: Works only for 5e OGL Sheet.
'+message+'
' : ''; let contents = message+makeList(listItems, styles.reset + styles.list + styles.overflow, styles.overflow)+'You can always come back to this config by typing `!'+state[state_name].config.command+' config`.