2018/02/15

ADnD, Low Pass Filter and Extract Method

As I am very fond of old style Role Playing Games, I am working on a toy project about Advanced Dungeons and Dragons, 1st edition.

Now, this game is full of strange rules. For example, when the characters encounter a group of monsters, both parties have to roll a d6 (standard six faced die); if one of the parties rolls 1 or 2, that party is surprised. Also, in this case, the value of the die (1 or 2) indicates the number of "segments" (6 seconds period) for which that party is surprised.

In my first Python implementation, this lead me to write a method in the Party class, which was something like this:

def surprise_segments(self):
roll = random.randint(1, 6)
return roll if roll <= 2 else 0
Pretty simple, right?

This simple piece of code didn't satisfy me very much. The roll variable wasn't very useful here: it was just a temp variable to keep the roll value so that it could be used in the following expression.

So, I decided to extract that part and see if I could come with something better:

def _upper_bound(self, roll):
return roll if roll <= 2 else 0
def surprise_segments(self):
return _upper_bound(random.randint(1, 6))
This was much better, as now I just invoked the randint function without holding the result somewhere.

What was not satisfactory now was the name of the auxiliary function; it wasn't saying very much about the actual behavior of the code. Moreover, if I read "upper bound", I expect something which will cap at a specific value.

From the experiences of some previous (working) life, I remembered that I was implementing some sort of filter, a low pass filter ( https://en.wikipedia.org/wiki/Low-pass_filter ). In my case, this is an "Ideal low pass filter", but this was enough for me. So, now I could rename the function:

def _low_pass_filter(self, value, cutoff):
return value if value <= cutoff else 0
def surprise_segments(self):
return self._low_pass_filter(random.randint(1, 6), 2)
While I wasn't able (yet) to find other parts of my code which needed a low_pass_filter, I found similar patterns like:

def a_method(self, ...)
x = something
y = something_else
do_something_with_x_and_y


So, this kind of pattern can be easily refactored:

def _do_something(self, x, y):
do_something_with_x_and_y
def a_method(self, ...)
self._do_something(something, something_else)
There are some advantages in doing this:
  • a_method becomes shorter, which could make it easier to read 
  • do_something can get a better name which really explains what you are trying to do_something 
  • do_something is a behavior which can be re-used 
  • do_something is a behavior which can be stubbed/mocked in a test 

There are a couple of refactorings which are relevant here:




2018/02/09

You've got to be taught to hate and fear

You've got to be taught to hate and fear
You've got to be taught from year to year
It's got to be drummed in your dear little ear
You've got to be carefully taught

You've got to be taught to be afraid
Of people whose eyes are oddly made
And people whose skin is of diff'rent shade
You've got to be carefully taught

You've got to be taught before it's too late
Before you'r six or seven or eight
To hate all the people youre relatives hate
You've got to be carefully taught


2018/01/09

Adding initiative table




A new version of the Calc spreadsheet to handle the combats.

I added on the right side the initiative order; also, the current attacker is highlighter both on the initiative order table (right side) and on the couplings table (middle).

I also restructured a lot the table on the left. My idea was to make it a little more "storytelling" and a little less "data entry". The labels will change according to what is the next expected action (by me or by the players) and thus I should avoid to be confused during the combat resolution.

I plan to create a new sheet to resolve social and academic actions, so that they can have the required depth as well.




2018/01/08

Game session of Sunday



Yesterday was Sunday, and as usual, we had our (short) session playing Decipher's Lord of the Rings RPG.

In this game, I am the Narrator (or Dungeon Master if you prefer); my wife plays Carawen, an Elven female warrior from Mirkwood, and my daughter plays Luna, a (very young) wizard, pupil of Radagast, from the land of Rohan.

They are in year 2700 from Third Era. At the moment, they are traveling in the Iron Hills directed to Cape East, the most eastern of the Dwarven settlements in the Iron Hills. They are following the tracks of another Dwarf, Nar son of Dar, who was hunting a Dragon years before.

In the last short session, while they were camping on the road they met Morwen, a mysterious woman who was traveling alone coming from Cape East. During the night, they were attacked by a group of six orcs, but they were able to overcome them, also thanks to the prowess of Morwen with her sword. While they were warned about the possibility of attacks of Orcs on this road, they have not discovered yet if there was something more behind this.

Aside from the story (very little happened), I had the possibility to play-test the new version of my spreadsheet.

What went well:
  • spreadsheet is very good at keeping track of effects, like Staggered, Wounded, Broken Leg, etc.
  • since I can track them, I will actually use them


What went wrong
  • I didn't have the stats for a creature in the spreadsheet, hence I had to add them on-the-fly (lack of preparation);
  • having a single creature to make a test is fine, having 6 of them is cumbersome (need automation here);
  • some skills like Elusion (?) where I need to roll 3d6 and drop the lowest one are hard (create a generic dice roller to use);
  • while the system keeps track of who is doing who, I have to ensure that this is actually what is happening (interface is sometimes confusing);
  • Staggered tests are very common, better to have a dedicated button for it (add staggered button);
  • also, sometimes I am not sure of what is happening: maybe I need to add a little more log;


Actions (still to be cleared)
  • ensure that you have the proper stats loaded;- devise testing for a group, both for players and for other creatures;
  • create a generic dice roller (how many dice, how many to drops, etc);
  • have the system explain what it is doing;
  • add a button to check for Staggering;



2018/01/06

A toolbar for the combat spreadsheet


Another version, with a few more changes, namely:

  • the buttons have been moved away from the spreadsheet to a toolbar
  • the grid has been removed and re-added only where necessary
  • a new sheet has been included which I will use to look-up the attributes, reactions and skills
  • a problem with critical hits has been fixed: only melee critical were shown

Calendars, weather sense and honesty

I am currently running a couple of RPG campaigns in Tolkien's Middle Earth; the first one is set seventy years before the fall of Erebor, and the second one four years after the Quest for Erebor.
So, I decided the day of the year (in game time) when the two campaigns were going to start, and we started from there. My players were very diligent in keeping track of the time, and we had a nice journal with all their notes about the events.
After a while, I decided to use some random weather generator. The first one was https://donjon.bin.sh/d20/weather/ ; this is a very simple weather generator, which is very good if you have to generate a week or two of data, but it becomes somehow cumbersome if you want to generate a longer calendar.
The second one was https://www.reddit.com/r/DnDBehindTheScreen/comments/6ckopi/rpg_weather_generator_daily_weather_based_in/ ; this is a very detailed generator, which will generate one year of weather. I modified it so that the names and descriptions were in Italian, and I switched to it.

For me, as a DM, this had the effect of removing the burden to think what was going to be the weather that day. I had it, I had different types of weather, and this made the game more enjoyable for my players and me.

But this had also an interesting effect on my players: all of sudden, the Weathersense skill, which up to that point was useless for them, became important, because they wanted to know if they were going to face a storm when they were going to adventure outdoor.

My learning on this is: be honest with your players.

For example, if as a DM I am not going to use any kind of calendar and weather, the Weathersense skill will be a waste for a player 99% of times. So, I should  let the players know that this skill will be (more or less) useless for them. This is not a problem: as we are not really adventurers in the Middle Earth, there will always be abstractions and simplifications; but the players should know about them.

On the other hand, when I decide that the weather is a factor, as I said before, the game is enriched, and the game is more fun for everyone (including me), and allows you to play adventures which are more than the usual hack and slash.

Take the case that your adventures are underground (like in Moria, or in another abandoned Dwarven mine); they need water; how they can find it? How long can they resist without it? In such and similar conditions the adventurers will have to rely on their Survival skills. They will need fire: the perfect opportunity for a Dwarven character, or for a Mage with the suitable spell. Even the Light enchantment of a a Mage is important in the darkness.

Or, take the case that the adventures meet a bunch of strangers; can they understand where the strangers come from by their accent? I am pretty sure that a native English speaker can understand that I am from southern Europe (maybe even from Italy); can my adventurers understand if the strangers are from Bree? Or maybe from Esgaroth? Or maybe they are Southern people from Gondor; or maybe they are from Umbar, and in this case what are they doing here?

The same applies to the adventurers as well: a man from Esgaroth walking in the Prancing Pony in Bree will raise questions, some of them could just be innocent questions, like the ones which could make Barliman Butterbur; or a Ranger of the North (like Strider) could take an interest in them; or, even worse, a spy of the White Hand could send a message to the South.

So, the lesson for me is: check the available skills, and understand the encounters where they will be useful; and use this to enrich my world.

Roll the dice.

Have fun.