• NOW LIVE! Into the Woods--new character species, eerie monsters, and haunting villains to populate the woodlands of your D&D games.

d20Engine: Core Mechanic

nopantsyet

First Post
This is a starter discussion related to the thread Open Source d20 API/Engine. The purpose of this thread is to begin the type of discussion that I imagine will be necessary in order to develop a portable, reusable software implementation of the d20 SRD. As I mentioned in the original thread, If discussion indicates that this is a viable project, we can discuss how to turn these dialogs into practical results in a consistent manner.

To start out, I thought I would go in the same order the SRD does, so my first topic is the core mechanic. It might seem odd to start the discussion here, but it's a very simple topic that illustrates a number of the design decisions that need to be made.

The SRD presents the core mechanic as d20 + modifier vs. target number. But it goes on to explain that other dice may be used, and those results may be used in different ways. Now, at some level this has to know where the d20 mechanic is applied, and where other dice mechanics are applied. Furthermore, it has to provide for rule-specific mechanics (e.g. turning, Jump skill).

It seems all resolution scenarios break down to as many as three discrete components: a determination of success, a determination of degree, and an adjudication of effect. Leaving effect to the rule to which it applies, we should consider mechanic in relation to both success and degree.

Why abstract it like this rather than just put it in the code? Well, we want to allow alternate rules to be used, and they might have alternate resolution mechanics for certain actions. We need to be able to override the mechanic for any given entity.

What does this imply about the data model? First of all, that it will be object-oriented to some degree, allowing entities to be defined and reused or defined inline. Second, that there will be some extensibility points for implementing and replacing the necessary functions. For example, I might consider using a true entropic random number generator (random.org), but for the most part I would like use dice for resolution. So one implementation might get the random number from random.org, and another might pop up a window telling me to enter the die rolls.

Unfortunately, this leads us to the point of having to impose some aspect of implementation--every implementation must support the same integration points. But is that inferior to requiring that every implementation correctly implement the rule set? It's probably easier to reimplement the extensibility model than to reimplement the rules. I think it is important that rules be self-describing in order to support portability and overrides.

So I would propose a base entity, which I'll describe as:
Code:
<mechanic id="dX">
  <parameter id="rolls" type="int"/>
  <parameter id="faces" type="int"/>
  <parameter id="bonus" type="int"/>
  <implementation>
	<!-- Implementation via extensibility points -->
  </implementation>
</mechanic>

<mechanic id="d20">
<parameter id="faces" type="int"/>
   <parameter id="bonus" type="int"/>
   <implementation>
 	<!-- Implementation via extensibility points -->
   </implementation>
</mechanic>
Let's ignore for the moment the question of doing some Kung Fu like d20 being an inherited implementation of dX. What I want to know is your thoughts about the design questions I've raised and my suggested approaches.

.:npy:.
 
Last edited:

log in or register to remove this ad

nopantsyet said:
This is a starter discussion related to the thread Open Source d20 API/Engine. The purpose of this thread is to begin the type of discussion that I imagine will be necessary in order to develop a portable, reusable software implementation of the d20 SRD. As I mentioned in the original thread, If discussion indicates that this is a viable project, we can discuss how to turn these dialogs into practical results in a consistent manner.

To start out, I thought I would go in the same order the SRD does, so my first topic is the core mechanic. It might seem odd to start the discussion here, but it's a very simple topic that illustrates a number of the design decisions that need to be made.

Note: I use the term mechanics separate from data for clarity, but the mechanics should be defined as data...

Going through the mechanics in the order of the book is a good way of going about it since the authors intentionally tried to avoid forward references of rules. Though I would like to point out that it might be advantageous to start with how you want to represent data (for define all the spells before you define the spell system, so you know everything you are looking at). Keeping the data simple to design is more important than keeping the mechanics simple for the end user.

What does this imply about the data model? First of all, that it will be object-oriented to some degree, allowing entities to be defined and reused or defined inline.

I think AOP is a better design paradigm for this than OOP.

Second, that there will be some extensibility points for implementing and replacing the necessary functions. For example, I might consider using a true entropic random number generator (random.org), but for the most part I would like use dice for resolution. So one implementation might get the random number from random.org, and another might pop up a window telling me to enter the die rolls.

I think embedded script is the best way to go about this sort of thing. The only downfall to embedded script is language choice. I feel .NET as the platform of choice is a good idea because it allows each developer to use their own language. (I just want to point out that .NET IS cross-platform before people start complaining that it isn't; I have created several applications in that run on both Linux and Windows in .NET/Mono).

Unfortunately, this leads us to the point of having to impose some aspect of implementation--every implementation must support the same integration points. But is that inferior to requiring that every implementation correctly implement the rule set? It's probably easier to reimplement the extensibility model than to reimplement the rules. I think it is important that rules be self-describing in order to support portability and overrides.

I think the trick is to design a way to use XML to create and attach events to different pieces of data. The event handlers can then be in the XML with embedded script to handle it. I've only experimented with this idea so far, nothing concrete. But it seems to be a good direction.

So I would propose a base entity, which I'll describe as:
Code:
<mechanic id="dX">
  <parameter id="rolls" type="int"/>
  <parameter id="faces" type="int"/>
  <parameter id="bonus" type="int"/>
  <implementation>
	<!-- Implementation via extensibility points -->
  </implementation>
</mechanic>

<mechanic id="d20">
<parameter id="faces" type="int"/>
   <parameter id="bonus" type="int"/>
   <implementation>
 	<!-- Implementation via extensibility points -->
   </implementation>
</mechanic>

I assume you meant to put rolls instead of faces in the D20.

Any way, I think you should first start with a random number generator. As we are designing this for game use, it is safe to assume that random numbers would be integral to almost any game conceivable, so I have no problem relegating that to the App. The app can always ignore it if it wants (for a program made to simply print character sheets there would be no need). So as part of the contract, an application that intends to support logic (rather than just static representations of data) has to support a number of core functions. Some of these follow:

<random min-result="..." max-result="..." />
<add>...</add>
<subtract>...</subtract>
<multiply>...</multiply>
<divide options="round-down|round-up|round|float">...</divide>
<repeat num-times="...">...</repeat>
<set name="...">...</set>
<return>...</return>

The ... represents passed arguments in the form <a>reference</a> or internal commands to run, depending on context.

So to define a roll function we might do the following:

Code:
<function name="roll" face="6" num="1" mod="0">
	<repeat num-times="num">
		<set name="result">
			<add>
				<a>result</a>
				<a><random min-result="1" max-result="face" /></a>
			</add>
		</set>
	</repeat>
	<add>
		<a>result</a>
		<a>mod</a>
	</add>
</function>

Note: return is not necessary; it is implied that the function returns the last result calculated (from the add function). Also note that the values set in the function tag are the default values. You can now call <roll face="20" /> to get a d20 roll.

You could then further define a d20 function for simplicity:

Code:
<function name="d20">
	<roll face="20" />
</function>

and now use <d20 /> for a result.

Pretend we've now defined all the dice. We now need a check function to make a check of some kind. In this case, it uses context. Whenever the code encounter .whatever it is a reference to the whatever property of the calling context. If it encounters .[whatever] it resolves the whatever value and references that property of the calling context. When a passed paramete is given the "!" default value, then it must be supplied.

Code:
<function name="check" type="!" dc="!">
	<gte> <!-- greater than or equal to -->
		<add>
			<a><d20 /></a>
			<a>.[type]-mod</a></add>
		</add>
		<a>dc</a>
	</gte>
</function>

In the character, of course, we need to define how strength-mod, etc. is determined:

Code:
<character>
	<strength-mod>
		<divide options="round-down">
			<subtract>
				<a default="10">.strength</a>
				<a>10</a>
			</subtract>
			<a>2</a>
		</divide>
	</strength-mod>
</character>

The default attribute of a specifies that if the calling context does not have a .strength property set, then it should use 10 (to get no modifier).

you can now call <check type="strength" dc="15" /> to make a DC 15 strength check.

Anyway, some thoughts to bounce around. I know there are some holes in there that need to be plugged (for instace, setting the context - is this done by the application or by further XML script).
 
Last edited:

Oh, might also want to add something like the following to the roll function:

Code:
<function name="roll" ...>
	<text-representation>
		<!--
			compare might be worth having, basically returns one of three things:
			if first argument < second argument, return third argument
			if first argument = second argument, return fourth argument
			if first argument > second argument, return fifth argument
		-->
		<compare>
			<a>num</a>
			<a>1</a>
			<error />
			<text />
			<text>num</text>
		</compare>
		<text>"d"</text>
		<text>face</text>
		<compare>
			<a>mod</a>
			<a>0</a>
			<text>mod</text>
			<text />
			<text>
				<text>"+"</text>
				<text>mod</text>
			</text>
		</compare>
	</text-representation>
	...
</function>

The function can now be represented as a string. Food for thought.
 

Thinking some more, check should be renamed ability-check. There should be something more generic for check.

Going through the SRD rule by rule, next up is:

srd said:
Rounding Fractions

In general, if you wind up with a fraction, round down, even if the fraction is one-half or larger.

Exception: Certain rolls, such as damage and hit points, have a minimum of 1.

Exceptions I'll come to as necessary, but the following can set the default option on divide:

<set-defaults>
<divide options="round-down" />
</set-defaults>
 

nopantsyet said:
Let's ignore for the moment the question of doing some Kung Fu like d20 being an inherited implementation of dX. What I want to know is your thoughts about the design questions I've raised and my suggested approaches.

So what you're suggesting is to make a XML-based format for describing mechanics, so that a theoretical program can handle changes to the rules as easily as an unchanged rule set?

Sounds like an interesting idea. I'm not sure how worthwhile it will be, as opposed to simply making a library of functions for the common rule-determinations, but very interesting.

I'm more interested in a model for the data than the mechanics, and the biggest question I need to know is "what's the best way to add the mechanics-data"? My intitial result is just to have a <mechanic> tag, which contains <modifiers>, <actions> (i.e., d20 rolls), and <checks> leading to <results>.

As an example:

Code:
<skill>
  <skillname>Heal</skillname>
  <use>
	<usename>bind wound</usename>
	<mechanic>
	  [b]<check>[/b]
		<action name="Heal" DC="15"/>
		<result result="1d8+1" />You heal # hit points.</result>
	  [b]</check>
[/b]	</mechanic>
  <use>
</skill>
 

Planesdragon said:
So what you're suggesting is to make a XML-based format for describing mechanics, so that a theoretical program can handle changes to the rules as easily as an unchanged rule set?

Exactly. That's what I meant in the other thread by wanting to have all the rules in xml. Let's face it, if all one needed was the data, someone would have done it a long time ago. But the main thing people seem to exchange in OGL is not new spells, etc., but new rules. That's the tricky part. I would also like a utility that can theoretically be used for D&D, Arcana Unearthed, Masque of the Red Death, my own system, World of Darkness, etc. While it may seem at first that some of these systems are totally different, there are certain to be a lot of similarities.

Sounds like an interesting idea. I'm not sure how worthwhile it will be, as opposed to simply making a library of functions for the common rule-determinations, but very interesting.

The problem is that as soon as someone adds a house rule, all the data becomes useless (I am, of course, exaggerating). You need a way to extend not only the data set but the functionality. I've experimented in the past with an OOP approach, and at a certain point it hits a wall. The extensibility model becomes absurdly complicated and you have to code for exceptions all the time. My new AOP approach is coming along much nicer (I'm almost glad I lost all the code to the previous attempt). I've accomplished more in a couple of weeks then I did in months with an OOP approach.

I'm more interested in a model for the data than the mechanics, and the biggest question I need to know is "what's the best way to add the mechanics-data"? My intitial result is just to have a <mechanic> tag, which contains <modifiers>, <actions> (i.e., d20 rolls), and <checks> leading to <results>.

As an example:

Code:
<skill>
  <skillname>Heal</skillname>
  <use>
	<usename>bind wound</usename>
	<mechanic>
	  [b]<check>[/b]
		<action name="Heal" DC="15"/>
		<result result="1d8+1" />You heal # hit points.</result>
	  [b]</check>
[/b]	</mechanic>
  <use>
</skill>

This is why I've approached it in a manner very much like Lisp. By design, it is extensible in ways that make it able to do things it was never designed to do.

My question to you (given your example): How does the application know what to do with a skill in the first place? That has to be hardcoded in. It also needs to understand what a skillname is, how to perform a check (including what a DC means, how to "roll" 1d8+1 and maybe some other things I'm not seeing right away.

While it may seem fin to hardcode this, what happens when someone wants to houserule action points? Changes it so that all die rolls are rerolled on maximum results? Use a med kit? Deal with a form of aggravated damage that can not be healed in that fashion? Implements Wound/Vitality? Any of these house rules could make your entire snippet up there useless to the end use (some only occasionally, some completely).

Since house rules are par for the course, that's why I am trying to focus on a system that can handle them. I appreciate this thread coming up, because it offers us a chance to really home in on this idea.

The stuff I wrote above I did off the top of my head during work. There are all sorts of ideas floating in my head on how to implement a system that can do this (I've even revised some of the stuff above - for instance, I've now designed it so that the application doesn't need to explicitly understand compare, but instead can infer it from a much simpler assert function [if (condition) { run code }]).

Does anyone know of a good free web app (ASP/ASP.NET/PHP) that would allow me to host what I am working on and allow people to make comments and suggested changes? I think it would be very useful for discussion.
 

reanjr said:
Exactly. That's what I meant in the other thread by wanting to have all the rules in xml. Let's face it, if all one needed was the data, someone would have done it a long time ago. But the main thing people seem to exchange in OGL is not new spells, etc., but new rules. That's the tricky part. I would also like a utility that can theoretically be used for D&D, Arcana Unearthed, Masque of the Red Death, my own system, World of Darkness, etc. While it may seem at first that some of these systems are totally different, there are certain to be a lot of similarities.

The problem is that as soon as someone adds a house rule, all the data becomes useless (I am, of course, exaggerating). <snip...>
My thoughts exactly. These two threads are reinforcing my thinking on this point.

One of the reasons I started the dice at the low level is I thought, what if somebody wants to adjudicate something with a dice pool? Sure, that's not d20, but why does it have to be inherently incompatible? Why does anything have to be inherently incompatible? I say nothing should be because at some point, somebody's going to want to do it. And "it can't be done" is not acceptable in my opinion.

The idea behind starting with a flexible mechanic is that every entity that has an adjudication aspect to it, will require some mechanic. Rather than hardwire the mechanic in the application or have to recreate it for every rule, you can specify the base mechanics that are used, a default, and the necessary exceptions. That is all resolved at the time of adjudication.

reanjr - I agree re: AOP. That more accurately reflects how I envision this working than OOP. I'm not sure specifically what type of app you're interested in, but what about a Wiki?

I think there will be in some cases be an OOP-style hierarchy. Because if you start at the d20 mechanic as just the die roll, you then add a bonus and a target (possibly opposed) number for a basic check with success or failure being the result. Then you get into attacks and some skills where there is a second mechanic for adjudicating the degree of success (damage, distance jumped, etc.).
 

My new AOP approach is coming along much nicer (I'm almost glad I lost all the code to the previous attempt). I've accomplished more in a couple of weeks then I did in months with an OOP approach.

AOP? Care to elaborate for the peanut gallery?

My question to you (given your example): How does the application know what to do with a skill in the first place? That has to be hardcoded in. It also needs to understand what a skillname is, how to perform a check (including what a DC means, how to "roll" 1d8+1 and maybe some other things I'm not seeing right away.

Yes, exactly.

Die rolling is easy enough -- either write something that takes the integers from 1d8+1 out and generates it, or just flash a message box saying "Roll 1d8+1".

Any of these house rules could make your entire snippet up there useless to the end use (some only occasionally, some completely).

Yes, they would. Or, rather, they would for a program that runs the rules. For those people, the programmers, we can make a standard that use specific rules and treats them consistently--someone who rules that, say, special wounds cannot be treated normally would have condition tracking, that states that [cannot heal HP] or [all [heal] checks automatically fail]

Does anyone know of a good free web app (ASP/ASP.NET/PHP) that would allow me to host what I am working on and allow people to make comments and suggested changes? I think it would be very useful for discussion.

Yahoo has file storage that d20-XML and the FGA have used. PHP seems to be a common enough skill in the RPG community that we might be able to find something there.

The key, IME, is setting whatever we/you do so that someone else can come along and pick up where we left off. (Look at Avangor; he did a lot of work, and he's eager for someoen else to pick up where HE left off.)
 

Planesdragon said:
The key, IME, is setting whatever we/you do so that someone else can come along and pick up where we left off. (Look at Avangor; he did a lot of work, and he's eager for someoen else to pick up where HE left off.)

Avangor? Is that me? ;)

If it's not, could you point us to his work. If it is, then I'm not waiting for anyone to pick up where I've left off, I'm waiting to lose my job so I have more time to do this kind of stuff. :D

I would like to repost some stuff here that has been in discussion since 2003 concerning what represents an engine, and interoperability considerations.

I apologize for the length of the post, but it is a summary of two years of thinking. You may want to look at this thread:
Suite Interoperability.

First, my take on any XML or other implementation of an engine, in summary:

- There are three basic layers: data, engine, and GUI.

- Data should be separate from code. That is, data is static, what comes from the books, and should never changed except for errata (which is the bane of PCGen: when there are code changes, everything follows, since the LST language mixes processing with static data).

- There is a gray zone between code and data, what I term "business rules": how do you describe what a feat or other special ability does, for example. A way to do this in a code independent way is using markup such as RDF-OWL (which has been proposed) or rule markup like RuleML or SWRL (which is a W3C Recommendation)

- The engine is what is the core of any program, using your language of preference. It loads the data into an internal representation which may be custom, and implements the "business rules" on the data.

- GUI interfaces with the engine and provides user interaction.

If you've looked at the prototype engine I had posted, data is encoded in XML, and the business rules are implemented in javascript (although RuleML looks more attractive, since it is more portable). The engine and GUI code is in C++, but that becomes irrelevant if the base data and rule implementation is correctly done.

This is from the prototype's README:

Engine Components

panther.exe

- Canned demo executable
- Provides XML manipulation services using libxml2 (input, output, XPath, xml node trees)
- Provides a SpiderMonkey Javascript execution environment, for user scripting
- Maps XML nodes to Javascript objects, allowing dot-notation access (e.g.: config.base_directory)
- Provides a generic (non game system specific) API to manipulate XML and to implement Observer Pattern object management (see below)

Observer Pattern Objects

The observer programming pattern is a way to isolate each object in its own environment, and provide abstract interfaces to other objects, which may be Subjects (data providers) or Observers (which use and transform data). Subjects notify Observers when they change state, so that Observers may refresh their data. Panther implements this by allowing all objects to be both Observer and Subject.

For more information on the Observer Pattern, please consult the following:

http://pages.cpsc.ucalgary.ca/~kremer/patterns/index.html
http://www.wohnklo.de/patterns/observer.html

Javascript Implementation of Game System

The game system is implemented in Javascript. The XML format used for the raw data is independent of Panther itself. There are no special tags or structures.

Rather, the Javascript routines in the game system determine how an object is defined and "registered" as an Observer/Subject with Panther.

Example:

<object>
<name>A</name>
<value>100<value>
<interfaces>
<default>addThemUp</default>
</interfaces>
</object>

<object>
<name>B</name>
<value>10<value>
<targets>
<target>
<name>A</name>
</target>
</targets>
</object>

<object>
<name>C</name>
<value>20<value>
<targets>
<target>
<name>A</name>
</target>
</targets>
</object>

Using Javascript and XPath, the above objects are retrieved, parsed and registered with Panther using the API (e.g. API_registerObject). The specific tag names are not relevant to Panther, only to the JS code. In this example, the JS code would "attach" objects B and C to A (API_attachObject). When the value of A is retrieved, it would return the result of addThemUp.

addThemUp is a Javascript function that is defined by the user, compiled at load time and stored in Panther, and may be as simple as adding the values of attached objects. The arguments to addThemUp are the current object and the attached Javascript objects themselves (i.e. the XML nodes as mapped by Panther). So addThemUp could look like:

addThemUp () {
var result = 0;

for(var i=0;i<arguments.length;i++) {
result += arguments.value; // arguments contain A, B and C
}

return result; // 130
}

If the values of B or C change, A is notified by Panther and evaluates the function again. The result is cached to accelerate lookups.

Interfaces

Panther currently only implements one interface per object. However, the plan is to have several interfaces. For example another interface could be added to A that lists itself and it's subject objects (i.e.: listThemAll that returns "A, B, C").

The dependency chain may be extended, so that A is in turn a subject to one or more other objects.

Currently, no infinite loop detection, observer-subject link or notification optimization is implemented, but is planned.


Finally, this is an overview of my personal vision of what an open framework is:


rpg-xml.gif



HTH,

Andargor
 

andargor said:
<snip>

Andargor

Yeah that's about what I figured a universally useable chargen need to be.
What's a bit of a problem with this approach is all the XML-coding to be done (I don't like XML).
But seeing what you've done there I think perhaps I should learn C++... seems good at building javascript-enabled objects.

The distinction between data and code is good, as long as the code doesn't define the data. My first approach in my program was to code the whole rulesets in the objects data. So I got to have the rules for gaining new feats in the rules for the character level-data. While this could be easily changed using the object administration GUI it's not easy to just change this rule by a modification rule. So I will just put the rules that define data directly into the data.

What I want to know is what size of a footprint (memory size) your program would need. Does it parse all the XML files and do all objects always exist in memory? Those XML-files can get realy big, how fast is XML-parsing? While I see the XML as a somewhat unified export format I wonder if it's useable for an application...

Greetings
Firzair
 

Into the Woods

Remove ads

Top