ReGex :/

Discuss macro implementations, ask for macro help (to share your creations, see User Creations, probably either Campaign Frameworks or Drop-in Resources).

Moderators: dorpond, trevor, Azhrei, giliath, jay, Mr.Ice

Post Reply
User avatar
Sereptus
Giant
Posts: 123
Joined: Tue Jun 07, 2011 12:08 pm
Location: Canada

ReGex :/

Post by Sereptus »

Ok, so I've been working on this piece of ReGex for a while now and I'm at my wits end. When I put this formula in https://regexr.com/ it works perfectly but Maptool doesn't like it at all.

Code: Select all

CHA\n([0-9]*).[(\+)].[0-9]*.[(\+)]\s([0-9]*).[(\+)].[0-9]*.[(\+)]\s([0-9]*).[(\+)].[0-9]*.[(\+)]\s([0-9]*).[(\+)].[0-9]*.[(\+)]\s([0-9]*).[(\+)].[0-9]*.[(\+)]\s([0-9]*).[(\+)].[0-9]*.[(\+)]\s
It's for this statblock:
Spoiler
Ghast

Medium undead, chaotic evil

Armor Class 13
Hit Points 36 (8d8)
Speed 30 ft.

STR DEX CON INT WIS CHA
16 (+3) 17 (+3) 10 (+0) 11 (+0) 10 (+0) 8 (-1)
Damage Resistances necrotic
Damage Immunities poison
Condition Immunities charmed, exhaustion, poisoned
Senses darkvision 60 ft., passive Perception 10
Languages Common
Challenge 2 (450 XP)
Stench. Any creature that starts its turn within 5 feet of the ghast must succeed on a DC 10 Constitution saving throw or be poisoned until the start of its next turn. On a successful saving throw, the creature is immune to the ghast's Stench for 24 hours.

Turning Defiance. The ghast and any ghouls within 30 feet of it have advantage on saving throws against effects that turn undead.

ACTIONS
Bite. Melee Weapon Attack: +5 to hit, reach 5 ft., one creature. Hit: 12 (2d8 + 3) piercing damage.

Claws. Melee Weapon Attack: +5 to hit, reach 5 ft., one target. Hit: 10 (2d6 + 3) slashing damage. If the target is a creature other than an undead, it must succeed on a DC 10 Constitution saving throw or be paralyzed for 1 minute. The target can repeat the saving throw at the end of each of its turns, ending the effect on itself on a success.
I'm only trying to extract the main ability's (strength, Dexterity, etc.) without any of the subset's (eg. (+3)) and like I said, it work perfectly on regexr although it DOES say Match #0 but all the Group's following that have the exact number I'm trying to extract. This is the code (mostly stolen from AM) I put in Maptools to try and achieve this:

Code: Select all

[H: id = strfind(statblock, "(?i)(?<!CHA )([0-9]*).[(\+)].[0-9]*.[(\+)]\\s([0-9]*).[(\+)].[0-9]*.[(\+)]\\s([0-9]*).[(\+)].[0-9]*.[(\+)]\\s([0-9]*).[(\+)].[0-9]*.[(\+)]\\s([0-9]*).[(\+)].[0-9]*.[(\+)]\s([0-9]*).[(\+)].[0-9]*.[(\+)]\\s")]

[H, IF(0< getFindCount(id)), CODE: {
   [Strength=getGroup(id, 0, 0)]
   [IF(Strength==""):Strength=10]
   [Dexterity=getGroup(id, 0, 1)]
   [IF(Dexterity==""):Dexterity=10]
   [Constitution=getGroup(id, 2, 1)]
   [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]

}]
I realize the getGroup numbers are all mixed up, I was just trying to extract any number at all! (to no avail.) Any help would be greatly appreciated before I go completely bald. :P
Last edited by Sereptus on Tue Feb 19, 2019 7:03 pm, edited 1 time in total.
OOOHH RegEx....YOU BITTER-SWEET BEAST!!!

User avatar
aliasmask
RPTools Team
Posts: 9024
Joined: Tue Nov 10, 2009 6:11 pm
Location: Bay Area

Re: ReGex :/

Post by aliasmask »

I went ahead and did it how I would do it rather than finding what's wrong with your code.

First I find the pattern of the six stats group together separated by tabs and save that as 1 string. Then I regex that string to pull out the stat digits because regex2 pattern could appear elsewhere in statblock, but 6 in a row doesn't. A possible exception would be a creature with 2 sets of statblocks (which I've seen). This would only get the first set.

Code: Select all

@@ @Test
[H: statblock = "Ghast

Medium undead, chaotic evil

Armor Class 13
Hit Points 36 (8d8) 
Speed 30 ft.

STR    DEX    CON    INT    WIS    CHA
16 (+3)    17 (+3)    10 (+0)    11 (+0)    10 (+0)    8 (-1)
Damage Resistances necrotic
Damage Immunities poison
Condition Immunities charmed, exhaustion, poisoned
Senses darkvision 60 ft., passive Perception 10 
Languages Common
Challenge 2 (450 XP)
Stench. Any creature that starts its turn within 5 feet of the ghast must succeed on a DC 10 Constitution saving throw or be poisoned until the start of its next turn. On a successful saving throw, the creature is immune to the ghast's Stench for 24 hours.

Turning Defiance. The ghast and any ghouls within 30 feet of it have advantage on saving throws against effects that turn undead.

ACTIONS
Bite. Melee Weapon Attack: +5 to hit, reach 5 ft., one creature. Hit: 12 (2d8 + 3) piercing damage.

Claws. Melee Weapon Attack: +5 to hit, reach 5 ft., one target. Hit: 10 (2d6 + 3) slashing damage. If the target is a creature other than an undead, it must succeed on a DC 10 Constitution saving throw or be paralyzed for 1 minute. The target can repeat the saving throw at the end of each of its turns, ending the effect on itself on a success."]

<!-- get stats -->
[H: regex1 = "((\\d+) *[(][\\d +-]+[)]\\t*){6}"]
[H: regex2 = "(\\d+) *[(][\\d +-]+[)]\\t*"]
[H: id = strfind(statblock,regex1)]

[H, if(getFindCount(id)), code: {
   [H: stats = json.append("[]","Strength","Dexterity","Constitution","Intelligence","Wisdom","Charisma")]
   [H: match = getGroup(id,1,0)]
   [H: id = strfind(match,regex2)]
   [H, foreach(stat,stats), code: {
      [H: set(stat,getGroup(id,roll.count+1,1))]
   }]
};{
   [H: assert(0,"Stats in statblock not found.",0)]
}]

!!
 

User avatar
aliasmask
RPTools Team
Posts: 9024
Joined: Tue Nov 10, 2009 6:11 pm
Location: Bay Area

Re: ReGex :/

Post by aliasmask »

Also, regex stands for regular expression. ReGex should be RegEx if you're going to capitalize. ;)

User avatar
Sereptus
Giant
Posts: 123
Joined: Tue Jun 07, 2011 12:08 pm
Location: Canada

Re: ReGex :/

Post by Sereptus »

aliasmask wrote:Also, regex stands for regular expression. ReGex should be RegEx if you're going to capitalize. ;)
Haha! Well, I'm a newb to all this! :P Thank you sooo much for your help AM! I thought that repeating the formula though the code six times was inefficient but was looking for results. I always like to try and figure this stuff out for myself because obviously the euphoria associated is great, but sometimes I have to step aside and lets the pro's help. Never-the-less, I learned a lot from your example (which of course worked). I'm sure I'll be learning and looking at that one for reference for a while now. I've decided to start taking some courses in programming with Javascript and Python because I get up at 4am to code for a couple hours before I go to work so I obviously have a passion for it! :P

Thanks again! :D
OOOHH RegEx....YOU BITTER-SWEET BEAST!!!

bennejam000
Kobold
Posts: 1
Joined: Tue Feb 19, 2019 1:22 pm

Re: ReGex :/

Post by bennejam000 »

So I've been looking for a 5e statblock importer that will work with copied and pasted stats from DnDBeyond and this code is so close. The problem is the regex looking for tab separated table of stats vs. the way DnDBeyond copies out. If I could get the regex strings for this:

STR
8 (-1)
DEX
14 (+2)
CON
10 (+0)
INT
10 (+0)
WIS
8 (-1)
CHA
8 (-1)

As opposed to the horizontal strings currently there, I would have a functional importer.

Anyone good at regex?

User avatar
aliasmask
RPTools Team
Posts: 9024
Joined: Tue Nov 10, 2009 6:11 pm
Location: Bay Area

Re: ReGex :/

Post by aliasmask »

It's essentially the same as above except you need to account for the stat names in between.

Code: Select all

<!-- get input -->
[H: abort(input("statblock||Enter Stat Block|TEXT"))]

<!-- regex to find stats in the form: STAT(spaces)Number(spaces)(stuff before next stat) where only Number is saved -->
[H: regex = "STR\\s+(\\d+)\\s*[(][+-]\\d+[)]\\s+DEX\\s+(\\d+)\\s*[(][+-]\\d+[)]\\s+CON\\s+(\\d+)\\s*[(][+-]\\d+[)]\\s+INT\\s+(\\d+)\\s*[(][+-]\\d+[)]\\s+WIS\\s+(\\d+)\\s*[(][+-]\\d+[)]\\s+CHA\\s+(\\d+)"]

<!-- do string search. Results saved in to memory and accessed by the id -->
[H: findId = strfind(statblock,regex)]

<!-- loop through the group numbers for each stat -->
[H: propNames = "Strength,Dexterity,Constitution,Intelligence,Wisdom,Charisma"]
[H, foreach(propName,propNames), code: {
   [H: set(propName,getGroup(findId,1,roll.count+1))]<br>
}]

User avatar
Sereptus
Giant
Posts: 123
Joined: Tue Jun 07, 2011 12:08 pm
Location: Canada

Re: ReGex :/

Post by Sereptus »

I worked on a functioning statblock importer that works with D&D Beyond with the help of AliasMask and several others in this community. Although you may have different properties etc for your campaign tokens. I am no expert, never the less, this should work.

Code: Select all

[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 5E statblock here|Enter statblock|TEXT|WIDTH=40")]
[H: abort(if(status < 1, 0, 1))]

[H: CRLF = decode("%0D%0A")]

[H: setPropertyType("5E-NPC")]
[H: GP=getProperty("dnd.weapons")]
[H: propnames = getPropertyNames()]
[H, foreach(propname,propnames),CODE: {
   [resetProperty(propname)]
}]

[H: setProperty("dnd.weapons", GP)]


[H: '<!-- 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, "  ", " ")]

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

[H: '<!-- Start formatting imported statblock and set it to GM notes -->']



[H: '<!-- Search for lines and sections of statblock individually -->']

[H: NameSearch = strfind(statblock, "(.*?)(CoS|OotA|SKT|PotA|ToD|VGM|MM|Tiny|Tags|Small|Medium|Large|Huge|Gargantuan)")]
[H: THEName= getGroup(NameSearch, 1, 1)]
[H: NameSearch=trim(THEName)]

[H: setName(trim(THEName))]


[H: setTokenShape("Top down")]



<!-- get stats -->
[H: regex1 = "((\\d+) *[(][\\d +-]+[)]\\t*){6}"]
[H: regex2 = "(\\d+) *[(][\\d +-]+[)]\\t*"]
[H: id = strfind(statblock,regex1)]

[H, if(getFindCount(id)), code: {
   [H: stats = json.append("[]","Strength","Dexterity","Constitution","Intelligence","Wisdom","Charisma")]
   [H: match = getGroup(id,1,0)]
   [H: id = strfind(match,regex2)]
   [H, foreach(stat,stats), code: {
      [H: set(stat,getGroup(id,roll.count+1,1))]
   }]
};{
[H: id = strfind(statblock, "(?i)(?<!base )ft.*?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="Str: "+Strength+", Dex: "+Dexterity+", Con: "+Constitution+", Int: "+Intelligence+", Wis: "+Wisdom+", Cha: "+Charisma+"<br>"]
}]
}]


[H: '<!-- STATS END -->']

[H: '<!-- SET AC -->']
[H: id = strfind(statblock, "(?i)(?<!Hit )Armor Class.([0-9]*) (.*?)\Hit Points ")]
[H, IF(0< getFindCount(id)), CODE: {
   [AC=getGroup(id, 1, 1)]
      [ACC=getGroup(id, 1, 2)]
   [IF(AC==0):AC=10+Dx]

   [AC=""+AC+" "+ACC+""]
}]


[H: '<!-- SET Speed -->']

[H: id = strfind(statblock, "(?i)(?<!STR )(Speed.|burrow.|climb.|fly.|swim.)([0-9]+)")]
[H, IF(0< getFindCount(id)), CODE: {
   [Speed1=getGroup(id, 1, 2)]
   [IF(Speed1==""): setProperty("Speed1","")]
   [IF(Speed1!=""): Speed11=getGroup(id, 1, 2)]
   [IF(Speed11==""): setProperty("Speed11","")]

   
[Speed1="Move: "+Speed1+""]
[Spd1=""+Speed11+""]
} ;{
	[Speed1=""]
	[Spd1=0]

}]
[H, IF(1< getFindCount(id)), CODE: {
   [Speed2=getGroup(id, 2, 1)]
   [IF(Speed2==""): setProperty("Speed2","")]
   [IF(Speed2!=""): Speed22=getGroup(id, 2, 2)]
   [IF(Speed22==""): setProperty("Speed22","")]
[Speed2=""+upper(Speed2,1) + ": "+Speed22+""]
[Spd2=""+Speed22+""]
};{
	[Spd2=0]

}]
[H, IF(2< getFindCount(id)), CODE: {
   [Speed3=getGroup(id, 3, 1)]
   [IF(Speed3==""): setProperty("Speed3","")]
   [IF(Speed3!=""): Speed33=getGroup(id, 3, 2)]
   [IF(Speed33==""): setProperty("Speed33","")]
   [Speed3=""+upper(Speed3,1) + ": "+Speed33+""]
   [Spd3=""+Speed33+""]
};{
	[Spd3=0]

}]
[H, IF(3< getFindCount(id)), CODE: {
   [Speed4=getGroup(id, 4, 1)]
   [IF(Speed4==""): setProperty("Speed4","")]
   [IF(Speed4!=""): Speed44=getGroup(id, 4, 2)]
   [IF(Speed44==""): setProperty("Speed44","")]
   [Speed4=""+upper(Speed4,1) + ": "+Speed44+""]
   [Spd4=""+Speed44+""]
};{
	[Spd4=0]

}]
[H, IF(4< getFindCount(id)), CODE: {
   [Speed5=getGroup(id, 5, 1)]
   [IF(Speed5==""): setProperty("Speed5","")]
   [IF(Speed5!=""): Speed55=getGroup(id, 5, 2)]
   [IF(Speed55==""): setProperty("Speed55","")]
   [Speed5=""+upper(Speed5,1) + ": "+Speed55+""]
   [Spd5=""+Speed55+""]
};{
	[Spd5=0]

}]

[h:Speed=" "+Speed1+" "+Speed2+" "+Speed3+" "+Speed4+" "+Speed5+"" ]

[h: Spd= Max(eval("Spd1"),eval("Spd2"),eval("Spd3"),eval("Spd4"),eval("Spd5"))]



[H: '<!-- SET Hit Points -->']
[H: id = strfind(statblock, "Hit Points (\\d+) [(]([^)]+)[)]")]
[H, IF(0< getFindCount(id)), CODE: {
   [HP=getGroup(id, 1, 1)]
   [MaxHP=getGroup(id, 1, 1)]
   [HitDice=getGroup(id,1,2)]
}]

[H: '<!-- Hit Points END -->']



[H: '<!-- SET SIZE -->']
[H: id = strfind(statblock, "(Tiny|Small|Medium|Large|Huge|Gargantuan|\w-]+)")]
[H, IF(0< getFindCount(id)),CODE: {

   [Size=getGroup(id, 1, 1)]

   [setSize(Size)]

}]

[H: '<!-- SET TYPE -->']
[H: id = strfind(statblock,  "(aberration.*?|beast.*?|celestial.*?|construct.*?|dragon.*?|elemental.*?|fey.*?|fiend.*?|giant.*?|humanoid.*?|monstrosity.*?|ooze.*?|plant.*?|undead.*?|-)\,")]

[H, IF(0< getFindCount(id)),CODE: {
   [Type=getGroup(id, 1, 1)]
   [Type=upper(Type, 1)]

 }]

[H: '<!-- SET ALIGNMENT -->']
[H: id = strfind(statblock,  "\,.(lawful.|neutral.|chaotic.|)(good|neutral|unaligned|evil|\w-]+)")]

[H, IF(0< getFindCount(id)),CODE: {
   [Alignment1=getGroup(id, 1, 1)]
   [Alignment2=getGroup(id, 1, 2)]
   [Alignment1=upper(Alignment1,1)]
   [Alignment2=upper(Alignment2,1)]
   [Alignment1=trim(Alignment1,1)]
   [Alignment2=trim(Alignment2,1)]

   [IF(Alignment1==""): Alignment1=""]

[Alignment=""+Alignment1+" " + Alignment2+""]
 }]




[H: id = strfind(statblock, "Passive Perception.([0-9]+)")]
[H, IF(0< getFindCount(id)), CODE: {
   [pass=getGroup(id, 1, 1)]
	
   [IF(pass>=0): setProperty("Passive Perception",pass)]
}]




[H: '<!-- Challenge BEGIN -->']
[H: id = strfind(statblock, "Challenge.([0-9]+)")]
[H, IF(0< getFindCount(id)), CODE: {
   [CR=getGroup(id, 1, 1)]
   [CR=trim(CR)]
   [IF(CR<=4): setProperty("SkillDie",2)]
   [IF(CR<=8&&CR>=5): setProperty("SkillDie",3)]
   [IF(CR<=12&&CR>=9): setProperty("SkillDie",4)]
   [IF(CR<=16&&CR>=13): setProperty("SkillDie",5)]
   [IF(CR<=20&&CR>=17): setProperty("SkillDie",6)]
   [IF(CR<=24&&CR>=21): setProperty("SkillDie",7)]
   [IF(CR<=28&&CR>=25): setProperty("SkillDie",8)]
   [IF(CR<=32&&CR>=29): setProperty("SkillDie",9)]

}]

[H: id = strfind(statblock, "Languages (.*) \Challenge")]
[H, IF(0< getFindCount(id)), CODE: {
   [Lang1=getGroup(id, 1, 1)]
   [Lang1 =trim(Lang1)]
   [Lang1 =upper(Lang1,1)]
   [IF(Lang1==""): setProperty("Lang1","")]




[Languages=" "+Lang1+""]
}]




[H: id = strfind(statblock, "(?i)\Damage Resistances?(.*?)(Damage Immunities|Condition Immunities|Senses)")]
[H, IF(0< getFindCount(id)), CODE: {
   [Resist1=getGroup(id, 1, 1)]
   [Resist1=trim(Resist1)]
   [Resist1=upper(Resist1,1)]
   [IF(Resist1==""): setProperty("Resistance","")]
   [IF(Resist1!=""): setProperty("Resistance",Resist1)]
}]
[H: id = strfind(statblock, "(?i)\Damage Immunities?(.*?)(Condition Immunities|Senses)")]
[H, IF(0< getFindCount(id)), CODE: {
   [Resist2=getGroup(id, 1, 1)]
   [Resist2=trim(Resist2)]
   [Resist2=upper(Resist2,1)]
   [IF(Resist2==""): setProperty("Immunities","")]
   [IF(Resist2!=""): setProperty("Immunities",Resist2)]
}]

[H: id = strfind(statblock, "(?i)\Condition Immunities?(.*?)(Senses)")]
[H, IF(0< getFindCount(id)), CODE: {
   [Resist3=getGroup(id, 1, 1)]
   [Resist3=trim(Resist3)]
   [Resist3=upper(Resist3,1)]
   [IF(Resist3==""): setProperty("Condition Immunities","")]
   [IF(Resist3!=""): setProperty("Condition Immunities",Resist3)]
}]

[H: '<!-- SET SENSES AND SIGHT -->']
[h, IF(0==0), CODE:{
[H: id = strfind(statblock, "(Blindsight.|Darkvision.|Tremorsense.|Truesight.)([0-9]+)(.ft.).*?\,")]
[H, IF(0< getFindCount(id)), CODE: {
   [Sense1=getGroup(id, 1, 1)]
   [Sense2=getGroup(id, 1, 2)]
   [Sense3=getGroup(id, 1, 3)]
   [Sense1=trim(Sense1)]
   [Sense2=trim(Sense2)]
   [Sense3=trim(Sense3)]

[Sense1=upper(Sense1,1)]
   [IF(Sense1==""): Sense1=""]
   [IF(Sense2==""): Sense2=""]


[Senses=""+Sense1+" " + Sense2+" " + Sense3+" "]
[Sight1=(Sense1 +Sense2)]
[setSightType(Sight1)]
}]

[H, IF(2== getFindCount(id)), CODE: {
   [Sense4=getGroup(id, 2, 1)]
   [Sense5=getGroup(id, 2, 2)]
   [Sense6=getGroup(id, 2, 3)]
   [Sense4=trim(Sense4)]
   [Sense5=trim(Sense5)]
   [Sense6=trim(Sense6)]


[Sense4=upper(Sense4,1)]

   [IF(Sense4==""): Sense4=""]
   [IF(Sense5==""): Sense5=""]
[Senses=" "+Sense1+" " + Sense2+" " + Sense3+" " +Sense4+" " +Sense5+" " +Sense6+""]
[Sight2=(Sense4 +Sense5)]
 
[IF(Sense2>Sense5): setSightType(Sight1) ; setSightType(Sight2)]
}]

   [IF(Senses==""): setProperty("Senses","")]


   [IF(Senses==""): setHasSight(0)]
   [IF(Senses!=""): setHasSight(1)]
}]

[H: '<!-- SET XP TO GM NAME -->']
[H: id = strfind(statblock, "Challenge.[0-9]+.(.*XP.)")]
[H, IF(0< getFindCount(id)), CODE: {
   [XP=getGroup(id, 1, 1)]
	[setGMName(XP)]
  
}]
[H: '<!-- HATE BARS -->']
[h: setBarVisible("Health", 0)]


[h: ids=getTokenNames()]
[h:gTok=getTokenImage()] 
[h:iTok=getTokenHandout()] 
[h:setProperty("PIC1",gTok)]
[h:setProperty("PIC2",iTok)]



[H: '<!-- GET SAVES---- GET SAVES---- GET SAVES---- GET SAVES---- GET SAVES---- GET SAVES--v>']



	[H: ST1 = strfind(statblock, "(?i)(Str.?|Dex.?|Con.?|Int.?|Wis.?|Cha.?)[+]([0-9]+)")]

[H,count(getFindCount(ST1), ""), CODE:{

   [SaveName=getGroup(ST1, roll.count+1, 1)]
      [SaveNum=getGroup(ST1, roll.count+1, 2)]
   [SaveName=trim(SaveName)]
      [SaveNum=trim(SaveNum)]

  
[IF(SaveName=="Str"):SaveNam="Strength",SaveName=""]
[IF(SaveName=="Str"): SaveN=(St),SaveN=0]   
[IF(SaveName=="Str"): srt=1,srt=1]
		
        [IF(SaveName=="Dex"): SaveNam="Dexterity",SaveName=""]
        [IF(SaveName=="Dex"): SaveN=(Dx),SaveN=0]
        [IF(SaveName=="Dex"): srt=2,srt=2]
       
			[IF(SaveName=="Con"): SaveNam="Constitution",SaveName=""]
			[IF(SaveName=="Con"): SaveN=(Cn),SaveN=0]
			[IF(SaveName=="Con"): srt=3,srt=3]
			  
				[IF(SaveName=="Int"): SaveNam="Intelligence",SaveName=""]
				[IF(SaveName!="Int"): SaveNa="Intelligence",SaveNa=""]
				[IF(SaveName=="Int"): SaveN=(In),SaveN=0]
				[IF(SaveName=="Int"): srt=4,srt=4]
				  
					 [IF(SaveName=="Wis"): SaveNam="Wisdom",SaveName=""]
					 [IF(SaveName=="Wis"): SaveN=(Ws),SaveN=0]
					 [IF(SaveName=="Wis"): srt=5,srt=5]
					 
						   [IF(SaveName=="Cha"): SaveNam="Charisma",SaveName=""]    
						   [IF(SaveName=="Cha"): SaveN=(Ch),SaveN=0]
						   [IF(SaveName=="Cha"): srt=6,srt=6]
						 					
     				



	   	[H,IF(SaveNum>=(SkillDie+SaveN)&&hasMacro(SaveNam)==0), CODE:{
	   		 
[ButtonProps='{"color":"olive","sortBy":'+srt+',"fontColor":"black","group":"3.Saving Throws","minWidth":90}']

[h:CommandText2 = strformat('
[h:jsonData = json.set("{}",	"SaveNum", "%{SaveNum}")]	[MACRO("Mon'+SaveNam+'@Lib:CharacterSheet"):jsonData]')]

[tix="Meanwhile, behind the DM Screen, dice are rolled... "]

[tex="/self"]
	  [CommandText = strformat('
	  [MACRO("M'+SaveNam+'@Lib:CharacterSheet"):""]')] 		
   [createMacro(SaveNam, tix+tex+decode(CommandText2), ButtonProps)]	


	   	}]	     			 
	   	
	  
}]

	   	[H,If(hasMacro("Strength")==1), CODE:{	};{

	  [h:jix="Strength"]

[tix="Meanwhile, behind the DM Screen, dice are rolled... "]


	   		[ButtonProps3='{"color":"pink","fontColor":"black","sortBy":'+1+',"group":"3.Saving Throws","minWidth":90}']
			[tex="/self"]
	  [CommandText3 = strformat('

	  [MACRO("'+jix+'@Lib:CharacterSheet"):""]')] 	
		[createMacro(jix,tex+decode(CommandText3), ButtonProps3)]
	   	}]
	
	   	[H,If(hasMacro("Dexterity")==1), CODE:{	};{

	  [h:jix="Dexterity"]

	   		[ButtonProps3='{"color":"pink","fontColor":"black","sortBy":'+2+',"group":"3.Saving Throws","minWidth":90}']
			[tex="/self"]
	  [CommandText3 = strformat('
	  [MACRO("'+jix+'@Lib:CharacterSheet"):""]')] 	
		[createMacro(jix, tex+decode(CommandText3), ButtonProps3)]
	   	}]


	   	[H,If(hasMacro("Constitution")==1), CODE:{	};{

	  [h:jix="Constitution"]

	   		[ButtonProps3='{"color":"pink","fontColor":"black","sortBy":'+3+',"group":"3.Saving Throws","minWidth":90}']
			[tex="/self"]
	  [CommandText3 = strformat('
	  [MACRO("'+jix+'@Lib:CharacterSheet"):""]')] 	
		[createMacro(jix, tex+decode(CommandText3), ButtonProps3)]
	   	}]

	   	[H,If(hasMacro("Intelligence")==1), CODE:{	};{

	  [h:jix="Intelligence"]

	   		[ButtonProps3='{"color":"pink","fontColor":"black","sortBy":'+4+',"group":"3.Saving Throws","minWidth":90}']
			[tex="/self"]
	  [CommandText3 = strformat('
	  [MACRO("'+jix+'@Lib:CharacterSheet"):""]')] 	
		[createMacro(jix, tex+decode(CommandText3), ButtonProps3)]
	   	}]

	   		   	[H,If(hasMacro("Wisdom")==1), CODE:{	};{

	  [h:jix="Wisdom"]

	   		[ButtonProps3='{"color":"pink","fontColor":"black","sortBy":'+5+',"group":"3.Saving Throws","minWidth":90}']
			[tex="/self"]
	  [CommandText3 = strformat('
	  [MACRO("'+jix+'@Lib:CharacterSheet"):""]')] 	
		[createMacro(jix, tex+decode(CommandText3), ButtonProps3)]
	   	}]

	   		   	[H,If(hasMacro("Charisma")==1), CODE:{	};{

	  [h:jix="Charisma"]

	   		[ButtonProps3='{"color":"pink","fontColor":"black","sortBy":'+6+',"group":"3.Saving Throws","minWidth":90}']
			[tex="/self"]
	  [CommandText3 = strformat('
	  [MACRO("'+jix+'@Lib:CharacterSheet"):""]')] 	
		[createMacro(jix, tex+decode(CommandText3), ButtonProps3)]
	   	}]
[H: '<!-- ATTACKS BEGIN ---- ATTACKS BEGIN ---- ATTACKS BEGIN ---- ATTACKS BEGIN ---- ATTACKS BEGIN -->']

[H, IF(0==0), CODE: {
   [MiscDamageBonus="0+0"]
   [MiscDamageType=""]
[PrimaryStat="max(St,Dx)"]
[MagicBonus="0+0"]
[SpecialAbility=""]
[MiscAttackBonus="0"]
[MinimumCritRoll="20"]
[FlavorText=""]
[ButtonColor="black"]
[FontColor="white"]

[H: WN = strfind(statblock, "(Actions)*([A-z]+)\\. \Melee")]
[H, IF(0< getFindCount(WN)), CODE: {
   [WeaponName=getGroup(WN, 1, 2)]
   };{  [WeaponName=""]		
}]
   [H, IF(1< getFindCount(WN)), CODE: {
         [WeaponName2=getGroup(WN, 2, 2)]
         };{  [WeaponName2=""]		
}]
            [H, IF(2< getFindCount(WN)), CODE: {
                  [WeaponName3=getGroup(WN, 3, 2)]
                  };{  [WeaponName3=""]		
}]
                     [H, IF(3< getFindCount(WN)), CODE: {
                           [WeaponName4=getGroup(WN, 4, 2)]
                     };{  [WeaponName4=""]		

}]

   
[H: id = strfind(statblock, "([A-z][a-z. ]).*? Hit:.([0-9]+)(.+?)(.slashing|.bludgeoning|.piercing)")]
[H, IF(0< getFindCount(id)), CODE: {
     [DamageType=getGroup(id, 1, 4)]
      [DamageType=trim(DamageType)]
            [DamageType=upper(DamageType,1)]

};{  [DamageType=""]		

}]
[H, IF(1< getFindCount(id)), CODE: {
     [DamageType2=getGroup(id, 2, 4)]
      [DamageType2=trim(DamageType2)]
            [DamageType2=upper(DamageType2,1)]

};{  [DamageType2=""]		

}]
[H, IF(2< getFindCount(id)), CODE: {
     [DamageType3=getGroup(id, 3, 4)]
      [DamageType3=trim(DamageType3)]
            [DamageType3=upper(DamageType3,1)]

};{  [DamageType3=""]		

}]
[H: dd = strfind(statblock, "(\\d+d\\d+)")]
[H, IF(1< getFindCount(dd)), CODE: {
   [DamageDie=getGroup(dd, 2, 1)]
};{  [DamageDie=""]		

}]
		[H, IF(2< getFindCount(dd)), CODE: {
    [DamageDie2=getGroup(dd, 3, 1)]
                
};{  [DamageDie2=""]		

}]
		[H, IF(3< getFindCount(dd)), CODE: {
    [DamageDie3=getGroup(dd, 4, 1)]
                
};{  [DamageDie3=""]		

}]


}]<!--END OF GETTING WEAPONS-->

[h: Wrang=5]

<!--THIS IS WHERE THE MACRO GOES-->
[h:CommandTextW = strformat('[h:jsonWeaponData = json.set("{}",
	"WeaponName", "%{WeaponName}",
	"DamageType", "%{DamageType}",
	"DamageDie", "%{DamageDie}",
	"DamageDie2", "%{DamageDie}",
	"PrimaryStat", "%{PrimaryStat}",
	"MagicBonus","%{MagicBonus}",
	"SpecialAbility","%{SpecialAbility}",
	"MiscAttackBonus","%{MiscAttackBonus}",
	"MiscDamageBonus","%{MiscDamageBonus}",
	"MiscDamageType","%{MiscDamageType}",
		"MinimumCritRoll","%{MinimumCritRoll}",
		"FlavorText","%{FlavorText}",
	"Wrang","%{Wrang}",
	"ButtonColor","%{ButtonColor}",
	"FontColor","%{FontColor}")]

[macro("NPC_WEAPON_ATTACK@campaign"):jsonWeaponData]')]

[h:CommandTextW2 = strformat('[h:jsonWeaponData = json.set("{}",
	"WeaponName", "%{WeaponName2}",
	"DamageType", "%{DamageType2}",
	"DamageDie", "%{DamageDie2}",
	"DamageDie2", "%{DamageDie2}",
	"PrimaryStat", "%{PrimaryStat}",
	"MagicBonus","%{MagicBonus}",
	"SpecialAbility","%{SpecialAbility}",
	"MiscAttackBonus","%{MiscAttackBonus}",
	"MiscDamageBonus","%{MiscDamageBonus}",
	"MiscDamageType","%{MiscDamageType}",
		"MinimumCritRoll","%{MinimumCritRoll}",
		"FlavorText","%{FlavorText}",
	"Wrang","%{Wrang}",
	"ButtonColor","%{ButtonColor}",
	"FontColor","%{FontColor}")]

[macro("NPC_WEAPON_ATTACK@campaign"):jsonWeaponData]')]

[h:CommandTextW3 = strformat('[h:jsonWeaponData = json.set("{}",
	"WeaponName", "%{WeaponName3}",
	"DamageType", "%{DamageType3}",
	"DamageDie", "%{DamageDie3}",
	"DamageDie2", "%{DamageDie3}",
	"PrimaryStat", "%{PrimaryStat}",
	"MagicBonus","%{MagicBonus}",
	"SpecialAbility","%{SpecialAbility}",
	"MiscAttackBonus","%{MiscAttackBonus}",
	"MiscDamageBonus","%{MiscDamageBonus}",
	"MiscDamageType","%{MiscDamageType}",
		"MinimumCritRoll","%{MinimumCritRoll}",
	"ButtonColor","%{ButtonColor}",
		"FlavorText","%{FlavorText}",
	"Wrang","%{Wrang}",
	"FontColor","%{FontColor}")]


[macro("NPC_WEAPON_ATTACK@campaign"):jsonWeaponData]')]
<!--THIS IS WHERE THE MACRO GOES-->

[h:ButtonProps='{"color":"'+ButtonColor+'","fontColor":"'+FontColor+'","group":"2.Combat (Weapons)","minWidth":90}']
[h:ButtonProps2='{"color":"'+ButtonColor+'","fontColor":"'+FontColor+'","group":"2.Combat (Weapons)","minWidth":90}']

[H, IF(0< getFindCount(WN)), CODE: {
	[if(hasMacro(WeaponName)==0), CODE:{
   [createMacro(WeaponName, decode(CommandTextW), ButtonProps)]
}]
}]
[H, IF(1< getFindCount(WN)), CODE: {
	[if(hasMacro(WeaponName2)==0), CODE:{
   [createMacro(WeaponName2, decode(CommandTextW2), ButtonProps)]
}]
}]

[H, IF(2< getFindCount(WN)), CODE: {
	[if(hasMacro(WeaponName3)==0), CODE:{
   [createMacro(WeaponName3, decode(CommandTextW3), ButtonProps)]

}]
}]

[h:ButtonProps9='{"color":"black","sortBy":"zz","fontColor":"white","group":"2.Combat (Weapons)","minWidth":90}']


[H: MA = strfind(statblock, "(Multiattack)")]
[H, IF(0< getFindCount(MA)), CODE: {
   [MAD=getGroup(MA, 1, 1)]
[tex="/self"]
   [if(hasMacro(MAD)==0), CODE:{
   	[CommandText = strformat('
   	[MACRO("'+MAD+'@global"):""]')]	   
		   	[createMacro(MAD, tex+decode(CommandText), ButtonProps9)]

};{   
	[MAD=""]
      }]
}]


[H: id = strfind(statblock,"(Abberant Ground|Action Surge|Acid Absorption|Adhesive|Advanced Telepathy|Aggressive|Air Form|Ambusher|Amorphous|Amphibious|Angelic Weapons|Antimagic Cone|Antimagic Susceptibility|Artificers Lore|Assassinate|Aversion of Fire|Aversion of Damage Type|Avoidance|Axiomatic Mind|Band of the Black Earth|Barbed Hide|Beast of Burden|Berserk|Berserk|Blessing of Mother Night|Blind Senses|Blood Frenzy|Bonded Mount|Bound|Brave|Brave Devotion|Brute|Call to the Wave|Cantrip|Cavalry Training|Celestial Legacy|Celestial Resistance|Chameleon Carapace|Chameleon Skin|Charge|Chilling Mist|Cold Aura|Confer X Resistance|Confusing Gaze|Consume Life|Corrode Metal|Corrosive Form|Cunning Action|Damage Absorption|Damage Resistance Draconic Ancestry|Damage Resistance|Damage Transfer|Dark Advantage|Dark Devotion|Death Burst|Death Burst|Deathly Choir|Death Throes|Detect Invisibility|Detect Life|Detect Sentience|Devils Sight|Devils Tongue|Discorporation|Disintegration|Displacement|Distress Spores|Dive|Divine Awareness|Divine Eminence|Draconic Majesty|Draconic Majesty|Draconic Majesty|Dragon Fanatic|Dreadful Glare|Drone|Drow Magic|Drow Weapon Training|Duergar Magic|Duergar Resilience|Duergar Resilience|Dwarven Armor Training|Dwarven Combat Training|Dwarven Resilience|Dwarven Toughness|Earthen Defeat|Earthen Passage|Earth Glide|Earth Walk|Echolocation|Eerie Resemblance|Elemental Demise|Elf Weapon Training|Empowered Attacks|Ephemeral|Ethereal Jaunt|Ethereal Sight|Etherealness|Evasion|Extra Language|Extraordinary Feature|False Appearance|Fanatical Advantage|Faultless Tracker|Fear Aura|Fear of Fire|Fear of Damage|Feat|Feral|Fey Ancestry|Fey Step|Fiendish Blessing|Fire Aura|Fire Absorption|Fire Form|Fleet of Foot|Flaming Weapon|Flight|Flyby|Foul|Freedom of Movement|Frightful Presence|Freeze|Funeral Pyre|Fungus Stride|Giant Slayer|Gibbering|Gnome Cunning|Grappler|Grasping Tendrils|Grim Harvest|Gruumshs Fury|Guiding Wind|Halfling Nimbleness|Heart of Hruggek|Heart Sight|Heated Body|Heated Weapon|Hellfire|Hellish Weapons|Hellish Rejuvenation|Hellish Resistance|Hold Breath|Horrific Appearance|Howling Defeat|Ice Walk|Ignite Enemy|Ignited Illumination|Illumination|Immolation|Immutable Form|Improved Critical|Incite Rampage|Incorporeal Movement|Indomitable|Infernal Legacy|Innate Spellcasting|Ignited Illumination|Insanity|Inscrutable|Invisibility|Invisible in Water|Iron Scent|Keen Hearing and Smell|Keen Smell|Keen Senses|Keen Sight|Keen Sight and Smell|Labyrinthine Recall|Legendary Resistance|Light Sensitivity|Limited Amphibiousness|Limited Flight|Limited Magic Immunity|Limited Spines|Limited Telepathy|Limited Telepathy|Limited Telepathy|Living Shadow|Lucky|Magic Resistance|Magic Weapons|Malison Type|Marshal Undead|Martial Advantage|Mask of the Wild|Master of Undeath|Menacing|Merge with Stone|Mimicry|Mingle with the Wind|Misty Escape|Mountain Born|Mucous Cloud|Multiple Heads|Mushroom Portal|Natural Athlete|Natural Illusionist|Naturally Stealthy|Negative Energy Cone|Nimble Escape|Nondetection|Olyhydras Armor|Ooze Cube|Otherworldly Perception|Pack Tactics|Petrifying Gaze|Petrifying Gaze|Poison Sense|Poison Spores|Poor Depth Perception|Phalanx Formation|Potent Cantrips|Pounce|Powerful Build|Probing Telepathy|Prone Deficiency|Psychic Defense|Rampage|Reach to the Blaze|Reactive|Reactive Heads|Reckless|Reflective Carapace|Regeneration|Regeneration|Rejuvenation|Rejuvenation|Rejuvenation|Rejuvenation|Rejuvenation|Relentless|Relentless Endurance|Rolling Charge|Running Leap|Rust Metal|Savage Attacks|Sculpt Spells|Searing Armor|Second Wind|Sense Magic|Shadow Stealth|Shapechanger|Shapechanger|Shark Telepathy|Shell Camouflage|Shielded Mind|Shrapnel Explosion|Siege Monster|Silent Speech|Slippery|Skewer|Skill Versatility|Sneak Attack|Speak with Beasts and Plants|Speak with Frogs and Toads|Speak with Small Beasts|Spectral Armor and Shield|Spell Turning|Spell Storing|Special Equipment|Spellcasting|Spell Immunity|Spider Climb|Standing Leap|Steadfast|Stench|Stone Camouflage|Stonecunning|Stones Endurance|Stout Resilience|Stunning Strike|Summon Mephits|Sun Sickness|Sunlight Sensitivity|Sunlight Weakness|Superior Darkvision|Superior Invisibility|Sure-Footed|Surprise Attack|Swarm|Swift Animation|Swim|Tail Spike Regrowth|Talons|Telepathic Bond|Telepathic Bond|Telepathic Shroud|Terrain Camouflage|Tiamats Blessing of Retribution|Tinker|Tool Proficiency|Trampling Charge|Trance|Transparent|Treasure Sense|Tree Stride|Tunneler|Turn Immunity|Turn Resistance|Turning Defiance|Two Heads|Unarmoured Defence|Unarmoured Movement|Unending Breath|Undead Fortitude|Undead Slayer|Undetectable|Vampire Weaknesses|Variable Illumination|Vengeful Tracker|Wakeful|Wakeful|War Magic|Water Bond|Water Breathing|Water Form|Water Susceptibility|Water Walk|Watery Fall|Weapon Bond|Web Sense|Web Walker|Winged|Wounded Fury|Wreathed in Flame)")]



[h:ButtonProps='{"color":"pink","fontColor":"black","group":"Traits and Features","minWidth":90}']
[H,count(getFindCount(id), ""), CODE:{
	[TraitName=getGroup(id, roll.count+1, 1)]

[tex="/self"]

	[if(hasMacro(TraitName)==0), CODE:{
	[CommandText = strformat('
	[MACRO("'+TraitName+'@global"):""]')]	   
		   	[createMacro(TraitName, tex+decode(CommandText), ButtonProps)]
	
}]
}]
[H: id = strfind(statblock,"(Acrobatics.?|Animal Handling.?|Arcana.?|Athletics.?|Deception.?|History.?|Insight.?|Intimidation.?|Investigation.?|Medicine.?|Nature.?|Perception.?|Performance.?|Persuasion.?|Religion.?|Sleight of Hand.?|Stealth.?|Survival.?)[+]([0-9]+)")]




[h:ButtonProps='{"color":"olive","fontColor":"black","group":"6.Skills","minWidth":90}']

[H,count(getFindCount(id), ""), CODE:{
	[SkillName=getGroup(id, roll.count+1, 1)]
[SkillNum=getGroup(id, roll.count+1, 2)]
[SkillName=trim(SkillName)]


[tex="/self"]

	[h,if(hasMacro(SkillName)==0), CODE:{

[h:CommandText = strformat('
[h:jsonData = json.set("{}",	"SkillNum", "%{SkillNum}")]	[MACRO("-'+SkillName+'@Lib:CharacterSheet"):jsondata]')]

	[createMacro(SkillName, tex+decode(CommandText), ButtonProps)]

}]


	}]

OOOHH RegEx....YOU BITTER-SWEET BEAST!!!

Post Reply

Return to “Macros”