Skip to content

Instantly share code, notes, and snippets.

@SteveKoontz
Last active June 21, 2017 17:09
Show Gist options
  • Save SteveKoontz/6953050 to your computer and use it in GitHub Desktop.
Save SteveKoontz/6953050 to your computer and use it in GitHub Desktop.
roll20.net World of Darkness God Machine Chronicle Scripts
// WoD Damage/Status Tracker v1.2
// Bashing, Lethal, and Aggrivated damage are marked on the selected token
// The 'API' commands are, "!b", "!l", "!a" respectively.
// I.E. "!b 3" would put 3 bashing on the token.
// If there is a character attached to the token and it has the attirbutes 'Bashing','Lethal','Aggrivated','Health','Vitae'
// then the script will record and update the sheet as well as automatically applying a wound penalty status icon.
// The status icons being used are Bashing = 'fist', Lethal = 'skull', Aggrivated = 'chemical-bolt', Wounded = 'pummeled'
on('chat:message', function(msg) {
if(msg.type != 'api') return;
var parts = msg.content.toLowerCase().split(' ');
var command = parts.shift().substring(1);
var selected = msg.selected;
if(!selected) return; // have one or more things selected
var damage = +parts[0];
if(!damage) damage = 0; // if no damage is returned, treat as 0
_.each(selected, function(obj) {
if(obj._type != 'graphic') return; // only damage graphics
var tok = getObj("graphic", obj._id);
if(tok.get('subtype') != 'token') return; // don't try to damage cards
var oCharacter = getObj("character", tok.get("represents"));
if (oCharacter != undefined ) {
oBashing = findObjs({name: "Bashing",_type: "attribute", _characterid: oCharacter.id}, {caseInsensitive: true})[0];
oLethal = findObjs({name: "Lethal",_type: "attribute", _characterid: oCharacter.id}, {caseInsensitive: true})[0];
oAggrivated = findObjs({name: "Aggrivated",_type: "attribute", _characterid: oCharacter.id}, {caseInsensitive: true})[0];
oHealth = findObjs({name: "Health",_type: "attribute", _characterid: oCharacter.id}, {caseInsensitive: true})[0];
oVitae = findObjs({name: "Vitae",_type: "attribute", _characterid: oCharacter.id}, {caseInsensitive: true})[0];
if (command == 'b') var oDmg = oBashing
else if (command == 'l') var oDmg = oLethal
else if (command == 'a') var oDmg = oAggrivated
}
if (oDmg != undefined ) {
oDmg.set('current', damage);
if (oBashing != undefined && oLethal != undefined && oAggrivated != undefined && oHealth != undefined) {
Clear_Status(tok);
Status_wSheet(tok,oBashing,oLethal,oAggrivated,oHealth,oVitae)}; }
else {Status_woSheet(tok,command,damage) }
});
});
// Update changes from sheet on token update
on('change:token', function(tok) {
var oCharacter = getObj("character", tok.get("represents"));
if (oCharacter != undefined ) {
oBashing = findObjs({name: "Bashing",_type: "attribute", _characterid: oCharacter.id}, {caseInsensitive: true})[0];
oLethal = findObjs({name: "Lethal",_type: "attribute", _characterid: oCharacter.id}, {caseInsensitive: true})[0];
oAggrivated = findObjs({name: "Aggrivated",_type: "attribute", _characterid: oCharacter.id}, {caseInsensitive: true})[0];
oHealth = findObjs({name: "Health",_type: "attribute", _characterid: oCharacter.id}, {caseInsensitive: true})[0];
oVitae = findObjs({name: "Vitae",_type: "attribute", _characterid: oCharacter.id}, {caseInsensitive: true})[0]; }
if (oBashing != undefined && oLethal != undefined && oAggrivated != undefined && oHealth != undefined) {
Clear_Status(tok);
Status_wSheet(tok,oBashing,oLethal,oAggrivated,oHealth,oVitae)}
else {Status_woSheet(tok) };
});
// Apply Status for a token assigned to a functional Character Sheet
function Status_wSheet(tok,oBashing,oLethal,oAggrivated,oHealth,oVitae) {
// Check if Hungry or Starving
if (oVitae != undefined ) {
if (oVitae.get('current') <= 0) {tok.set('status_half-heart', '2')}
else if (oVitae.get('current') <= 4) {tok.set('status_half-heart', '1')} };
// Check for Wound Penalties
var oEffHealth = parseInt((oHealth.get('current')),10) - (parseInt((oBashing.get('current')),10) + parseInt((oLethal.get('current')),10) + parseInt((oAggrivated.get('current')),10))
var oCrtHealth = parseInt((oHealth.get('current')),10) - (parseInt((oLethal.get('current')),10) + parseInt((oAggrivated.get('current')),10))
if(oCrtHealth <= 0) {tok.set('status_dead', true)}
else if(oEffHealth == 2) {tok.set('status_pummeled', '1');}
else if(oEffHealth == 1) {tok.set('status_pummeled', '2');}
else if(oEffHealth <= 0) {tok.set('status_pummeled', '3');};
// Set Damage in correct order
if (oBashing.get('current') > 0) {Apply_Damage(tok,oBashing.get('current'),'fist')};
if (oLethal.get('current') > 0) {Apply_Damage(tok,oLethal.get('current'),'skull')};
if (oAggrivated.get('current') > 0) {Apply_Damage(tok,oAggrivated.get('current'),'chemical-bolt')};
}
// Apply Status for a token without a Character Sheet
function Status_woSheet(tok,command,damage) {
if (command == 'b') {tok.set('status_fist', false);
Apply_Damage(tok,damage,'fist')}
else if (command == 'l') {tok.set('status_skull', false);
Apply_Damage(tok,damage,'skull')}
else if (command == 'a') {tok.set('status_chemical-bolt', false);
Apply_Damage(tok,damage,'chemical-bolt')};
}
function Clear_Status(tok) {
tok.set('status_fist', false);
tok.set('status_skull', false);
tok.set('status_chemical-bolt', false);
tok.set('status_pummeled', false);
tok.set('status_red', false);
tok.set('status_half-heart', false);
tok.set('status_dead', false);
}
function Apply_Damage(tok,damage,icontype) {
var dmgicon = '';
while(damage > 0)
{
// get current digit, starting from ones
var digit = damage / 10;
digit -= Math.floor(digit);
digit = Math.round(digit * 10);
// shift damage
damage = Math.floor(damage / 10);
dmgicon += icontype+'@'+digit+',';
}
if(dmgicon.length > 0) dmgicon = dmgicon.substring(0, dmgicon.length - 1); // trim trailing comma
var markers = tok.get('statusmarkers');
if(markers != '') markers += ',';
markers += dmgicon;
tok.set('statusmarkers', markers);
}
// WoD Auto Sheet v1.0
// The sheet is using the latest God Machine and Strix Chronciles rules and attributes.
// The script is called by the 'API' command of !sheet (Character Name) (template type).
// I.E. "!sheet Testy McTesterson vampire"
// The command only works on pre-existing characters created in the journal.
// I've only created two templates (mortal,vampire)
attributes = [
'Intelligence','Wits','Resolve',
'Strength','Dexterity','Stamina',
'Presence','Manipulation','Composure'
];
skills_mental = [
'Academics','Computer','Crafts','Investigation','Medicine','Occult','Politics','Science'
]
skills_other = [
'Athletics','Brawl','Drive','Firearms','Larceny','Stealth','Survival','Weaponry',
'Animal Ken','Empathy','Expression','Intimidation','Persuasion','Socialize','Streetwise','Subterfuge'
]
other = [
'Health','Bashing','Lethal','Aggrivated','Willpower','Size','Speed','Defense','Initiative','Armor','Armor-Balistic','Fast Reflexes'
]
mortal = [
'Virtue','Vice','Concept','Integrity'
]
vampire = [
'Mask','Dirge','Concept','Clan','Bloodline','Covenant','Humanity','Blood Potency','Vitae'
]
disciplines = [
'Animalism','Auspex','Celerity','Dominate','Majesty','Nightmare','Obfuscate','Protean','Resilience','Vigor'
]
on('chat:message', function(msg) {
if(msg.type != 'api') return;
var oParts = msg.content.toLowerCase().split(' ');
var oCommand = oParts.shift().substring(1);
if(oCommand != 'sheet') return; //Confirms the message used the '!sheet' command
var oTemplate = oParts.pop(); //Pulls the template setting from the API command
if (oParts.length > 0) {
oCharName = oParts[0]; // Recombine the name if it's more than one word
for (i=1; i<oParts.length; i++) {
oCharName = oCharName + ' ' + oParts[i];}
}
else {oCharName = oParts};
if(!oCharName) {
sendChat('System', 'Error: No character name given'); //Returns an error if no character name was chosen
return;};
var oChar = findObjs({name: oCharName, _type: 'character'}, {caseInsensitive: true})[0]; //Finds the character object
if(oChar == undefined) {
sendChat('System', 'Error: No character by the name of ' + oCharName + ' found.');
return;};
if (oTemplate == undefined || oTemplate == 'mortal') { //Checks which template of stats you want to add
CheckAddAttr(oChar,mortal,'','');}
else if (oTemplate == 'vampire') {
CheckAddAttr(oChar,vampire,'','');}
else {sendChat('System', 'Error: Invalid Template ' + oTemplate);
return;}
CheckAddAttr(oChar,attributes,'1','5'); // Add Attributes to character sheet
CheckAddAttr(oChar,skills_mental,'-3','5'); // Add Mental skills to character sheet
CheckAddAttr(oChar,skills_other,'-1','5'); // Add Physical and Social skills to character sheet
CheckAddAttr(oChar,other,'0',''); // Add Other Traits to character sheet
if (oTemplate == 'vampire') {
CheckAddAttr(oChar,disciplines,'0','5');} // Add disciplines to the vampire template
CheckAddAbil(oChar,'Chance','/r {1d10!}>10'); // Adding macros of useful rolls to character sheet.
CheckAddAbil(oChar,'Normal-Roll','/r {?{Number of Dice to Roll}d10!}>8');
CheckAddAbil(oChar,'9-Again-Roll','/r {?{Number of Dice to Roll}d10!>9}>8');
CheckAddAbil(oChar,'8-Again-Roll','/r {?{Number of Dice to Roll}d10!>8}>8');
CheckAddAbil(oChar,'Initiative','/em @{selected|token_name} rolls initiative.\n/r 1d10+@{selected|Initiative}+@{selected|Fast Reflexes}-?{Weapon Initiative Penalty|0} &{tracker}');
CheckAddAbil(oChar,'Perception','/me rolls for Perception.\n/r {(@{Wits}+@{Composure}+@{Auspex}+?{Modifier|0})d10!}>8');
if (oTemplate == 'vampire') {CheckAddAbil(oChar,'Full-Dodge','/me full dodges!\n/r {(((@{Defense}+@{Celerity})*2)+?{Modifier|0})d10!}>8');}
else {CheckAddAbil(oChar,'Full-Dodge','/me full dodges!\n/r {((@{Defense}*2)+?{Modifier|0})d10!}>8');};
if (oTemplate == 'vampire') {
CheckAddAbil(oChar,'Will/Degeneration/Frenzy','/me makes a will check.\n/r {(@{Resolve}+@{Composure}+?{Modifier|0})d10!}>8');}
else {CheckAddAbil(oChar,'Will-Check','/me makes a will check.\n/r {(@{Resolve}+@{Composure}+?{Modifier|0})d10!}>8');}
sendChat('System', 'You have successfully added the ' + oTemplate + ' template to ' + oCharName + '.');
});
function CheckAddAttr(oChar, oNames, oCur, oMax) {
_.each(oNames, function(oName){
var oAttrChk = findObjs({_type: 'attribute', _characterid: oChar.id, name: oName})[0];
if (oAttrChk == undefined) {createObj('attribute', {name: oName, current: oCur, max: oMax, characterid: oChar.id}) };
});
}
function CheckAddAbil(oChar, oNames, oAction) {
var oAbilChk = findObjs({_type: 'ability', _characterid: oChar.id, name: oNames})[0];
if (oAbilChk == undefined) {createObj('ability', {name: oNames, characterid: oChar.id, action: oAction}) };
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment