3
\$\begingroup\$

I'm making a MUD game engine that supports D&D , Pathfinder and other tabletop-RPG rule sets. I am starting to build out how characters interact with the world (e.g. dialog, battle, searching for traps).

The engine is pretty loosely coupled, to facilitate swapping out components with downloaded plugins and I want to continue down that path with the rules. I've got an ICharacter interface and both a player and non-playable character interface that inherits from ICharacter. I feel that making a developer re-implement those interfaces when making a plugin because the developer is building a Pathfinder plugin instead of a D&D plugin is poor design. Instead, I want to allow them to specify at runtime (via an editor) what rules each character must abide by when performing specific tasks.

I was thinking I'd have a RuleEngine that would be provided an object and process a rule. Some pseudo code for this:

public void Attack(ICharacter target)
{
    IRuleResult result = RuleEngine.Process(
            RuleFactory.CreateRule("CharacterAttack"),
            this);
    // Check result to see what was given back like damage, hit/miss etc.
}

The user within my editor can specify that for CharacterAttack rule requests, uses PathfinderAttackRule, which would be a Type implementing IRule.

This approach feels like it might be to restrictive though. The interface would have to have some knowledge of D&D implementations, like critical miss, damage amounts etc. What if the user wants to build something that isn't D&D, but just a custom combat rule? The interface doesn't allow it and the engine would expect the interface properties to be usable.

Another option I was thinking about was having delegates perform the rule checks and process the attack.

public void Attack(ICharacter target)
{
    Func<ICharacter, IPlayer, bool> attackCheck =
            RuleFactory.CreateRule<IPlayer>("PreAttach");

    if (attachCheck(target, this))
    {
        // Invokes a delegate fetched by an internal factory.
        RuleFactory.Process<IPlayer>("AttachPlayer");
    }
}

This lets builders specify within the editor what custom delegates to use before an attack starts. (it would be a dropdown list of delegates supported, scanned from the assemblies loaded). The user might want a D&D rule delegate from a plugin they downloaded for pre-attack rule checks, then use a pathfinder rule for the actual attack from a 2nd plugin they downloaded.

Now that I've explained what I'm wanting to do, am I way off base here? Are both of the above examples horribly thought-out and/or is there a better approach to take that is loosely coupled and allows swapping rules out?

As a side-note, I chose player combat as the example, but rules are applied to more than just combat, and more than just players. Rooms, items and other objects will have rules. Some of the rules can be shared, some can not.

Where should I be going with this? I'm looking for general concepts and best-practices.

\$\endgroup\$
  • \$\begingroup\$ Sounds like a good candidate for the Strategy pattern. \$\endgroup\$ – Vaughan Hilts Apr 26 '15 at 23:49
1
\$\begingroup\$

The rules you speak of are basically character actions (or commands). The commands can be divided into several types:

  • Self-targeted
  • ally-targeted
  • creature-targeted
  • area-targeted

The main difference is, do we target someone or an area? You can write an abstract action type for these two kinds of actions. These actions will have access to the rules which is a service object that when given the situation and the action taken, can compute to probability of success, roll the virtual dies and also decide on the proper damage formula.

The issue is that the the action, needs to know and be compatible with the characters' attributes and the tools used in the action.

So in the general case, you need to allow others to input a list of attributes and compatible value ranges and distributions, representing a character and a tool. Allow actions to access that data and modify it. The commands or rules will need to be programmable items. It is very convoluted to describe how commands work without code and requires that you'll have predictive knowledge of everything that will ever be done with the system.

What you can do is make some basic types of actions and allow others to inherit from those base types to create their own. The issue there is that the computation of probability and damage output will change depending on the game play system.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.