1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300
|
/*
* Copyright (C) 2002,2003,2004 Daniel Heck
* Copyright (C) 2007,2008,2009 Ronald Lamprecht
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#ifndef OBJECT_HH
#define OBJECT_HH
#include "display.hh"
#include "ecl_alist.hh"
#include "ecl_math.hh"
#include "Value.hh"
#include <map>
#include <stdint.h>
namespace enigma {
using std::string;
struct Message;
enum ObjectFlagsBits {
OBJBIT_LIGHTNEWDIRS = 15, ///< GridObject 4 direction bits with current/new light
OBJBIT_LIGHTOLDDIRS = 240, ///< GridObject 4 direction bits with previous light
OBJBIT_LIGHTALLDIRS = 255, ///< GridObject all 8 direction bits with old an new light
OBJBIT_PHOTOACTIV = 1<<8, ///< GridObject registered as photo activ
OBJBIT_INVERSE = 1<<9, ///< Object invert action value
OBJBIT_NOP = 1<<10, ///< Object use nop instead toggle as default action
OBJBIT_INIT = 1<<11 ///< Object needs init message for @ finalization
};
enum ValidationResult {
VALID_OK,
VALID_ACCESS_DENIED,
VALID_UNKNOWN_KEY,
VALID_TYPE_MISMATCH,
VALID_ILLEAGAL_VALUE
};
class Value;
/**
* Object is the base class for all "objects" in the world.
* The most important facilities this class provides are:
*
* - A way to clone() and dispose() objects. This is mainly used
* in function MakeObject() to create new objects of a given
* type.
*
* - A way to pass messages between unrelated objects via message().
* This allows us to send messages to objects from Lua and to
* decouple objects types as much as possible.
*
* - A way to get and set attributes. These attributes are quite
* similar to instance variables, but they can be easily modified
* from Lua. This makes it possible to modify certain object
* parameters (such as the text on a piece of paper or the color
* of an oxyd stone) in level descriptions.
*
* The various Object subclasses instances need to register a template
* instance for each object name. To avoid the inclusion of every
* subclass declaration file into the registry for registry driven forward
* initialization we make use of the static file based initialization
* that occurs prior to the main application startup. To be independent of
* the undefined sequence in which the files are initialized we store the
* template instances, object names and id's in function local static caches.
* These caches are copied to the final runtime data structures on the main
* application startup. We call this feature "boot"-initialization. The macros
* BOOT_REGISTER_START and BOOT_REGISTER_END will be used once at the end of
* every subclass file. They embrace the BootRegister() function calls that
* register the templates.
*/
class Object {
public:
enum ObjectType {
OBJECT,
OTHER,
STONE,
FLOOR,
ITEM,
ACTOR
};
typedef ecl::AssocList<std::string, Value> AttribMap;
Object();
Object(const char *kind);
Object(const Object &src_obj);
virtual ~Object();
static Object * getObject(int id);
int getId() const;
/* ---------- depreceated methods ---------- */
const AttribMap &get_attribs() const { return attribs; } // just used by ObjectRepos::dump_info()
/* ---------- Helper routines ---------- */
void send_impulse(const GridPos& dest, Direction dir);
/* ---------- Object interface ---------- */
/**
* The main object category name of the object that describes its gaming class.
* All objects of a gaming class support the same attributes and messages. But
* they may still be members of different kind subcategories. E.g. "st_panel"
* is a class with "st_panel_n", "st_panel_s",... as kinds. A gaming object
* class is often implemented as a separate C++ class. But sometimes several
* gaming classes share a single C++ class. E.g. "st_panel", "st_bluesand" are
* both implemented by the class "ClusterStone". In this case we talk about a
* common "family".
*/
virtual std::string getClass() const =0;
/**
* The most specific object category name. Many objects change their kind during
* their lifecycle. All attributes are evaluated to determine the current kind
* of a gaming object.
*/
std::string getKind() const;
/**
* Check the current kind of the object versus the given name.
*/
bool isKind(const std::string &kind) const;
bool validateMessage(std::string msg, Value arg);
/**
*
*/
virtual Value message(const Message &m);
/**
* Store the value information for the given key with prior checking of
* write allowance. All level code attribute settings should pass this
* central call. If a set is granted the virtual unchecked setAttr is
* executed.
*/
void setAttrChecked(const std::string &key, const Value &val);
/**
* Store the value information for the given key. If it is a XML declared
* system attribute or a user attribute it will be stored in the attribute
* map. Otherwise an ivar may be set. Nothing happens if the attribute is
* declared as read only. If the value is "nil" the attribute will be reset
* to its declared default. If the default is "nil", too, or if it is a user
* attribute, it will be deleted in the attribute map. In these cases a read
* will return "nil" either way.
*/
virtual void setAttr(const std::string &key, const Value &val);
/**
* Get an attribute or value for the given key with prior checking of
* read allowance. All level code attribute reads should pass this central
* call. If a read is granted the virtual unchecked getAttr is executed.
*/
Value getAttrChecked(const std::string &key) const;
/**
* Get an attribute that has been set or that stands as a proxy for a
* trait or ivar. Object itself will just return attribute values
* that are stored in its attribute map. For not existing attributes
* a XML declared standard default value will be returned. If the default
* is "nil" type DEFAULT will be returned.
*
* Subclasses may override this method to supply values of traits or
* ivars. This way levels can gain read access to attributes that can
* not to be stored in the attribute map due to performance reasons.
*/
virtual Value getAttr(const std::string &key) const;
/**
* Get an attribute or a special given default value. This method
* gets attributes like the simple argumented getAttr method but
* returns the given default value instead of a DEFAULT value if
* no explicit attribute exists.
*/
Value getDefaultedAttr(const string &key, Value defaultValue) const;
virtual Object *clone() =0;
virtual void dispose() =0;
virtual void warning(const char *format, ...) const;
virtual ObjectType getObjectType() const;
void transferName(Object *target);
virtual void transferIdentity(Object *target);
virtual double squareDistance(const Object *other) const;
virtual bool isSouthOrEastOf(const Object *other) const;
protected:
/** This function is used by all triggers, switches etc. that
* perform some particular action when activated (like opening
* doors or switching lasers on and off). It interprets the
* "action" and "target" attributes of `o'.
*/
void performAction(const Value &val);
virtual Value invertActionValue(const Value &val) const;
/**
* Evaluate multiple destinations described by tokenized destination
* attribute where every token may be a group by itself. All valid
* destinations are indexed in the sequence of tokens and group positions.
* The position at the given index is returned as the destination position.
* If the caller did index beyond the last valid position this convenience
* method returns false, otherwise true to mark a valid position.
* Objects with destinations like Vortex and Horse make use of this method.
* @arg idx requested index of destination starting with 0
* @arg destpos return value for position that is centered to a grid
* @return validity of position at given index
*/
bool getDestinationByIndex(int idx, ecl::V2 &dstpos);
/**
* A central managed container for 32 single bit flags to be used by
* subclasses. Object is reponsible for efficiently cloning, saving and
* restoring these flags on demand. Subclasses use the bits as follows:
*
* - Bit 0-15 are reserved for classes Object to GridObject
*
* - Bit 16-23 are reserved for classes Item, Stone, Floor, Actor
*
* - Bit 24-31 are reserved for the final subclass
*
* See enumeration ObjectFlagsBits for Bitmasks of Bit 0-15. Note that
* Bitmasks would not have been an alternative as the subclasses may
* and will use the upper bits in a quite different manner.
*/
uint32_t objFlags;
private:
friend void InitWorld(); // for bootFinished() access
static int next_id;
static std::map<int, Object *> objects;
int id;
AttribMap attribs;
void finalizeNearestObjectReferences(std::string attr);
void finalizeNearestObjectReferences();
static int getNextId(Object *obj, bool bootFinished);
static void bootFinished();
static void freeId(int id);
};
} // namespace enigma
#define BOOT_REGISTER_START \
namespace { \
bool do_boot_register() {
#define BOOT_REGISTER_END \
return true; \
} \
static bool boot_registered = do_boot_register(); \
}
#define CLONEOBJ(TYPE) \
TYPE* clone() { return new TYPE(*this); } \
void dispose() { delete this; }
#define CLONEACTOR(TYPE) \
TYPE* clone() { TYPE *o=new TYPE(*this); o->init(); return o; } \
void dispose() { delete this; }
#define INSTANCELISTOBJ(TYPE) \
typedef std::vector<TYPE*> InstanceList; \
static InstanceList instances; \
TYPE *clone() { TYPE *o = new TYPE(*this); instances.push_back(o); return o;} \
void dispose() { \
instances.erase(find(instances.begin(), instances.end(), this)); \
delete this; \
}
#endif
|