Getting started with rule authoring can feel overwhelming at first. To help with this, one of the things I suggest to our users (after they finish Rule Authoring training) is to take a process that they know very well and model it in InRule. So for this blog post, I thought it would be a nice exercise to model a fun process…Dungeons & Dragons!
Everybody roll initiative!
The Greatest Adventure Is What Lies Ahead
For this exercise, we’re going to model some simple combat rules for D & D. For rule authoring, we usually start by building our entity structure or schema. For combat in D & D, you have your party of adventurers and their opponent, usually a monster.
We will have a top-level entity representing the Encounter with a collection of Party Members and a Monster to fight.
Next, we need to define the attributes and statistics for both the party members and the monster. We add fields for the name, class, and statistics for their major attributes, Strength, Intelligence, Dexterity, Wisdom, Constitution, and Charisma for the adventure party as well as the monster. Plus since this is a combat simulator, we also need to include some fields for their Hit Points (how much damage they can take), attack type (whether it is a Dexterity or Strength based weapon attack or a spell), attack bonuses, damage bonuses, their initiative (which determines in what order the party and the monster will attack), plus a few status indicators for conditions like “Paralyzed” and “Stunned”. In the end, we will have an entity structure for our Party, which we can also use for our monster.
Knights of the Lookup Tables
One common feature of table top role-playing games is the use of lookup tables. In this case, attack bonuses are determined by their bonus score attached to the primary attribute for their class. For example, a fighter would have an attack bonus based on their Strength score while a Wizard would have a spell attack bonus based on their Intelligence score. So we can create a generic stat bonus table with a quick SQL query to return the bonus based on the attribute value.
Roll Initiative!
Next, we need to determine the order, or initiative, in which our party members or monster will engage in combat. In the tabletop world, this would be determined rolling a 20-sided dice and adding the bonus to the Dexterity bonus. For our rule, I used the “Declare Variable” action, and set that variable using the “Execute SQL Query” action.
I used a Language rule to set the Initiative field using a generated random number between 1 and 20 and added the Dexterity bonus. Finally, I used the “Fire Notification” action to provide feedback on the results of the Initiative roll.
Let’s Get Ready to Rumble!
Now that we have our order determined, we can build the attack rules. For our party, we first need to determine the attack bonus. Different classes can have different attack bonuses depending how they attack. For example, our fighter swinging a heavy axe would use the bonus score from his Strength score, while a nimble rogue with a bow would use a Dexterity-based attack.
Spell casters add an additional point of complexity in that some spells use an ability based attack roll. For example, Wizards would use their Intelligence for a spell whereas a Cleric would use Wisdom; Other spells require a saving throw to be made by the target to avoid the worst of the spell’s effects.
Because of this complexity, I used a combination of a decision table and the Execute SQL Query action to define the bonus based on their class and how they are attacking.
Next, we need to determine if the attack requires a saving throw or a regular attack. So, for this point I branch the logic using an “if then else” statement. If it is a Spell requiring a saving throw, we need to roll a D20 and then the target would add the bonus to their attribute rated saving throw. I created a short spell table indicating the saving throw that is required.
This way we can use a query to look up the results within a select case statement as illustrated in the rule below.
Then we can roll out saving throw and if it is under the amount, the target takes the damage and if it is equal to or over then they can avoid it.
Next, we need to determine if our regular attacks will succeed. In the tabletop world, we would roll our 20-sided dice, add the bonus score, and compare the result against the opponent’s armor class. If the modified roll is higher, then the attack succeeds and we can determine damage. If it is lower, then it will fail. But if the roll before the modifier was a 20, then that would be a critical hit and then the attack does twice the damage!
For this part of the rule, I used the Select Case action to create the condition statements and used the Fire Notification action to provide feedback on the success of the attack. Any successful attack will deduct the damage dealt from the opponents Hit Point score. Note: this is a simplified version of combat and if desired, we could expand this to include damage rolls, saving throws, and other rules.
After our attack, we need to check to see if the opponent is still alive or if the Hit Point score is greater than zero. This definition is a great opportunity to create a simple classification. Classification is a simple vocabulary template that will evaluate for true or false for a given entity or field. By using this, we can define in our own language that our monster or party member is Alive if their Hit Point score is above zero, as seen below.
By doing this, our rule becomes more transparent as we check the condition of the target after the attack.
For the monster, we will execute a similar structure for the combat. However, monsters generally have set stats with attach and damage bonuses, so we will not need a decision table for that, but we do need to know which person the monster will target. I’ve chosen to do this randomly, using a declared variable to store the party member to attack, but other options could be created like targeting the party member with hit points.
We can then use that integer to have the attack target the identified member.
Controlling the Combat
After I authored the basic combat rules, I opted to build a couple of controlling rulesets to coordinate the execution of the rules. For the Initiative rules, I created a Language rule with the Execute Member Ruleset action. I used the filter option combined with the “none of the following are true” template, so we don’t roll initiative for party members that are unable to act. I also used the sort collection action to place the party in order of their Initiative score.
For controlling the attack rolls, I used a similar technique using the Execute Member Ruleset action. Since we sorted the collection of party members in the step above we can be sure the party will go in order of their Initiative Score.
Finally, we can coordinate these two rules with one more controlling rule, shown below.
Feel free to download this rule modeling exercise from our GitHub site.
Hopefully, this exercise will help illustrate how you can use irAuthor to model the processes that are important you and your organization.
Happy Authoring!