/* $Id: bot.hpp,v 1.8 2005/07/18 06:48:10 uwe Exp $ */ #ifndef _BOT_HPP_ #define _BOT_HPP_ #include "player.hpp" #include "playerinput.hpp" /**********************************************************/ class Object; /**********************************************************/ //! base class for bots /*! This class represents the abstract base class for bots in WoP. * \br\br * \b Configuration \br * The configuration of bots starts in directory BOT_MAP_PATH * in file BOT_MAP_FILE (both constants defined in constants.hpp) * and follows this way: * - \b (1) The setting "bots" in the WoP configuration file or the * command line contains a list of names of the bots, that should * be added to the world. So first the program has to create a * suitable bot object (class derived from class Bot, e.g. * ScusiBot). For the decition, which class belongs to the name * in setting "bots", the static method Bot::createBot uses some * protected methods to read section \c NAME2CLASS in the bot * map file. Here the setting "name2class" contains pairs of * strings, each representing a mapping from a bot name to the * ID string of its class. The ID strings are fixed in member * Bot::m_internalTypeString. \br * \b NOTE: If you want to add a new bot type, you must add * a mapping pair ", " to this setting * "name2class". Example for section \c NAME2CLASS: * * \code * >>section_enter<< NAME2CLASS * * name2class = \ * scusibot, SCUSI_BOT, \ * tombot, TOM_BOT * * >>end<< * >>section_leave<< NAME2CLASS * \endcode * * - \b (2) After the bot object was created, it is configured. * First Bot::defaultConfig is called. This method sets the bot's * player name, a random color and team ID to 10. This method is * relevant for all player settings, that are not overwritten later * by a configuration file. Method defaultConfig is virtual so * that the random configuration can be adapted in derived classes. * - \b (3) Then the bot searches the setting equal to its name, e.g * "scusibot" (\b NOT \c "SCUSI_BOT") in section NAME2CONFIG in * the same configuration file. The presence of this setting is * optional and can specifie one relative path to an additional * configuration file. For example: * * \code * >>section_enter<< NAME2CONFIG * * scusibot = scusibot.conf * * >>end<< * >>section_leave<< NAME2CONFIG * \endcode * * - \b (4) If an individual configuration file is specified (and * present, Bot::load reads section \c BASE_BOT and accepts the * following settings: * * \code * >>section_enter<< BASE_BOT * * name = "Scusi Smith", "Scusibot", "Scusi Bender" * team = 1, 2, 3 * color = 0, 255, 0 \ * 20, 255, 50 * >>end<< * >>section_leave<< BASE_BOT * \endcode * * *
* \b name: * a list of player names (one is randomly chosen)
* \b team: * a list of teams (one is randomly chosen)
* \b color: * a list of colors (one is randomly chosen). \b Remember that one * color consist of three integers
* \b follow: * a list of strings. This setting and its usage is completely * arbitrary. If this setting is present, a pointer to the Setting * object will be passed to the virtual method derivedLoad. To add * additional settings in derived classes, reimplement the method * Bot::derivedLoad and interprete the strings in the passed settings * (for example as path or/and section).
*/ class Bot : public Player, public PlayerInput { public: Bot(); virtual ~Bot(); virtual Event getEvent() const = 0; virtual void update() = 0; ////////////////////////////////////////// //! \name access //@{ //! returns the bot's ID Sint32 getID() const { return m_ID; } //! returns the bot's ID string const char* getIDString() const { return m_typeString[m_ID]; } //@} ////////////////////////////////////////// //! \name creation //@{ //! creates a bot /*! * A bot should be created exclusively by the static method * Bot::createBot, that takes a string to specify the bot. * This string is the one we get from the WopSettings object. * \b Note that this string is not identical to the one you * get from Bot::getIDString. Bot::getIDString is a unique * string for each bot type, i.e. each class derived from * class Bot. The bot's name is a string, that is mapped in * method Bot::createBot to one of the classes, and that is * used for configuration and loading of the bot's properties. * So the map \b Bot::[getID(),getIDString()] -> \b class is * bijective, but the map \b name -> \b class is injective, * since two different names might create the same Bot class, * but load different configurations for them. */ static Bot* createBot( const char* const botName ); //@} ////////////////////////////////////////// //! \name (de)serialization //@{ virtual Uint32 getSerializeBufferSize() const; virtual void serialize( Uint8*& bufferPointer ) const; virtual void deserialize( Uint8*& bufferPointer ); //@} //! \name constants //@{ //! enumeration constants for derived classes enum { UNDEFINED_BOT = -1, SCUSI_BOT, TOM_BOT, GISMO_BOT, NUM_BOT_TYPES }; //@} protected: ////////////////////////////////////////// //! \name loading, configuration //@{ //! random configuration of the bot virtual void defaultConfig(); //! loads the basic configuration for a bot bool load( const char* const botName ); //! loads special configuration of derived class virtual bool loadDerived( Setting &setting ) { return true; } //! map: bot name -> configuration file name bool name2config( const char* const botName, String& file ); //! map: bot name -> bot ID static Sint32 name2classID( const char* const botName ); //! load the settings for the map: bot name -> bot ID static bool loadName2classIDsettings( SettingDataBase& settings, const String& mapFile ); //@} ////////////////////////////////////////// //! \name methods to receive visible objects /*! \brief Like a human player a bot must have the possibility * to observe its neighborhood in the world and the contained * objects. Of course a bot could access at arbitrary time a * list of all existing objects, but this would implement a * "god bot". These methods provide an interface to receive * objects, that can be detected by the bot in a certain * neighborhood. This also implies, that invisible objects * cannot be seen by this avatar. \br * There are two different possibilities to access the visible * objects: * - iterating through the objects, that can be seen by this * bot, using Bot::get[First,Next]VisibleObject. These * methods do not create any vector data. * - letting methods Bot::getVisible[Non]CollidableObjects * fill a passed vector with pointers to the demanded * objects. These methods allow you to access the objects * randomly in a vector, but imply generation of this * vector. */ //@{ //! returns the first visible object and initializes the iterator /*! One possibility to get visible objects is to iterate * through them. The "iterator" has to be initialized first * by calling Bot::getFirstVisibleObject, that returns a * pointer to the first visible object in addition. This * iteration process starts with the collidable object in * the world and continues with the non collidable objects * (they might be interesting as well, e.g. a shield corona * of an invisible avatar ... for more sophisticated bots :)). * To get one visible object after the other call method * Bot::getNextVisibleObject, that returns a NULL pointer, * if the last visible non collidable object hast been * returned in the previous call. */ Object* getFirstVisibleObject(); //! returns the next visible object /*! Returns the next visible object. The iterator data must * be in a valid state for this call, which means, that * you must start iterating through the visible objects * with Bot::getFirstVisibleObject. The iterator data are * reset into a non valid state after the last visible * object has been returned and getNextVisibleObject has * been called once again and returned a NULL pointer. * In debug mode the method will warn you, if called in * a non valid state and return a NULL pointer. In non * debug mode the behaviour is undefined in this case. * To iterate through all visible objects, write a loop * like this: * * \code * for( Object *object = getFirstVisibleObject(); * object; object = getNextVisibleObject() ) { * // * // any code using the object pointer * // * } * \endcode * * To iterate only through collidable objects, * simply stop with the first non collidable object: * * \code * for( Object *object = getFirstVisibleObject(); * object && object->isCollidable(); * object = getNextVisibleObject() ) { * // * // any code using the object pointer * // * } * \endcode */ Object* getNextVisibleObject(); //! fills the passed vector with visible collidable objects void getVisibleCollidableObjects( std::vector& vector ); //! fills the passed vector with visible non collidable objects void getVisibleNonCollidableObjects( std::vector& vector ); //@} //! bot id, unique for each derived class Sint32 m_ID; static const char** m_typeString; ////////////////////////////////////////// //! \name variables for iterations through visible objects //@{ enum ObjVecType { UNDEFINED, COLLIDABLES, NONCOLLIDABLES }; ObjVecType m_currObjVecType; Uint32 m_currIndex; //@} //! enumeration constants as access indices in the array of setting definitions enum { NAME_DEF = 0, TEAM_DEF, COLOR_DEF, FOLLOW_DEF, NUM_SETTING_DEFS }; //! definitions for general settings static const SettingDef m_SettingDef[NUM_SETTING_DEFS+1]; private: static const char* m_internalTypeString[NUM_BOT_TYPES+1]; }; /**********************************************************/ #endif // _BOT_HPP_