/* $Id$ */ #ifndef _OBJECT_HPP_ #define _OBJECT_HPP_ #include #include #include #include "global.hpp" #include "constants.hpp" #include "vector.hpp" #include "serializable.hpp" #include "areaitem.hpp" #include "objectitem.hpp" #include "vector.hpp" /**********************************************************/ #ifdef USE_DE_SERIALIZATION_TAGS #define SERIALIZE_OBJECT_TAG( BUFFER ) \ SERIALIZE_TAG( BUFFER ); #define DESERIALIZE_OBJECT_TAG( BUFFER ) { \ char testTag[sizeof( DE_SERIALIZE_TAG )]; \ Serialize::deserialize( sizeof( DE_SERIALIZE_TAG ), BUFFER, testTag ); \ testTag[sizeof( DE_SERIALIZE_TAG )-1] = 0; \ ASSERT( ! strncmp( DE_SERIALIZE_TAG, testTag, TAG_SIZE ), \ "bad tag deserialized in %s, line %d\n" \ " read \"%s\", should be \"%s\"\n" \ " occured in object of type \"%s\"\n", \ __FILE__, __LINE__, \ (const char*)testTag, DE_SERIALIZE_TAG, \ getIDString() ); } //! macros for checking the match of getSerializeBufferSize #define START_OBJECT_SERIALIZED_SIZE_CHECK( BUFFER ) \ const Uint8* serializedSizeCheckStartBuffer = BUFFER; #define END_OBJECT_SERIALIZED_SIZE_CHECK( BUFFER, CLASS ) { \ ASSERT( (Uint32)(BUFFER - serializedSizeCheckStartBuffer) \ == CLASS::getSerializeBufferSize(), \ "getSerializeBufferSize() == %d, but the pointer " \ "moved %d bytes\n %s, line %d, in object of " \ "type \"%s\"\n", \ CLASS::getSerializeBufferSize(), \ BUFFER - serializedSizeCheckStartBuffer, \ __FILE__, __LINE__, getIDString() ); \ } #else // USE_DE_SERIALIZATION_TAGS #define SERIALIZE_OBJECT_TAG( BUFFER ) #define DESERIALIZE_OBJECT_TAG( BUFFER ) #define START_OBJECT_SERIALIZED_SIZE_CHECK( BUFFER ) #define END_OBJECT_SERIALIZED_SIZE_CHECK( BUFFER, CLASS ) #endif // USE_DE_SERIALIZATION_TAGS /**********************************************************/ class World; class Sprite; template class SpriteSet; /**********************************************************/ //! base class for objects in the world /*! This is the base class for all objects in the world, except * particles, which have their own class Particles. *

* How to introduce a new object class?
* - Add an object ID for the new object type in the enumeration * constants in file constants.hpp and add the corresponding ID * string in the array ObjectIDString in file constants.cpp. * Follow the rules in constants.hpp for adding the new constants. * Note that the value of this constant will also decide, whether the * new object gets collidable or not. * - Derive a new class from class Object * - Implement the pure virtual member function getID, that should * return the new enumeration constant added in constants.hpp * - Implement the pure virtual member function update. This method is * responsible for the update in each time cycle and the adaption of * the frame and sequence indices for the sprite selection. * Important: Do not modify the member variable m_Sequence * manually, but use the method Object::setSequence, since it will * update the variable m_SequenceLength, too. m_SequenceLength keeps * the number of frames in the sequence, that hat been set using * setSequence. This also means, that you have to take care that the * frame index m_Frame always is in range [0,m_SequenceLength-1]. * - Add a new case branch in the switch statement in method * World::newObject, that creates the new object, if its ID (enum in * constants.hpp and return value of getID) is passed to that method. * - Create graphics for the new object and add them in the data tree * in a subdirectory of directory "images". Write a * configuration file for the object's sprite set (see * documentation of class SpriteSet) and place it in directory . * - Add the string pair in sprite configuration file * /SPRITE_CONFIG_PATH/SPRITE_CONFIG. SPRITE_CONFIG(_PATH) * are strings defined in constants.hpp. * * Now the new object can be created using the function World::newObject. */ class Object: public Serializable { protected: Object( World* wp = 0 ); Object( const Object& o ): m_state( LIVING | VISIBLE | WEAPON_VISIBLE ) { ASSERT( false, "Object::Object: do not use the " "copy operator\n" ); } Vector m_pos, m_vel, m_force; //real m_positionX, m_positionY; //real m_speedX, m_speedY; Uint32 m_state; bool m_removeMeAfterUpdate; //////////////////////////////////////////////////// //! \name data concerned with the graphics and the class WopGraphics //@{ Sint32 m_Sequence, //!< sequence index in SpriteSet m_SequenceLength, //!< length of the current sequence m_Frame, //!< frame index in SpriteSet m_ColorInstance; //!< index for colored instance //@} enum { VISIBLE = 1 << 0, WEAPON_VISIBLE = 1 << 1, GROUNDED = 1 << 2, LIVING = 1 << 3, LAST_OBJECT_STATE = LIVING }; // change LIVING to highest defined state public: //! we need a public destructor for deletion in the object list virtual ~Object(); //////////////////////////////////////////////////// //! \name some attributes important for the behaviour of the object //!@{ //! returns true, if the object is a collidable object bool isCollidable( void ) const { return getID() <= LAST_COLLIDABLE; } //! returns true, if an object with the passed ID is collidable static bool isCollidable( const int ID ) { return ID <= LAST_COLLIDABLE; } //! returns true, if the object is visible bool isVisible( void ) const { return m_state & VISIBLE; } //! returns true, if the object is visible for weapons like mines, homings, ... bool isWeaponVisible( void ) const { return m_state & WEAPON_VISIBLE; } //! bool isGrounded( void ) const { return m_state & GROUNDED; } bool isLiving( void ) const { return m_state & LIVING; } bool isAvatar( void ) const { return getID() >= FIRST_AVATAR && getID() <= LAST_AVATAR; } bool isGoal( void ) const { return getID() >= SMALLEST_GOAL && getID() <= BIGGEST_GOAL; } void setState( const int state, const bool value ) { if( value == true ) m_state |= state; else m_state &= ~state; } bool getState( const int state ) { return m_state & state; } void setWorldPointer( World* wp ) { m_worldPointer = wp; } bool removeMeAfterUpdate( void ) const { return m_removeMeAfterUpdate; } void setRemoveMeAfterUpdate( const bool newRemoveMeAfterUpdate ) { m_removeMeAfterUpdate = newRemoveMeAfterUpdate; } //@} //////////////////////////////////////////////////// //! \name functions concerned with the object's position and speed in the world //@{ //! set the position coordinates void setPos( const real posX, const real posY ) { m_pos.set( posX, posY ); } void setPos( const Vector& pos ) { m_pos = pos; } //! returns x-component of the object's position real getPosX() const { return m_pos.x; } //! returns y-component of the object's position real getPosY() const { return m_pos.y; } //! returns both, x- and y-component of the position in a vector const Vector& getPos() const { return m_pos; } //! returns the x-component of the object's position, truncated to the nearest integer Sint32 getIntPosX() const { return ROUND( m_pos.x ); } //! returns the y-component of the object's position, truncated to the nearest integer Sint32 getIntPosY() const { return ROUND( m_pos.y ); } //! sets the velocity vector of the object void setVel( const Vector& vel ) { m_vel = vel; } //! returns the x-component of the speed vector real getVelX() const { return m_vel.x; } //! returns the y-component of the speed vector real getVelY() const { return m_vel.y; } //! returns the speed vector of the object const Vector& getVel() const { return m_vel; } //! sets the force acting on the object void setForce( const Vector& force ) { m_force = force; } //! adds a force vector to the object's force void addForce( const Vector& dForce ) { m_force += dForce; } //@} //////////////////////////////////////////////////// /*! \name methods concerned with the object's initialisation at * the world's creation time */ //@{ //! \brief returns a pointer to the surrounding, area, //! that should be locked for random map stuff /*! If an object is placed by the server in the world during * setup time, i.e. before any map stuff is placed in the * map, a certain area surrounding the object can be defined, * that will be keept free from any random mapstuff. Method * getLockedArea returns a pointer to this area (see * areaitem.hpp). If it returns NULL, simply no area will * be locked for random mapstuff. * \note For any object, that could be placed by the server * in the world in setup phase and that cares about the flag * map of the world, a sensible area should be defined. */ virtual const AreaItem* getLockedArea() const { return 0x0; } //! return getLockedArea() != 0x0; bool definesLockedArea() const { return getLockedArea() != 0x0; } //! initialize an object from a passed definition item /*! This method initializes the object from a passed item, * that defines the state of the object. The base version * Object::initFromItem sets position and speed of the object. * Derived objects, that use their own extention of this * method to extract additional information from derived * classes of class ObjectItem, should invoke this base * class implementation, too. */ virtual bool initFromItem( const ObjectItem &item ); //! initialize the object in the world's map /*! Objects, that are placed in the world at the world's creation * time might want to draw something in the color map or in * the flag map of the world. Therefore this method is called * at each object, that is placed in the world initially \b * after the object's coordinates were fixed. For this * initialization in the maps the object might want to use * some sprite graphics. Since the usual sprites are not * available on the server, because only their structure is * loaded, but not the graphics itselves, special server * graphics can be defined in file SPRITE_CONFIG_PATH (#defined * in constants.hpp) in section "OBJECT_PATHS_THEME_GRAPHICS". * In this section you can specify a configuration file (for * class SpriteSet) and its path for these special server * graphics. In case such graphics were loaded, a pointer * to the according SpriteSet object is passed to this method, * otherwise NULL. * \note The object itself accesses the world's map through * Object::m_worldPointer->getMap(). */ virtual bool initInMaps( SpriteSet *gfx = NULL ) { return true; } //@} //////////////////////////////////////////////////// //! \name functions concerning the object's graphic //!@{ //! returns the index of the current animation sequence Sint32 getSequence() const { return m_Sequence; } //! sets a new index for the animation sequence for the object. //! This call also updates the length of the current sequence. void setSequence( const Sint32 seq ) { m_Sequence = seq; updateSequenceLength(); } //! returns the frame index in the current animation sequence Sint32 getFrame() const { return m_Frame; } //! sets the frame index in the current animation sequence void setFrame( const Sint32 fra ) { m_Frame = fra; } //! returns the index of the uses color instance of the object's //! sprite set. (if < 0, then it is not (yet) defined) Sint32 getColorInstance() const { return m_ColorInstance; } //! sets the index of the used color instance. This function //! should be used by class SpriteSet only. void setColorInstance( const Sint32 inst ) { m_ColorInstance = inst; } //! updates the length of the current sequence void updateSequenceLength(); //! selects the correct sequence index for the current state /*! This function selects the correct sequence index. Call this * function, whenever you change the state of the avatar, to * make sure that the correct graphics are selected. */ virtual void updateSpriteSelection() {} //! returns a pointer to object colors (length == getNumColors) virtual const Uint32* getColors() const { return 0; } //! returns the number of colors, that are defined for this objet virtual Sint32 getNumColors() const { return 0; } //@} //////////////////////////////////////////////////// //! \name (de)serialization //@{ virtual Uint32 getSerializeBufferSize() const; virtual void serialize( Uint8*& bufferPointer ) const; virtual void deserialize( Uint8*& bufferPointer ); //@} //! \name methods concerning the object ID //@{ /*! \brief derived classes must return a valid ID, defined in * constants.hpp, i.e. from 0 to (NUMBER_OF_OBJECT_IDs - 1) */ virtual Sint32 getID() const = 0; //! returns the objects ID string const char* getIDString() const { return ObjectIDString[getID()]; } //! returns the string of the passed object ID static const char* getIDString( const Sint32 id ) { DBG(1) ASSERT( INVALID_OBJECT < id && id < NUMBER_OF_OBJECT_IDs, "Object::getIDString(%d): invalid ID %d\n", id, id ); return ObjectIDString[id]; } //! returns the object ID belonging to the passed string static Sint32 getID( const char* const str ) { Sint32 id = NUMBER_OF_OBJECT_IDs-1; while( id > INVALID_OBJECT && strcmp(str, ObjectIDString[id]) ) id--; return id; } //@} virtual void update( void ) = 0; //! pointer to the world, all objects live in World *m_worldPointer; virtual void dump( std::ostream& out ) const; }; /**********************************************************/ #endif // _OBJECT_HPP_