Hello, here is a first draft, be advised that it don't make security checks for the character existance nor fill all the sheet. at the moment it only fill the 6 main attributes, create powercards and associated macros, it also add the trained skills (via the checkbox) it still a WIP version and it's quite far from being released (but i'm on vacation this week so it'll evolve fast i think.) And of course it's mainly HoneyBadger's Work so Kudos to him var AddPCAttribute = AddPCAttribute || {};
var AddPCPower = AddPCPower || {};
var AddPCPowerMacro = AddPCPowerMacro || {};
on("chat:message", function(msg) {
// Exit if not an api command
if (msg.type != "api") return;
// Get the API Chat Command
msg.who = msg.who.replace(" (GM)", "");
msg.content = msg.content.replace("(GM) ", "");
var command = msg.content.split(" ", 1);
if (command == "!build-character") {
if (!msg.selected) return;
var n = msg.content.split(" ", 2);
var Token = getObj("graphic", n[1])
if (Token.get("subtype") != "token") return;
if (Token.get("gmnotes").indexOf("D20Character") == -1) return;
// USER CONFIGURATION
var USE_POWER_CARDS = true;
// REPLACE SPECIAL CHARACTERS StatBlock = StatBlock.replace(//g, "");
var StatBlock = Token.get("gmnotes");
StatBlock = StatBlock.replace(/%20/g, " "); // Replace %20 with a space
StatBlock = StatBlock.replace(/%21/g, "!"); // Replace %21 with a !
StatBlock = StatBlock.replace(/%22/g, "'"); // Replace %22 (quotation) with '
StatBlock = StatBlock.replace(/%26amp/g, "&"); // Replace %26amp (ampersand) with &
StatBlock = StatBlock.replace(/%26apos/g, "'"); // Replace %26apos with '
StatBlock = StatBlock.replace(/%26lt/g, "<"); // Replace %26lt with <
StatBlock = StatBlock.replace(/%26gt/g, ">"); // Replace %26gt with >
StatBlock = StatBlock.replace(/%27/g, "'"); // Replace %27 with '
StatBlock = StatBlock.replace(/%28/g, "("); // Replace %28 with (
StatBlock = StatBlock.replace(/%29/g, ")"); // Replace %29 with )
StatBlock = StatBlock.replace(/%2C/g, ","); // Replace %2C with ,
StatBlock = StatBlock.replace(/%3A/g, ":"); // Replace %3A with :
StatBlock = StatBlock.replace(/%3B/g, ""); // Remove %3B (semi-colon)
StatBlock = StatBlock.replace(/%3Cbr/g, ""); // Remove carriage returns
StatBlock = StatBlock.replace(/%3D/g, "="); // Replace %3D with =
StatBlock = StatBlock.replace(/%3E/g, ""); // Remove %3E (???)
StatBlock = StatBlock.replace(/%3F/g, "?"); // Replace %3F with ?
StatBlock = StatBlock.replace(/\s{2,}/g, " "); // Replace multiple spaces with one space
StatBlock = StatBlock.replace(/%u2013/g, "-"); // Replace %u2013 with -
StatBlock = StatBlock.replace(/%u2019/g, "'"); // Replace %u2019 with '
// END SPECIAL CHARACTER REPLACEMENT or REMOVAL
// GET NAME OF CHARACTER
var CharacterName = StatBlock.match(/<name>(.*?)<\/name>/g)[0].split(">")[1].split("<", 1)[0].trim();
// CHECK FOR DUPLICATE CHARACTERS
var CheckSheet = findObjs({
_type: "character",
name: CharacterName
});
// CREATE CHARACTER SHEET & LINK TOKEN TO SHEET
var Character = createObj("character", {
name: CharacterName,
gmnotes: Token.get("gmnotes"),
archived: false
});
// CHARACTER LEVEL
var Level = parseInt(StatBlock.match(/<Level>(.*?)<\/Level>/g)[0].match(/\d+/g)[0]);
// ABILITY SCORE MODS, SKILLS, HP, & MORE
var Stats = StatBlock.match(/<Stat value=(.*?)\/>/g);
log (Stats);
var Skills = {};
var SkillTraining = {};
var s = 0;
while (s < Stats.length) {
// ABILITY SCORE
if (Stats[s].indexOf("'Constitution'") != -1) var CONValue = parseInt(Stats[s].match(/\d+/g)[0]);
if (Stats[s].indexOf("'Strength'") != -1) var STRValue = parseInt(Stats[s].match(/\d+/g)[0]);
if (Stats[s].indexOf("'Dexterity'") != -1) var DEXValue = parseInt(Stats[s].match(/\d+/g)[0]);
if (Stats[s].indexOf("'Intelligence'") != -1) var INTValue = parseInt(Stats[s].match(/\d+/g)[0]);
if (Stats[s].indexOf("'Wisdom'") != -1) var WISValue = parseInt(Stats[s].match(/\d+/g)[0]);
if (Stats[s].indexOf("'Charisma'") != -1) var CHAValue = parseInt(Stats[s].match(/\d+/g)[0]);
// HIT POINTS & SURGES
if (Stats[s].indexOf("'Hit Points'") != -1) var HitPoints = parseInt(Stats[s].match(/\d+/g)[0]);
if (Stats[s].indexOf("'Healing Surges'") != -1) var HealingSurges = parseInt(Stats[s].match(/\d+/g)[0]);
// SKILLS
if (Stats[s].indexOf("'Acrobatics'") != -1) Skills["acrobatics"] = parseInt(Stats[s].match(/\d+/g)[0]);
if (Stats[s].indexOf("'Arcana'") != -1) Skills["arcana"] = parseInt(Stats[s].match(/\d+/g)[0]);
if (Stats[s].indexOf("'Athletics'") != -1) Skills["athletics"] = parseInt(Stats[s].match(/\d+/g)[0]);
if (Stats[s].indexOf("'Bluff'") != -1) Skills["bluff"] = parseInt(Stats[s].match(/\d+/g)[0]);
if (Stats[s].indexOf("'Diplomacy'") != -1) Skills["diplomacy"] = parseInt(Stats[s].match(/\d+/g)[0]);
if (Stats[s].indexOf("'Dungeoneering'") != -1) Skills["dungeoneering"] = parseInt(Stats[s].match(/\d+/g)[0]);
if (Stats[s].indexOf("'Endurance'") != -1) Skills["endurance"] = parseInt(Stats[s].match(/\d+/g)[0]);
if (Stats[s].indexOf("'History'") != -1) Skills["history"] = parseInt(Stats[s].match(/\d+/g)[0]);
if (Stats[s].indexOf("'Heal'") != -1) Skills["heal"] = parseInt(Stats[s].match(/\d+/g)[0]);
if (Stats[s].indexOf("'Insight'") != -1) Skills["insight"] = parseInt(Stats[s].match(/\d+/g)[0]);
if (Stats[s].indexOf("'Intimidate'") != -1) Skills["intimidate"] = parseInt(Stats[s].match(/\d+/g)[0]);
if (Stats[s].indexOf("'Nature'") != -1) Skills["nature"] = parseInt(Stats[s].match(/\d+/g)[0]);
if (Stats[s].indexOf("'Perception'") != -1) Skills["perception"] = parseInt(Stats[s].match(/\d+/g)[0]);
if (Stats[s].indexOf("'Religion'") != -1) Skills["religion"] = parseInt(Stats[s].match(/\d+/g)[0]);
if (Stats[s].indexOf("'Stealth'") != -1) Skills["stealth"] = parseInt(Stats[s].match(/\d+/g)[0]);
if (Stats[s].indexOf("'Streetwise'") != -1) Skills["streetwise"] = parseInt(Stats[s].match(/\d+/g)[0]);
if (Stats[s].indexOf("'Thievery'") != -1) Skills["thievery"] = parseInt(Stats[s].match(/\d+/g)[0]);
// SKILL TRAINING
if (Stats[s].indexOf("'Acrobatics Trained'") != -1) SkillTraining["acrobatics"] = parseInt(Stats[s].match(/\d+/g)[0]);
if (Stats[s].indexOf("'Arcana Trained'") != -1) SkillTraining["arcana"] = parseInt(Stats[s].match(/\d+/g)[0]);
if (Stats[s].indexOf("'Athletics Trained'") != -1) SkillTraining["athletics"] = parseInt(Stats[s].match(/\d+/g)[0]);
if (Stats[s].indexOf("'Bluff Trained'") != -1) SkillTraining["bluff"] = parseInt(Stats[s].match(/\d+/g)[0]);
if (Stats[s].indexOf("'Diplomacy Trained'") != -1) SkillTraining["diplomacy"] = parseInt(Stats[s].match(/\d+/g)[0]);
if (Stats[s].indexOf("'Dungeoneering Trained'") != -1) SkillTraining["dungeoneering"] = parseInt(Stats[s].match(/\d+/g)[0]);
if (Stats[s].indexOf("'Endurance Trained'") != -1) SkillTraining["endurance"] = parseInt(Stats[s].match(/\d+/g)[0]);
if (Stats[s].indexOf("'History Trained'") != -1) SkillTraining["history"] = parseInt(Stats[s].match(/\d+/g)[0]);
if (Stats[s].indexOf("'Heal Trained'") != -1) SkillTraining["heal"] = parseInt(Stats[s].match(/\d+/g)[0]);
if (Stats[s].indexOf("'Insight Trained'") != -1) SkillTraining["insight"] = parseInt(Stats[s].match(/\d+/g)[0]);
if (Stats[s].indexOf("'Intimidate Trained'") != -1) SkillTraining["intimidate"] = parseInt(Stats[s].match(/\d+/g)[0]);
if (Stats[s].indexOf("'Nature Trained'") != -1) SkillTraining["nature"] = parseInt(Stats[s].match(/\d+/g)[0]);
if (Stats[s].indexOf("'Perception Trained'") != -1) SkillTraining["perception"] = parseInt(Stats[s].match(/\d+/g)[0]);
if (Stats[s].indexOf("'Religion Trained'") != -1) SkillTraining["religion"] = parseInt(Stats[s].match(/\d+/g)[0]);
if (Stats[s].indexOf("'Stealth Trained'") != -1) SkillTraining["stealth"] = parseInt(Stats[s].match(/\d+/g)[0]);
if (Stats[s].indexOf("'Streetwise Trained'") != -1) SkillTraining["streetwise"] = parseInt(Stats[s].match(/\d+/g)[0]);
if (Stats[s].indexOf("'Thievery Trained'") != -1) SkillTraining["thievery"] = parseInt(Stats[s].match(/\d+/g)[0]);
// SPEED
if (Stats[s].indexOf("'Speed'") != -1) var Speed = parseInt(Stats[s].match(/\d+/g)[0]);
s++;
}
// ADD ATTRIBUTES TO SHEET (Non-character sheet version)
AddPCAttribute("level", Level, Character.id);
var HitPointsID = AddPCAttribute("hp", HitPoints, Character.id).id;
var SurgesID = AddPCAttribute("surges", HealingSurges, Character.id).id;
AddPCAttribute("surge-value", Math.floor(HitPoints/4), Character.id);
AddPCAttribute("strength", STRValue, Character.id);
AddPCAttribute("constitution", CONValue, Character.id);
AddPCAttribute("dexterity", DEXValue, Character.id);
AddPCAttribute("intelligence", INTValue, Character.id);
AddPCAttribute("wisdom", WISValue, Character.id);
AddPCAttribute("charisma", CHAValue, Character.id);
AddPCAttribute("speed", Speed, Character.id);
// SET TOKEN SETTINGS
Token.set("represents", Character.id);
Token.set("name", CharacterName);
Token.set("showplayers_name", true);
Token.set("bar2_link", SurgesID);
Token.set("bar3_link", HitPointsID);
Token.set("showplayers_bar3", true);
Token.set("aura2_radius", "0");
Token.set("aura2_color", "#14A70A");
Token.set("aura2_square", true);
var SkillList = ["acrobatics", "arcana", "athletics", "bluff", "diplomacy", "dungeoneering", "endurance", "heal", "history", "insight", "intimidate", "nature", "perception", "religion", "stealth", "streetwise", "thievery"];
var s = 0;
while (s < SkillList.length) {
if (SkillTraining[SkillList[s]] !=0) AddPCAttribute(SkillList[s]+ "-trained",1,Character.id);
s++
}
AddPCPowerMacro("█▓▒░POWERS░▒▓█", "", Character.id, true);
var PowersBlock = StatBlock.match(/<Power name=(.*?)<\/Power>/g);
var p = 0;
while (p < PowersBlock.length) {
// DEFINE VARIABLES
var Power = {};
var Key = "";
var Content = "";
var PowerName = PowersBlock[p].match(/<Power name='(.*?)' >/g)[0].split("='")[1].split("' ")[0];
var AtkBonus = (PowersBlock[p].match(/<AttackBonus>(.*?)<\/AttackBonus>/g) != null) ? PowersBlock[p].match(/<AttackBonus>(.*?)<\/AttackBonus>/g)[0].match(/\d+/g)[0] : "0";
var DmgRoll = (PowersBlock[p].match(/<Damage>(.*?)<\/Damage>/g) != null) ? PowersBlock[p].match(/<Damage>(.*?)<\/Damage>/g)[0].split(">")[1].split("</")[0] : "";
var DmgType = (PowersBlock[p].match(/<DamageType>(.*?)<\/DamageType>/g) != null) ? PowersBlock[p].match(/<DamageType>(.*?)<\/DamageType>/g)[0].split(">")[1].split("</")[0] : "";
// REMOVE EMPTY ENTRIES TO PREVENT ERRORS
PowersBlock[p] = PowersBlock[p].replace("<specific name='Keywords' />", "");
PowersBlock[p] = PowersBlock[p].replace("<specific name='Keywords'/>", "");
PowersBlock[p] = PowersBlock[p].replace("<specific name='Level' />", "");
PowersBlock[p] = PowersBlock[p].replace("<specific name='Level'/>", "");
PowersBlock[p] = PowersBlock[p].replace("<specific name='Attack Type' />", "");
PowersBlock[p] = PowersBlock[p].replace("<specific name='Attack Type'/>", "");
PowersBlock[p] = PowersBlock[p].replace("<table>", "");
PowersBlock[p] = PowersBlock[p].replace("</table>", "");
// PARSE POWER INFORMATION
var PowerInfo = PowersBlock[p].match(/<specific name=(.*?)<\/specific>/g);
var i = 0;
var HitCount = 1;
while (i < PowerInfo.length) {
Key = PowerInfo[i].match(/='(.*?)' >/g)[0].split("='")[1].split("' >")[0];
Content = PowerInfo[i].split(" > ")[1].split(" </")[0].split("Level")[0];
// CHECK FOR DUPLICATE HIT ENTRIES - MOST OFTEN FOUND ON POWERS
// WITH SECONDARY/TERTIARY TARGETS &/OR ATTACKS
if (Key == "Hit" && Power["Hit"] != undefined) {
HitCount++;
Key = "Hit" + HitCount;
}
Power[Key] = Content;
i++;
}
// CHECK FOR MULTIPLE ATTACK POWERS
var MultiAttack = "";
if (Power["Target"] != undefined) {
switch (Power["Target"]) {
case "One ally":
case "One creature":
case "One enemy":
case "Same as primary target":
case "The triggering ally":
case "The triggering creature":
case "The triggering enemy":
case "The triggering ally in the burst":
case "The triggering creature in the burst":
case "The triggering enemy in the burst":
case "One ally adjacent to you":
case "One creature adjacent to you":
case "One enemy adjacent to you":
MultiAttack = "";
break;
default: MultiAttack = "?{Number of Targets|1}";
}
}
var c = p+1
// BUILD POWERSTRING
PowerString = "!power --name|@{power-" + c + "-name}";
PowerString += (Power["Display"] != undefined) ? " --title|" + Power["Display"] : "";
PowerString += (Power["Power Usage"] != undefined) ? " --format|@{power-" + c + "-useage} --leftsub|" + Power["Power Usage"] : "";
PowerString += (Power["Action Type"] != undefined) ? " --rightsub|" + Power["Action Type"] : "";
PowerString += (Power["Flavor"] != undefined) ? " --emote|" + Power["Flavor"] : "";
PowerString += (Power["Attack Type"] != undefined) ? " --Range|" + Power["Attack Type"] : "";
PowerString += (Power["Trigger"] != undefined) ? " --Trigger|" + Power["Trigger"] : "";
PowerString += (Power["Requirement"] != undefined) ? " --Requirement|" + Power["Requirement"] : "";
PowerString += (Power["Target"] != undefined) ? " --Target(s)|" + Power["Target"] : "";
PowerString += (Power["Attack"] != undefined) ? " --attack" + MultiAttack + "|[[1d20 + " + AtkBonus + "]]" : "";
PowerString += (Power["Attack"] != undefined) ? " --defense|" + Power["Attack"].split("vs.")[1] : "";
PowerString += (Power["Primary Target"] != undefined) ? " --Primary Target|" + Power["Primary Target"] : "";
PowerString += (Power["Primary Attack"] != undefined) ? " --Primary Attack|[[1d20 + " + AtkBonus + "]] vs " + Power["Primary Attack"].split("vs.")[1] : "";
PowerString += (Power["Hit"] != undefined && isNaN(Power["Hit"].charAt(0)) == true) ? " --On Hit|" + Power["Hit"] : "";
PowerString += (Power["Hit"] != undefined && isNaN(Power["Hit"].charAt(0)) == false) ? " --damage|[[" + DmgRoll + "]] " + DmgType.toLowerCase() + " " + Power["Hit"].substring(Power["Hit"].indexOf("damage")) : "";
PowerString += (Power["Secondary Target"] != undefined) ? " --^Secondary Target|" + Power["Secondary Target"] : "";
PowerString += (Power["Secondary Attack"] != undefined) ? " --^Secondary Attack|[[1d20 + " + AtkBonus + "]] vs " + Power["Secondary Attack"].split("vs.")[1] : "";
PowerString += (Power["Hit2"] != undefined && isNaN(Power["Hit2"].charAt(0)) == true) ? " --^Secondary Hit|" + Power["Hit2"] : "";
PowerString += (Power["Hit2"] != undefined && isNaN(Power["Hit2"].charAt(0)) == false) ? " --^Secondary Hit|[[" + DmgRoll + "]] " + DmgType.toLowerCase() + " " + Power["Hit2"].substring(Power["Hit2"].indexOf("damage")) : "";
PowerString += (Power["Tertiary Target"] != undefined) ? " --^2Tertiary Target|" + Power["Tertiary Target"] : "";
PowerString += (Power["Tertiary Attack"] != undefined) ? " --^2Tertiary Attack|[[1d20 + " + AtkBonus + "]] vs " + Power["Tertiary Attack"].split("vs.")[1] : "";
PowerString += (Power["Hit3"] != undefined && isNaN(Power["Hit3"].charAt(0)) == true) ? " --^2Tertiary Hit|" + Power["Hit3"] : "";
PowerString += (Power["Hit3"] != undefined && isNaN(Power["Hit3"].charAt(0)) == false) ? " --^2Tertiary Hit|[[" + DmgRoll + "]] " + DmgType.toLowerCase() + " " + Power["Hit3"].substring(Power["Hit3"].indexOf("damage")) : "";
PowerString += (Power["Miss"] != undefined) ? " --Miss|" + Power["Miss"] : "";
PowerString += (Power["Effect"] != undefined) ? " --Effect|" + Power["Effect"] : "";
PowerString += (Power[""] != undefined) ? " --Range|" + Power[""] : "";
AddPCPowerMacro(PowerName, "@{power-" + c + "-macro}", CheckSheet.id, true, p);
AddPCPower("power-" + c + "-name", PowerName, CheckSheet.id);
AddPCPower("power-" + c + "-useage", Power["Power Usage"], CheckSheet.id);
AddPCPower("power-" + c + "-macro", PowerString, CheckSheet.id);
AddPCPower("power-" + c + "-toggle", "on", CheckSheet.id);
p++;
}
}
});
function AddPCAttribute (attr, value, charid) {
var attrid = "";
if (attr === "hp") {
attrid = createObj("attribute", {
name: attr,
current: value,
max: value,
characterid: charid
});
} else {
attrid = createObj("attribute", {
name: attr,
current: value,
characterid: charid
});
}
return attrid;
}
function AddPCPowerMacro (powername, powerstring, charid, tokenaction) {
createObj("ability", {
name: powername,
description: "",
action: powerstring,
istokenaction: tokenaction,
characterid: charid
});
}
function AddPCPower (attr, value, charid) {
var attrid = "";
attrid = createObj("attribute", {
name: attr,
current: value,
characterid: charid
});
return attrid;
}