Try this script below. It's what I use as part of my combat efficiency. It allows for a few more options, and uses the API for dice rolls which is more efficient. Note: You need to unlink journal HP from the Token otherwise all tokens of the same type will share hitpoints. This is very beta, but it's been working nicely for me. Feel free to report any issues. var CM = CM || {};
CM.CAMPAIGN_MANAGER_VERSION = ".3 BETA";
/*
Commands:
!CM range = Find range between two selected tokens.
!CM kill = Kill the selected tokens.
!CM rollhp = Roll hitpoints for selected tokens.
!CM xp = Find total XP for selected tokens.
*/
/*
Setup:
Commands require the following attributes and abilities:
(It is easiest to add these to a NPC Template journal entry, and then
simply duplicate that journal entry whenever adding a new NPC.)
The following ability must exist to identify NPC MOBS: "CMIsMOBYES"
(This keeps the game from rolling new HP for a player, if you accidentally
select one.)
The following attributes must exist for HP rolls:
HPDieNum = Number of dice to be rolled
HPDieSides = Number of sides on each die
HPBonus = Bonus to be added after roll completed
The following attributes must exist for XP rolls:
XP = The number of experience points one of these mobs is worth
Hitpoints will be rolled and added to Bar 2 Value. It is intended that Bar 2
NOT be attached to the HP value on the journal entry so that each selected
MOB can have a different number of hitpoints, even if they are all linked
to the same entry.
*/
/*
Setup:
Other options:
*/
CM.LOG_ON = true; //Default is true
CM.PUBLIC_MESSAGES = true; //Default is true
on("chat:message", function (msg) {
var response = "";
if (msg.type=="api") {
response = CM.ChatParse(msg);
sendChat("CampaignManager",response);
}
});
CM.Log = function (logtext) {
if (CM.LOG_ON) log(logtext);
return;
}
CM.Chat = function (chattext) {
if (CM.PUBLIC_MESSAGES) sendChat("CampaignManager", chattext);
return;
}
CM.IsGM = function (msg){
if (CM.GM_CHAT_TAG == msg.who) return true;
return false;
}
CM.AttributeValue = function (attributename,token) {
if (token.get('represents') !== "") {
var charid=token.get('represents');
} else {
return false; //It doesn't have a journal so it can't have the attribute.
}
var obj = findObjs({
_characterid: charid,
_type: "attribute",
name: attributename,
}, {
caseInsensitive: true
}); // End findObjs
var value=-1;
if (obj.length != 1) {
return false;
} else {
_.each(obj, function(attribute) {
value = attribute.get("current");
});
return Number(value);
} //End if more than 1 attribute found
}
CM.HasAbility = function (abilityname, token) {
if (token.get('represents') !== "") {
var charid=token.get('represents');
} else {
return false; //It doesn't have a journal so it can't have the ability.
}
var foundabilities = findObjs({
_characterid: charid,
_type: "ability",
name: abilityname,
}, {
caseInsensitive: true
}); // End findObjs
if (foundabilities.length == 0) {
return false;
} else {
return true;
}; //End isnull localabilties
};
CM.Roll = function(rolls,die)
{
roll=0;
for (x=0;x<rolls;x++) {
this_roll=randomInteger(die);
roll += this_roll;
} //End die roll FOR loop
return roll;
}
CM.ChatParse = function(msg) {
if (msg.type !== "api") return; //Ignore any message that isn't an API call (Starts with !)
var message = msg.content;
message = message.trim();
message = message.toLowerCase();
if (!(message.indexOf("!cm") == 0)) return; //We only listen for commands that start with CM
message_from_gm = CM.IsGM(msg);
message = message.substr(4,message.length-4);
var response_text = "/w " + msg.who + " ";
response_text = response_text.replace(" (GM)","");
var token = new Array();
//Now we setup selected tokens as a lot of commands require tokens selected
var counter=0;
_.each(msg.selected, function (obj) {
if (obj._type == 'graphic') {
token[counter] = getObj('graphic', obj._id);
counter++;
}
});
var selected_objects = counter;
switch (message) {
case "range":
if (selected_objects!=2) {
response_text += "Please select two tokens for a range calculation.";
} else {
response_text += "The range from " + token[0].get("name") + " to " + token[1].get("name") + " is " + CM.TokenRange(token[0],token[1]);
}
break;
case "rollhp":
var selectedObjs = msg.selected;
response_text += "HP Rolls: ";
_.each(selectedObjs, function (obj) {
if (obj._type == 'graphic') {
var token = getObj('graphic', obj._id);
if (CM.HasAbility("CMIsMOBYES",token)) {
var die_num = CM.AttributeValue("HPDieNum", token);
var die_sides = CM.AttributeValue("HPDieSides", token);
var hp = 0;
hp += CM.Roll(die_num,die_sides);
hp += CM.AttributeValue("HPBonus",token);
response_text += hp + ",";
token.set("bar2_value",hp);
token.set("bar2_max",hp);
//Now set the default view permissions so the players can see what we want them to.
token.set("showplayers_bar1",false);
token.set("showplayers_bar2",true);
token.set("showplayers_bar3",true);
} //End CMIsMOBYES
} //End if Graphic
});// End each SelectedObjs
break;
case "kill":
var selectedObjs = msg.selected;
response_text += "HP Zeroed: ";
_.each(selectedObjs, function (obj) {
if (obj._type == 'graphic') {
var token = getObj('graphic', obj._id);
if (CM.HasAbility("CMIsMOBYES",token)) {
response_text += 0 + ",";
token.set("bar2_value","");
token.set("bar2_max","");
token.set("status_dead",true);
} //End CMIsMOBYES
} //End if Graphic
});// End each SelectedObjs
break;
case "xp":
var selectedObjs = msg.selected;
response_text += "XP Total: ";
var xp = 0;
_.each(selectedObjs, function (obj) {
if (obj._type == 'graphic') {
var token = getObj('graphic', obj._id);
if (CM.HasAbility("CMIsMOBYES",token)) {
xp += CM.AttributeValue("XP",token);
} //End CMIsMOBYES
} //End if Graphic
});// End each SelectedObjs
response_text += xp;
break;
default:
response_text += "Command not understood.";
}//End switch content
return response_text;
}
CM.TokenRange = function (token1,token2)
{
var page=getObj("page", token1.get("_pageid"));
var scale=page.get("scale_number");
var scale_unit=page.get("scale_units");
var range=CM.GetDistance(token1.get('left'),token1.get('top'),token2.get('left'),token2.get('top'));
range = range - (( ((token1.get("width")+token1.get("height"))/2) + ((token2.get("width")+token2.get("height"))/2) )/2);
range=range / (70 / scale);
range=range*100;
range=Math.round(range);
range=range/100;
var range_txt=range + " " + scale_unit;
return range_txt;
}
CM.GetDistance = function (x1, y1, x2, y2) {
var dist = 0;
dist = Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2));
return dist;
};