About Me

My photo
Seattle, Washington, United States
I'm an old time roleplayer who became a soldier who became a veteran who became a developer who became a dba who became a manager who never gave up his dream of a better world. Even if I have to create it myself.

Thursday, March 15, 2012

Macro for Random Gems

I've previously posted how Phoenix randomly generates gems.  This is the sort of thing I like to automate, and MapTool provides an easy platform for that automation.

(created for MapTool v1.3.b87)

It was a good chance to enhance my MapTool macro coding skills a little bit, so here we go.

First, I created two MapTool tables - Base Gem Values, and Gem Names.  You can download these here if you like.  You can modify the Gem Names table by adding or removing elements to each individual array.

Next I created a subroutine macro called Create Gem, and a macro called Gem that calls it in a loop.  Gem will pop up a dialog box asking for both the number of gems (text box) and the tier (a dropdown box).

You might wonder why I did this as two macros instead of one, when the code nesting wouldn't violate MapTool's 2-level policy.  Well, it is to allow larger lists of gems - in one macro, 100 gems would exceed the default stack space.  Splitting it into a subroutine allows up to 100 gems with no problems - and since that was my upper use case, I have limited the macro to that maximum.

Having the subroutine macro also lets me re-use it in the future, such as with a broader "treasure generation" macro.

Macro:  Create Gem
[h:assert(isGM(),"You must be the GM to use this macro.")]

[h: BaseValueRoll = macro.args]
[h, if (BaseValueRoll > 40): BaseValueRoll = 40]
[h: BaseValueScalar = floor(BaseValueRoll / 5)]
[h: BaseValue = table("Base Gem Values", BaseValueScalar)]

[h: NameRoll = eval("1d" + json.length(table("Gem Names", BaseValueScalar)) + "-1")]
[h: Name = json.get(table("Gem Names", BaseValueScalar), NameRoll)]

[h: WeightRoll = 1d100]
[h: Weight = if (WeightRoll <= 85, 1d10e * 0.1, 1d6e)]

[h: QualityRoll = 1d100]
[h: QualityName = ""]
[h, if(QualityRoll > 30 && QualityRoll <= 40), code:
  [h: BaseValue = BaseValue * (1 + (0.1 * 1d4e))]
  [h: QualityName = "remarkable"]
[h, if(QualityRoll > 10 && QualityRoll <= 30), code:
  [h: BaseValue = BaseValue * (1 - (0.1* 3d3))]
  [h: QualityName = "poor"]
[h, if(QualityRoll > 5 && QualityRoll <= 10), code:
  [h: BaseValue = BaseValue / 2]
  [h: QualityName = "uncut"]
[h, if(QualityRoll <= 5), code:
  [h: BaseValue = BaseValue / 2]
  [h: QualityName = "powdered"]

[h: Value = round(BaseValue * Weight)]
[h, if (Value < 1): Value = 1]
[h: gpValue = round(Value / 100, 1)]
[h, if (gpValue == floor(gpValue)): gpValue = floor(gpValue)]
[h, if (Value >= 100): ValueDesc = gpValue + "gp"; ValueDesc = Value + "sp"]

<!-- Summary -->
[h: macro.return = Weight + "ct " + QualityName + " " + Name + ", worth " + ValueDesc]

Macro:  Gem
[h:assert(isGM(),"You must be the GM to use this macro.")]

[h: status = input
  "NumberOfGems|1|Number of Gems",
  "Tier|Mortal, Heroic, Demigod|Tier|LIST|SELECT=0 VALUE=STRING"
[h: abort (status)]

[h: NumberOfGems = min(NumberOfGems, 100)]
[r,g: "<b>" + NumberOfGems + " " + Tier + " Gem" + if (NumberOfGems > 1, "s", "") + "</b><br>"]

[r,g, count(NumberOfGems, "<br>"), code:
  [h, switch(Tier):
    case "Mortal": BaseValueRoll = 2d10e;
    case "Heroic": BaseValueRoll = 3d10e;
    case "Demigod": BaseValueRoll = 4d10e;

  [h, macro("Create Gem@this"): BaseValueRoll]
  [r,g: macro.return]

Sample Output

50 Mortal Gems
4ct remarkable Bloodstone, worth 44sp
0.2ct Bloodstone, worth 2sp
0.9ct uncut Turquoise, worth 5sp
0.7ct Citrine, worth 18sp
0.1ct remarkable Orange Topaz, worth 3sp
0.4ct poor Turquoise, worth 1sp
0.4ct White Coral, worth 4sp
0.7ct powdered Bone, worth 2sp
0.1ct Turquoise, worth 1sp
0.1ct uncut Blue Topaz, worth 3sp
1.9ct uncut Obsidian, worth 10sp
1.5ct Obsidian, worth 15sp
0.7ct Heliodor, worth 18sp
2ct poor White Coral, worth 4sp
0.1ct poor White Quartz, worth 1sp
3ct poor Yellow Topaz, worth 6gp
0.9ct remarkable Pyrite, worth 5sp
0.9ct poor White Coral, worth 5sp
0.5ct White Coral, worth 5sp
0.9ct remarkable Eye Agate, worth 12sp
0.3ct Eye Agate, worth 3sp
0.1ct Malachite, worth 1sp
0.5ct Eye Agate, worth 5sp
0.6ct Eye Agate, worth 6sp
0.8ct Red Zircon, worth 40sp
5ct Turquoise, worth 50sp
0.4ct poor Malachite, worth 1sp
0.9ct poor Blue Topaz, worth 14sp
0.3ct White Quartz, worth 2sp
0.1ct poor Bloodstone, worth 1sp
0.8ct poor Pyrite, worth 1sp
0.3ct White Diamond, worth 7.5gp
0.7ct Iolite, worth 18sp
0.6ct Eye Agate, worth 6sp
0.8ct uncut Obsidian, worth 4sp
0.5ct remarkable Bloodstone, worth 7sp
0.1ct Bone, worth 1sp
0.4ct remarkable Heliodor, worth 13sp
0.4ct White Coral, worth 4sp
0.2ct remarkable Blue Quartz, worth 2sp
1ct remarkable Lapis Lazuli, worth 10sp
2.7ct White Coral, worth 27sp
0.3ct remarkable Bone, worth 2sp
0.4ct Yellow Sapphire, worth 40sp
0.6ct Pyrite, worth 3sp
1.8ct Obsidian, worth 18sp
1.5ct Citrine, worth 38sp
0.7ct Moss Agate, worth 4sp
3ct poor Bone, worth 8sp
0.2ct Lapis Lazuli, worth 1sp


  1. Read through the code, looks flawless. Although I thought the MapTool language didn't have exploding dice (e.g. 1d10e) ?

    The tables in the zip file are in a binary format, so I can't look inside them without maptools (and I'm at work).

  2. Hmm, I wrote a decent sized comment but it somehow got lost. Maybe the captcha failed and I didn't notice it.

    Anyway, without rewriting it all.

    - Read the code, looks great.
    - Thought the language didn't have exploding dice (1d10e)?
    - Downloaded the gems.zip file, was binary formatted so can't look at it from work.

    1. Congratulations you triggered the spam filter!

    2. Funny thing I figured out about maptool files... rename the extension to .zip. Compressed XML files inside!

      It does have exploding dice, but the reason they didn't fit the use case before is that they don't show the individual dice and/or explosions. So 2d6e = 9.... did you just get a 5/4, or was it a 6/2/1?

      Phoenix revolves around the exploding aspect too much to not have that visible.

    3. That spam filter sucks, what did it pick up on that made it think I was spam? My flawless grammar and punctuation? :-)

      I suppose I should just create an account or login with my Google account or something, but meh.

      Ah, I should have realised it was a zip file, when I opened it up in my text editor the first two bytes were PK, obviously a zip file.

      I remember you telling me about the exploding dice in the previous post, just plum forgot!

    4. Yep, the PK was a dead give away when I did the same thing. Probably the most famous 2 letter file headings, except maybe MZ.


Related Posts Plugin for WordPress, Blogger...