0

I'm writing a Mafia (Werewolf)-style game engine in C#. Writing out the logic of an extended mafia game, the model:

A Player (Actor) has one or more Roles, and a Role contains one or more Abilities. Abilities can be Static, Triggered, or Activated (similar to Magic the Gathering) and have an "MAction" with 0 or more targets (in which order can be important) along with other modifiers. Some occur earlier in the Night phase than others, which is represented by a Priority.

MActions are resolved by placing them in a priority queue and resolving the top one, firing its associated event (which can place more actions on the queue, mostly due to Triggered Abilities) and then actually executing a function.

The problem I see with this approach is that there's no way for an MAction to be Cancelled through its event in this mechanism, and I see no clear way to solve it. How should I implement a system so that either MActions can be cancelled or that responses with higher Priorities end up executing first/delaying the initial MAction?

Thanks in advance. I've spent quite some time thinking (and diagramming) this through, can't quite get over this hurdle.

  • I'm also interested how this could be implemented with C# Action<>'s and Events. The problem I'm seeing with Action generics is that my base class won't know what arguments the derived classes will take. – Anatoly Makarevich Mar 18 '16 at 14:50
  • You probably shouldn't look at a language feature as a goal. Instead think of them as tools to be used. Action delegates might be the perfect solution to your problem, but trying to shoehorn them in if they don't work will just cause pain. Ideally the process you go through is "My life would be so much easier if XYZ would happen like ABC. Wow language feature EFG does exactly that and as a bonus I get JKL which would help too!" – Erik Mar 18 '16 at 15:10

2 Answers2

1

Would it be possible to implement a cancellation stack that is checked by each MAction function and only executes if the MAction you are trying to execute is not in that stack. That way any time an action is popped it would only do something if it wasn't canceled already.

Jesse Miller
  • 31
  • 2
  • 6
  • Yes, I guess that's one way to do it. Plus, not trigger the event for other subscribers... But I'm curious how to implement it on the base of the existing Action<> and Event classes/delegates. – Anatoly Makarevich Mar 18 '16 at 14:47
1

The situation as I understand it:

You have a series of things that happen with complicated rules which decide the order of what happens, and the order of what happens decides the quality/magnitude of the effect.

First things first, in order to make your life easier I'd recommend you limit your players to making all their moves before action resolution takes place. Even if this model is abandoned later it should make it easier for you to debug and resolve the actions. This is especially true if later actions can undo the effects of earlier actions like in the following example:

Dave transforms to a werewolf because he triggers the Full Moon ability. Then with werewolf powers he jumps over a wall and bites Buffy. Before Buffy dies she activates her time reverse ability and kills Dave before he jumps over the wall.

Regardless, your dilemma makes me think that you need to use a rules engine like NRules1, or implement your own. The primary goal of the rules engine will be to order/discard the stuff that happens according to your business logic.

Next you put these actions into a queue/list. The actions are applied against the targets until the business rules tell you to stop (Werewolf Dave died) or there aren't any more actions to apply. Once you stop then the results of the battle/actions are reported to the user.

There are other ways to accomplish your goals but I think this will give you a viable pathway towards your end goal.


1: I've never used this library so I don't know if it is any good.

Community
  • 1
  • 1
Erik
  • 820
  • 12
  • 22
  • Yes, night actions are "sent in" and only processed afterwards. Day actions are processed immediately, but can't be "pre-responded" to by players, only by Triggered abilities. Time travel (backwards) is beyond the scope of this project. :P – Anatoly Makarevich Mar 18 '16 at 14:39
  • Bah, can't multi-line comment... Anyways, thanks for the links/key words. I guess I am indeed trying to write a specialized rules engine myself. Since roles will be "built" out of actions, which are derived from basic actions, etc. I don't see how a rule-based system will be able to flexibly cover possible role combinations. – Anatoly Makarevich Mar 18 '16 at 14:44
  • 1
    @AnatolyMakarevich you need to define a clear order of operations/precedence first. I'd probably look at Magic the Gathering's rules since you seem to be familiar with that system and adapt it to yours. MtG has defined rules for stacking instants vs triggered abilites vs enchantments etc. Once you have the order of operations/precedence established you use a rules engine or something else that you write to sort the block of actions. Now that the actions are sorted or dropped then you apply the actions sequentially until it is time to stop. – Erik Mar 18 '16 at 14:54
  • 1
    @AnatolyMakarevich another thing to consider is there might be a critical design flaw that you're bumping up against. Quite often when I find something is absurdly hard to implement it is because there is something that I missed in the design. Changing my approach to the design, in order to reflect my deeper understanding of the problem domain, often yields a better solution and one that is easier to implement. If you revisit how you are defining/composing your actions/abilities/roles you might find a way to side step your road block while improving your code base. – Erik Mar 18 '16 at 15:04
  • Thank you very much for all the tips. I'll consider reworking the idea, and I'll look at MTG (though their base rules work on a LIFO resolution, and the mafia rules are almost always FIFO). – Anatoly Makarevich Mar 18 '16 at 15:39