// Ryzom - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 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 Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef RY_ZONE_MANAGER_H #define RY_ZONE_MANAGER_H #include "nel/misc/types_nl.h" #include "nel/misc/singleton.h" #include "nel/ligo/primitive.h" #include "game_share/base_types.h" #include "game_share/continent.h" #include "server_share/respawn_point_type.h" #include "server_share/place_type.h" #include "entity_manager/entity_base.h" #include "game_share/string_manager_sender.h" #include "mission_manager/ai_alias_translator.h" #include "deposit.h" class CCharacter; extern NLMISC::CRandom RandomGenerator; static const uint16 InvalidSpawnZoneId = 0xFFFF; static const uint16 InvalidPlaceId = 0xFFFF; /** * A teleport destination zone * \author Nicolas Brigand * \author Nevrax France * \date 2003 */ class CTpSpawnZone : public NLLIGO::CPrimPoint { public: /** * build the zone from a primitive file * \return true on success */ bool build(const NLLIGO::CPrimPoint * point); /// get a random destination point void getRandomPoint( sint32 & x, sint32 & y, sint32 & z, float & heading )const { static const float angleMax = (float)(2 * NLMISC::Pi); z = (sint32)Point.z; float angle = RandomGenerator.frand( angleMax ); sint32 radius = (sint32)RandomGenerator.rand( (uint16) _Radius ); x = sint32( radius * cos ( angle ) + Point.x ); y = sint32( radius * sin ( angle ) + Point.y ); heading = Angle; } void getCenter( sint32 & x, sint32 & y )const { x = sint32(Point.x); y = sint32(Point.y); } RESPAWN_POINT::TRespawnPointType getType() const { return _Type; } void setContinent( CONTINENT::TContinent contId ) { _Continent = contId; } CONTINENT::TContinent getContinent() const { return _Continent; } void setRegion( uint16 regionId ) { _Region = regionId; } uint16 getRegion() const { return _Region; } const std::string &getName() const { return _Name; } PLACE_TYPE::TPlaceType getPlaceType() const { return _PlaceType; } void setPlaceType(PLACE_TYPE::TPlaceType placeType) { _PlaceType = placeType; } private: /// Name of the zone std::string _Name; /// radius of the zone uint16 _Radius; /// type of the zone ( useful for respawn points ) RESPAWN_POINT::TRespawnPointType _Type; /// parent continent id CONTINENT::TContinent _Continent; /// parent region id uint16 _Region; // place type: capital, village etc PLACE_TYPE::TPlaceType _PlaceType; }; /** * A place in Ryzom is a patatoid that delimits a named place (village, special zones,...) * Regions and Continents inherits from theis class. * Places are in region, which are in continents * \author Nicolas Brigand * \author Nevrax France * \date 2003 */ class CPlace : public NLLIGO::CPrimZone { public: /** * build the place from a primitive file * \param prim: the source primitive * \param id: id of the place * \return true on success */ bool build(const NLLIGO::CPrimZone * zone,uint16 id, bool reportAutorised = true); bool build(const NLLIGO::CPrimPath * zone,uint16 id); ///\return the name of the place inline const std::string & getName() const{ return _Name; } ///\return the id of the place inline uint16 getId() const{ return _Id; } ///\return center coords inline sint32 getCenterX(){ return _CenterX;} inline sint32 getCenterY(){ return _CenterY;} bool getReported() const { return _Reported; } bool isGooPath() const { return _GooPath; } bool isMainPlace() const { return _MainPlace; } TAIAlias getAlias()const{ return _Alias; } const std::vector & getRespawnPoints() const { return _RespawnPoints; } protected: ///\id of the place uint16 _Id; private: /// Name of the place std::string _Name; /// center coords sint32 _CenterX; sint32 _CenterY; /// Flag for sending enter message to client bool _Reported; /// Flag indicate this place is a goo path bool _GooPath; /// true if the place is the main place where a user can be bool _MainPlace; /// respawn points validated when a user enters the place std::vector _RespawnPoints; /// persistant alias TAIAlias _Alias; }; /** * Region class * \author Nicolas Brigand * \author Nevrax France * \date 2003 */ class CRegion : public CPlace { public: /** * build the region from a primitive file * \param prim: the source primitive * \param id: id of the region * \return true on success */ bool build(const NLLIGO::CPrimZone * zone,uint16 id); /// ctor CRegion() : _Continent(CONTINENT::UNKNOWN) { } /// dtor ~CRegion(); /** * add a place in that region * \param place: the place to add */ inline void addPlace( CPlace* place ) { _Places.push_back( place ); } /** * add a deposit in that region * \param deposit: the deposit to add */ inline void addDeposit( CDeposit* deposit ) { _Deposits.push_back( deposit ); } ///\return the places contained in that region inline const std::vector< CPlace* > & getPlaces() const {return _Places;} ///\return the deposits contained in that region inline std::vector< CDeposit* > & getDeposits(){return _Deposits;} ///\return true if the region is a newbie region inline bool isNewbieRegion()const { return _NewbieRegion; } /// add a user to the region void addPlayer( const NLMISC::CEntityId & id ); /// remove a user from the region void removePlayer( const NLMISC::CEntityId & id ); /// register the region chat group void registerChatGroup(); /// players in region const std::set< NLMISC::CEntityId > & getPlayersInside() { return _Players; } /// get the continent of the region CONTINENT::TContinent getContinent() const { return _Continent; } /// set Continent of region void setContinent( CONTINENT::TContinent continent ) { _Continent = continent; } private: /// places contained in this region std::vector< CPlace* > _Places; /// deposits contained in this region std::vector< CDeposit* > _Deposits; /// true if the region is a newbie region bool _NewbieRegion; /// players in the region std::set< NLMISC::CEntityId > _Players; /// continent where the region are CONTINENT::TContinent _Continent; }; /** * Continent class * \author Nicolas Brigand * \author Nevrax France * \date 2003 */ class CContinent : public CPlace { public: /// continent names // static const std::string ContNames []; /** * build the continent from a primitive file * \param prim: the source primitive * \return true on success */ bool build(const NLLIGO::CPrimZone * zone); /// dtor ~CContinent(); /** * add a region in that continent * \param region: the region to add */ inline void addRegion( CRegion * region ){ _Regions.push_back(region); } ///\return the regions contained in that continent inline const std::vector< CRegion* > & getRegions(){return _Regions;} private: ///\regions contained in this continent std::vector< CRegion* > _Regions; }; /** * Singleton used to manage zones in the EGS. * Its purpose is to store the data concerning zones forbe used for gameplay rules linked to geographic position. * \author Nicolas Brigand * \author Nevrax France * \date 2003 */ class CZoneManager : public NLMISC::CSingleton { public: const uint DepositSearchTime; /// start point structure struct CStartPoint { uint16 SpawnZoneId; TAIAlias Mission; TAIAlias Welcomer; }; // default constructor CZoneManager() : DepositSearchTime(50) {}; ~CZoneManager(); /// init the manager void init(); /// release the manager void release (); /// callback called when IOS connects void iosConnection(); /// get a teleport zone inline const CTpSpawnZone * getTpSpawnZone( uint16 idx ) const; /// get a teleport zone id from its name. return InvalidSpawnZoneId if not found. uint16 getTpSpawnZoneIdByName( const std::string & name); /** * get the continent where an entity is * \param entity: the entity to check * \return a pointer on the continent */ inline const CContinent * getContinent( CEntityBase * entity ); /** * get the region where an entity is * \param entity: the entity to check * \param region: pointer to be filled with the appropriate value ( must be allocated ) * \param continent: pointer to be filled with the appropriate value ( must be allocated if not NULL ) * \return a pointer on the continent */ inline bool getRegion( CEntityBase * entity, const CRegion ** region, const CContinent ** continent = NULL); /** * get the place where an entity is * \param entity: the entity to check * \param stable: pointer to be filled with the appropriate value ( must be allocated ) * \param place: pointer to be filled with the appropriate value ( must be allocated ) * \param region: pointer to be filled with the appropriate value ( must be allocated if not NULL) * \param continent: pointer to be filled with the appropriate value ( must be allocated if not NULL ) * \return a pointer on the continent */ inline bool getPlace( CEntityBase * entity, float& gooDistance, const CPlace ** stable, std::vector& places, const CRegion ** region = NULL, const CContinent ** continent = NULL ); /** * get the continent containing the given position * \param x: X coord of the position * \param y: Y coord of the position * \return a pointer on the continent */ CContinent * getContinent( sint32 x, sint32 y ); /// Same with vector CContinent * getContinent( const NLMISC::CVector& pos ); /** * get the region containing the given position * \param x: X coord of the position * \param y: Y coord of the position * \param region: pointer to be filled with the appropriate value ( must be allocated ) * \param continent: pointer to be filled with the appropriate value ( must be allocated if not NULL ) * \return a pointer on the continent */ bool getRegion( sint32 x, sint32 y, const CRegion ** region, const CContinent ** continent = NULL); /// Same with vector CRegion * getRegion( const NLMISC::CVector& pos ); /** * get the place containing the given position * \param x: X coord of the position * \param y: Y coord of the position * \param stable: pointer to be filled with the appropriate value ( must be allocated ) * \param place: pointer to be filled with the appropriate value ( must be allocated ) * \param region: pointer to be filled with the appropriate value ( must be allocated if not NULL) * \param continent: pointer to be filled with the appropriate value ( must be allocated if not NULL ) * \return a pointer on the continent */ bool getPlace( sint32 x, sint32 y, float& gooDistance, const CPlace ** stable, std::vector& places, const CRegion ** region = NULL, const CContinent ** continent = NULL ); /** * get the deposits under the position * \param user: user which position is to be checked * \param deposits: vector of deposits to be filled */ void getDepositsUnderPos( const NLMISC::CVector& pos, std::vector& deposits, bool warnIfOutsideOfRegion=true ); /** * get the first deposit found under the position (faster than getDepositsUnderPos()), or NULL if not found */ CDeposit* getFirstFoundDepositUnderPos( const NLMISC::CVector& pos ); /** * Get a place from id, alias or name. * A Place is a region, a zone, a stable or a goo border */ //@{ /// get a place from its id (no search - direct access) inline CPlace* getPlaceFromId( uint16 id ); /// get a place from its alias (search with a map.find) CPlace* getPlaceFromAlias( TAIAlias alias ); /// get a place from its name (linear search in a vector) CPlace* getPlaceFromName( const std::string & name ); //@} /** * get a continent from its id * \param id: id of the continent * \return a pointer on the continent */ CContinent* getContinentFromId( CONTINENT::TContinent id ); /** * update the position of a character * \param entityRow: row id of the chracter to update */ void updateCharacterPosition( CCharacter * user ); ///update called at each tick void tickUpdate(); /* * dump the world organisation * \param log: log in which we want to dump the result. */ void dumpWorld(NLMISC::CLog & log); /* * dump the tp spawn zones * \param log: log in which we want to dump the result. */ void dumpTpSpawnZones(NLMISC::CLog & log); /** * a player used the /where command * \param eId : entity leaving the zone */ void answerWhere(const NLMISC::CEntityId & eId); /** * a player harvest a deposit * \param character the harvesting player */ //void harvestDeposit(CCharacter * user); /** * remove a raw material from a deposit * \param user: harvesting player * \param depositindex: index of the deposit * \param depositIndexContent : index of the harvested content in the deposit */ //void removeRmFromDeposit( CCharacter * user, uint32 depositIndex, uint32 depositIndexContent, uint16 quantity ); /* * dump one or all the deposits * \param log: log in which we want to dump the result. * \param depName: name of the deposit to dump, or "ALL" for all deposits * \param extendedInfo: true to get more info on the raw materials of the deposit */ void dumpDeposits( NLMISC::CLog & log, const std::string& depName, bool extendedInfo=false ); /// Accessor for deposits const std::vector< CDeposit* >& getDeposits() const { return _Deposits; } /// Used by CDeposit only. void registerDepositToAutoSpawnUpdate(CDeposit *); void unregisterDepositToAutoSpawnUpdate(CDeposit *); /// get a starting point for new character. NULL if invalid const CTpSpawnZone * getStartPoint( uint16 startPointIdx, TAIAlias & bot, TAIAlias & mission ) { if ( startPointIdx >= _StartPoints.size() ) { nlwarning("bad start point index %u ( count %u )",startPointIdx , _StartPoints.size() ); return NULL; } // select a spawn zone randomly among the village spawn zones if ( _StartPoints[startPointIdx].empty() ) { nlwarning("bad start point index %u: no spawn point in vector",startPointIdx ); return NULL; } uint16 idx = (uint16)RandomGenerator.rand( _StartPoints[startPointIdx].size() - 1 ); mission = _StartPoints[startPointIdx][idx].Mission; bot = _StartPoints[startPointIdx][idx].Welcomer; return getTpSpawnZone( _StartPoints[startPointIdx][idx].SpawnZoneId ); } /// get start point vector, slow because it makes a copy /// warning: this should only be used by CCharacterVersionAdapter::adaptToVersion3() std::vector getStartPointVector( uint16 startPointIdx ) const; /// send place name to a user uint32 sendPlaceName( const TDataSetRow & userRow, const std::string & placeName ) { SM_STATIC_PARAMS_1(params, STRING_MANAGER::place); params[0].Identifier = placeName; return STRING_MANAGER::sendStringToClient( userRow,"SOLE_PLACE",params ); } /// Add an ecotype information static void addEcotype( CEcotypeZone *ecotypeZone ) { _EcotypeZones.push_back( ecotypeZone ); } /* * Get the ecosystem under the position. * If not found, a NULL pointer is returned. */ ECOSYSTEM::EECosystem getEcotype( const NLMISC::CVector& pos ); /* * Clear ecotype information */ void clearEcotypes(); private: /** * init the instance. We had to do a separate method because there where methods that where called in the ctor that accessed to the singleton instance, but the intance is valid just AFTER the call to the ctor... */ void initInstance(); /** * parse the continents in a primitive * \param prim : the root node of the primitive */ bool parseContinents(const NLLIGO::IPrimitive* prim); /** * parse the regions in a primitive * \param prim : the root node of the primitive */ bool parseRegions(const NLLIGO::IPrimitive* prim); /** * parse the zones in a primitive * \param prim : the root node of the primitive */ bool parseZones(const NLLIGO::IPrimitive* prim); /** * parse the ecotypes in a primitive * \param prim : the root node of the primitive */ bool parseEcotypes( const NLLIGO::IPrimitive* prim ); /** * parse the deposits in a primitive * \param prim : the root node of the primitive */ bool parseDeposits( const NLLIGO::IPrimitive* prim ); /** * CZoneManager parseStables * \param prim : the root node of the primitive */ bool parseStables( const NLLIGO::IPrimitive* prim ); /** * CZoneManager parseTpSpawnZones * \param prim : the root node of the primitive */ bool parseTpSpawnZones( const NLLIGO::IPrimitive* prim ); /** * CZoneManager parseGooBorder * \param prim : the root node of the primitive */ bool parseGooBorder( const NLLIGO::IPrimitive* prim ); /** * CZoneManager parseStartPoints * \param prim : the root node of the primitive */ bool parseStartPoints( const NLLIGO::IPrimitive* prim ); /** * parse the PVP zones in a primitive * \param prim : the root node of the primitive */ bool parsePVPZones( const NLLIGO::IPrimitive* prim ); /** * parse the PVP safe zones in a primitive * \param prim : the root node of the primitive */ bool parsePVPSafeZones( const NLLIGO::IPrimitive* prim ); /// the continents std::vector< CContinent > _Continents; /// the places, regions and continent std::vector< CPlace* > _Places; /// the deposits std::vector< CDeposit* > _Deposits; /// time related to deposits update uint32 _NextDepositIndexUpdated; NLMISC::TGameCycle _SpreadUpdateLoopBeginTick; /// The deposits that need updates for auto spawn std::set< CDeposit* > _DepositNeedingAutoSpawnUpdate; /// teleport spawn zones std::vector< CTpSpawnZone > _TpSpawnZones; std::map _TpSpawnZoneIdByName; /// initial starting points for new character. It is a vector of vector : each entry of the enclosing vector is a village. A village is a vector of spawn zone ids std::vector< std::vector > _StartPoints; std::map _PlacesByAlias; /// The ecotype zones static CEcotypeZones _EcotypeZones; }; //----------------------------------------------- // CZoneManager getTpSpawnZone //----------------------------------------------- inline const CTpSpawnZone * CZoneManager::getTpSpawnZone( uint16 idx )const { if ( idx >= _TpSpawnZones.size() ) { nlwarning("CZoneManager::getTpSpawnZone -> invalid zone %u (count = %u )", idx, _TpSpawnZones.size() ); return NULL; } return &_TpSpawnZones[idx]; }// CZoneManager getTpSpawnZone //----------------------------------------------- // CZoneManager getContinent //----------------------------------------------- inline const CContinent * CZoneManager::getContinent( CEntityBase * entity ) { return getContinent(entity->getState().X, entity->getState().Y); }// CZoneManager getContinent //----------------------------------------------- // CZoneManager getRegion //----------------------------------------------- inline bool CZoneManager::getRegion( CEntityBase * entity, const CRegion ** region, const CContinent ** continent) { return getRegion(entity->getState().X, entity->getState().Y,region,continent); }// CZoneManager getRegion //----------------------------------------------- // CZoneManager getPlace //----------------------------------------------- inline bool CZoneManager::getPlace( CEntityBase * entity, float& gooDistance, const CPlace ** stable, std::vector& places, const CRegion ** region, const CContinent ** continent ) { return getPlace(entity->getState().X, entity->getState().Y,gooDistance, stable,places,region,continent); }// CZoneManager getPlace //----------------------------------------------- // CZoneManager getPlaceFromId //----------------------------------------------- inline CPlace* CZoneManager::getPlaceFromId( uint16 id ) { if ( id < _Places.size() ) return _Places[id]; return NULL; }// CZoneManager getPlaceFromId #endif // RY_ZONE_MANAGER_H /* End of zone_manager.h */