Last week I worked on two features: menus and pawn movement. What's interesting about it is that a lot of menu & pawn movement code is automated. To explain:
In my game player interacts with the game by performing actions (The only way to change anyting in the game state is to call World::performAction(...)). Each action can have a fixed number of simple parameters: either an identifier of an integer. Each parameter also has to satisfy some predicates. For example:
Action 'move' has two parameters:
- hireling_id: which has to be hired
- region_id: has to be close enough to hireling's position
In code it's defined like this:
vector<Parameter> move_params = {
PARAM(hireling, { return hireling.isHired(); }),
PARAM(region, { auto hpos = world(params.hireling()).hex(); return distance(region.hex(), hpos) <= 1; })
};
world.add("move", Action(move_params, ACTION() {
auto &hireling = world(params.hireling());
hireling.setPos(world(params.region()).hex());
return true;
}));
Because number of values one can pass as a parameter to some action is quite limited, it's possible to quickly decide whether some action can be performed or not with some constraints. This can be used for automatic generation of menus: When player clicks on some entity, game iterates over all the actions and generates the menu only with actions which actually can be performed.
For example, when you click on building_lot entity, the game will figure out that only a 'build' action can be performed and list only the buildings which actually can be built (because they satisfy some predicates while others don't).
This action system is also used, when moving pawns (which are moved by dragging and dropping, like in ShogunTW): after grabbing some hireling game will iterate over all the actions which are related to it and generate a list of entities on which this pawn can be dropped (See screenshot: possible targets are outlined in green).
The obvious advantage of this kind of action system is that one can quickly make serious changes in logic without any modifications in hud or visual layer.
It's also useful for serialization: I can simply save all the actions which player performed to save the game and replay them when loading it.