This section will have a look at actions, how they are created and handled during play and how to add new actions.
Actions are used to represent actions taken by characters. This include things like moving, fighting and drinking potions. Every time an action is taken by a character, new instance of Action class (or rather subclass of it) needs to be created.
Actions are instantiated via ActionFactory, by giving it correct parameter class. For example, for character to move around, it can do it by:
action = self.action_factory.get_action(MoveParameters(self,
direction,
'walk'))
action.execute()
This creates a WalkAction and executes it, causing the character to take a single step to given direction.
Lets say we want to create an action that allows characters to wait for specific amount of ticks.
Actions are located in pyherc.rules
. Custom is to have own package for each type of action. For example, code related to moving is placed in pyherc.rules.move
while code for various attacks is in pyherc.rules.attack
. Parameter classes are placed to pyherc.rules.public
and imported to top level for ease of use.
Last important piece is factory that knows how to read parameter class and construct action class based on it. Factories are placed in the same location as the actions.
Sub action factory is used to create specific types of actions. Start by inheriting it and overriding type of action it can be used to construct:
from pyherc.rules.factory import SubActionFactory
class WaitFactory(SubActionFactory):
def __init__(self):
self.action_type = 'wait'
Next we need to define factory method that can actually create our new action:
def get_action(self, parameters):
wait_time = parameters.wait_time
target = parameters.target
return WaitAction(target, wait_time)
WaitParameters class is very simple, almost could do without it even:
class WaitParameters(ActionParameters):
def __init__(self, target, wait_time):
self.action_type = 'wait'
self.target = target
self.wait_time = wait_time
Constructor takes two parameters: target who is character doing the waiting and wait_time, which is amount of ticks to wait. action_type is used by the factory system to determine which factory should be used to create action based on parameter class. It should match to the action_type we defined in WaitFactory constructor.
WaitAction is not much more complex:
class WaitAction(object):
def __init__(self, target, wait_time):
self.target = target
self.wait_time = wait_time
def is_legal(self):
return True
def execute(self):
self.target.tick = self.target.tick + self.wait_time
Constructor is used to create a new instance of WaitAction, with given Character and wait time.
is_legal can be called by system before trying to execute the action, in order to see if it can be safely done. We did not place any validation logic there this time, but one could check for example if the character is too excited to wait.
Calling execute will trigger the action and in our case increment internal timer of the character. This will effectively move his turn further in the future.
pyherc.rules.public.ActionFactory
needs to be configured in order it to be able to create our new WaitAction. This is done in pyherc.config.Configuration
:
wait_factory = WaitFactory()
self.action_factory = ActionFactory(
self.model,
[move_factory,
attack_factory,
drink_factory,
wait_factory])
Last finishing step is to add easy to use method to Character class:
def wait(self, ticks, action_factory):
action = action_factory.get_action(WaitParameters(self,
ticks))
action.execute()
Now we can have our character to wait for a bit, just by calling:
player_character.wait(5, action_factory)
Notice how we are passing ActionFactory from outside of Character objects, instead of defining it as an attribute of Character. We do not want to inject service objects into domain objects, because it would complicate saving and loading later on.
Below is shown the whole example of wait action and demonstration how it changes value in character's internal clock.
from pyherc.data import Character, Model from pyherc.rules import ActionFactory, ActionParameters from pyherc.rules.factory import SubActionFactory from random import Random
class WaitParameters(ActionParameters):
- def __init__(self, target, wait_time):
self.action_type = 'wait' self.target = target self.wait_time = wait_time
class WaitAction(object):
- def __init__(self, target, wait_time):
self.target = target self.wait_time = wait_time
- def is_legal(self):
return True
- def execute(self):
self.target.tick = self.target.tick + self.wait_time
class WaitFactory(SubActionFactory):
- def __init__(self):
self.action_type = 'wait'
- def get_action(self, parameters):
wait_time = parameters.wait_time target = parameters.target return WaitAction(target, wait_time)
model = Model() wait_factory = WaitFactory() action_factory = ActionFactory(model = model, factories = [wait_factory]) character = Character(model) action = character.create_action(WaitParameters(character, 5), action_factory)
print('Ticks {0}'.format(character.tick)) action.execute() print('Ticks after waiting {0}'.format(character.tick))
The output shows how it is character's turn to move (tick is 0), but after executing wait action, the tick is 5.
Ticks 0 Ticks after waiting 5