Is anyone familiar with this script? Im trying to use it with the Faerun Calendar set up. I think it works so far but I'm trying to get it to display the Month with its Name instead of with the number of the month. This is what it looks like now "(From Chronos): 10th Day, 1343.8.2.3.41." I would like it to cleaner and display the names instead of all those numbers. /* Chronos Timekeeper: Calendar and Timekeeper Script for roll20.net * * !chronos returns elapsed time so far (needs updating) * !chronos #y,#m,#d,#h,#n adds a number of years, months, days, hours, minutes (n) to clock. * !chronos #y,#m,#d,#h,#n -xyz parameters: t for torch tracking, r for regular rest, h for bedrest * !chronos 6:00am move timer to next occurrence of given hour (not implemented yet) * */ state.bpd_chronos = state.bpd_chronos || {}; state.bpd_chronos.years = state.bpd_chronos.years || 0; state.bpd_chronos.months = state.bpd_chronos.months || 0; state.bpd_chronos.days = state.bpd_chronos.days || 1; state.bpd_chronos.hours = state.bpd_chronos.hours || 0; state.bpd_chronos.minutes = state.bpd_chronos.minutes || 0; state.bpd_chronos.weekday = state.bpd_chronos.weekday || 0; var month = [['Hammer',30],[ 'Midwinter',1],['Alturiak',30],["Ches",30],['Tarsakh',30],[ 'Greengrass',1],['Mirtul',30],['Kythorn',30],['Flamerule',30],[ 'Midsummer',1],['Eleasis',30],['Eleint',30],[ 'Highharvesttide',1],['Marpenoth',30],['Uktar',30],[ 'The Harvest of The Moon',1],['Nightal',30]]; var lengthOfYear = lengthOfYear(); var week = ['1st Day','2nd Day','3rd Day','4th Day','5th Day','6th Day','7th Day','8th Day','9th Day','10th Day']; var weekday = 0; var attributesToHeal = ['HP','Strength','Agility','Stamina','Personality','Intelligence']; /* healingData objects: healingData[0][0]: minimum hours of rest for healing healingData[0][1]: hp for minimum rest healingData[0][2]: attributes points for minimum rest healingData[1][0]: hours required for full rest healingData[1][1]: hp healed for full rest healingData[1][2]: attribute points for full tended rest */ var healingData = [[8,1,1],[1,2,2]]; function lengthOfYear() { n = 0; for (i = 0; i <= month.length -1; i++) { if (month[i][2] == undefined) { n = parseInt(n) + parseInt(month[i][1]); }; }; return n; }; function updateChronos(years,months,days,hours,minutes) { if (minutes != 0) { var chronosMinuteMax = 60; // hard-coding this for now if (state.bpd_chronos.minutes + parseInt(minutes) >= parseInt(chronosMinuteMax)) { hours = parseInt(hours) + Math.floor((state.bpd_chronos.minutes + parseInt(minutes)) / chronosMinuteMax); state.bpd_chronos.minutes = Math.floor((state.bpd_chronos.minutes + parseInt(minutes)) % chronosMinuteMax); } else { state.bpd_chronos.minutes = parseInt(state.bpd_chronos.minutes) + parseInt(minutes) }; }; if (hours != 0) { var chronosHourMax = 24; // hard-coding this for now, under new state setup if (state.bpd_chronos.hours + parseInt(hours) >= parseInt(chronosHourMax)) { days = parseInt(days) + Math.floor((state.bpd_chronos.hours + parseInt(hours)) / chronosHourMax); state.bpd_chronos.hours = Math.floor((state.bpd_chronos.hours + parseInt(hours)) % chronosHourMax); } else { state.bpd_chronos.hours = parseInt(state.bpd_chronos.hours) + parseInt(hours) }; }; if (days != 0) { // this currently won't work if you add enough days to move the timer forward more than one month var chronosDayMax = month[state.bpd_chronos.months -1][1]; if (state.bpd_chronos.days + parseInt(days) > parseInt(chronosDayMax) && month[state.bpd_chronos.months-1][1] != 1) { months = parseInt(months) + Math.floor((state.bpd_chronos.days + parseInt(days)) / chronosDayMax); state.bpd_chronos.days = Math.floor((state.bpd_chronos.days + parseInt(days)) % chronosDayMax); } else if (state.bpd_chronos.days + parseInt(days) > parseInt(chronosDayMax) && month[state.bpd_chronos.months-1][1] == 1) { months = parseInt(months) + 1; state.bpd_chronos.days = Math.floor((state.bpd_chronos.days + parseInt(days)) - 1); } else { state.bpd_chronos.days = parseInt(state.bpd_chronos.days) + parseInt(days); }; }; if (months != 0) { var chronosMonthMax = month.length -1; if (state.bpd_chronos.months + parseInt(months) > parseInt(chronosMonthMax)) { years = parseInt(years) + Math.floor((state.bpd_chronos.months + parseInt(months)) / chronosMonthMax); state.bpd_chronos.months = Math.floor((state.bpd_chronos.months + parseInt(months)) % chronosMonthMax); } else { state.bpd_chronos.months = parseInt(state.bpd_chronos.months) + parseInt(months) }; }; if (years != 0) { state.bpd_chronos.years = parseInt(state.bpd_chronos.years) + parseInt(years); }; n = 0; for (i = 0; i < state.bpd_chronos.months -1; i++) { // get all the days in preceding months if (month[i][2] == undefined) { n = parseInt(n) + parseInt(month[i][1]); }; }; state.bpd_chronos.weekday = (((lengthOfYear * state.bpd_chronos.years) + n + state.bpd_chronos.days) % week.length); sendChat("Chronos","/w gm " + week[state.bpd_chronos.weekday] + ", " + state.bpd_chronos.years + "." + state.bpd_chronos.months + "." + state.bpd_chronos.days + "." + state.bpd_chronos.hours + "." + state.bpd_chronos.minutes + "."); }; function healCharacters(hd,lengthOfRest,typeOfHealing) { // healCharacters function, called when parameter includes "r" for rest, "b" for bedrest // lengthOfRest = number of hours or days to rest // hoursOrDays = h or d // typeOfHealing = normal, bedrest // put all the tokens on the page that represent characters into charactersToHeal[] array var charactersToHeal = filterObjs(function(obj) { if(obj.get("_pageid") == Campaign().get("playerpageid") && obj.get("_subtype") == "token" && obj.get("_represents") != "") return true; else return false; }); // get attributes to heal, any healingData related attributes for (i = 0; i < charactersToHeal.length; i++) { var character = getObj("character", charactersToHeal[i].get("represents")); var attributes = filterObjs(function(obj){ if (obj.get("_type") == "attribute" && obj.get("_characterid") == character.get("_id") && attributesToHeal.indexOf(obj.get("name")) != -1) return true; else return false; }); for (i = 0; i <= attributes.length -1; i++) { // now go through all the attributes for this character // and update based on the right parameters // if DCC, then [[8,1,1],[24,2,2]] // if BFRPG, then [[6,1,1],[24,2,1]] // if 3.5E, then [[8,1,'LVL'],[24,2,'LVL']] if (typeOfHealing == "normal") { if (lengthOfRest > 0 && hd == "d") { var amountToHeal = healingData[0][1] * lengthOfRest; } else if (lengthOfRest >= healingData[0][0] && hd == "h") { var amountToHeal = healingData[0][1]; } else { sendChat("Chronos","/w gm Not enough time for normal rest, aborting."); return; }; } else if (typeOfHealing == "bedrest") { if (lengthOfRest > 0 && hd == "d") { var amountToHeal = healingData[1][1] * lengthOfRest; } else { sendChat("Chronos","/w gm Not enough time for bedrest, aborting."); return; }; }; if (parseInt(attributes[i].get("current")) < parseInt(attributes[i].get("max"))) { attributes[i].set("current", parseInt(attributes[i].get("current")) + parseInt(amountToHeal)); if (attributes[i].get("current") > attributes[i].get("max")) { attributes[i].set("current", attributes[i].get("max")); }; }; }; }; }; function updateLights(lightSource,elapsedTime) { var lightSourceName = lightSource.get("name"); var brightRadius = lightSource.get("bar3_max"); var dimRadius = lightSource.get("bar3_value"); var burningTimeTotal = lightSource.get("bar1_max"); var burningTimeRemaining = lightSource.get("bar1_value"); var trigger_dim = Math.floor(burningTimeTotal * 0.3); var trigger_flicker = Math.floor(burningTimeTotal * 0.15); var trigger_almostOut = Math.floor(burningTimeTotal * 0.05); var newBurningTimeRemaining = burningTimeRemaining - (1.0 * elapsedTime); if (burningTimeRemaining == 0 || lightSource.get("bar2_value") == 0) return; // make sure light source is lit & has fuel remaining if (newBurningTimeRemaining >= trigger_dim && lightSource.get("light_radius") !== brightRadius) { lightSource.set({ light_radius: brightRadius, light_dimradius: dimRadius}); } else if (newBurningTimeRemaining <= trigger_dim && newBurningTimeRemaining > trigger_flicker && (burningTimeRemaining > trigger_dim || burningTimeRemaining == newBurningTimeRemaining)) { sendChat("","/emas " + lightSourceName + " grows dim. "); lightSource.set({ light_dimradius: Math.floor(dimRadius * 0.66)}); } else if (newBurningTimeRemaining <= trigger_flicker && newBurningTimeRemaining > trigger_almostOut && (burningTimeRemaining > trigger_flicker || burningTimeRemaining == newBurningTimeRemaining)) { sendChat("","/emas " + lightSourceName + " begins to flicker. "); lightSource.set({ light_radius: Math.floor(brightRadius * 0.75), light_dimradius: Math.floor(dimRadius * 0.5)}); } else if (newBurningTimeRemaining <= trigger_almostOut && newBurningTimeRemaining > 0&& (burningTimeRemaining > trigger_almostOut || burningTimeRemaining == newBurningTimeRemaining)) { sendChat("","/emas " + lightSourceName + " is about to go out. "); lightSource.set({ light_radius: Math.floor(brightRadius * 0.5), light_dimradius: 0 }); } else if (newBurningTimeRemaining <= 0) { newBurningTimeRemaining = 0; sendChat("","/emas " + lightSourceName + " goes out!"); lightSource.set({ bar2_value: 0, light_radius: "", light_dimradius: "" }); }; lightSource.set({ bar1_value: newBurningTimeRemaining }); }; function findLights(numRounds) { var playerVisibleLights = filterObjs(function(obj) { if(obj.get("_pageid") == Campaign().get("playerpageid") && obj.get("_subtype") == "token" && obj.get("bar2_value") == "1" && obj.get("bar2_max") == "1" && obj.get("light_otherplayers") == true) return true; else return false; }); _.each(playerVisibleLights, function(obj) { updateLights(obj,numRounds); }); }; /* on('ready', function() { state.chronosid = findObjs({_type: "character", name: "Chronos"})[0].get("_id"); }); */ on("chat:message", function(msg) { if (msg.type == "api" && msg.who.indexOf("(GM)") !== -1 && msg.content.indexOf("!chronos") !== -1) { var years = 0, months = 0, days = 0, hours = 0, minutes = 0; var n = msg.content.split(" "); if (n[1] == undefined) { // i.e., just "!chronos" updateChronos(years,months,days,hours,minutes); return; } else if (n[2] == undefined) { // i.e., "!chronos 1d" or "!chronos 1d,4h" var time = n[1].split(","); for (i = 0; i < time.length; i++) { if (time[i].indexOf("y") != -1) { years = time[i].slice(0, time[i].indexOf("y")); }; if (time[i].indexOf("m") != -1) { months = time[i].slice(0, time[i].indexOf("m")); }; if (time[i].indexOf("d") != -1) { days = time[i].slice(0, time[i].indexOf("d")); }; if (time[i].indexOf("h") != -1) { hours = time[i].slice(0, time[i].indexOf("h")); }; if (time[i].indexOf("n") != -1) { minutes = time[i].slice(0, time[i].indexOf("n")); }; }; } else { // i.e., params (only makes sense with values for time, should add some error catching) var time = n[1].split(","); var params = n[2].slice(1); for (i = 0; i < time.length; i++) { if (time[i].indexOf("y") != -1) { years = time[i].slice(0, time[i].indexOf("y")); }; if (time[i].indexOf("m") != -1) { months = time[i].slice(0, time[i].indexOf("m")); }; if (time[i].indexOf("d") != -1) { days = time[i].slice(0, time[i].indexOf("d")); }; if (time[i].indexOf("h") != -1) { hours = time[i].slice(0, time[i].indexOf("h")); }; if (time[i].indexOf("n") != -1) { minutes = time[i].slice(0, time[i].indexOf("n")); }; }; // kick off torches burning, healing, etc. here for (i = 0; i < params.length; i++) { switch (params[i]) { case "h": // heal, i.e. bedrest for 24+ hours healCharacters("d",days,"bedrest"); break; case "r": // rest, i.e. sleep for 8+ hours if (_.contains(params, "h")) { sendChat("Chronos","/w gm Cannot use 'h' and 'r' in the same command, using 'h'."); } else { if (days > 0) { healCharacters("d",days,"normal"); } else { healCharacters("h",hours,"normal"); }; }; break; case "t": // torches, i.e. track light source's fuel findLights(minutes); break; }; }; }; updateChronos(years,months,days,hours,minutes); }; }); on("change:graphic:bar1_value", function(obj) { if (obj.get("_pageid") == Campaign().get("playerpageid") && obj.get("_subtype") == "token" && obj.get("bar2_max") == "1" && obj.get("light_otherplayers") == true) { var maxValue = obj.get("bar1_max"); if (obj.get("bar1_value") > maxValue ) { obj.set({bar1_value: maxValue}); }; updateLights(obj,0); }; }); on("change:graphic:bar2_value", function(obj) { if (obj.get("_pageid") == Campaign().get("playerpageid") && obj.get("_subtype") == "token" && obj.get("bar2_max") == "1" && obj.get("light_otherplayers") == true) { if (obj.get("bar2_value") > 0 ) { if (obj.get("bar1_value") > 0) { obj.set({bar2_value: 1}); } else { obj.set({bar2_value: 0}) }; updateLights(obj,0); } else if (obj.get("bar2_value") <= 0 ) { obj.set({bar2_value: 0}); obj.set({light_radius: "",light_dimradius: ""}); }; }; });