Recursive macros to support a subset of a dice roll

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
iperetta
Kobold
Posts: 2
Joined: Wed Aug 18, 2021 9:13 pm

Recursive macros to support a subset of a dice roll

Post by iperetta »

I'm new to MapTools and I have some experience on programming. I'm having some difficulties with macros without knowing how to implement recursion or the fact MapTool can only handle two levels of nested code. I have the following code that can handle the first instance of my dice rolls.

Consider DiceNumber as any number (e.g. 6) related to an attribute. Keep in mind that 4+ is a success and 6 is a magnificient success.

Code: Select all

Dice: 
[r:num=DiceNumber]
[h:nss=0]
[h:nsm=0]
[WHILE(num > 0), CODE:
{
  [d6roll=1d6]
  [IF(d6roll >= 4 && d6roll < 6),CODE:
  {
    [h:nss=nss+1]
  }; {};
  ]
  [IF(d6roll == 6),CODE:
  {
    [h:nsm=nsm+1]
  }; {};]
  [h:num=num-1]
}]
<br>
Success: [nss]<br>
Magnificient success: [nsm]<br>
The thing is, I need players to chose if they want to reroll "magnificient success" dice with the following recursive behaviour (example):
Roll 6 dice:

Code: Select all

5, 4, 1, 6, 4, 6
Success: 3
Magnificient success: 2
- reroll? no = ends roll; yes = reroll up to 2 dice (keeping the rerolled as +1 simple success)

Reroll:

Code: Select all

3, 6
Success: 4 (up to now)
Magnificient success: 1 - reroll? no = ends roll; yes = reroll up to 1 dice

Reroll:

Code: Select all

6
Success: 5 (up to now)
Magnificient success: 1 - reroll? no = ends roll; yes = reroll up to 1 dice

Reroll:

Code: Select all

6
Success: 6 (up to now)
Magnificient success: 1 - reroll? no = ends roll; yes = reroll up to 1 dice

Reroll:

Code: Select all

3
Success: 7 (up to now)
Magnificient success: 0 - no rerolls allowed
* End of dice roll*
Is there a way for implementing this kind of roll in MapTool? At least, how can I implement recursive macros or functions in MapTool?

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

Re: Recursive macros to support a subset of a dice roll

Post by aliasmask »

Is there a reason to not reroll? Seems to me you always keep your successes, so rerolling only increases the successes or at least maintains.

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

Re: Recursive macros to support a subset of a dice roll

Post by aliasmask »

Recursion can be done by calling the called macro and passing the info it needs, but you can do this without recursion.

Code: Select all

[H: numDice = 8]

[H: continue = 1]
[H: successes = 0]
[H: clearRolls() ]

[H, while(continue && numDice), code: {
   [H: roll(numDice,6)]
   [H: rolls = getNewRolls()]
   [H: success = json.length(json.path.read(rolls,'\$[?(@ in [4,5])]'))]
   [H: mSuccess = json.length(json.path.read(rolls,'\$[?(@ == 6)]'))]
   [H: successes = successes + success]
   [H: continue = input(strformat('tip|<html>Rolls: %{rolls}<br>Sucesses: %{successes}<br>Magnificient Success: %{mSuccess}</html>|Rolls|LABEL|SPAN=TRUE'),
     'tip|<html><div width="100px"><hr></div></html>|bar|label|span=true',
     "tip|CONTINUE...|tip|label|span=true"
   )]
   [H, if(! continue), code: {
      [H: successes = successes + mSuccess]
   };{
      [H: numDice = mSuccess]
      [H, if(mSuccess): successes = successes + 1]
   }]
}]

[R: strformat("Successes: %{successes}")]

iperetta
Kobold
Posts: 2
Joined: Wed Aug 18, 2021 9:13 pm

Re: Recursive macros to support a subset of a dice roll

Post by iperetta »

Thanks @aliasmask for your insight. Answering your question, it's Adventure Time RPG and the roll let you choose to re-roll magnificient successes or not. For each magnificient success, you could both turn it into a simple success and re-roll a dice. The thing is, you need a minimum number of success in order to perform an action, but the final number of magnificient ones can add flavor to the result (e.g. extend effect, inflict scars, etc).

It turned out that with some deeper research, I finally understand some key aspects on how to do it. I'm using Library Tokens (https://wiki.rptools.info/index.php/Library_Token) to define global functions and Tables (https://wiki.rptools.info/index.php/Int ... _to_Tables) to include images of dice (e.g. with Help > Add Default Tables) .

Here is the solution I've implemented so far:

---------------
Lib:BookOfRolls token in hidden layer in a hidden map, with two macros:

> hdaBasicRoll macro

Code: Select all

<!-- rollDice Macro -->
[h:returnData = ""]
[h:num=eval(macro.args)]
[h:nss=0]
[h:nsm=0]
Dice: 
[WHILE(num > 0, ""), CODE:
{
	[h:d6roll=1d6]
	<image src='[r: tableImage("D6", d6roll)]'></image>
	[IF(d6roll >= 4 && d6roll < 6),CODE:
	{
	  [h:nss=nss+1]
	}; {};
	]
	[IF(d6roll == 6),CODE:
	{
	  [h:nsm=nsm+1]
	}; {};]
	[h:num=num-1]
}]
<br>
[h:returnData=setStrProp(returnData, "nSS", nss)]
[h:returnData=setStrProp(returnData, "nSM", nsm)]
[h:macro.return=returnData]
> hdaRoll macro

Code: Select all

<!-- (re)rollDice Macro -->
[h:ndices=macro.args]
[h:totalSS=0]
[h:totalSM=0]
[h:again=1]
[while(again==1, ""), code:
{
	[h:returnData = ""]
	[MACRO("hdaBasicRoll@Lib:BookOfRolls"):ndices]
	[h:rollResult=macro.return]
	[h:varsFromStrProp(rollResult)]
	[h:totalSS=totalSS+nSS]
	[h:totalSM=totalSM+nSM]
	[h:nreroll=0]
	[if(totalSM > 0), code:
	{
		[h:status=input("junkVar|" + totalSS + "|#Success|LABEL",
			"junkVar|" + totalSM + "|# Magnificient Success|LABEL", 
			"nreroll|" + totalSM + "|How many magnificient successes to re-roll (CANCEL for 0)?")]
	};{
		[h:status=0]
	};]
	[if(nreroll > totalSM && status == 1), code:
	{
		[h:nreroll=totalSM]
	};
	{};]
	[if(nreroll > 0 && status == 1), code:
	{
		---<br>
		[h:totalSS=totalSS+nreroll]
		[h:totalSM=totalSM-nreroll]
		[h:ndices=" "+nreroll]
		[h:again=1]
	};
	{
		[h:again=0]
	};]
}]
------<br>
<b>Total Success: <font color="blue">[totalSS + totalSM]</font>, from which <font color="red">[totalSM]</font> are magnificient ones.</b><br>
[h:returnData=setStrProp(returnData, "totalSS", totalSS)]
[h:returnData=setStrProp(returnData, "totalSM", totalSM)]
[h:macro.return=returnData]
------------
For my character tokens, I just need to include one macro for each type of preset roll they need. For example, a generic roll to test "attribute + modifier" goes like this:

> actHold macro

Code: Select all

[h:status=input(
"attrib|Knack, Confusion, Muscles, Head, Contacts, Smartness, Talkativeness, Coolness, Stubbornness|Attribute|LIST|SELECT=0 VALUE=STRING",
"mod|0|Modifier"
)]
[if(status == 1), code:
{
	Roll based on [r:attrib] + [r:mod]<br>
	[MACRO("hdaRoll@Lib:BookOfRolls"):attrib+"+"+mod]
};
{};
]
The fact that MapTool can only handle two levels of nested code and that it needs Lib:tokens to store global functions really busted my gears, but I think I can handle this from now on :D
Of course, I need to keep an eye open for json methods, as @aliasmask suggested. Maybe I could clean my code a little bit with them.

Post Reply

Return to “Macros”