Long run

This was rather a long run of refactoring and occasionally added features. Locked doors and keys for them: one door just before the last room on each level and some monster will hold the key to it. Added inventory class for monsters, which incapsulates all fiddling with items (and wielding/wearing also). Emptyable (or rather refillable) items like water flask: you could consume it and an empty flask will remain. You could refill it then in fountain, so it’ll be turn into water flask again. For that I needed a Put action for wielded items (one need to put empty flask into a fountain in order to refill it). This action also serves as light Fire action analog: putting wielded item in free passable direction will serve as Drop action. Also all level generation and storage functionality was collected into one big Dungeon class, which serves as level container and generator altogether.

Type system

Most important change is types of entities: item types, monster types, object types and cell types, of course.

Each entity has its Type object associated with it. All types are stored in TypeRegistry objects, one for each type of entities. Internally it is a map. Type has string id, which should uniquely determine it. Now entity could just specify its type as an id string (for example, when being serialized or generated) and game engine will know for sure which type object should be assigned. Types are generated when Dungeon is created and doesn’t needed to be saved, as they’re recreated at each game start exactly the same way (same id-s).

Also objects and items now has two types each. Object has a type for closed state and a type for opened state, each state has its one sprite, name, passability and other parameters. Like door, which can be closed (and impassable) and opened (passable). During opening or closing action, corresponding type is substituted. Item could be full or empty, mechanics are the same. This feature also gives ability to specify object state without using boolean or enum values.

Entity class should have ::Type and ::Builder subclasses and string id field.

template  
struct TypeRegistry {  
	typedef typename Value::Type ValueType;  
	std::map types;  
  
	bool has(const std::string & id) const  
	{  
		return (types.count(id) > 0);  
	}  
	const ValueType * get(const std::string & id) const  
	{  
		if(has(id)) {  
			return &types.find;(id)->second;  
		}  
		return 0;  
	}  
	const ValueType * insert(const ValueType & type)  
	{  
		return &(types[type.id] = type);  
	}  
	typename ValueType::Builder insert(const std::string & id)  
	{  
		types[id].id = id;  
		return typename ValueType::Builder(types[id]);  
	}  
};  

Messages

Another new feature is messaging system. I’ve turned action function into classes of one base Action class, each class has commit() method which does all work. Also I’ve divided all messages into action exceptions (like “this object is not drinkable”) and event messages (“you hit scorpion”).

Major role in this is played by Info class, which incapsulates type is, name, sprite, and passability and trasparency of entity. Entity could be of any kind: due to function overloading, any object or item or whatever could be used as source for Info object.

Action exceptions is a normal C++ exceptions, which has type (simple enum for now - each value for another type of exception, like NOTHING_TO_EAT) and Info objects for entities: who did action, to whom it did it. Action classes has assert() function, which checks boolean expression and throws an exception if expression is evaluated to false. Almost like normal assert function. Exception are turned to plain text messages after each creature’s turn. As only one exception could be raised during a function, only one message could be produced from it, safely breaking action execution.

Events should be considered as natural physical events, which have sense in game and could be observed by game monsters, for example. Thay also has a type (e.g. HITS or OPENS), actor (who did it) and optionally target (of the action; doors, for example). Sometimes event has amount of action (like hitpoints being healed or damage being taken) and helper entity (like SOMEONE-actor putting TARGET-item into a HELPER-container). Events are collected during action execution (they’re not break the flow, of course), and are converted into messages when and only when interface needs them (normally this is when player is making their turn).