Skip to content

Instantly share code, notes, and snippets.

@birdbrainiac
Forked from fmonaca/turncounter
Created September 14, 2018 08:35
Show Gist options
  • Save birdbrainiac/3c8c2122aa2545b8a78d58dcce31d027 to your computer and use it in GitHub Desktop.
Save birdbrainiac/3c8c2122aa2545b8a78d58dcce31d027 to your computer and use it in GitHub Desktop.
Turn Counter
/* --------------------------------------------------------------------------------------------------- */
// Initiative Script
//
// Usage: Select the tokens you want the initiative to be rolled for and use the command "!initiative"
// This command rolls a die of the type specified using the "initiativeDie" variable, adds
// the result to the attribute specified using the "initiativeAttribute" variable (for each
// token), then sorts the tokens by the total achieved (higher to lower) and puts them into
// the Turn Tracker. Use the command "!nextround" to move to the next round and increase the
// counter.
//
// Notes: Tokens must have a linked character sheet that contains the attribute used for the
// initiative (see variable "initiativeAttribute")
// You can add further tokens at any time selecting them and using the command "!addtokens"
// This will re-sort the list of tokens, so it is best used at the beginning o a Round.
// You can reset the round counter to 1 using the command "!restart"
// The command "!restart reroll" will reset the round counter to 1 and reroll for the tokens
// already present in the Turn Tracker, sorting them by their total score
// The script also visualizes the round counter on a token named "Round 1", if any, and if the
// variable useTokenCounter is set to true (default).
//
// Warning: Changing manually the order of the tokens in the Turn Tracker is possible (and the changes
// will be kept) but if the command "!nextround" is given while the "ROUND x" item is not the
// topmost item in the Turn Tracker, the order of the tokens in the next round will be different
// than the order chosen - it will be a "snapshot" of the Turn Tracker WITHOUT the "ROUND x" item:
//
// Having a Turn Order like this, manually adjusted:
//
// ROUND x
// Token 1
// Token 3
// Token 2
//
// Then cycling two times will show this:
//
// Token 3
// Token 2
// ROUND x
// Token 1
//
// Once you issue the !nextround command, the order of the tokens will be this one:
//
// ROUND x
// Token 3
// Token 2
// Token 1
//
// So if you manually adjusted the order of the tokens in the Turn Tracker ALWAYS have your
// "ROUND x" counter as the topmost item before using the !nextround command if you want to
// keep your custom order between rounds
/* --------------------------------------------------------------------------------------------------- */
var initiativeDie = 20; // Type of die to roll for initiative
var initiativeAttribute = "Initiative"; // Attribute to add to the roll. Change it to whatever attribute you use for initiative - i.e. Dex or Dexterity, etc.
var useTokenCounter = false; // Put it to true if you also want a token in the page to show Round number - it has to be named "Round 1".
var allowDuplicateTokens = false; // If set to true, a token can be added more than once in the Turn Tracker
state.iTurn = state.iTurn || 0;
state.turnOrder = state.turnOrder || {};
state.aChars = state.aChars || {};
var aChars;
var iTurn;
var turnorder;
var adding = false;
var duplicate = false;
on("ready", function() {
if(state.iTurn != 0)
{
aChars = state.aChars;
iTurn = state.iTurn;
if(iTurn == 0) iTurn = 1;
turnorder = state.turnOrder;
}
else
{
aChars = new Array();
iTurn = 1;
if(Campaign().get("turnorder") == "")
turnorder = [];
else
turnorder = JSON.parse(Campaign().get("turnorder"));
state.aChars = aChars;
state.iTurn = iTurn;
state.turnOrder = turnorder;
}
});
on("change:campaign:turnorder", function(obj) {
if(state.turnOrder!="")
{
var tempTO = JSON.parse(obj.get("turnorder")).shift();
if(tempTO != undefined)
if(tempTO.custom == "") // We have a token
{
var tempTok = getObj("graphic", tempTO.id);
sendPing(tempTok.get("left"), tempTok.get("top"), Campaign().get('playerpageid'), null, true);
}
}
});
on('chat:message', function(msg) {
var command = msg.content.toLowerCase();
if (msg.type == "api" && command == "!initiative"){
if(command == "!initiative"){
var selected = msg.selected;
aChars.length = 0;
createArray(selected, false);
if(aChars.length>0) {sendChat("GM", "/desc Combat begins!");}
else{sendChat("Script", "/w GM No tokens selected!");}
rollandsort(false);
}
if(iTurn != 1 && useTokenCounter) updateTurnToken(iTurn);
iTurn = 1;
fillTracker(iTurn);
}
if (msg.type == "api" && command.indexOf("!restart") >= 0){
currTurn = 1;
if(useTokenCounter) updateTurnToken(currTurn);
iTurn = 1;
if(command.split(" ").pop() == "reroll") rollandsort(false);
fillTracker(iTurn);
}
if (msg.type == "api" && command.indexOf("!addtokens") >= 0){
var selected = msg.selected;
adding = true;
createArray(selected, true);
if(duplicate)
{
sendChat("Initiative script", "/w gm Duplicate token detected.");
duplicate = false;
}
else
{
rollandsort(true);
fillTracker(iTurn);
}
adding = false;
}
if (msg.type == "api" && command.indexOf("!nextround") >= 0){
nextRound(iTurn);
}
});
function rollandsort(addtokens)
{
var dieRolled;
var chatMsg = "/direct Initiative rolled:<br>";
for (var a = 0; a < aChars.length; a++)
{
dieRolled = randomInteger(initiativeDie);
if(addtokens)
{
if(aChars[a][1] == "")
{
aChars[a][1] = aChars[a][2] + dieRolled;
chatMsg += aChars[a][3] + ": " + dieRolled + "<br>";
}
}
else
{
aChars[a][1] = aChars[a][2] + dieRolled;
chatMsg += aChars[a][3] + ": " + dieRolled + "<br>";
}
}
sendChat("GM", chatMsg);
aChars = aChars.sort(function(a,b) { // sorts characters by initiative
if (a[1] < b[1]) return 1;
if (a[1] > b[1]) return -1;
return 0;
});
state.aChars = aChars;
}
function updateTurnToken(currTurn)
{
if(iTurn==1) tokName = "Round 1";
else tokName = "Round " + (iTurn-1);
var curName = "Round " + currTurn;
oToken = findObjs({
_pageid: Campaign().get("playerpageid"),
_type: "graphic",
name: tokName,
});
if(oToken == "")
sendChat("Script", "/w GM No Round token present!");
else
oToken[0].set("name", curName);
}
function fillTracker(currTurn)
{
turnorder.length = 0;
if(aChars.length>0 && !adding)
{
sendChat("GM", "/desc Round " + currTurn + " begins!");
turnorder.push({
id: "-1",
pr: " ",
custom: "ROUND " + currTurn
});
}
if(adding)
{
var actualTurn = currTurn-1;
turnorder.push({
id: "-1",
pr: " ",
custom: "ROUND " + actualTurn,
});
}
for (var a = 0; a < aChars.length; a++)
{
turnorder.push({
id: aChars[a][0],
pr: aChars[a][1],
custom: ""
});
}
state.turnOrder = turnorder;
Campaign().set("turnorder", JSON.stringify(turnorder));
}
function createArray(ob, newtokens)
{
var nCount = 0;
if(newtokens)
nCount = aChars.length;
_.each(ob, function(obj)
{
if(!allowDuplicateTokens && newtokens)
{
if(JSON.stringify(aChars).indexOf(obj._id) >=0)
{
duplicate = true;
return;
}
}
if(obj._type != 'graphic') return;
var token = getObj("graphic", obj._id);
var oCharacter = getObj("character", token.get("represents"));
if (oCharacter != "")
{
aChars[nCount] = new Array(4);
aChars[nCount][0] = token.get('_id');
aChars[nCount][3] = token.get('name');
var oInitiative = findObjs({name: initiativeAttribute, _type: "attribute", _characterid: oCharacter.id}, {caseInsensitive: true})[0];
if (oInitiative)
{
aChars[nCount][1] = "";
aChars[nCount][2] = parseInt(oInitiative.get('current'));
}
else{sendChat("Initiative script", "/w gm No " + initiativeAttribute + " attribute for character " + token.get('name')); return;}
nCount++;
}
});
}
function deleteToken(currentTurnOrder)
{
for(var i=0;i<aChars.length;i++)
{
for(var a=0;a<currentTurnOrder.length;a++)
{
var found = false;
var curToken = currentTurnOrder.shift();
if(aChars[i][0] == curToken.id)
found = true;
}
if(!found)
aChars.splice(i,1);
}
state.aChars = aChars;
}
function saveTurnOrder()
{
var aTemp = new Array();
for(var t=0; t<turnorder.length;t++)
{
for(var a=0; a<aChars.length;a++)
{
if(turnorder[t].id == aChars[a][0])
{
aTemp[t] = new Array(4);
aTemp[t][0] = turnorder[t].id;
aTemp[t][1] = aChars[a][1];
aTemp[t][2] = aChars[a][2];
aTemp[t][3] = aChars[a][3];
}
}
}
aChars = aTemp.slice(0);
state.aChars = aChars;
}
function nextRound(round)
{
if(Campaign().get("turnorder") == "")
turnorder = state.turnOrder;
else
turnorder = JSON.parse(Campaign().get("turnorder"));
if(turnorder.length < aChars.length)
{
deleteToken(turnorder);
return;
}
if(round == 1) round++;
for(var n=0;n<turnorder.length;n++)
{
if(turnorder[n].id == "-1" && round > 1 && !adding)
{
sendChat("GM", "/desc Round " + round + " begins!");
turnorder.splice(n,1);
saveTurnOrder();
turnorder.unshift({
id: "-1",
pr: " ",
custom: "ROUND " + round
});
Campaign().set("turnorder", JSON.stringify(turnorder));
state.turnOrder = turnorder;
if(useTokenCounter) updateTurnToken(round);
round++;
state.iTurn = round;
iTurn = round;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment