The Biblyon Broadsheet

Gods & Monsters Fantasy Role-Playing

Beyond here lie dragons
Biblyon, Highland
Tuesday, October 18, 1988
Jerry Stratton, Ed.
Command-line Die Square—Wednesday, June 27th, 2018
Skull d6

Is it any surprise that a die covered in skulls is biased?

Because Pythonista does not contain scipy, calculating chi-square values using it can have trouble on edge cases. This command-line script can run on data files created by the DieSquare mobile app, and uses scipy to make more reliable calculations.

Specify the DieSquare data file on the command line.

  • $ ~/bin/diesquare "Bronze d20.diesquare"
  • Degrees of freedom: 19.0 X-square: 20.6
  • p-value: 0.359317617197
  • d20 bias is unlikely.

You can also specify the die size and a file of tab-delimited or colon-delimited data. The file should contain two columns: the result, and how many of those results occurred.

The DieSquare file format is:

  • d6
  • 1: 3
  • 2: 16
  • 3: 9
  • 4: 8
  • 5: 6
  • 6: 18

That is, any line beginning with a lower-case “d” is assumed to be specifying the die size; any line with a number followed by a colon and space followed by a number is assumed to be a result. You can also put comments in by preceding the line with a pound symbol (#).

And as you might guess, this die is almost certainly biased.

  • $ ~/bin/diesquare "Skull d6.diesquare"
  • Degrees of freedom: 5.0 X-square: 17.0
  • p-value: 0.00449979697797
  • d6 bias is probable.

The code itself (Zip file, 1.6 KB) is very simple.

[toggle code]

  • #!/usr/bin/python
  • #
  • import argparse
  • import scipy.stats
  • parser = argparse.ArgumentParser(description='Calculate Chi Square p-value using DieSquare data files.')
  • parser.add_argument('--die', type=int, help='die size')
  • parser.add_argument('data', type=argparse.FileType('r'), nargs=1)
  • parser.add_argument('--verbose', action='store_true')
  • args = parser.parse_args()
  • class ChiSquare():
    • def __init__(self, die, rolls):
      • self.die = die
      • self.parseRolls(rolls)
    • def parseRolls(self, rolls):
      • self.rollCount = 0
      • self.rolls = {}
      • for roll in rolls:
        • if not roll:
          • continue
        • if roll.startswith('d'):
          • self.die = int(roll[1:])
          • continue
        • if roll.startswith('#'):
          • continue
        • if "\t" in roll:
          • separator = "\t"
      • if args.verbose:
        • print(self.rollCount)
        • print(self.rolls)
    • def calculate(self):
      • if args.verbose:
        • print '\n# ', self.die
      • expected = float(self.rollCount)/float(self.die)
      • freedom = float(self.die - 1)
      • observed = self.rolls.values()
      • expected = [expected]*self.die
      • chisquare, pvalue = scipy.stats.chisquare(observed, expected)
      • print "Degrees of freedom:", freedom, "X-square:", chisquare
      • print "p-value:", pvalue
  • calculator = ChiSquare(args.die,[0])
  • calculator.calculate()

Half of the code is just parsing the datafile; the actual calculation is a couple of lines using scipy:

  • observed = self.rolls.values()
  • expected = [expected]*self.die
  • chisquare, pvalue = scipy.stats.chisquare(observed, expected)

The variable “observed” is the list of observed result counts. The variable “expected” is the list of expected result counts. For example, rolling a d6 60 times, the expected result count is 10 for each result, so expected will equal “[10, 10, 10, 10, 10, 10]”. And observed will be the actual results; for example, in the above data the die face 1 was rolled three times, 2 sixteen times, 3 nine times, 4 eight times, 5 six times, and 6 eighteen times. This is the list “[3, 16, 9, 8, 6, 18]”. The script, of course, uses the lists it constructed by reading the datafile.

Surprise and initiative in Advanced Dungeons & Dragons—Wednesday, June 13th, 2018
Charles Marion Russell

Initiative, surprise, who knows?

Last weekend I ran an AD&D game at the North Texas RPG Convention, a run through Karl Merris’s Fell Pass from Dragon Magazine 32. Fortunately, I also ran a playtest with my local group, because I’ve forgotten a lot about how AD&D worked. Much of what I didn’t forget was wrong. I’m pretty sure we always used d10 for initiative, for example.

When I started using Gods & Monsters, I planned never to run AD&D again; preparing for this game I began to remember why. It’s not that the rules are overly complex; it’s that they’re explained in bits and pieces, scattered throughout the text, with strangely-ignored edge cases.

Take surprise, for example. Surprise is basically very easy. Roll a d6 for the entire group. If you roll a 1 or 2, the group is surprised, and that’s the number of segments they’re surprised. Individuals with high dexterity can adjust that up or down.

That some characters are surprised only on a 1 on d6 isn’t a big deal either, because the group uses their most advantageous member for the surprise roll. And that some creatures (and characters) have specific rules for when they cause surprise also works surprisingly simply, though it could have been worded better. When a group with special surprise rules meets a group with special not-surprised rules, the range needs to be converted to a modifier from the standard, and then applied to the die roll. It seems like it would have made more sense to have it be a modifier to begin with, but that’s D&D.

But no mention is made of characters who roll a percentile die to be surprised. If their most advantageous character is a Monk, and they roll 19 on d100, this means they’re surprised. It cannot possibly mean that they are surprised for 19 segments, however.

I chose to read the Monk surprise as basically a 1 in d4 chance, so that if the most advantageous party member is a Monk, the party will only be surprised for one segment.

Well-behaved deities seldom make history—Wednesday, June 6th, 2018

I was inspired a few weeks ago to make a Gods & Monsters t-shirt out of Doré’s engraving of Moses breaking the tablets of the law. After a minor issue with the first batch, they are ready. I have one in white and one in ash grey.

It looks nice enough that it inspired me to finally open the Zazzle store I started back when I first published Gods & Monsters back in 2000. This means you can also purchase an “I survived Illustrious Castle” with the completely esoteric symbol of Eliazu on the front. I made up those shirts for the first group to go through Illustrious Castle in its Gods & Monsters form. I also made up shirts that said “I died in Illustrious Castle”. I don’t know what happened to them.

This page should automatically update with the latest Zazzle products, should there be any more.

Well-behaved deities (ash)
Well-behaved deities seldom make history, a t-shirt in ash.
Well-behaved deities (white)
Well-behaved deities seldom make history. A t-shirt in white.
I survived Illustrious Castle t-shirt
From the time capsule, a never-before-released shirt from 2000 or so. I distributed these to the first players who went through Illustrious Castle (and survived).
DieSquare for iOS—Wednesday, May 16th, 2018
DieSquare chi-square test on d20

Well, the die is apparently okay. That means it’s intelligent and it hates me.

Ole Zorn’s Pythonista for iOS is an amazing mobile development environment. If you can do it in base Python, you can do it, inside a GUI, on your iPhone or iPad. This makes it a great tool for gamers who are also programmers.

My dice always seem to be conspiring against me, which is a big reason I’m interested in running chi-square tests. R is an amazing tool for doing so, but it isn’t an amazing tool for entering the data. Last week, after yet another accusation from my teammates that my die is clearly biased to roll low—in a D&D 5 game, where high is better—I started to think they might be right. The first time the accusation was made, I said, look, it’s just because the die knows I’m attacking. I’m going to roll it right now for no reason whatsoever, and the die will come up 20. It did. The die isn’t biased to roll low, it’s biased against me. But it just kept failing.

I thought I’d better double check. Because I am a typical superstitious gamer, I have different dice for different purposes, and this is in fact the first time I’ve used this die—I had it reserved for playing rather than gamemastering. It occurred to me that, since I wrote Are my dice random? in 2006, I have acquired both a great mobile device and a great development environment for it. Wouldn’t it be nice to be able to bring up a table of possible rolls, and tap on each possibility when it came up on the die so as to keep track of each count? That would make rolling through a chi-square test dead easy.

I wrote it this weekend in Pythonista. The basic idea is that you choose the die size, and then each possible die roll shows up in a table as a row. Tap the row to add one hit to that result. Slide to remove if you accidentally tapped the wrong row.1 Give the die a name if you want the results saved, and there is an icon to (a) share, for example, copy, the data or results, (b) trash the data and start over, (c) load previously-saved data. Data is automatically saved if you give the die a name. Once you hit a minimum of ten rolls per face on the die (with an absolute minimum of 50 rolls), it calculates the p-value for that data.

Combining damage dice into attack roll—Wednesday, April 18th, 2018

In Gods & Monsters, as in many role-playing games, the damage roll is completely separate from the attack roll. Dungeons and Dragons, historically, has had the same behavior: rolling a 20 is the same as rolling a 10, as long as both hit, with the caveat that a 1 always misses. The current edition, fifth edition, mixes things up a little by offering critical hits on a roll of 20, but a roll of 19 is still the same as any other roll.

This clearly goes against the grain for some players. You can see it in their eyes when they make a great attack roll and then roll a one or two for damage.

Because of this, I have occasionally considered making the damage roll somehow part of the attack roll, so that high attack rolls do more damage than low ones. The sticking point has always been that I’ve always thought about it in terms of the quality of the success, which would make such a rule more complex than it’s worth. It would also make it very difficult to damage opponents that were very difficult to hit, since the quality of success against an opponent that requires a 20 to hit, for example, will always be the minimum.

It occurred to me, though, that just using the raw attack roll wouldn’t be a big deal. While it’s true that, if you have to roll a 20 to hit and you’re doing, say, d8 damage, this would mean that you always do 8 points instead of 4.5, the real increase is from an average of .225 points per attack to .4 points per attack, since you’re almost never hitting anyway. Sure, it’s a big increase percentage-wise, but it really isn’t that big of an increase.

Using the raw attack roll makes the calculations much easier. There’s no adjustment for “how much did you make it by”. It removes agility, strength, and any situational modifiers from affecting damage unless you want them to, in which case just add it to the final damage.

Here’s how the common damage rolls in Gods & Monsters turn out in such a system:

The Great Falling War, Revisited—Tuesday, February 6th, 2018
Early Flight: Mort de Harris, Paris, 1824

“Whatever happens, I’ll send the results to Dragon Magazine!”

Delta’s D&D Hotspot claims to focus on “Math, History, and Design of Old-School D&D”, so it isn’t surprising that Delta has revisited the great falling war of 1983-84.

What is surprising is the data that Delta provides. After a lengthy analysis of the participants in the war, Delta adds:

The real-world statistics of falling mortality are expressed in terms of “median lethal distance” (LD50), that is, the distance at which a fall will kill 50% of victims (who are presumably normal adults). Smith, Trauma Anesthesia, p. 3, asserts that LD50 is around 50 feet (4 stories). Wikipedia asserts that LD50 for children is at a similar height; 40-50 feet. Dickinson, et. al., in “Falls From Height: Injury and Mortality” (Journal of the Royal Army Medical Corps, 2013) notes that LD50 varies greatly by injury type: about [34 feet] for those who land on their head or chest; about [73 feet] for those who do not.

Fifty feet is a long way, and I don’t think I would have ever guessed that the mortality rate was only 50% falling that distance. Asked to guess, I’d probably have said 75% to 85% at least. This may be yet another case where real life is allowed to be stranger than fiction. Even more amazing is how much of a difference knowing how to fall makes: raising the LD50 to seventy feet just by falling better sounds like movie reality.

Of course, even not dying there’s likely to be a lot of injuries involved—although seeing the LD50 numbers does make me wonder what the serious injury rate is, and whether I’ve been overestimating that, too—and Gods & Monsters, unlike OD&D has a system for that. As Leland J. Tankersley writes in the comments,

I think the fundamental problem in reconciling reality with D&D-like games is that health in D&D is in some respects binary—you are either dead or effectively so (0 hp or less), or else you are “fine” (1 or more hp, which might be “near-death” in some sense but which doesn’t impair your ability to act in any way. While LD50 may be 50' for a typical human, I feel confident in asserting without evidence that the vast majority of those that are NOT killed by a 50' fall are nevertheless incapacitated (broken/shattered legs, for example).

Rolling random levels across a range of experience points in AD&D—Saturday, November 4th, 2017
Substandard ability rolls

I’m prepping for a North Texas RPG Convention session, an Advanced Dungeons & Dragons adventure I’m going to run in June, in which the characters should be from levels four through six. I wanted to create these characters completely randomly; the adventure is an old-school adventure designed for old-school characters. This means a random variety of abilities and levels.

Initially, I eyeballed the level range, going from class to class in the Players Handbook knowing that I didn’t want the lowest experience point total in the range to produce a level lower than four, and that I didn’t want the highest experience point total in the range to produce a level higher than six. I correctly calculated that I needed to roll d25,000 experience and add 10,000 to it.1 The easiest way to handle this was to roll d100,000, divide by 4, round up, and add to 10,000. So, on creating each character I randomly rolled a d100,000 and performed the calculation, possibly adding 10% if the character had an earned experience bonus.2

However, reading over the adventure I wasn’t sure if perhaps I might want to make the characters level 5 to 7 instead. This would make the calculation 22,500 plus d100,000 times .375. Since I still had all of the d100,000 rolls, I first just pulled out my trusty Tandy PC-73 and wrote a quick BASIC program to handle the calculations.

  • 10 INPUT A
  • 20 B=A*.375+22500
  • 30 B=- INT(-B)
  • 40 PRINT B

Since 10% is easy to add mentally, it was faster to handle that calculation on my own instead of adding another line of code to ask whether the character merited the bonus.

Nowadays I would usually use Pythonista on the iPhone or iPad rather than the PC-7, but I was in an old-school mode, and I’ve had this BASIC-programmable pocket calculator since I first bought it in 1986, often using it for repetitive game calculations.4

It worked well enough that I decided to keep track of the d100,000 rolls in a text file.

Mighty Protectors release: Villains & Vigilantes 3.0—Friday, October 13th, 2017

As of today, Monkey House Games is selling the new edition of Villains and Vigilantes: Villains and Vigilantes 3.0 Mighty Protectors. Since I contributed to the Kickstarter for the game, I have been able to read through it for a while now; I also played in an earlier version of the game last year at the North Texas con. It’s a worthwhile game, and a worthwhile update to V&V.

I really like how Villains and Vigilantes seems to create cool PCs against all odds. The Tenth Saint, who I wrote about while reviewing the 2.1 edition of the game, was a just a random creation for a review, but I thought it was so great I’ve kept it for actual play. Going through this rulebook for the first time, I created The Old Man of the Mountain just for review purposes, and now want to play him. It’s almost impossible not to create a cool hero in V&V.

The default character creation process remains random in the new Mighty Protectors edition.1 I started by rolling my birthplace, which turned out to be local. This meant skipping over the alien and other-dimensional birthplace charts and going to Species, where I rolled Monster, “a catch-all category for characters whose appearance or Abilities render them socially unacceptable…”

Most things have a default assumption of rolling, with choice allowed, but for Age and Gender the default is choice, with rolling allowed. “Non-human characters can be of any age, from a few hours to many aeons…”. I decided to be an ancient monster. I chose an even 1,000 years.

Earlier editions did not have a specific rule for rolling player character basic characteristics, that is, strength, endurance, and so on. It was assumed that you would play yourself and that your friends would stat you up. In Mighty Protectors the campaign’s power level determines your character’s five basic characteristic scores. In a standard campaign, characters have 18, 16, 14, 12, and 10 for initial characteristics. Randomness, rather than creating the score, applies the score to a characteristic. That is, every character has the same numbers (pre-powers) but in a different order. I ended up with:

  • Strength 18
  • Endurance 10
  • Agility 14
  • Intelligence 12
  • Cool 16

Older posts.