OK, so where IS the latest version of this drop-in? I see a post of a .txt above and a copy/paste of code but not sure which one is the latest and some don't work quite right?
I've taken the 1.8 that was int the framework (latest!), which btw, also seems out of date with most of the drop-ins
I'm not complaining and love all the work, it's just taking me forever to cobble together the latest code everywhere for my new PF campaign...
Code:
<!-- Statblock2Token v1.9
Changes: HD fixed, Resets token, Skills with space in the name except SleightOfHand
Macro takes a Pathfinder statblock as input and updates selected token with various stats.
Macro assumes pathfinder properties in the selected token.
Statblock format should mirror PF bestiary format.
Not handled: SQ, Spells
-->
[H: ids = getSelected()]
[H: abort(if(ids == "", 0, 1))]
[H: status=input("statblock|Insert statblock here|Enter statblock|TEXT|WIDTH=40")]
[H: abort(if(status < 1, 0, 1))]
[H: setPropertyType("Pathfinder")]
[H: propnames = getPropertyNames()]
[H, foreach(propname,propnames),CODE:
{
[resetProperty(propname)]
}]
[H: setGMNotes(statblock)]
[H: output="Token Updated:<br>"]
[H: id = strfind(statblock, "^(.+).*CR ")]
[H, IF(0<getFindCount(id)),CODE:
{
[name=trim(getGroup(id, 1, 1))]
[output=output+"Name: "+name+", "]
[Race = json.set(Race, "name", name)]
[setName( name)]
}]
<!-- Setting ECL to CR from statblock. For CR 1/3 & 1/6 we will set it to .338 & .1625 so XP calcs correctly.-->
[H: id = strfind(statblock, "(?<=[ |\\t]CR )([1-9]+)(/[1-9]+)?")]
[H, IF(0<getFindCount(id)),CODE:
{
[ECL=trim(getGroup(id, 1, 0))]
[output=output+"CR: "+ECL+", "]
[IF(ECL == "1/3"),CODE:{
[ECL=".338"]
}]
[IF(ECL == "1/6"),CODE:{
[ECL=".1625"]
}]
[Levels = setStrProp(Levels, "ECL", ECL)]
}]
[H: id = strfind(statblock, "(Fine|Diminutive|Tiny|Small|Medium|Large|Huge|Gargantuan|Colossal).([a-zA-Z]+\\s?[a-zA-Z]*?)\\s?(\\((.+)\\))?.?Init")]
[H, IF(0<getFindCount(id)),CODE:
{
[Size_txt=getGroup(id, 1, 1)]
[setSize(Size_txt)]
[sizeList = table( "SysVars", json.get( table( "SysVars", 0 ), "sizeList" ) ) ]
[sizeModList = "8,4,2,1,0,-1,-2,-4,-8"]
[Size=listFind(sizeList, Size_txt)]
[SizeM = listGet(sizeModList, Size)]
[type=upper(substring(getGroup(id, 1, 2),0,1))+substring(getGroup(id, 1, 2),1)]
[Race = json.set(Race, "type", type)]
[subtypes=getGroup(id, 1, 4)]
[output=output+"Size: "+Size_txt+", type: "+type+", subtypes: "+subtypes+"<br>"]
[subtypes="['"+replace(subtypes,", *","','")+"']"]
[Race = json.set(Race, "subtype",subtypes)]
}]
[H: id = strfind(statblock, "Senses ([lL]ow-?light|[dD]arkvision)")]
[H, IF(0<getFindCount(id)),CODE:
{
[sighttype=upper(substring(getGroup(id, 1, 1),0,1))+substring(getGroup(id, 1, 1),1)]
[sighttype=replace(sighttype, "-", "")]
[setSightType(sighttype)]
[setHasSight(1)]
[output=output+"Sighttype: "+sighttype+", "]
}]
[H: id = strfind(statblock, "Reach ([0-9]+)")]
[H, IF(0<getFindCount(id)),CODE:
{
[Reach=getGroup(id, 1, 1)]
[output=output+"Reach: "+Reach+", "]
}]
[H: id = strfind(statblock, "DR(.?[0-9]+)/(.+?)[;O]")]
[H, IF(0<getFindCount(id)),CODE:
{
[DR=getGroup(id, 1, 1)+"/"+getGroup(id, 1, 2))]
[output=output+"DR: "+DR+", "]
}]
[H: id = strfind(statblock, "Resist (\\w+) (\\d+)")]
[H, IF(0<getFindCount(id)),CODE:
{
[resist = getGroup(id, 1, 1)+" "+getGroup(id, 1, 2))]
[DR=DR+" Resist "+resist]
[output=output+"Resist: "+resist+", "]
}]
[H: id = strfind(statblock, "SR ([0-9]+)")]
[H, IF(0<getFindCount(id)),CODE:
{
[SR=getGroup(id, 1, 1)]
[SpecialQual="SR "+SR]
[output=output+"SR: "+SR+", "]
}]
<!-- STATS BEGIN -->
[H: id = strfind(statblock, "Str.?([0-9]*).+?Dex.?([0-9]*).+?Con.?([0-9]*).+?Int.?([0-9]*).+?Wis.?([0-9]*).+?Cha.?([0-9]*)")]
[H, IF(0<getFindCount(id)), CODE:
{
[Strength=getGroup(id, 1, 1)]
[IF(Strength==""):Strength=10]
[Dexterity=getGroup(id, 1, 2)]
[IF(Dexterity==""):Dexterity=10]
[Constitution=getGroup(id, 1, 3)]
[IF(Constitution==""):Constitution=10]
[Intelligence=getGroup(id, 1, 4)]
[IF(Intelligence==""):Intelligence=10]
[Wisdom=getGroup(id, 1, 5)]
[IF(Wisdom==""):Wisdom=10]
[Charisma=getGroup(id, 1, 6)]
[IF(Charisma==""):Charisma=10]
[output=output+"Str: "+Strength+", Dex: "+Dexterity+", Con: "+Constitution+", Int: "+Intelligence+", Wis: "+Wisdom+", Cha: "+Charisma+"<br>"]
}]
<!-- STATS END -->
<!-- SAVES BEGIN -->
[H: id = strfind(statblock, "Fort (.?[0-9]+)")]
[H, IF(0<getFindCount(id)),CODE:
{
[Fort=getGroup(id, 1, 1)-ConB]
[output=output+"Fort: "+fort+", "]
}]
[H: id = strfind(statblock, "Ref (.?[0-9]+)")]
[H, IF(0<getFindCount(id)),CODE:
{
[Reflex=getGroup(id, 1, 1)-DexB]
[output=output+"Ref: "+reflex+", "]
}]
[H: id = strfind(statblock, "Will (.?[0-9]+)")]
[H, IF(0<getFindCount(id)),CODE:
{
[Will=getGroup(id, 1, 1)-WisB]
[output=output+"Will: "+Will+"<br>"]
}]
<!-- SAVES END -->
[H: id = strfind(statblock, "hp ([0-9]+).+?([0-9]+)")]
[H, IF(0<getFindCount(id)),CODE:
{
[HP=getGroup(id, 1, 1)]
[HPmax="[R: max(Level, ( "+(HP-ConB*Level)+" + (ConB * Level) ) )]"]
[HD=getGroup(id, 1, 2)]
[Level = max(1,HD)]
[output=output+"HP: "+HP+", HD: "+HD+"<br>"]
}]
[H: id = strfind(statblock, "Base Atk.?(.?[0-9]+);")]
[H, IF(0<getFindCount(id)), CODE:
{
[BAB=getGroup(id, 1, 1)]
[output=output+"Base Atk: "+BAB+", "]
}]
<!-- AC BEGIN -->
[H: id = strfind(statblock, "(.?[0-9]+) natural")]
[H, IF(0<getFindCount(id)): natural=getGroup(id, 1, 1); natural=0]
[H: ArmorClass = setStrProp(ArmorClass, "Natural", natural)]
[H: id = strfind(statblock, "(.?[0-9]+) armor")]
[H, IF(0<getFindCount(id)): armor=getGroup(id, 1, 1);armor=0]
[H: ArmorClass = setStrProp(ArmorClass, "Armor", armor)]
[H: id = strfind(statblock, "(.?[0-9]+) deflection")]
[H, IF(0<getFindCount(id)): deflect=getGroup(id, 1, 1); deflect=0]
[H: ArmorClass = setStrProp(ArmorClass, "Deflection", deflect)]
[H: id = strfind(statblock, "(.?[0-9]+) dodge")]
[H, IF(0<getFindCount(id)): dodge=getGroup(id, 1, 1); dodge=0]
[H: ArmorClass = setStrProp(ArmorClass, "Dodge", dodge)]
[H: id = strfind(statblock, "(.?[0-9]+) shield")]
[H, IF(0<getFindCount(id)): shield=getGroup(id, 1, 1); shield=0]
[H: ArmorClass = setStrProp(ArmorClass, "Shield", shield)]
[H: id = strfind(statblock, "AC ([0-9]+),")]
[H, IF(0<getFindCount(id)), CODE:
{
[AC=getGroup(id, 1, 1)]
[tch=AC-armor-shield]
[FF=AC-dodge-DexB]
[CMD=10+BAB+StrB+DexB-SizeM+dodge+deflect]
[CMDFF=CMD-DexB-dodge]
[AC=concat(AC,"/",tch,"/",FF,"/",CMD,"/",CMDFF)]
[output=output+"AC/tch/FF/CMD/CMDFF: "+AC+"<br>"]
}]
<!-- AC END -->
[H: id = strfind(statblock, "(Speed|Spd) ([0-9]+) ft")]
[H, IF(0<getFindCount(id)), CODE:
{
[spd=getGroup(id, 1, 2)]
[output=output+"Spd: "+spd]
[Speed = json.set(Speed, "base",spd)]
}]
[H: id = strfind(statblock, "fly ([0-9]+) ft")]
[H, IF(0<getFindCount(id)), CODE:
{
[spd=getGroup(id, 1, 1)]
[output=output+", Fly: "+spd]
[Speed = json.set(Speed, "fly",spd)]
}]
[H: id = strfind(statblock, "swim ([0-9]+) ft")]
[H, IF(0<getFindCount(id)), CODE:
{
[spd=getGroup(id, 1, 1)]
[output=output+", Swim: "+spd]
[Speed = json.set(Speed, "swim",spd)]
}]
[H: id = strfind(statblock, "burrow ([0-9]+) ft")]
[H, IF(0<getFindCount(id)), CODE:
{
[spd=getGroup(id, 1, 1)]
[output=output+", Burrow: "+spd]
[Speed = json.set(Speed, "burrow",spd)]
}]
[H: id = strfind(statblock, "climb ([0-9]+) ft")]
[H, IF(0<getFindCount(id)), CODE:
{
[spd=getGroup(id, 1, 1)]
[output=output+", Climb: "+spd]
[Speed = json.set(Speed, "climb",spd)]
}]
[H: output=output+"<br>"]
<!-- SKILLS BEGIN -->
[H: tSkillsJ ="[]"]
[H: output=output+"Skills: "]
[H, FOREACH(s, SkillsJ), CODE:
{
[skN = json.get(s, "name")]
[id=0]
[id = strfind(statblock, skN+"\\s(.?[0-9]+)")]
[H, IF(0<getFindCount(id)), CODE:
{
[skN = replace(skN, " ", "")] <!-- Remove spaces from skill name -->
[skStat = getStrProp(SkillStat, skN)]
[skVal = getGroup(id, 1, 1)]
[output=output+skN+" "+skVal+", "]
[s = json.set( s, "rank", skVal-eval(skStat))]
}]
[tSkillsJ = json.append(tSkillsJ,s)]
}]
[H: output=output+"<br>"]
[H: SkillsJ=tSkillsJ]
<!-- SKILLS END -->
<!-- FEATS BEGIN -->
[H: output=output+"Feats: "]
[H: id = strfind(statblock, "(Improved Initiative)")]
[H, IF(0<getFindCount(id)), CODE:
{
[Feats=setStrProp(Feats, "ImprovedInitiative",1)]
[H: output=output+getGroup(id, 1, 1)+", "]
};{
[Feats=setStrProp(Feats, "ImprovedInitiative",0)]
}]
[H: id = strfind(statblock, "(Agile Maneuvers)")]
[H, IF(0<getFindCount(id)), CODE:
{
[Feats=setStrProp(Feats, "AgileManeuvers",1)]
[H: output=output+getGroup(id, 1, 1)+", "]
};{
[Feats=setStrProp(Feats, "AgileManeuvers",0)]
}]
[H: id = strfind(statblock, "(Improved Bull Rush)")]
[H, IF(0<getFindCount(id)), CODE:
{
[Feats=setStrProp(Feats, "ImprovedBullRush",1)]
[H: output=output+getGroup(id, 1, 1)+", "]
};{
[Feats=setStrProp(Feats, "ImprovedBullRush",0)]
}]
[H: id = strfind(statblock, "(Improved Disarm)")]
[H, IF(0<getFindCount(id)), CODE:
{
[Feats=setStrProp(Feats, "ImprovedDisarm",1)]
[H: output=output+getGroup(id, 1, 1)+", "]
};{
[Feats=setStrProp(Feats, "ImprovedDisarm",0)]
}]
[H: id = strfind(statblock, "(Improved Grapple)")]
[H, IF(0<getFindCount(id)), CODE:
{
[Feats=setStrProp(Feats, "ImprovedGrapple",1)]
[H: output=output+getGroup(id, 1, 1)+", "]
};{
[Feats=setStrProp(Feats, "ImprovedGrapple",0)]
}]
[H: id = strfind(statblock, "(Improved Overrun)")]
[H, IF(0<getFindCount(id)), CODE:
{
[Feats=setStrProp(Feats, "ImprovedOverrun",1)]
[H: output=output+getGroup(id, 1, 1)+", "]
};{
[Feats=setStrProp(Feats, "ImprovedOverrun",0)]
}]
[H: id = strfind(statblock, "(Improved Sunder)")]
[H, IF(0<getFindCount(id)), CODE:
{
[Feats=setStrProp(Feats, "ImprovedSunder",1)]
[H: output=output+getGroup(id, 1, 1)+", "]
};{
[Feats=setStrProp(Feats, "ImprovedSunder",0)]
}]
[H: id = strfind(statblock, "(Improved Trip)")]
[H, IF(0<getFindCount(id)), CODE:
{
[Feats=setStrProp(Feats, "ImprovedTrip",1)]
[H: output=output+getGroup(id, 1, 1)+", "]
};{
[Feats=setStrProp(Feats, "ImprovedTrip",0)]
}]
[H: id = strfind(statblock, "(Improved Channeling)")]
[H, IF(0<getFindCount(id)), CODE:
{
[Feats=setStrProp(Feats, "ImprovedChanneling",1)]
[H: output=output+getGroup(id, 1, 1)+", "]
};{
[Feats=setStrProp(Feats, "ImprovedChanneling",0)]
}]
[H: id = strfind(statblock, "(Two.?Weapon Fighting)")]
[H, IF(0<getFindCount(id)), CODE:
{
[Feats=setStrProp(Feats, "TwoWeaponFighting",1)]
[H: output=output+getGroup(id, 1, 1)+", "]
};{
[Feats=setStrProp(Feats, "TwoWeaponFighting",0)]
}]
[H: id = strfind(statblock, "(Multi.?[aA]ttack)")]
[H, IF(0<getFindCount(id)), CODE:
{
[Feats=setStrProp(Feats, "MultiAttack",1)]
[H: output=output+getGroup(id, 1, 1)+", "]
};{
[Feats=setStrProp(Feats, "MultiAttack",0)]
}]
[H: id = strfind(statblock, "(Weapon Finesse)")]
[H, IF(0<getFindCount(id)), CODE:
{
[Feats=setStrProp(Feats, "WeaponFinesse",1)]
[H: output=output+getGroup(id, 1, 1)+", "]
};{
[Feats=setStrProp(Feats, "WeaponFinesse",0)]
}]
[H: id = strfind(statblock, "(Uncanny Dodge)")]
[H, IF(0<getFindCount(id)), CODE:
{
[Feats=setStrProp(Feats, "UncannyDodge",1)]
[H: output=output+getGroup(id, 1, 1)+", "]
};{
[Feats=setStrProp(Feats, "UncannyDodge",0)]
}]
[H: id = strfind(statblock, "(Die.?[hH]ard)")]
[H, IF(0<getFindCount(id)), CODE:
{
[Feats=setStrProp(Feats, "DieHard",1)]
[H: output=output+getGroup(id, 1, 1)+", "]
};{
[Feats=setStrProp(Feats, "DieHard",0)]
}]
[H: output=output+"<br>"]
<!-- FEATS END -->
[H: id = strfind(statblock, "Special Attacks (.+)(Statis|STATIS)")]
[H, IF(0<getFindCount(id)), CODE:
{
[SpecialATK=getGroup(id, 1, 1)]
[SpecialATK=trim(SpecialATK)]
[SpecialATK=substring(SpecialATK,0,min(length(SpecialATK),70))]
[output=output+"SA: "+SpecialATK+"<br>"]
};{
[SpecialATK=""]
}]
<!-- ATTACKS BEGIN -->
<!-- Insert empty weapon strings -->
[H: wpnstr=getPropertyDefault( "Weapon0" )]
[H, c(7,""),CODE:
{
[wpn="Weapon"+roll.count]
[eval(wpn + " = '" + wpnstr+ "'")]
}]
[H: atkno = 0]
<!-- MELEE -->
<!-- The '(?i)' makes the expression case-insensitive -->
[H: id = strfind(statblock, "Melee (.+?)(?i)(Tactic|Face|Space|Reach|Special|Ranged|Stat)")]
[H, IF(0<getFindCount(id)), CODE:
{
[allmelee=getGroup(id, 1, 1)]
<!-- separate each attack option -->
[allmelee=stringToList(allmelee, "( or (Melee)?)|(Melee)",":")]
[atkno = listCount(allmelee, ":")]
}]
<!-- Loop through each attack option and divide into weapons -->
[H: wpnarray=""]
[H: wpnno=0]
[H, FOR(i,0,atkno,1), CODE:
{
[atkstr=listget(allmelee, i, ":")]
[atkstr=stringToList(atkstr, "( and )|(, )",":")]
[wpns = listCount(atkstr, ":")]
[FOR(j,0,wpns,1), CODE:
{
[WpnName = "Weapon" + wpnno]
[wpnarray=json.append(wpnarray, trim(listGet(atkstr,j,":")))]
[ x = eval(WpnName) ]
[IF(j>0):eval(WpnName + "= '" + replace(x,"Primary=\\d+", "Primary=2")+ "'")]
<!-- Set attack options after first to secondary attacks -->
[eval(WpnName + "= '" + replace(x,"OHLight=\\d+", "OHLight=2")+ "'")]
<!-- Default to not multiattack -->
[wpnno = wpnno +1]
}]
}]
<!-- RANGED -->
[H: atkno = 0]
[H: id = strfind(statblock, "Ranged (.+?)(Tac|Face|Space|Reach|Special|Ranged|STAT|Stat)")]
[H, IF(0<getFindCount(id)), CODE:
{
[allranged=getGroup(id, 1, 1)]
<!-- separate each attack option -->
[allranged=stringToList(allranged, "(\\s?or (Ranged)?)|(Ranged)",":")]
[atkno = listCount(allranged, ":")]
}]
<!-- Loop through each attack option and divide into weapons -->
[H, FOR(i,0,atkno,1), CODE:
{
[atkstr=listget(allranged, i, ":")]
[atkstr=stringToList(atkstr, "( and )|(, )",":")]
[wpns = listCount(atkstr, ":")]
[FOR(j,0,wpns,1), CODE:
{
[WpnName = "Weapon" + wpnno]
[wpnarray=json.append(wpnarray, trim(listGet(atkstr,j,":")))]
[eval(WpnName + "= '" + setStrProp(eval(WpnName),"Ranged", 1)+ "'")]
[wpnno = wpnno +1]
}]
}]
<!-- extract info from each attack -->
[H: wpnno=0]
[H, FOREACH(atkstr, wpnarray), CODE:
{
[atkstr=trim(atkstr)]
[id = strfind(atkstr, "([+-]\\d+)?(\\d+)?(\\d?\\s?[a-zA-Z ]+?) ([+-]\\d+)[/+\\-0-9\\s]*?\\((.+)\\)")]
[IF(0<getFindCount(id)), CODE:
{
[WpnName = "Weapon" + wpnno]
[eval(WpnName + "= '" + setStrProp(eval(WpnName),"Name", getGroup(id, 1, 3))+ "'")]
<!-- Quantity -->
[wquant = 1]
[wbonus = ""]
[IF(getGroup(id,1,1)==""): wquant = getGroup(id, 1, 2); wbonus="+ "+getGroup(id,1,1)]
[IF(getGroup(id,1,2)==""): wquant = 1]
[IF(1<wquant):eval(WpnName + "= '" + setStrProp(eval(WpnName),"Quantity", wquant)+ "'")]
<!-- Manufactored ? -->
[id2 = strfind(atkstr, "(slam|bite|claw|gore|hoof|tentacle|wing|pincer|tail|sting|talon)")]
[IF(0==getFindCount(id2)):eval(WpnName + "= '" + setStrProp(eval(WpnName),"Manufactured", 1)+ "'")]
<!-- Not a natural weapon -->
<!-- Attack bonus (assumes StrB for melee and DexB for ranged) -->
[watkbonus=getGroup(id, 1, 4)]
[Ranged=getStrProp(eval(WpnName),"Ranged")]
[IF(Ranged>0):watkbonus=watkbonus-BAB-DexB;watkbonus=watkbonus-BAB-StrB-SizeM]
[eval(WpnName + "= '" + setStrProp(eval(WpnName),"AtkBonus", watkbonus)+ "'")]
<!-- CritMult-->
[wdam=getGroup(id, 1, 5)]
[CritMult=2]
[id2 = strfind(wdam, "/[xX](\\d)")]
[IF(0<getFindCount(id2)):CritMult=getGroup(id2, 1, 1)]
[eval(WpnName + "= '" + setStrProp(eval(WpnName),"CritMult", CritMult)+ "'")]
<!-- CritRange-->
[CritRange=20]
[id2 = strfind(wdam, "/(1[0-9])")]
[IF(0<getFindCount(id2)):CritRange=getGroup(id2, 1, 1)]
[eval(WpnName + "= '" + setStrProp(eval(WpnName),"CritRange", CritRange)+ "'")]
<!-- Damage -->
[Damage="0d4 plus" + wdam]
[id2 = strfind(wdam, "(\\dd\\d+)[^p]*(plus .+)?")]
[IF(0<getFindCount(id2)):Damage=getGroup(id2, 1, 1)+wbonus+" "+getGroup(id2, 1, 2)]
[eval(WpnName + "= '" + setStrProp(eval(WpnName),"Damage", Damage)+ "'")]
<!-- Two handed ? -->
[eval(WpnName + "= '" + setStrProp(eval(WpnName),"TwoHanded", 0)+ "'")] <!-- Default to onehanded weapon -->
[id2 = strfind(atkstr, "(longspear|quarterstaff| spear|falchion|glaive|greataxe|greatclub|greatsword|guisarme|halberd|lance|ranseur|scythe|spiked chain|elven curve blade|dire flail|two-bladed sword|urgrosh|hooked hammer)")]
[IF(0<getFindCount(id2)):eval(WpnName + "= '" + setStrProp(eval(WpnName),"TwoHanded", 1)+ "'")]
}]
[wpnno = wpnno +1]
}]
[H: output = output + "Weapons: " + wpnarray+"<br>"]
<!--
Name=Slam ; Primary=1 ; Quantity=1 ; Manufactured=0 ; AtkBonus=0 ; CritMult=2 ; CritRange=20 ; Damage=1d4 ; DmgMax=4 ; DmgExtra=0d6 ; DmgExtraCrit=0d10 ; DmgExtraName= ; DmgBonusCap=50 ; TwoHanded=0 ; Finesse=0 ; OHLight=0 ; Ranged=0 ;
ATTACKS END -->
[R,S,G: output]