Page 3 of 4

Re: [AM Macros] Lindsay's PF/3.5 Campaign FW (8-15-15)

Posted: Wed Aug 26, 2015 3:04 pm
by aliasmask
Which output, casting a spell?

Re: [AM Macros] Lindsay's PF/3.5 Campaign FW (8-15-15)

Posted: Wed Aug 26, 2015 4:00 pm
by lmarkus001
Yeah, output.basic. I am going to resolve that now.

It is a Mote bug around isGM(). I am reporting it.

Re: [AM Macros] Lindsay's PF/3.5 Campaign FW (8-15-15)

Posted: Wed Aug 26, 2015 4:51 pm
by aliasmask
lmarkus001 wrote:Yeah, output.basic. I am going to resolve that now.

It is a Mote bug around isGM(). I am reporting it.
Ah, I think that was an MT change after their port. I have a better solution.

REMOVE

Code: Select all

[H: players.gm = "[]"]
[H, foreach(player,players.all), if(isGM(player)): players.gm = json.append(players.gm,player)]
ADD IN ITS PLACE

Code: Select all

[H: players.gm = json.get(getInfo("server"),"gm")]
This too was a change after their port, but I recall discussion on one of their forums about adding this. This will only work in MT b91 or later though. I'm not sure if they kept the same function name or changed it to one of their other naming conventions.

Re: [AM Macros] Lindsay's PF/3.5 Campaign FW (8-15-15)

Posted: Wed Aug 26, 2015 6:06 pm
by lmarkus001
Nice thought, but the Mote getInfo() reports differently...


So here is my near term workaround where I do version checking and use isGM() on MT and getGMNames() on Mote. Next Mote version will include isGM() functionality :-)

Code: Select all

[H: info        = getInfo("client")]
[H: mtVersion    = json.get(info, "version")]
[h: id        = strfind(mtVersion, ".+\\.(.+)\\.[A-z]*([0-9]+)[A-z]*")]
[H: mtMainVerNr    = getGroup(id, 1, 1)]
[H: mtVersionNr    = getGroup(id, 1, 2)]

<!-- validate token is on current map -->
[H: tokenId = findToken(token)]
[H, if(! json.isEmpty(tokenId)), code: {
   [H: tokenName = getName(tokenId)]
   [H: tokenImage = getImage(tokenName)]
};{}]

<!-- parse list of targets in to list of players names -->
[H, if(json.type(targets) == "UNKNOWN"): targets = json.fromList(targets)]

<!-- get player groups -->
[H: players.all = getAllPlayerNames("json")]

[H,IF(mtVersionNr>88),CODE: {
    [H: players.gm = "[]"]
    [H, foreach(player,players.all), if(isGM(player)): players.gm = json.append(players.gm,player);""]    
};{
    [H: players.gm = getGMNames("json")]
}] 

Re: [AM Macros] Lindsay's PF/3.5 Campaign FW (8-15-15)

Posted: Wed Aug 26, 2015 7:23 pm
by aliasmask
Maybe we can skip the longer version checking with this:

Code: Select all

...
<!-- get player groups -->
[H: isMT = json.contains(json.fields(getInfo("server"),"json"),"gm")]
[H, if(isMT): players.gm = json.get(getInfo("server"),"gm"); players.gm = getGMNames("json")]
[H: players.all = getAllPlayerNames("json")]
[H: player.self = json.append("",getPlayerName())]
...
 
It accomplishes the same thing, but has the same flaw of when "gm" doesn't exist it will call a function that doesn't exist. We already know it's a pain in the behind to get gm Names before b89(?) so I'll just leave this as an incompatibility with versions.

Re: [AM Macros] Lindsay's PF/3.5 Campaign FW (8-15-15)

Posted: Sun Aug 30, 2015 7:58 pm
by aliasmask
I just found a mistake (oversight) with the template fix. When counting spells, I only counted the number of different spells rather than the number memorized. This only matter if you're a prep caster and you memorized duplicates. It will wrongly show you have an extra spell(s) to memorize. I'll fix this tomorrow.

Re: [AM Macros] Lindsay's PF/3.5 Campaign FW (8-15-15)

Posted: Mon Aug 31, 2015 1:16 pm
by lmarkus001
Here is the output.basic version check I am now using...

Code: Select all

[H: clientType = json.get(getInfo("client"),"name")]
[H: players.gm = "[]"]
[H, if(clientType=="Mote"), CODE: {
    [ players.gm = getGMNames() ]
};{
    [H, foreach(player,players.all), if(isGM(player)): players.gm = json.append(players.gm,player);""]
}] 

Re: [AM Macros] Lindsay's PF/3.5 Campaign FW (8-15-15)

Posted: Mon Aug 31, 2015 1:32 pm
by aliasmask
isGM(player) and json.get(getInfo("server"),"gm") were implemented at the same time so there's no advantage as far as version-ing goes, but I personally like getting a single value over running a loop. So, it's just apples and oranges at this point and they accomplish the same thing. I also try to avoid the double roll option which is an MT quirk that MOTE gave in and implemented by prioritizing left to right when running the roll options.

Re: [AM Macros] Lindsay's PF/3.5 Campaign FW (8-15-15)

Posted: Mon Aug 31, 2015 4:07 pm
by lmarkus001
The isGM("player") was broken as implemented in Mote (hence my alternate code). They just repaired it today :-)

Re: [AM Macros] Lindsay's PF/3.5 Campaign FW (8-15-15)

Posted: Tue Sep 01, 2015 11:26 pm
by aliasmask
More updates to lib:spells3
(9-1-15)
* Fixed Local Cheating when there is more than one spell casting class.
* Fixed template restore to include correct remainder of spells when prep casters memorize the same spell more than once.
* Fixed ability score mod when ability changes between levels. Re-calcs on Rest now.
* Fixed formula for calculating SPD so it uses class base for that level + ability adjustment.
* Added spells known per level for Oracle (don't know why this was blank)
The recalc of SPD on rest was needed for ability adjustments between levels, but this means if you usually have an abnormal number of spell per day from the class and you change it under local cheating, then you're going not want to do that because of the reset on rest. You will want to make new class and adjust the SPD there. Pain in the behind either way. I may, if there is demand put in an SPD modifier that you can edit. I know there are some classes where you get -1 SPD each level.

Re: [AM Macros] Lindsay's PF/3.5 Campaign FW (8-15-15)

Posted: Wed Sep 02, 2015 1:17 pm
by lmarkus001
aliasmask wrote:More updates to lib:spells3
(9-1-15)
...
* Added spells known per level for Oracle (don't know why this was blank)
...
So you did not make your changes off of my updated token where there are a lot of class and list updates. Any list of macros modified for your token? That way I can just apply those and avoid another data massage...

Re: [AM Macros] Lindsay's PF/3.5 Campaign FW (9-1-15)

Posted: Wed Sep 02, 2015 2:25 pm
by aliasmask
I did actually use your token. After I did a quick code comparison to make sure we were matched up, I then started using your token as a base for modding. You'll notice the druid_storm in class list which is something I didn't have before. I just remade the oracle by making a new one, using the cleric list and setting the spd and spell known to sorcerer.

Re: [AM Macros] Lindsay's PF/3.5 Campaign FW (9-1-15)

Posted: Wed Sep 02, 2015 2:34 pm
by aliasmask
Let's see I updated:
* Rest Start
* Ability Adjustments
* Tweak Token
* Restore Template

I think that's it.

Re: [AM Macros] Lindsay's PF/3.5 Campaign FW (9-1-15)

Posted: Tue Sep 08, 2015 11:10 am
by lmarkus001
Yep I spoke too soon, lookin good!

Re: [AM Macros] Lindsay's PF/3.5 Campaign FW (9-1-15)

Posted: Thu Oct 29, 2015 5:25 pm
by aliasmask
Update to pfStatBlockImport

AM (v2.0.5): Fixed Speed when "Spd" is used. Puts blank for XP when not in stat block instead of error. Fixed init/senses line error. (updated)

UPDATED CODE to v2.0.6
Lib:libDnD35Pathfinder wrote:
||| pfStatBlockImport |||

Code: Select all

@@ @pfStatBlockImport
<!-- Statblock2Token v2.0.4 (3-15-15)
   Statblock2Token v2.0.4 (10-29-15)
   Statblock2Token v2.0.6 (02-13-16)
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
LGM: Corrected vulnerability, Added Feats
AM (v2.0.3): fixed hp each; name get; default sight off; valid ulnerability check; made UDF; output change 
AM (v2.0.4): fixed stat sheet input error (infinite loop on mouse over)
AM (v2.0.5): Fixed Speed when "Spd" is used. Puts blank for XP when not in stat block instead of error. Fixed init/senses line error.
AM (v2.0.6): Fixed AC notes when () isnt present. 
   Fixed feats so it sets the states. Problem was that sysVars didnt have SysFeats.
   Put Special Abilities in to json for later use and to put line spaces between abilities.
-->
[H: ids = getSelected()]
[H: abort(if(ids == "", 0, 1))]

[H: status=input("junk|Statblock info from Creature Name through Treasure line of Ecology (if it exists). Don't include flavor text/background/descriptions.||LABEL|SPAN=TRUE","junk|If Ecology section comes before Special Abilities, be sure to include Special Abilities section as well. Still no flavor text.||LABEL|SPAN=TRUE","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: TAB = decode("%09")]
[H: EOL = decode("%0A")]
[H: gmNotes = "[]"]

<!-- Lets clean up those pesky non-ascii characters! -->
[H: statblock = replace(statblock, "\\xD7", "x")]
[H: statblock = replace(statblock, "\\u2013", "-")]
[H: statblock = replace(statblock, "\\u2014", "-")]
[H: statblock = replace(statblock, "%E2%80%93", "-")]
[H: statblock = replace(statblock, "Ecolo gy", "Ecology")]
[H: statblock = replace(statblock, "  ", " ")]

<!-- change brackets and braces to parens to avoid stat sheet variable input error -->
[H: statblock = replace(statblock, "[\\[\\{]","(")]
[H: statblock = replace(statblock, "[\\]\\}]",")")]

<!-- Start formatting imported statblock and set it to GM notes -->

<!-- If Ecology section comes before Special Abilities, cut it out and put it last. If the Ecology section doesn't exist, create a blank one last -->
[H: EcologyThenSAbSearch = strfind(statblock, "(?i)(ECOLOGY)(.*?)(Special Abilities)")]
[H, IF(0<getFindCount(EcologythenSAbSearch)), CODE: {
	[IF(getGroup(EcologyThenSAbSearch, 1, 3) == "special abilities" || getGroup(EcologyThenSAbSearch, 1, 3) == "Special Abilities" || getGroup(EcologyThenSAbSearch, 1, 3) == "Special abilities" || getGroup(EcologyThenSAbSearch, 1, 3) == "SPECIAL ABILITIES"), CODE: {
		[EcologyString = getGroup(EcologyThenSAbSearch, 1, 0)]
		[statblock = replace(statblock, "(?i)((ECOLOGY)(.*?))((Special Abilities)(.*))", "\$4  \$1" )]
		[EcologySearch = strfind(statblock, "(?i)(ECOLOGY)(.*)")]
	};{
	}]
};{
	[EcologySearch = strfind(statblock, "(?i)(ECOLOGY)(.*)")]
	[IF(0<getFindCount(EcologySearch)), CODE: {
		[statblock = statblock]
	};{
		[statblock = statblock + " ECOLOGY "]
		[EcologySearch = strfind(statblock, "(?i)(ECOLOGY)(.*)")]
	}]
}]

<!-- Search for lines and sections of statblock individually -->
[H: NameSearch = strfind(statblock, "(.*?)CR")]
[H: assert(getFindCount(NameSearch),"CR could not be found",0)]
[H: CRSearch = strfind(statblock, "(CR ?[0-9]+(/[0-9]+)?)")]
[H: XPSearch = strfind(statblock, "(XP [0-9,]+)")]
[H: GenderEtcSearch = strfind(statblock, "(?i)XP [0-9,]+ ([a-z ,0-9]*)( LG | LN | LE | NG | N | NE | CG | CN | CE )")]
[H: AlignmentSizeRaceSearch = strfind(statblock, "(?i)(( LG | LN | LE | NG | N | NE | CG | CN | CE ).*?)Init")]
[H: InitSensesSearch = strfind(statblock, "(?i)(Init.*?) +(Aura|DEFENSE|Weakness)")]
[H: AuraSearch = strfind(statblock, "(?i)(Aura.*?) DEFENSE")]
[H: ACStringSearch = strfind(statblock, "(?i)(AC [0-9].*?) +HP")]
[H: HPStringSearch = strfind(statblock, "(?i)((HP) .*?)Fort ")]
[H: SavesSearch = strfind(statblock, "(?i)(Fort (.*?))(Defensive Abilit|DR [0-9]|Immune|Resist|SR|Weakness|OFFENSE)")]
[H: DefensiveAbilitiesSearch = strfind(statblock, "(?i)((Defensive Abilities|Defensive Ability|DR |Immune|Resist|SR)(.*?))(Weakness|OFFENSE)")]
[H: WeaknessesSearch = strfind(statblock, "(?i)(Weaknesse?s?(.*?))(DEFENSE|OFFENSE)")]
[H: SpeedSearch = strfind(statblock, "(?i)((Speed|Spd) (.+?))(Melee|Ranged|Tactic|Space|Reach|Special|Ranged|Stat|Spell)")]
[H: MeleeSearch = strfind(statblock, "(?i)(Melee (.+?))(Tactic|Space|Reach|Special|Ranged|Stat|Spell)")]
[H: RangedSearch = strfind(statblock, "(?i)(Ranged (.+?))(Tactic|Space|Reach|Special|Stat|Spell)")]
[H: SpaceReachSearch = strfind(statblock, "(?i)((Space|Reach)(.*?))(Tactic|Special|Stat|Spell)")]
[H: SpecialAttackSearch = strfind(statblock, "(?i)(Special Attacks?(.*?))(Tactic|Stat|Spell)")]
[H: SpellLikeSearch = strfind(statblock,  "(?i)((Arcane School |Gnome |Domain |Bloodline |Hellknight |Transmuter |Paladin |Cleric |Conjurer |Enchanter |Evoker |Necromancer |Arcane )?Spell-Like Abilities (.*?))(?=(Alchemist|Antipaladin|Bard|Cleric|Oracle|Druid|Inquisitor|Magus|Paladin|Ranger|Sorcerer|Wizard|Summoner|Witch|Arcane School|Gnome|Domain|Bloodline|Hellknight|Arcane|Abjurer|Conjurer|Diviner|Enchanter|Evoker|Illusionist|Necromancer|Transmuter|Tactic|Face|Stat|Spell))")]
[H: SpellsKnownSearch = strfind(statblock, "(?i)((Alchemist|Antipaladin|Bard|Cleric|Oracle|Druid|Inquisitor|Magus|Paladin|Ranger|Sorcerer|Wizard|Summoner|Witch|Abjurer|Conjurer|Diviner|Enchanter|Evoker|Illusionist|Necromancer|Transmuter)? ?Spells Known(.*?))(?=(Alchemist|Antipaladin|Bard|Cleric|Oracle|Druid|Inquisitor|Magus|Paladin|Ranger|Sorcerer|Wizard|Summoner|Witch|Abjurer|Conjurer|Diviner|Enchanter|Evoker|Illusionist|Necromancer|Transmuter|Tactic|Stat|Spells))")]
[H: SpellsPreparedSearch = strfind(statblock, "(?i)((Alchemist|Antipaladin|Bard|Cleric|Oracle|Druid|Inquisitor|Magus|Paladin|Ranger|Sorcerer|Wizard|Summoner|Witch|Abjurer|Conjurer|Diviner|Enchanter|Evoker|Illusionist|Necromancer|Transmuter)? ?Spells Prepared(.*?))(?=(Alchemist|Antipaladin|Bard|Cleric|Oracle|Druid|Inquisitor|Magus|Paladin|Ranger|Sorcerer|Wizard|Summoner|Witch|Abjurer|Conjurer|Diviner|Enchanter|Evoker|Illusionist|Necromancer|Transmuter|Tactic|Stat|Spells))")]
[H: TacticsSearch = strfind(statblock, "(?i)TACTICS(.*?)(?<!base )(?:STATISTICS)")]
[H: StatisticsSearch = strfind(statblock, "(?i)(base statistics)?.*?Statistics.*?(Str (.*?))Base Atk")]
[H: BaseAtkSearch = strfind(statblock, "(?i)(base statistics)?.*?Statistics.*?(Base Atk(.*?))(Feats|Skills|Languages|SQ|Combat Gear|Other Gear|Gear|SPECIAL|ECOLOGY)")]
[H: FeatsSearch = strfind(statblock, "(?i)(base statistics)?.*?Statistics.*?(Feats (.*?))(Skills|Languages|SQ|Combat Gear|Other Gear|Gear|SPECIAL|ECOLOGY)")]
[H: SkillsSearch = strfind(statblock, "(?i)(base statistics)?.*?Statistics.*?(Skills (.*?))(Languages|SQ|Combat Gear|Other Gear|Gear|SPECIAL|ECOLOGY)")]
[H: LanguagesSearch = strfind(statblock, "(?i)(base statistics)?.*?Statistics.*?(Languages? (.*?))(SQ|Combat Gear|Other Gear|Gear|SPECIAL|ECOLOGY)")]
[H: SQSearch = strfind(statblock, "(?i)(base statistics)?.*?Statistics.*?(SQ (.*?))(Combat Gear|Other Gear|Gear|SPECIAL|ECOLOGY)")]
[H: GearSearch = strfind(statblock, "(?i)(base statistics)?.*?Statistics.*?((Combat )?Gear (.*?))(BASE STATISTICS|SPECIAL|ECOLOGY) ")]
[H: BaseStatisticsSearch = strfind(statblock, "(?i)(Base Statistics.*?)(STATISTICS.*?Str [0-9]|SPECIAL ABILITIES|ECOLOGY)")]
[H: SpecialAbilitiesSearch = strfind(statblock, "(?i)(SPECIAL ABILITIES)(.*?)(ECOLOGY)")]

<!-- If the line or section exists, put it in a variable and give it a line break before it -->
[H, IF(0<getFindCount(GenderEtcSearch)), CODE: {
	[GenderEtcNote = "
" + trim(getGroup(GenderEtcSearch, 1, 1))]
};{
	[GenderEtcNote = ""]
}]

[H, IF(0<getFindCount(AuraSearch)), CODE: {
	[AuraNote = "
" + trim(getGroup(AuraSearch, 1, 1))]
};{
	[AuraNote = ""]
}]

[H, IF(0<getFindCount(DefensiveAbilitiesSearch)), CODE: {
	[DANote = "
" + trim(getGroup(DefensiveAbilitiesSearch, 1, 1))]
};{
	[DANote = ""]
}]

[H, IF(0<getFindCount(WeaknessesSearch)), CODE: {
	[WeaknessNote = "
" + trim(getGroup(WeaknessesSearch, 1, 1))]
};{
	[WeaknessNote = ""]
}]

[H, IF(0<getFindCount(MeleeSearch)), CODE: {
	[MeleeNote = "
" + trim(getGroup(MeleeSearch, 1, 1))]
};{
	[MeleeNote = ""]
}]

[H, IF(0<getFindCount(RangedSearch)), CODE: {
	[RangedNote = "
" + trim(getGroup(RangedSearch, 1, 1))]
};{
	[RangedNote = ""]
}]

[H, IF(0<getFindCount(SpaceReachSearch)), CODE: {
	[SpaceReachNote = "
" + trim(getGroup(SpaceReachSearch, 1, 1))]
};{
	[SpaceReachNote = ""]
}]

[H, IF(0<getFindCount(SpecialAttackSearch)), CODE: {
	[SANote = "
" + trim(getGroup(SpecialAttackSearch, 1, 1))]
};{
	[SANote = ""]
}]

<!-- If a Spell-Like Abilities section exists, break it up into subsections based on constant/at will/or # per day. Multiple Spell-Like sections may exist from different sources, so create a section for each -->
[H: SLNote = ""]
[H, IF(0<getFindCount(SpellLikeSearch)), FOR(NumSpellLikeTypes, 1, getFindCount(SpellLikeSearch)+1), CODE: {
	[SpellLikeString = getGroup(SpellLikeSearch, NumSpellLikeTypes, 1)]
	[SpellLikeHeaderSearch = strfind(SpellLikeString, "(?i)(.*?)(Constant|At[ -]Will|[0-9]+/day)")]
	[ConstantSearch = strfind(SpellLikeString, "(?i)((Constant)(.*?))(At[ -]Will|[0-9]+/day)")]
	[IF(1>getFindCount(ConstantSearch)): ConstantSearch = strfind(SpellLikeString, "(?i)((Constant)(.*))")]
	[AtWillSearch = strfind(SpellLikeString, "(?i)((At[ -]Will)(.*?))([0-9]+/day)")]
	[IF(1>getFindCount(AtWillSearch)): AtWillSearch = strfind(SpellLikeString, "(?i)((At[ -]Will)(.*))")]
	[PerDayStringSearch = strfind(SpellLikeString, "(?i)(([0-9]+/day)(.*))")]
	[IF(0<getFindCount(PerDayStringSearch)): PerDayString = getGroup(PerDayStringSearch, 1, 1); PerDayString = ""]
	[PerDayTypesSearch = strfind(PerDayString, "(?i)(([0-9]+/day)(.*?))(?=([0-9]+/day))")]
	[PerDayAbilities = ""]
	[IF(0<getFindCount(PerDayTypesSearch)), FOR(DifferentPerDays, 1, getFindCount(PerDayTypesSearch)+1), CODE: {
		[PerDayString = replace(PerDayString, "(?i)([0-9]+/day(.*?))(?=([0-9]+/day))", "")]
		[ThisPerDay = trim(getGroup(PerDayTypesSearch, DifferentPerDays, 1))]
		[PerDayAbilities = PerDayAbilities + "
	" + ThisPerDay]
	}]
	[IF(PerDayString != ""): PerDayAbilities = PerDayAbilities + "
	" + trim(PerDayString)]
	[IF(0<getFindCount(SpellLikeHeaderSearch)): SpellLikeHeader = "

" + trim(getGroup(SpellLikeHeaderSearch, 1, 1)); SpellLikeHeader = "" ]
	[IF(0<getFindCount(ConstantSearch)), CODE: {
		[ConstantAbilities = "
	" + trim(getGroup(ConstantSearch, 1, 1))]
	};{
		[ConstantAbilities = ""]
	}]
	[IF(0<getFindCount(AtWillSearch)), CODE: {
		[AtWillAbilities = "
	" + trim(getGroup(AtWillSearch, 1, 1))]
	};{
		[AtWillAbilities = ""]
	}]
	[SLNote = SLNote + SpellLikeHeader + ConstantAbilities + AtWillAbilities + PerDayAbilities]
};{
	[SLNote = ""]
}]

<!-- If a Spells Known section exists, break it up into subsections based on spell level. Multiple Spells Known sections may exist from different sources, so create a section for each -->
[SKNote = ""]
[H, IF(0<getFindCount(SpellsKnownSearch)), FOR(NumSpellClasses, 1, getFindCount(SpellsKnownSearch)+1), CODE: {
	[ThisSpellClass = getGroup(SpellsKnownSearch, NumSpellClasses, 1)]
	[SpellsKnownHeaderSearch = strfind(ThisSpellClass, "(?i)(.*?\\)) +(9th|8th|7th|6th|5th|4th|3rd|2nd|1st|0 \\(|0th \\()")]
	[NinthLevelSearch = strfind(ThisSpellClass, "(?i)((9th)(.*?))(8th)")]
	[EighthLevelSearch = strfind(ThisSpellClass, "(?i)((8th)(.*?))(7th)")]
	[SeventhLevelSearch = strfind(ThisSpellClass, "(?i)((7th)(.*?))(6th)")]
	[SixthLevelSearch = strfind(ThisSpellClass, "(?i)((6th)(.*?))(5th)")]
	[FifthLevelSearch = strfind(ThisSpellClass, "(?i)((5th)(.*?))(4th)")]
	[FourthLevelSearch = strfind(ThisSpellClass, "(?i)((4th)(.*?))(3rd)")]
	[ThirdLevelSearch = strfind(ThisSpellClass, "(?i)((3rd)(.*?))(2nd)")]
	[SecondLevelSearch = strfind(ThisSpellClass, "(?i)((2nd)(.*?))(1st)")]
	[FirstLevelSearch = strfind(ThisSpellClass, "(?i)((1st)(.*?))(0 \\(|0th \\()")]
	[ThisClassSpecialSearch = strfind(ThisSpellClass, "(?i)((D Domain|Bloodline|Domain|Mystery|Opposition School|Prohibited School)(.*))")]
	[IF(0<getFindCount(ThisClassSpecialSearch)): ZerothLevelSearch = strfind(ThisSpellClass, "(?i)((0 \\(|0th \\()(.*?))(D Domain|Bloodline|Domain|Mystery|Opposition School|Prohibited School)"); ZerothLevelSearch = strfind(ThisSpellClass, "((0 \\(|0th \\()(.*))")]
	[IF(0<getFindCount(SpellsKnownHeaderSearch)): SpellsKnownHeader = "

" + trim(getGroup(SpellsKnownHeaderSearch, 1, 1)); SpellsKnownHeader = ""]
	[IF(0<getFindCount(NinthLevelSearch)), CODE: {
		[NinthLevel = "
	" + trim(getGroup(NinthLevelSearch, 1, 1))]
	};{
		[NinthLevel = ""]
	}]
	[IF(0<getFindCount(EighthLevelSearch)), CODE: {
		[EighthLevel = "
	" + trim(getGroup(EighthLevelSearch, 1, 1))]
	};{
		[EighthLevel = ""]
	}]
	[IF(0<getFindCount(SeventhLevelSearch)), CODE: {
		[SeventhLevel = "
	" + trim(getGroup(SeventhLevelSearch, 1, 1))]
	};{
		[SeventhLevel = ""]
	}]
	[IF(0<getFindCount(SixthLevelSearch)), CODE: {
		[SixthLevel = "
	" + trim(getGroup(SixthLevelSearch, 1, 1))]
	};{
		[SixthLevel = ""]
	}]
	[IF(0<getFindCount(FifthLevelSearch)), CODE: {
		[FifthLevel = "
	" + trim(getGroup(FifthLevelSearch, 1, 1))]
	};{
		[FifthLevel = ""]
	}]
	[IF(0<getFindCount(FourthLevelSearch)), CODE: {
		[FourthLevel = "
	" + trim(getGroup(FourthLevelSearch, 1, 1))]
	};{
		[FourthLevel = ""]
	}]
	[IF(0<getFindCount(ThirdLevelSearch)), CODE: {
		[ThirdLevel = "
	" + trim(getGroup(ThirdLevelSearch, 1, 1))]
	};{
		[ThirdLevel = ""]
	}]
	[IF(0<getFindCount(SecondLevelSearch)), CODE: {
		[SecondLevel = "
	" + trim(getGroup(SecondLevelSearch, 1, 1))]
	};{
		[SecondLevel = ""]
	}]
	[IF(0<getFindCount(FirstLevelSearch)), CODE: {
		[FirstLevel = "
	" + trim(getGroup(FirstLevelSearch, 1, 1))]
	};{
		[FirstLevel = ""]
	}]
	[IF(0<getFindCount(ZerothLevelSearch)), CODE: {
		[ZerothLevel = "
	" + trim(getGroup(ZerothLevelSearch, 1, 1))]
	};{
		[ZerothLevel = ""]
	}]
	[IF(0<getFindCount(ThisClassSpecialSearch)), CODE: {
		[ThisClassSpecial = "
	" + trim(getGroup(ThisClassSpecialSearch, 1, 1))]
	};{
		[ThisClassSpecial = ""]
	}]
	[SKNote = SKNote + SpellsKnownHeader + NinthLevel + EighthLevel + SeventhLevel + SixthLevel + FifthLevel + FourthLevel + ThirdLevel + SecondLevel + FirstLevel + ZerothLevel + ThisClassSpecial]
};{
	[SKNote = ""]
}]

<!-- If a Spells Prepared section exists, break it up into subsections based on spell level. Multiple Spells Prepared sections may exist from different sources, so create a section for each -->
[H: SPNote = ""]
[H, IF(0<getFindCount(SpellsPreparedSearch)), FOR(NumSpellClasses, 1, getFindCount(SpellsPreparedSearch)+1), CODE: {
	[ThisSpellClass = getGroup(SpellsPreparedSearch, NumSpellClasses, 1)]
	[SpellsPreparedHeaderSearch = strfind(ThisSpellClass, "(?i)(.*?\\)) +(9th|8th|7th|6th|5th|4th|3rd|2nd|1st|0 \\(|0th \\))")]
	[NinthLevelSearch = strfind(ThisSpellClass, "(?i)((9th)(.*?))(8th)")]
	[EighthLevelSearch = strfind(ThisSpellClass, "(?i)((8th)(.*?))(7th)")]
	[SeventhLevelSearch = strfind(ThisSpellClass, "(?i)((7th)(.*?))(6th)")]
	[SixthLevelSearch = strfind(ThisSpellClass, "(?i)((6th)(.*?))(5th)")]
	[FifthLevelSearch = strfind(ThisSpellClass, "(?i)((5th)(.*?))(4th)")]
	[FourthLevelSearch = strfind(ThisSpellClass, "(?i)((4th)(.*?))(3rd)")]
	[ThirdLevelSearch = strfind(ThisSpellClass, "(?i)((3rd)(.*?))(2nd)")]
	[SecondLevelSearch = strfind(ThisSpellClass, "(?i)((2nd)(.*?))(1st)")]
	[FirstLevelSearch = strfind(ThisSpellClass, "(?i)((1st)(.*?))(0 \\(|0th \\()")]
	[ThisClassSpecialSearch = strfind(ThisSpellClass, "(?i)((D Domain|Bloodline|Domain|Mystery|Opposition School|Prohibited School)(.*))")]
	[IF(0<getFindCount(ThisClassSpecialSearch)): ZerothLevelSearch = strfind(ThisSpellClass, "(?i)((0 \\(|0th \\()(.*?))(D Domain|Bloodline|Domain|Mystery|Opposition School|Prohibited School)"); ZerothLevelSearch = strfind(ThisSpellClass, "((0 \\(|0th \\()(.*))")]
	[IF(0<getFindCount(SpellsPreparedHeaderSearch)): SpellsPreparedHeader = "

" + trim(getGroup(SpellsPreparedHeaderSearch, 1, 1)); SpellsPreparedHeader = ""]
	[IF(0<getFindCount(NinthLevelSearch)), CODE: {
		[NinthLevel = "
	" + trim(getGroup(NinthLevelSearch, 1, 1))]
	};{
		[NinthLevel = ""]
	}]
	[IF(0<getFindCount(EighthLevelSearch)), CODE: {
		[EighthLevel = "
	" + trim(getGroup(EighthLevelSearch, 1, 1))]
	};{
		[EighthLevel = ""]
	}]
	[IF(0<getFindCount(SeventhLevelSearch)), CODE: {
		[SeventhLevel = "
	" + trim(getGroup(SeventhLevelSearch, 1, 1))]
	};{
		[SeventhLevel = ""]
	}]
	[IF(0<getFindCount(SixthLevelSearch)), CODE: {
		[SixthLevel = "
	" + trim(getGroup(SixthLevelSearch, 1, 1))]
	};{
		[SixthLevel = ""]
	}]
	[IF(0<getFindCount(FifthLevelSearch)), CODE: {
		[FifthLevel = "
	" + trim(getGroup(FifthLevelSearch, 1, 1))]
	};{
		[FifthLevel = ""]
	}]
	[IF(0<getFindCount(FourthLevelSearch)), CODE: {
		[FourthLevel = "
	" + trim(getGroup(FourthLevelSearch, 1, 1))]
	};{
		[FourthLevel = ""]
	}]
	[IF(0<getFindCount(ThirdLevelSearch)), CODE: {
		[ThirdLevel = "
	" + trim(getGroup(ThirdLevelSearch, 1, 1))]
	};{
		[ThirdLevel = ""]
	}]
	[IF(0<getFindCount(SecondLevelSearch)), CODE: {
		[SecondLevel = "
	" + trim(getGroup(SecondLevelSearch, 1, 1))]
	};{
		[SecondLevel = ""]
	}]
	[IF(0<getFindCount(FirstLevelSearch)), CODE: {
		[FirstLevel = "
	" + trim(getGroup(FirstLevelSearch, 1, 1))]
	};{
		[FirstLevel = ""]
	}]
	[IF(0<getFindCount(ZerothLevelSearch)), CODE: {
		[ZerothLevel = "
	" + trim(getGroup(ZerothLevelSearch, 1, 1))]
	};{
		[ZerothLevel = ""]
	}]
	[IF(0<getFindCount(ThisClassSpecialSearch)), CODE: {
		[ThisClassSpecial = "
	" + trim(getGroup(ThisClassSpecialSearch, 1, 1))]
	};{
		[ThisClassSpecial = ""]
	}]
	[SPNote = SPNote + SpellsPreparedHeader + NinthLevel + EighthLevel + SeventhLevel + SixthLevel + FifthLevel + FourthLevel + ThirdLevel + SecondLevel + FirstLevel + ZerothLevel + ThisClassSpecial]
};{
	[SPNote = ""]
}]

<!-- If a tactics section exists, break it up into subsections of Before Combat, During Combat, and Morale. The Base Statistics section, if it exists, may be in Tactics or it may be at the end of the Statistics section. In either case, put it in Tactics -->
[H, IF(0<getFindCount(TacticsSearch)), CODE: {
	[TacticsNote = "

-----TACTICS-----"]
	[TacticsString = getGroup(TacticsSearch, 1, 1)]
	[TacticsBeforeCombatSearch = strfind(TacticsString, "(?i)(Before Combat.*?)(During Combat|Morale|Base Statistics)")]
	[IF(1>getFindCount(TacticsBeforeCombatSearch)): TacticsBeforeCombatSearch = strfind(TacticsString, "(?i)(Before Combat.*)")]
	[IF(0<getFindCount(TacticsBeforeCombatSearch)): TacticsNote = TacticsNote + "
" + trim(getGroup(TacticsBeforeCombatSearch, 1, 1))]
	[TacticsDuringCombatSearch = strfind(TacticsString, "(?i)(During Combat.*?)(Morale|Base Statistics)")]
	[IF(1>getFindCount(TacticsDuringCombatSearch)): TacticsDuringCombatSearch = strfind(TacticsString, "(?i)(During Combat.*)")]
	[IF(0<getFindCount(TacticsDuringCombatSearch)): TacticsNote = TacticsNote + "
" + trim(getGroup(TacticsDuringCombatSearch, 1, 1))]
	[TacticsMoraleSearch = strfind(TacticsString, "(?i)(Morale.*?)(Base Statistics)")]
	[IF(1>getFindCount(TacticsMoraleSearch)): TacticsMoraleSearch = strfind(TacticsString, "(?i)(Morale.*)")]
	[IF(0<getFindCount(TacticsMoraleSearch)): TacticsNote = TacticsNote + "
" + trim(getGroup(TacticsMoraleSearch, 1, 1))]
};{
	[TacticsNote = ""]
}]
[H, IF(0<getFindCount(BaseStatisticsSearch)), CODE: {
	[IF(TacticsNote == ""), CODE: {
		[TacticsNote = "

-----TACTICS-----
" + trim(getGroup(BaseStatisticsSearch, 1, 1)))]
	};{
		[TacticsNote = TacticsNote + "
" + trim(getGroup(BaseStatisticsSearch, 1, 1)))]
	}]
}]

[H, IF(0<getFindCount(FeatsSearch)), CODE: {
	[FeatsNote = "
" + trim(getGroup(FeatsSearch, 1, 2))]
};{
	[FeatsNote = ""]
}]

[H, IF(0<getFindCount(SkillsSearch)), CODE: {
	[SkillsNote = "
" + trim(getGroup(SkillsSearch, 1, 2))]
};{
	[SkillsNote = ""]
}]

[H, IF(0<getFindCount(LanguagesSearch)), CODE: {
	[LangNote = "
" + trim(getGroup(LanguagesSearch, 1, 2))]
};{
	[LangNote = ""]
}]

[H, IF(0<getFindCount(SQSearch)), CODE: {
	[SQNote = "
" + trim(getGroup(SQSearch, 1, 2))]
};{
	[SQNote = ""]
}]

[H, IF(0<getFindCount(GearSearch)), CODE: {
	[GearNote = "
" + trim(getGroup(GearSearch, 1, 2))]
};{
	[GearNote = ""]
}]

<!-- AM Update - SPECIAL ABILITIES: format "name (ex|su|sp) text -->
[H, if(getFindCount(SpecialAbilitiesSearch)), code: {
   [H: SA.string = getGroup(SpecialAbilitiesSearch, 1, 2)]
   <!-- find the beginning of the special ability name in group 2 -->
   [H: SA.id = strfind(SA.string,"(?i)(^ *|[.] *)([^.]*? ([(](Ex|Su|Sp)[)]))")]
   [H: SA.count = getFindCount(SA.id)]
   [H: SA.strings = json.append("[]","-----SPECIAL ABILITIES-----")]
   [H, for(i,0,SA.count), code: {
      [H: start = getGroupStart(SA.id,i+1,2)]
      [H, if(i+1 < SA.count): end = getGroupStart(SA.id,i+2,2); end = ""]
      [H, if(json.isEmpty(end)): SA.strings = json.append(SA.strings,substring(SA.string,start)); SA.strings = json.append(SA.strings,substring(SA.string,start,end))]
   }]
   [H: SAbNote = EOL+EOL+json.toList(SA.strings,EOL+EOL)]
};{
   [H: SAbNote = ""]
}]

<!-- If the Ecology section exists, break it up into lines for Environment, Organization, and Treasure -->
[H, IF(0<getFindCount(EcologySearch)), CODE: {
	[EcologyNote = "

-----ECOLOGY-----"]
	[EcologyString = trim(getGroup(EcologySearch, 1, 2))]
	[EnvironmentSearch = strfind(EcologyString, "(?i)(Environment.*?)(Organization|Treasure)")]
	[IF(0<getFindCount(EnvironmentSearch)): EcologyNote = EcologyNote + "
" + trim(getGroup(EnvironmentSearch, 1, 1))]
	[OrganizationSearch = strfind(EcologyString, "(?i)(Organization.*?)(Treasure)")]
	[IF(0<getFindCount(OrganizationSearch)): EcologyNote = EcologyNote + "
" + trim(getGroup(OrganizationSearch, 1, 1))]
	[TreasureSearch = strfind(EcologyString, "(?i)(Treasure.*)")]
	[IF(0<getFindCount(TreasureSearch)), CODE: {
		[TreasureTypeSearch = strfind(getGroup(TreasureSearch, 1, 1), "(none|standard|double|incidental|NPC gear)")]
		[IF(0<getFindCount(TreasureTypeSearch)): TreasureType = getGroup(TreasureTypeSearch, 1, 1)]
	}]
	[IF(0<getFindCount(TreasureSearch)): EcologyNote = EcologyNote + "
" + trim(getGroup(TreasureSearch, 1, 1))]
};{
	[EcologyNote = ""]
}]

<!--Put it all together in the GM notes -->

<!-- AM Update - may use this later to redo gm notes. Needed for debugging. -->
[H: note.name = trim(getGroup(NameSearch, 1, 1))]
[H: note.cr = trim(getGroup(CRSearch, 1, 1))]
[H: note.align = trim(getGroup(AlignmentSizeRaceSearch, 1, 1))]
[H: note.senses = trim(getGroup(InitSensesSearch, 1, 1))]
[H: note.ac = trim(getGroup(ACStringSearch, 1, 1))]
[H: note.hp = trim(getGroup(HPStringSearch, 1, 1))]
[H: note.saves = trim(getGroup(SavesSearch, 1, 1))]
[H: note.speed = trim(getGroup(SpeedSearch, 1, 2))]
[H: note.stats = trim(getGroup(StatisticsSearch, 1, 2))]
[H: note.bab = trim(getGroup(BaseAtkSearch, 1, 2))]

<!-- This is actual fix for XP not being in statblock. It simply puts a blank -->
[H, if(getFindCount(XPSearch)): note.xp = trim(getGroup(XPSearch, 1, 1)); note.xp = ""]

[H: setGMNotes(trim(getGroup(NameSearch, 1, 1)) + "	" + trim(getGroup(CRSearch, 1, 1)) + "
------------
" + note.xp +
 GenderEtcNote + "
" + trim(getGroup(AlignmentSizeRaceSearch, 1, 1)) + "
" + trim(getGroup(InitSensesSearch, 1, 1)) + 
 AuraNote + "

-----DEFENSE-----
" + trim(getGroup(ACStringSearch, 1, 1)) + "
" + trim(getGroup(HPStringSearch, 1, 1)) + "
" + trim(getGroup(SavesSearch, 1, 1)) + 
 DANote + 
 WeaknessNote + "

-----OFFENSE-----
" + trim(getGroup(SpeedSearch, 1, 2)) +
 MeleeNote +
 RangedNote +
 SpaceReachNote +
 SANote +
 SLNote +
 SKNote +
 SPNote +
 TacticsNote + "

-----STATISTICS-----
" + trim(getGroup(StatisticsSearch, 1, 2)) + "
" + trim(getGroup(BaseAtkSearch, 1, 2)) + 
 FeatsNote +
 SkillsNote +
 LangNote +
 SQNote +
 GearNote +
 SAbNote +
 EcologyNote)]

[H: output="Token Updated:<br>"]
[H: id = strfind(statblock, "^(.+?)CR ?[0-9]")]
[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 ?)([0-9]+)(/[1-9]+)?")]
[H, IF(0<getFindCount(id)), CODE: {
	[ECL = trim(getGroup(id, 1, 0))]
	[output=output+"CR: "+ECL+", "]
	[IF(ECL == "1/3"): ECL=".338"]
	[IF(ECL == "1/6"): 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(0)]
	[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+", "]
}]

 <!-- Defensive Abilities Sample: Defensive Abilities incorporeal, channel resistance +2; -->
[H: DefensiveAbil = ""]
[H, IF(0<getFindCount(DefensiveAbilitiesSearch)),CODE: {
	[DefensiveAbilitiesString=getGroup(DefensiveAbilitiesSearch, 1, 1)]
	[DefensiveAloneSearch=strfind(DefensiveAbilitiesString, "(?i)Defensive (Abilities|Ability)(.*?); +(SR|Immune|Resist|DR)")]
	[IF(0==getFindCount(DefensiveAloneSearch)): DefensiveAloneSearch = strfind(DefensiveAbilitiesString, "(?i)Defensive (Ability|Abilities)(.*)")]
	[IF(0<getFindCount(DefensiveAloneSearch)), CODE: {
		[DefensiveAbil = trim(getGroup(DefensiveAloneSearch, 1, 2))]
		[output=output+"Defensive Abilities: "+DefensiveAbil+", "]
	}]
}]

<!-- Find Immunities. Sample: Immune acid, curse effects, flanking, mind-affecting effects, paralysis, poison, sleep -->
[H: Immune = ""]
[H: id = strfind(statblock, "(Immune )(([a-zA-Z]+[-]?,? ?)+);? +(Weakness|OFFENSE|Resist|SR)")]
[H, IF(0<getFindCount(id)),CODE: {
	[id2 = strfind(getGroup(id, 1, 2), "(.*) (Weakness|OFFENSE|[;]|Resist)")]
	[IF(0<getFindCount(id2)): Immune = getGroup(id2, 1, 1); Immune = getGroup(id, 1, 2)]
	[Immune = trim(Immune)]
	[output=output+"Immunities: "+Immune+", "]
 }]

<!-- Find Weaknesses. Sample: Weaknesses light sensitivity -->
[H: Weaknesses = ""]
[H: id = strfind(statblock, "(Weaknesse?s? )((\\w+-?,? ?)+) +(?i)(OFFENSE|DEFENSE)")]
[H, IF(0<getFindCount(id)),CODE: {
	[Weaknesses = trim(getGroup(id, 1, 2))]
	[output=output+"Weaknesses: "+Weaknesses+", "]
}]
  
<!-- Find DR. Sample: 1/-, 2/adamantine, 3/good -->
[h: DRSearch = ""]
[H: id = strfind(statblock, "DR(.?[0-9]+)/(.+?)[,;O]")]
[H, IF(0<getFindCount(id)), COUNT(getFindCount(id)), CODE: {
	[thisrollcount = roll.count+1]
	[thissearchDR = replace(getGroup(id, thisrollcount, 2), "Cold Iron", "ColdIron")]
	[drANDORsearch = strfind(thissearchDR, "(and|or) ([a-zA-Z]+ ?)")]
	[if(0<getFindCount(drANDORsearch)), COUNT(getFindCount(drANDORsearch)), CODE: {
	[DRSearch = trim(DRSearch + " " + getGroup(id, thisrollcount, 1)+"/"+getGroup(drANDORsearch, roll.count+1, 2))]
	}]
	[DRSearch = trim(DRSearch + " " + getGroup(id, thisrollcount, 1)+"/"+thissearchDR)]
	[DRSearch = replace(DRSearch, "/-", "/All")]
	[DRSearch = replace(DRSearch, "(?i)/Cold Iron", "/ColdIron")]
	[DRSearch = replace(DRSearch, "(?i)/Chaotic", "/Chaos")]
	[DRSearch = replace(DRSearch, "(?i)/Lawful", "/Law")]
}]
  
<!-- Find Resistences. Sample: Resist acid 5, cold 5, electricity 5 -->
[h: resistSearch = ""]
[H: id = strfind(statblock, "(\\bResist \\b(\\w+ \\d+,? ?)+)")]
[H, IF(0<getFindCount(id)),CODE: {
	[resistSearch = trim(getGroup(id, 1, 1))]
}]

<!-- Find SR -->  
[H: SRSearch = ""]
[H: id = strfind(statblock, "SR ([0-9]+)")]
[H, IF(0<getFindCount(id)),CODE: {
	[SRSearch=getGroup(id, 1, 1)]
}]

<!-- Put DR & Resist values into JSON Property DRER -->
[H, FOREACH( reduceTypes, json.fields( DRER ) ), CODE: {
 	[jRC = json.get( DRER, reduceTypes ) ]
 	[prefixT = substring( reduceTypes, 0, 1 ) ]
   

 	[FOREACH( reduceType, json.fields( jRC ) ), CODE: {
    	[preValue = json.get( jRC, reduceType ) ]
		[reduceVal = 0]

		[resistFind = strfind(resistSearch, "(?i)("+reduceType+" )(\\d+)")]

		 [IF(0<getFindCount(resistFind) && prefixT == "E"): reduceVal = getGroup(resistFind, 1, 2)]

		[drFind = strfind(DRSearch, "(?i)(\\d+)/("+reduceType+")")]
		[IF(0<getFindCount(drFind) && prefixT == "D"): reduceVal = getGroup(drFind, 1, 1)]
  
		[ chgValue = eval( "" + prefixT + reduceType + "=" + reduceVal ) ]
	  
    	[IF( reduceType != "Note" ): tmodV = json.get( DRERMod, if( reduceTypes == "Damage Reduction", "DR_", if( reduceTypes == "Energy Resistance", "ER_", if( reduceTypes == "Spell Resistance", "SR_", "EV_") ) ) + reduceType ) ]
    	[IF( reduceType != "Note" ): tVal = max( chgValue, tmodV ); tVal = chgValue ]
     
		[IF( tVal != 0 && tVal != "" && prefixT == "D"): DR = listAppend( DR, tVal + if( reduceType == "Note", "", "/" + if( reduceType == "All", "-", reduceType ) ) ) ]
	  
		[IF( tVal != 0 && tVal != "" && prefixT == "E"): DR = listAppend( DR, reduceType + if( reduceType == "Note", "", " (" + if( tVal == "999", "Immune", tVal ) + ")" ) ) ]
    	[IF( reduceType == "Note" && chgValue == 0 ): chgValue = "" ]
    	[IF( preValue != chgValue ):  output = output + reduceType + "= " + chgValue + " (" + preValue + "), "]
    	[IF( preValue != chgValue ): jRC = json.set( jRC, reduceType, chgValue ) ]

}]
 	[setProperty( "DRER", json.set( DRER, reduceTypes, jRC ) ) ]
   
 	[IF(DRSearch != "" || resistSearch != ""): output=output+"<br>"]
}]

[H, If(Immune != ""), CODE:{
	[jRC = json.get( DRER, "Energy Resistance" )]
	[jRCnew = json.set( jRC, "Note", "Immune: "+Immune)]
	[newDRER = json.set( DRER, "Energy Resistance", JRCnew)]
	[setProperty("DRER", newDRER)]
	[DR = listAppend(DR, "Immune: "+Immune)]
}]

[H, If(SRSearch != ""), CODE:{
	[jRC = json.get( DRER, "Spell Resistance" )]
	[jRCnew = json.set( jRC, "SR", SRSearch)]
	[newDRER = json.set( DRER, "Spell Resistance", JRCnew)]
	[setProperty("DRER", newDRER)]
	[DR = listAppend(DR, "SR: "+SRSearch)]
}]

[H: vulnerability =  strfind(Weaknesses, "(Vulnerability|Vulnerable|vulnerability|vulnerable) to ([a-zA-Z]*)")]
[H: vtypes = getFindCount(vulnerability)]
[H, IF(0<vtypes), CODE: {
	[COUNT(vtypes), CODE: {
		[jRC = json.get(DRER, "Energy Vulnerability")]
      [ tvuln = "V."+upper(lower(getGroup(vulnerability,roll.count+1,2)),1)]
      [ validVulnerability = listContains("V.Acid,V.Cold,V.Electricity,V.Fire,V.Sonic",tvuln)]
		[if(validVulnerability): jRCnew = json.set(jRC, tvuln, 1)]
		[if(validVulnerability): newDRER = json.set(DRER, "Energy Vulnerability", jRCnew)]
		[if(validVulnerability): setProperty("DRER", newDRER)]
		[if(validVulnerability): DR = listAppend(DR, tvuln)]
	}]
}]

<!-- STATS BEGIN -->
[H: id = strfind(statblock, "(?i)(?<!base )STATISTICS.*?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>"]
}]
[H: SavesString = getGroup(SavesSearch, 1, 1)]
[H: id = strfind(SavesString, ";(.*)")]
[H, IF(0<getFindCount(id)), CODE: {
	[SaveMisc = trim(getGroup(id, 1, 1))]
	[output=output+"Saves Misc Notes: "+SaveMisc+"<br>"]
}]

<!-- SAVES END -->

[H: id = strfind(statblock, "hp ([0-9]+).*?\\(([0-9]+ ?HD; ?)?([0-9d+]*)")]
[H: hpString = getGroup(id, 1, 3)]
[H: numOfEachHDType = strfind(hpString, "([0-9]+)d")]
[H: numOfHDTypes = getFindCount(numOfEachHDType)]
[H, IF(0<getFindCount(id)),CODE: {
	[H: HD = 0]
	[H, COUNT(numOfHDTypes), CODE:
	{
		[HD = HD + getGroup(numOfEachHDType, (roll.count+1), 1)]
	}]
	[HP=getGroup(id, 1, 1)]
	[Level = max(1,HD)]
	[HPmax="[R: max(Level, ( "+(HP-(ConB*Level))+" + (ConB * Level) ) )]"]
	[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-natural]
	[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)]
	[Movement = spd]
}; {
	[Speed = json.set(Speed, "base",0)]
	[Movement = 0]
}]
[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)]
	[Movement = getProperty("Movement") + ", Climb:" + 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)]
	[Movement = getProperty("Movement") + ", 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)]
	[Movement = getProperty("Movement") + ", Burrow:" + spd]
}]
[H: id = strfind(statblock, "fly ([0-9]+) ft\\.? ?\\(?([a-zA-Z]+)?\\)? ?(Melee|Ranged|Special|Spell)")]
[H, IF(0<getFindCount(id)), CODE: {
	[spd=getGroup(id, 1, 1)]
	[output=output+", Fly: "+spd]
	[Speed = json.set(Speed, "fly",spd)]
	[flyman=lower(getGroup(id, 1, 2))]
	[SWITCH(flyman), CODE:
		case "": {
			[flyman = "average"]
			[Speed = json.set(Speed, "flymaneuver",4)]
		};
		case "clumsy": {
			[flyman = "Clumsy"]
			[Speed = json.set(Speed, "flymaneuver",2)]
		};
		case "poor": {
			[flyman = "Poor"]
			[Speed = json.set(Speed, "flymaneuver",3)]
		};
		case "average": {
			[flyman = "Average"]
			[Speed = json.set(Speed, "flymaneuver",4)]
		};
		case "good": {
			[flyman = "Good"]
			[Speed = json.set(Speed, "flymaneuver",5)]
		};
		case "perfect": {
			[flyman = "Perfect"]
			[Speed = json.set(Speed, "flymaneuver",6)]
		};
	]
	[Movement = getProperty("Movement") + ", Fly:" + spd + " (" + flyman + ")"]
}]
[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 -->

<!--Languages Begin-->
[H, IF(0<getFindCount(LanguagesSearch)), CODE: {
	[LanguageList = strfind(getGroup(LanguagesSearch, 1, 2), "Languages?(.*)")]
	[IF(0<getFindCount(LanguageList)): Race = json.set(Race, "notes", trim(getGroup(LanguageList, 1, 1)))]
}]
<!--Languages End-->

<!-- SQ on popup begin -->
[H, IF(0<getFindCount(SQSearch)), CODE: {
	[SpecialQualWithoutSQ = strfind(getGroup(SQSearch, 1, 2), "SQ (.*)")]
	[SpecialQual = trim(getGroup(SpecialQualWithoutSQ, 1, 1))]
}]
<!--SQ on popup end-->

<!-- FEATS BEGIN -->
[H: output=output+"Feats: "]
[H, IF(0<getFindCount(FeatsSearch)), CODE: {
   [ tFeats = replace(getGroup(FeatsSearch, 1, 2), "Feats ", "", 1) ]
   [ tFeats = trim(replace(tFeats, "B,", ",")) ]
   [ tFEflag = endsWith(tFeats, "B") ]
   [ IF(tFEflag): tFeats = substring(tFeats, 0, length(tFeats)-1); "" ]
   [H: output=output+tFeats ]
   [ tFeatsJ = json.fromList(tFeats) ]
   [ tFeatsJ2 = "[]" ]
   [ tFeatsJparam = "{}" ]
   [ Foreach(p, tFeatsJ), CODE: {
      [ tidxp = indexOf(p,"(") ]
      [ IF( tidxp < 0 ): tpm = trim(p); tpm = trim(substring(p,0,tidxp)) ]
      [ IF( tidxp < 0 ): tpsub = ""; tpsub = substring(p,tidxp+1,length(p)-1) ]
      [ tFeatsJ2 = json.append(tFeatsJ2, tpm) ]
      [ IF( tidxp < 0 ): "";  tFeatsJparam = json.set(tFeatsJparam, tpm, tpsub) ]
   }]
   [ tFeatsJ2 = json.sort(tFeatsJ2) ]
   [ setProperty("FeatsJ", tFeatsJ2) ]
   [ setProperty("FeatsJparam", tFeatsJparam) ]
     
   <!-- AM Update - table SysVars doesnt have sysFeats so basing feats off of Feat var. 
      Also looping through known feats rather than global feats.
      Setting value to one. This will add new feats not know as well.
   -->
   [H: sysFeats = json.fromStrProp(getProperty("Feats"))]
   [H, foreach(featName,tFeatsJ2): sysFeats = json.set(sysFeats,replace(trim(featName)," |-",""),1)]
   [H: setProperty("Feats",json.toStrProp(sysFeats))]
      
};{
}]
[H: output=output+"<br>"]
<!-- FEATS END -->

<!-- Ferocity for Orcs works just like Die Hard -->
[H: id = strfind(DefensiveAbil, "(?i)(ferocity)")]
[H, IF(0<getFindCount(id)), CODE: {
	[Feats=setStrProp(Feats, "DieHard",1)]
	[H: output=output+getGroup(id, 1, 1)+", "]
}]  
  
[H: output=output+"<br>"]

[H: id = strfind(statblock, "(?i)Special Attacks? (.*?)(Spells|Spell[ -]Like|Statistics|Tactics)")]
[H, IF(0<getFindCount(id)), CODE: {
	[SpecialATK = trim(getGroup(id, 1, 1))]
	[SpecialATK=substring(SpecialATK,0,min(length(SpecialATK),70))]
	[output=output+"SA: "+SpecialATK+"<br>"]
  };{
	[SpecialATK=""]
}]

[H: id = strfind(statblock, "(Fast Healing )([0-9]+)")]
[H, IF(0<getFindCount(id)),CODE: {
	[FastHealing=getGroup(id, 1, 2)]
	[output=output+"Fast Healing: "+FastHealing+"<br>"]
}]

<!-- Setting Regeneration and Anti Regen Damage Type if present -->
[H: id = strfind(statblock, "(Regeneration )([0-9]+) ([(][a-zA-Z]+[)])?")]
[H, IF(0<getFindCount(id)),CODE: {
	[Regeneration=getGroup(id, 1, 2)]
	[output=output+"Regeneration: "+Regeneration+"<br>"]
	[AntiRegen=if(getGroup(id, 1, 3)=="", "", getGroup(id, 1, 3))]
	[output=output+"Regeneration: "+Regeneration+"<br>"+if(AntiRegen=="", "", "Anti-Regen Damage Type: "+AntiRegen+"<br>")]
}]
  
<!-- ATTACKS BEGIN -->
<!-- Insert empty weapon strings -->
[H: wpnstr=getPropertyDefault( "Weapon0" )]
[H, c(17,""),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|Space|Reach|Special|Ranged|Spell-Like|Spells|Statistic)")]
[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=replace(atkstr, "((\\(.+\\)) and )", "\$2, ")]
	[atkstr=stringToList(atkstr, "(, )",":")]
	[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 (.+?)(?i)(Tactic|Space|Reach|Special|Spell-Like|Spells|Statistic)")]
[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+)(/[+-]\\d+)?( [a-zA-Z]* )?[/+\\-0-9\\s]*?\\((.+)\\)")]
	[IF(0<getFindCount(id)), CODE: {
	[WpnName = "Weapon" + wpnno]

    <!-- Quantity / Weapon Bonus-->
  	[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)+ "'")]
	
		<!-- Weapon Name -->
	[eval(WpnName + "= '" + setStrProp(eval(WpnName),"Name", replace(wbonus, " ", "") + if(wbonus=="", "", " ") + getGroup(id, 1, 3) + if(getGroup(id, 1, 6)=="", "", " ("+trim(getGroup(id, 1, 6))+")")) + "'")]
    
	<!-- Manufactured ? -->
  	[id2 = strfind(atkstr, "(?i)(slam|bite|claw|gore|hoof|tentacle|wing|pincer|tail|sting|talon|Constrict)")]
  	[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-SizeM;watkbonus=watkbonus-BAB-StrB-SizeM]
  	[eval(WpnName + "= '" + setStrProp(eval(WpnName),"AtkBonus", watkbonus)+ "'")]

	<!-- CritMult-->
  	[wdam=getGroup(id, 1, 7)]
  	[CritMult=2]
  	[id2 = strfind(wdam, "([0-9]+d[0-9]+)?([+-][0-9]+)?/?([0-9]+-?[0-9]+)?([xX]([0-9]))? ?([a-zA-Z0-9 ]+)?")]
  	[IF(getGroup(id2, 1, 5)==""): CritMult=2; CritMult=replace(getGroup(id2, 1, 5),"[xX]", "")]
  	[eval(WpnName + "= '" + setStrProp(eval(WpnName),"CritMult", CritMult)+ "'")]

	<!-- CritRange-->
  	[CritRange=20]
  	[critFromWdam = getGroup(id2, 1, 3)]
	[critFromWdamsearch = strfind(critFromWdam, "([0-9]+)-20")]
	[IF(0<getFindCount(critFromWdamsearch)): CritRange = getGroup(critFromWdamsearch, 1, 1)]
  	[eval(WpnName + "= '" + setStrProp(eval(WpnName),"CritRange", CritRange)+ "'")]
	
	<!-- CritExtraDamage-->
  	[DmgExtraCrit=""]

	<!-- Damage -->
  	[Damage=if(getGroup(id2, 1, 1) == "", "0", getGroup(id2, 1, 1))]
	[DmgExtra = 0]
	[DmgExtraName = ""]
	[newPlusStr= ""]
	[DamagePlus = ""]
	[DmgExtraCrit = "0d10"]
	[DamagePlus = if(0<getFindCount(id2), getGroup(id2, 1, 6), "")]
	[DmgBonus = 0]
	[DmgBonus = if(0<getFindCount(id2), getGroup(id2, 1, 2), 0)]
  	[id2 = strfind(atkstr, "(?i)(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)")]
	[DmgBonus = if(DmgBonus == "", 0, DmgBonus)]
  	[IF(0<getFindCount(id2)):eval(WpnName + "= '" + setStrProp(eval(WpnName),"TwoHanded", 1)+ "'")]
	[DmgBonus = round(if(0<getFindCount(id2), DmgBonus-Str2hB, DmgBonus-StrB))]
	
  	[ExtraDamageSearch = strfind(DamagePlus, "(.*) ([0-9]+[d0-9]+?) ?([a-zA-Z]+) ?(.*)")]
	[IF(0<getFindCount(ExtraDamageSearch)):DmgExtra=getGroup(ExtraDamageSearch, 1, 2)]
	[IF(0<getFindCount(ExtraDamageSearch)):DmgExtraName=getGroup(ExtraDamageSearch, 1, 3)]
	[IF(0<getFindCount(ExtraDamageSearch)):newPlusStr = getGroup(ExtraDamageSearch, 1, 1) + getGroup(ExtraDamageSearch, 1, 4)]
	[IF(0<getFindCount(ExtraDamageSearch)):newPlusStr = replace(newPlusStr, "plus", "")]
	[IF(0<getFindCount(ExtraDamageSearch)):newPlusStr = replace(newPlusStr, "and", "")]
	[IF(0<getFindCount(ExtraDamageSearch)):newPlusStr = trim(newPlusStr)]
	[IF(0<getFindCount(ExtraDamageSearch)):newPlusStr = replace(newPlusStr, "  ", " ")]
	[IF(0<getFindCount(ExtraDamageSearch)):newPlusStr = replace(newPlusStr, " ", " plus ")]
	[IF(0<getFindCount(ExtraDamageSearch)):Damage = trim(Damage + if(DmgBonus<0, "", "+") + DmgBonus + " " + IF(newPlusStr != "", "plus " + newPlusStr, newPlusStr)); Damage = trim(Damage + if(DmgBonus<0, "", "+") + DmgBonus + " " + DamagePlus)]
	[burstsearch = strfind(getGroup(id, 1, 3), "([a-zA-Z]+ )([Bb]urst)")]
	[IF(0<getFindCount(burstsearch)): DmgExtraCrit = "1d10 " + trim(getGroup(burstsearch, 1, 1))]
	
	[eval(WpnName + "= '" + setStrProp(eval(WpnName),"Damage", Damage)+ "'")]
	[eval(WpnName + "= '" + setStrProp(eval(WpnName),"DmgExtra", DmgExtra)+ "'")]
	[eval(WpnName + "= '" + setStrProp(eval(WpnName),"DmgExtraName", DmgExtraName)+ "'")]
	[eval(WpnName + "= '" + setStrProp(eval(WpnName),"DmgExtraCrit", DmgExtraCrit)+ "'")]
	<!-- Two handed ? -->
    <!-- Default to onehanded weapon -->
	[eval(WpnName + "= '" + setStrProp(eval(WpnName),"TwoHanded", 0)+ "'")]

}]
  
	[wpnno = wpnno +1]
}]

[H: broadcast(strformat("Import Complete %{name}"),"self,gm")]
!!