diff --git a/NEWS b/NEWS index 0a2d066ce..ec6417f48 100644 --- a/NEWS +++ b/NEWS @@ -17,6 +17,7 @@ Version 0.16 * Under discussion. * OpenSSL lib upgrade to OpenSSL 1.0.0. * Sockets lib use dropped. + * dotconfpp lib use dropped. * Upgrade to client version 3.3.3a (build 11723). Version 0.15 diff --git a/sql/mangos.sql b/sql/mangos.sql index 84b3c8c96..098d2bb8a 100644 --- a/sql/mangos.sql +++ b/sql/mangos.sql @@ -24,7 +24,7 @@ CREATE TABLE `db_version` ( `version` varchar(120) default NULL, `creature_ai_version` varchar(120) default NULL, `cache_id` int(10) default '0', - `required_10045_01_mangos_spell_proc_event` bit(1) default NULL + `required_10089_01_mangos_game_event_pool` bit(1) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Used DB version notes'; -- @@ -577,6 +577,7 @@ INSERT INTO `command` VALUES ('gm ingame',0,'Syntax: .gm ingame\r\n\r\nDisplay a list of available in game Game Masters.'), ('gm list',3,'Syntax: .gm list\r\n\r\nDisplay a list of all Game Masters accounts and security levels.'), ('gm visible',1,'Syntax: .gm visible on/off\r\n\r\nOutput current visibility state or make GM visible(on) and invisible(off) for other players.'), +('go',1,'Syntax: .go [$playername|pointlink|#x #y #z [#mapid]]\r\nTeleport your character to point with coordinates of player $playername, or coordinates of one from shift-link types: player, tele, taxinode, creature, gameobject, or explicit #x #y #z #mapid coordinates.'), ('go creature',1,'Syntax: .go creature #creature_guid\r\nTeleport your character to creature with guid #creature_guid.\r\n.gocreature #creature_name\r\nTeleport your character to creature with this name.\r\n.gocreature id #creature_id\r\nTeleport your character to a creature that was spawned from the template with this entry.\r\n*If* more than one creature is found, then you are teleported to the first that is found inside the database.'), ('go graveyard',1,'Syntax: .go graveyard #graveyardId\r\n Teleport to graveyard with the graveyardId specified.'), ('go grid',1,'Syntax: .go grid #gridX #gridY [#mapId]\r\n\r\nTeleport the gm to center of grid with provided indexes at map #mapId (or current map if it not provided).'), @@ -1571,7 +1572,7 @@ UNLOCK TABLES; DROP TABLE IF EXISTS `game_event_creature`; CREATE TABLE `game_event_creature` ( `guid` int(10) unsigned NOT NULL, - `event` smallint(6) NOT NULL default '0' COMMENT 'Put negatives values to remove during event', + `event` smallint(6) NOT NULL default '0' COMMENT 'Negatives value to remove during event and ignore pool grouping, positive value for spawn during event and if guid is part of pool then al pool memebers must be listed as part of event spawn.', PRIMARY KEY (`guid`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8; @@ -1612,7 +1613,7 @@ UNLOCK TABLES; DROP TABLE IF EXISTS `game_event_gameobject`; CREATE TABLE `game_event_gameobject` ( `guid` int(10) unsigned NOT NULL, - `event` smallint(6) NOT NULL default '0' COMMENT 'Put negatives values to remove during event', + `event` smallint(6) NOT NULL default '0' COMMENT 'Negatives value to remove during event and ignore pool grouping, positive value for spawn during event and if guid is part of pool then al pool memebers must be listed as part of event spawn.', PRIMARY KEY (`guid`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8; @@ -13704,26 +13705,6 @@ LOCK TABLES `pool_template` WRITE; /*!40000 ALTER TABLE `pool_template` ENABLE KEYS */; UNLOCK TABLES; --- --- Table structure for table `game_event_pool` --- - -DROP TABLE IF EXISTS `game_event_pool`; -CREATE TABLE `game_event_pool` ( - `pool_entry` mediumint(8) unsigned NOT NULL default '0' COMMENT 'Id of the pool', - `event` smallint(6) NOT NULL default '0' COMMENT 'Put negatives values to remove during event', - PRIMARY KEY (`pool_entry`) -) ENGINE=MyISAM DEFAULT CHARSET=utf8; - --- --- Dumping data for table `game_event_pool` --- - -LOCK TABLES `game_event_pool` WRITE; -/*!40000 ALTER TABLE `game_event_pool` DISABLE KEYS */; -/*!40000 ALTER TABLE `game_event_pool` ENABLE KEYS */; -UNLOCK TABLES; - -- -- Table structure for table `prospecting_loot_template` -- @@ -17930,6 +17911,7 @@ INSERT INTO `spell_proc_event` VALUES (31244, 0x00, 8, 0x003E0000, 0x00000009, 0x00000000, 0x00000000, 0x00002034, 0.000000, 0.000000, 0), (31394, 0x20, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0.000000, 0.000000, 0), (31569, 0x00, 3, 0x00010000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0.000000, 0.000000, 0), +(31571, 0x00, 3, 0x00000000, 0x00000000, 0x00000008, 0x00004000, 0x00000000, 0.000000, 0.000000, 0), (31785, 0x00, 0, 0x00000000, 0x00000000, 0x00000000, 0x00008800, 0x00000000, 0.000000, 0.000000, 0), (31794, 0x00, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00010000, 0.000000, 0.000000, 0), (31801, 0x01, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0.000000, 0.000000, 0), @@ -18290,7 +18272,7 @@ INSERT INTO `spell_proc_event` VALUES (61618, 0x00, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0.000000, 0.000000, 45), (61846, 0x00, 9, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0.000000, 0.000000, 0), (62600, 0x00, 7, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000002, 0.000000, 0.000000, 0), -(63108, 0x00, 5, 0x00000002, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0.000000, 0.000000, 0), +(63108, 0x00, 5, 0x00000002, 0x00000000, 0x00000000, 0x00040000, 0x00000000, 0.000000, 0.000000, 0), (63156, 0x00, 0, 0x00000001, 0x00000040, 0x00000000, 0x00000000, 0x00000000, 0.000000, 0.000000, 0), (63280, 0x00, 11, 0x20000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0.000000, 0.000000, 0), (63320, 0x00, 5, 0x00040000, 0x00000000, 0x00008000, 0x00004000, 0x00000001, 0.000000, 0.000000, 0), diff --git a/sql/updates/10056_01_mangos_spell_proc_event.sql b/sql/updates/10056_01_mangos_spell_proc_event.sql new file mode 100644 index 000000000..d36333abe --- /dev/null +++ b/sql/updates/10056_01_mangos_spell_proc_event.sql @@ -0,0 +1,5 @@ +ALTER TABLE db_version CHANGE COLUMN required_10045_01_mangos_spell_proc_event required_10056_01_mangos_spell_proc_event bit; + +DELETE FROM spell_proc_event WHERE entry IN (31571, 31572); +INSERT INTO spell_proc_event VALUES +(31571, 0x00, 3, 0x00000000, 0x00000000, 0x00000008, 0x00004000, 0x00000000, 0.000000, 0.000000, 0); diff --git a/sql/updates/10086_01_mangos_command.sql b/sql/updates/10086_01_mangos_command.sql new file mode 100644 index 000000000..ae505e125 --- /dev/null +++ b/sql/updates/10086_01_mangos_command.sql @@ -0,0 +1,5 @@ +ALTER TABLE db_version CHANGE COLUMN required_10056_01_mangos_spell_proc_event required_10086_01_mangos_command bit; + +DELETE FROM command WHERE name IN('go'); +INSERT INTO command (name, security, help) VALUES +('go',1,'Syntax: .go [$playername|pointlink|#x #y #z [#mapid]]\r\nTeleport your character to point with coordinates of player $playername, or coordinates of one from shift-link types: player, tele, taxinode, creature, gameobject, or explicit #x #y #z #mapid coordinates.'); diff --git a/sql/updates/10089_01_mangos_game_event_pool.sql b/sql/updates/10089_01_mangos_game_event_pool.sql new file mode 100644 index 000000000..f51d71e37 --- /dev/null +++ b/sql/updates/10089_01_mangos_game_event_pool.sql @@ -0,0 +1,3 @@ +ALTER TABLE db_version CHANGE COLUMN required_10086_01_mangos_command required_10089_01_mangos_game_event_pool bit; + +DROP TABLE IF EXISTS `game_event_pool`; diff --git a/sql/updates/Makefile.am b/sql/updates/Makefile.am index 955657d31..0703cd7eb 100644 --- a/sql/updates/Makefile.am +++ b/sql/updates/Makefile.am @@ -88,6 +88,9 @@ pkgdata_DATA = \ 10044_02_mangos_spell_proc_event.sql \ 10045_01_mangos_spell_proc_event.sql \ 10051_01_characters_character_aura.sql \ + 10056_01_mangos_spell_proc_event.sql \ + 10086_01_mangos_command.sql \ + 10089_01_mangos_game_event_pool.sql \ README ## Additional files to include when running 'make dist' @@ -156,4 +159,7 @@ EXTRA_DIST = \ 10044_02_mangos_spell_proc_event.sql \ 10045_01_mangos_spell_proc_event.sql \ 10051_01_characters_character_aura.sql \ + 10056_01_mangos_spell_proc_event.sql \ + 10086_01_mangos_command.sql \ + 10089_01_mangos_game_event_pool.sql \ README diff --git a/src/framework/GameSystem/NGrid.h b/src/framework/GameSystem/NGrid.h index b3422c8bc..1ac8aa1c2 100644 --- a/src/framework/GameSystem/NGrid.h +++ b/src/framework/GameSystem/NGrid.h @@ -109,7 +109,7 @@ class MANGOS_DLL_DECL NGrid } const uint32& GetGridId() const { return i_gridId; } - void SetGridId(const uint32 id) const { i_gridId = id; } + void SetGridId(const uint32 id) { i_gridId = id; } grid_state_t GetGridState() const { return i_cellstate; } void SetGridState(grid_state_t s) { i_cellstate = s; } uint32 getX() const { return i_x; } diff --git a/src/game/AchievementMgr.cpp b/src/game/AchievementMgr.cpp index 6517f8157..d32d951a1 100644 --- a/src/game/AchievementMgr.cpp +++ b/src/game/AchievementMgr.cpp @@ -639,7 +639,7 @@ void AchievementMgr::SendAchievementEarned(AchievementEntry const* achievement) { MaNGOS::AchievementChatBuilder say_builder(*GetPlayer(), CHAT_MSG_ACHIEVEMENT, LANG_ACHIEVEMENT_EARNED,achievement->ID); MaNGOS::LocalizedPacketDo say_do(say_builder); - MaNGOS::PlayerDistWorker > say_worker(GetPlayer(),sWorld.getConfig(CONFIG_FLOAT_LISTEN_RANGE_SAY),say_do); + MaNGOS::CameraDistWorker > say_worker(GetPlayer(),sWorld.getConfig(CONFIG_FLOAT_LISTEN_RANGE_SAY),say_do); Cell::VisitWorldObjects(GetPlayer(), say_worker, sWorld.getConfig(CONFIG_FLOAT_LISTEN_RANGE_SAY)); } diff --git a/src/game/Camera.cpp b/src/game/Camera.cpp new file mode 100644 index 000000000..2c37b15e8 --- /dev/null +++ b/src/game/Camera.cpp @@ -0,0 +1,141 @@ +#include "Camera.h" +#include "GridNotifiersImpl.h" +#include "CellImpl.h" +#include "Log.h" +#include "Errors.h" +#include "Player.h" + +Camera::Camera(Player* pl) : m_owner(*pl), m_source(pl) +{ + m_source->GetViewPoint().Attach(this); +} + +Camera::~Camera() +{ + // view of camera should be already reseted to owner (RemoveFromWorld -> Event_RemovedFromWorld -> ResetView) + ASSERT(m_source == &m_owner); + + // for symmetry with constructor and way to make viewpoint's list empty + m_source->GetViewPoint().Detach(this); +} + +void Camera::ReceivePacket(WorldPacket *data) +{ + m_owner.SendDirectMessage(data); +} + +void Camera::UpdateForCurrentViewPoint() +{ + m_gridRef.unlink(); + + if (GridType* grid = m_source->GetViewPoint().m_grid) + grid->AddWorldObject(this); + + m_owner.SetUInt64Value(PLAYER_FARSIGHT, (m_source == &m_owner ? 0 : m_source->GetGUID())); + UpdateVisibilityForOwner(); +} + +void Camera::SetView(WorldObject *obj) +{ + ASSERT(obj); + + if (m_source == obj) + return; + + if (!m_owner.IsInMap(obj)) + { + sLog.outError("Camera::SetView, viewpoint is not in map with camera's owner"); + return; + } + + if (!obj->isType(TYPEMASK_DYNAMICOBJECT | TYPEMASK_UNIT)) + { + sLog.outError("Camera::SetView, viewpoint type is not available for client"); + return; + } + + // detach and deregister from active objects if there are no more reasons to be active + m_source->GetViewPoint().Detach(this); + if (!m_source->isActiveObject()) + m_source->GetMap()->RemoveFromActive(m_source); + + m_source = obj; + + if (!m_source->isActiveObject()) + m_source->GetMap()->AddToActive(m_source); + + m_source->GetViewPoint().Attach(this); + + UpdateForCurrentViewPoint(); +} + +void Camera::Event_ViewPointVisibilityChanged() +{ + if (!m_owner.HaveAtClient(m_source)) + ResetView(); +} + +void Camera::ResetView() +{ + SetView(&m_owner); +} + +void Camera::Event_AddedToWorld() +{ + GridType* grid = m_source->GetViewPoint().m_grid; + ASSERT(grid); + grid->AddWorldObject(this); + + UpdateVisibilityForOwner(); +} + +void Camera::Event_RemovedFromWorld() +{ + if (m_source == &m_owner) + { + m_gridRef.unlink(); + return; + } + + ResetView(); +} + +void Camera::Event_Moved() +{ + m_gridRef.unlink(); + m_source->GetViewPoint().m_grid->AddWorldObject(this); +} + +void Camera::UpdateVisibilityOf(WorldObject* target) +{ + m_owner.UpdateVisibilityOf(m_source, target); +} + +template +void Camera::UpdateVisibilityOf(T * target, UpdateData &data, std::set& vis) +{ + m_owner.template UpdateVisibilityOf(m_source, target,data,vis); +} + +template void Camera::UpdateVisibilityOf(Player* , UpdateData& , std::set& ); +template void Camera::UpdateVisibilityOf(Creature* , UpdateData& , std::set& ); +template void Camera::UpdateVisibilityOf(Corpse* , UpdateData& , std::set& ); +template void Camera::UpdateVisibilityOf(GameObject* , UpdateData& , std::set& ); +template void Camera::UpdateVisibilityOf(DynamicObject* , UpdateData& , std::set& ); + +void Camera::UpdateVisibilityForOwner() +{ + MaNGOS::VisibleNotifier notifier(*this); + Cell::VisitAllObjects(m_source, notifier, m_source->GetMap()->GetVisibilityDistance(), false); + notifier.Notify(); +} + +////////////////// + +ViewPoint::~ViewPoint() +{ + if (!m_cameras.empty()) + { + sLog.outError("ViewPoint destructor called, but some cameras referenced to it"); + } +} diff --git a/src/game/Camera.h b/src/game/Camera.h new file mode 100644 index 000000000..98431be04 --- /dev/null +++ b/src/game/Camera.h @@ -0,0 +1,132 @@ + +#ifndef MANGOSSERVER_CAMERA_H +#define MANGOSSERVER_CAMERA_H + +#include "GridDefines.h" + +class ViewPoint; +class WorldObject; +class UpdateData; +class WorldPacket; +class Player; + +/// Camera - object-receiver. Receives broadcast packets from nearby worldobjects, object visibility changes and sends them to client +class MANGOS_DLL_SPEC Camera +{ + friend class ViewPoint; + public: + + explicit Camera(Player* pl); + ~Camera(); + + WorldObject* GetBody() { return m_source;} + Player* GetOwner() { return &m_owner;} + + // set camera's view to any worldobject + // Note: this worldobject must be in same map, in same phase with camera's owner(player) + // client supports only unit and dynamic objects as farsight objects + void SetView(WorldObject *obj); + + // set view to camera's owner + void ResetView(); + + template + void UpdateVisibilityOf(T * obj, UpdateData &d, std::set& vis); + void UpdateVisibilityOf(WorldObject* obj); + + void ReceivePacket(WorldPacket *data); + + // updates visibility of worldobjects around viewpoint for camera's owner + void UpdateVisibilityForOwner(); + + private: + // called when viewpoint changes visibility state + void Event_AddedToWorld(); + void Event_RemovedFromWorld(); + void Event_Moved(); + void Event_ViewPointVisibilityChanged(); + + Player& m_owner; + WorldObject* m_source; + + void UpdateForCurrentViewPoint(); + + public: + GridReference& GetGridRef() { return m_gridRef; } + bool isActiveObject() const { return false; } + private: + GridReference m_gridRef; +}; + +/// Object-observer, notifies farsight object state to cameras that attached to it +class MANGOS_DLL_SPEC ViewPoint +{ + friend class Camera; + + std::list m_cameras; + std::list::iterator m_camera_iter; + GridType * m_grid; + + void Attach(Camera* c) { m_cameras.push_back(c); } + + void Detach(Camera* c) + { + if (m_camera_iter != m_cameras.end() && *m_camera_iter == c) // detach called during the loop + m_camera_iter = m_cameras.erase(m_camera_iter); + else + m_cameras.remove(c); + } + + void CameraCall(void (Camera::*handler)()) + { + if (!m_cameras.empty()) + { + for(m_camera_iter = m_cameras.begin(); m_camera_iter != m_cameras.end(); ++m_camera_iter) + { + ((*m_camera_iter)->*handler)(); + + // can be end() after handler + if (m_camera_iter == m_cameras.end()) + break; + } + } + } + +public: + + ViewPoint() : m_grid(0), m_camera_iter(m_cameras.end()) {} + ~ViewPoint(); + + bool hasViewers() const { return !m_cameras.empty(); } + + // these events are called when viewpoint changes visibility state + void Event_AddedToWorld(GridType *grid) + { + m_grid = grid; + CameraCall(&Camera::Event_AddedToWorld); + } + + void Event_RemovedFromWorld() + { + m_grid = NULL; + CameraCall(&Camera::Event_RemovedFromWorld); + } + + void Event_GridChanged(GridType *grid) + { + m_grid = grid; + CameraCall(&Camera::Event_Moved); + } + + void Event_ViewPointVisibilityChanged() + { + CameraCall(&Camera::Event_ViewPointVisibilityChanged); + } + + void Call_UpdateVisibilityForOwner() + { + CameraCall(&Camera::UpdateVisibilityForOwner); + } +}; + +#endif diff --git a/src/game/CharacterHandler.cpp b/src/game/CharacterHandler.cpp index 8357ede9e..5e4e2421b 100644 --- a/src/game/CharacterHandler.cpp +++ b/src/game/CharacterHandler.cpp @@ -703,6 +703,7 @@ void WorldSession::HandlePlayerLogin(LoginQueryHolder *holder) if (!pCurrChar->GetMap()->Add(pCurrChar)) { + // normal delayed teleport protection not applied (and this correct) for this case (Player object just created) AreaTrigger const* at = sObjectMgr.GetGoBackTrigger(pCurrChar->GetMapId()); if(at) pCurrChar->TeleportTo(at->target_mapId, at->target_X, at->target_Y, at->target_Z, pCurrChar->GetOrientation()); diff --git a/src/game/Chat.cpp b/src/game/Chat.cpp index 97506963b..e1491b9e8 100644 --- a/src/game/Chat.cpp +++ b/src/game/Chat.cpp @@ -216,7 +216,7 @@ ChatCommand * ChatHandler::getCommandTable() { "zonexy", SEC_MODERATOR, false, &ChatHandler::HandleGoZoneXYCommand, "", NULL }, { "xy", SEC_MODERATOR, false, &ChatHandler::HandleGoXYCommand, "", NULL }, { "xyz", SEC_MODERATOR, false, &ChatHandler::HandleGoXYZCommand, "", NULL }, - { "", SEC_MODERATOR, false, &ChatHandler::HandleGoXYZCommand, "", NULL }, + { "", SEC_MODERATOR, false, &ChatHandler::HandleGoCommand, "", NULL }, { NULL, 0, false, NULL, "", NULL } }; @@ -2057,7 +2057,7 @@ GameTele const* ChatHandler::extractGameTeleFromLink(char* text) // id, or string, or [name] Shift-click form |color|Htele:id|h[name]|h|r char* cId = extractKeyFromLink(text,"Htele"); if(!cId) - return false; + return NULL; // id case (explicit or from shift link) if(cId[0] >= '0' || cId[0] >= '9') @@ -2079,7 +2079,7 @@ static char const* const guidKeys[] = "Hplayer", "Hcreature", "Hgameobject", - 0 + NULL }; uint64 ChatHandler::extractGuidFromLink(char* text) @@ -2133,6 +2133,130 @@ uint64 ChatHandler::extractGuidFromLink(char* text) return 0; } +enum LocationLinkType +{ + LOCATION_LINK_PLAYER = 0, // must be first for selection in not link case + LOCATION_LINK_TELE = 1, + LOCATION_LINK_TAXINODE = 2, + LOCATION_LINK_CREATURE = 3, + LOCATION_LINK_GAMEOBJECT = 4 +}; + +static char const* const locationKeys[] = +{ + "Htele", + "Htaxinode", + "Hplayer", + "Hcreature", + "Hgameobject", + NULL +}; + +bool ChatHandler::extractLocationFromLink(char* text, uint32& mapid, float& x, float& y, float& z) +{ + int type = 0; + + // |color|Hplayer:name|h[name]|h|r + // |color|Htele:id|h[name]|h|r + // |color|Htaxinode:id|h[name]|h|r + // |color|Hcreature:creature_guid|h[name]|h|r + // |color|Hgameobject:go_guid|h[name]|h|r + char* idS = extractKeyFromLink(text,locationKeys,&type); + if(!idS) + return false; + + switch(type) + { + // it also fail case + case LOCATION_LINK_PLAYER: + { + // not link and not name, possible coordinates/etc + if (isNumeric(idS[0])) + return false; + + std::string name = idS; + if(!normalizePlayerName(name)) + return false; + + if(Player* player = sObjectMgr.GetPlayer(name.c_str())) + { + mapid = player->GetMapId(); + x = player->GetPositionX(); + y = player->GetPositionY(); + z = player->GetPositionZ(); + return true; + } + + if(uint64 guid = sObjectMgr.GetPlayerGUIDByName(name)) + { + // to point where player stay (if loaded) + float o; + bool in_flight; + return Player::LoadPositionFromDB(mapid, x, y, z, o, in_flight, guid); + } + + return false; + } + case LOCATION_LINK_TELE: + { + uint32 id = (uint32)atol(idS); + GameTele const* tele = sObjectMgr.GetGameTele(id); + if (!tele) + return false; + mapid = tele->mapId; + x = tele->position_x; + y = tele->position_y; + z = tele->position_z; + return true; + } + case LOCATION_LINK_TAXINODE: + { + uint32 id = (uint32)atol(idS); + TaxiNodesEntry const* node = sTaxiNodesStore.LookupEntry(id); + if (!node) + return false; + mapid = node->map_id; + x = node->x; + y = node->y; + z = node->z; + return true; + } + case LOCATION_LINK_CREATURE: + { + uint32 lowguid = (uint32)atol(idS); + + if(CreatureData const* data = sObjectMgr.GetCreatureData(lowguid) ) + { + mapid = data->mapid; + x = data->posX; + y = data->posY; + z = data->posZ; + return true; + } + else + return false; + } + case LOCATION_LINK_GAMEOBJECT: + { + uint32 lowguid = (uint32)atol(idS); + + if(GameObjectData const* data = sObjectMgr.GetGOData(lowguid) ) + { + mapid = data->mapid; + x = data->posX; + y = data->posY; + z = data->posZ; + return true; + } + else + return false; + } + } + + // unknown type? + return false; +} + std::string ChatHandler::extractPlayerNameFromLink(char* text) { // |color|Hplayer:name|h[name]|h|r @@ -2229,7 +2353,7 @@ char* ChatHandler::extractQuotedArg( char* args ) { char* space = strtok(args, "\""); if(!space) - return false; + return NULL; return strtok(NULL, "\""); } } diff --git a/src/game/Chat.h b/src/game/Chat.h index 87aa895cf..5250a857b 100644 --- a/src/game/Chat.h +++ b/src/game/Chat.h @@ -535,6 +535,7 @@ class ChatHandler uint32 extractSpellIdFromLink(char* text); uint64 extractGuidFromLink(char* text); GameTele const* extractGameTeleFromLink(char* text); + bool extractLocationFromLink(char* text, uint32& mapid, float& x, float& y, float& z); std::string extractPlayerNameFromLink(char* text); // select by arg (name/link) or in-game selection online/offline player bool extractPlayerTarget(char* args, Player** player, uint64* player_guid = NULL, std::string* player_name = NULL); @@ -558,6 +559,8 @@ class ChatHandler void HandleCharacterLevel(Player* player, uint64 player_guid, uint32 oldlevel, uint32 newlevel); void HandleLearnSkillRecipesHelper(Player* player,uint32 skill_id); void ShowSpellListHelper(Player* target, SpellEntry const* spellInfo, LocaleConstant loc); + bool HandleGoHelper(Player* _player, uint32 mapid, float x, float y, float const* zPtr = NULL); + /** * Stores informations about a deleted character diff --git a/src/game/ChatHandler.cpp b/src/game/ChatHandler.cpp index 3e575bb49..405118641 100644 --- a/src/game/ChatHandler.cpp +++ b/src/game/ChatHandler.cpp @@ -574,7 +574,7 @@ void WorldSession::HandleTextEmoteOpcode( WorldPacket & recv_data ) MaNGOS::EmoteChatBuilder emote_builder(*GetPlayer(), text_emote, emoteNum, unit); MaNGOS::LocalizedPacketDo emote_do(emote_builder); - MaNGOS::PlayerDistWorker > emote_worker(GetPlayer(), sWorld.getConfig(CONFIG_FLOAT_LISTEN_RANGE_TEXTEMOTE), emote_do); + MaNGOS::CameraDistWorker > emote_worker(GetPlayer(), sWorld.getConfig(CONFIG_FLOAT_LISTEN_RANGE_TEXTEMOTE), emote_do); Cell::VisitWorldObjects(GetPlayer(), emote_worker, sWorld.getConfig(CONFIG_FLOAT_LISTEN_RANGE_TEXTEMOTE)); GetPlayer()->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_DO_EMOTE, text_emote, 0, unit); diff --git a/src/game/Corpse.h b/src/game/Corpse.h index e01523850..fd867e550 100644 --- a/src/game/Corpse.h +++ b/src/game/Corpse.h @@ -90,8 +90,6 @@ class Corpse : public WorldObject GridReference &GetGridRef() { return m_gridRef; } - bool isActiveObject() const { return false; } - bool IsExpired(time_t t) const; private: GridReference m_gridRef; diff --git a/src/game/Creature.cpp b/src/game/Creature.cpp index 6e984a990..4305b3be7 100644 --- a/src/game/Creature.cpp +++ b/src/game/Creature.cpp @@ -117,7 +117,7 @@ m_subtype(subtype), m_defaultMovementType(IDLE_MOTION_TYPE), m_DBTableGuid(0), m m_AlreadyCallAssistance(false), m_AlreadySearchedAssistance(false), m_regenHealth(true), m_AI_locked(false), m_isDeadByDefault(false), m_needNotify(false), m_meleeDamageSchoolMask(SPELL_SCHOOL_MASK_NORMAL), -m_creatureInfo(NULL), m_isActiveObject(false), m_splineFlags(SPLINEFLAG_WALKMODE) +m_creatureInfo(NULL), m_splineFlags(SPLINEFLAG_WALKMODE) { m_regenTimer = 200; m_valuesCount = UNIT_END; @@ -248,11 +248,14 @@ bool Creature::InitEntry(uint32 Entry, uint32 team, const CreatureData *data ) SetByteValue(UNIT_FIELD_BYTES_0, 2, minfo->gender); // Load creature equipment - if(!data || data->equipmentId == 0) - { // use default from the template - LoadEquipment(cinfo->equipmentId); + if (!data || data->equipmentId == 0) + { + if (cinfo->equipmentId == 0) + LoadEquipment(normalInfo->equipmentId); // use default from normal template if diff does not have any + else + LoadEquipment(cinfo->equipmentId); // else use from diff template } - else if(data && data->equipmentId != -1) + else if (data && data->equipmentId != -1) { // override, -1 means no equipment LoadEquipment(data->equipmentId); } @@ -788,29 +791,6 @@ bool Creature::isCanTrainingAndResetTalentsOf(Player* pPlayer) const && pPlayer->getClass() == GetCreatureInfo()->trainer_class; } -void Creature::AI_SendMoveToPacket(float x, float y, float z, uint32 time, SplineFlags flags, SplineType type) -{ - /* uint32 timeElap = getMSTime(); - if ((timeElap - m_startMove) < m_moveTime) - { - oX = (dX - oX) * ( (timeElap - m_startMove) / m_moveTime ); - oY = (dY - oY) * ( (timeElap - m_startMove) / m_moveTime ); - } - else - { - oX = dX; - oY = dY; - } - - dX = x; - dY = y; - m_orientation = atan2((oY - dY), (oX - dX)); - - m_startMove = getMSTime(); - m_moveTime = time;*/ - SendMonsterMove(x, y, z, type, flags, time); -} - void Creature::PrepareBodyLootState() { loot.clear(); @@ -2218,4 +2198,4 @@ void Creature::RelocationNotify() MaNGOS::CreatureRelocationNotifier relocationNotifier(*this); float radius = MAX_CREATURE_ATTACK_RADIUS * sWorld.getConfig(CONFIG_FLOAT_RATE_CREATURE_AGGRO); Cell::VisitAllObjects(this, relocationNotifier, radius); -} +} \ No newline at end of file diff --git a/src/game/Creature.h b/src/game/Creature.h index c6dff5dfc..23d47e573 100644 --- a/src/game/Creature.h +++ b/src/game/Creature.h @@ -444,7 +444,6 @@ class MANGOS_DLL_SPEC Creature : public Unit bool AIM_Initialize(); - void AI_SendMoveToPacket(float x, float y, float z, uint32 time, SplineFlags MovementFlags, SplineType type); CreatureAI* AI() { return i_AI; } void AddSplineFlag(SplineFlags f) @@ -627,7 +626,6 @@ class MANGOS_DLL_SPEC Creature : public Unit void SetDeadByDefault (bool death_state) { m_isDeadByDefault = death_state; } - bool isActiveObject() const { return m_isActiveObject || HasAuraType(SPELL_AURA_BIND_SIGHT) || HasAuraType(SPELL_AURA_FAR_SIGHT); } void SetActiveObjectState(bool on); void SetNeedNotify() { m_needNotify = true; } @@ -692,7 +690,6 @@ class MANGOS_DLL_SPEC Creature : public Unit private: GridReference m_gridRef; CreatureInfo const* m_creatureInfo; // in difficulty mode > 0 can different from ObjMgr::GetCreatureTemplate(GetEntry()) - bool m_isActiveObject; SplineFlags m_splineFlags; }; diff --git a/src/game/CreatureAI.cpp b/src/game/CreatureAI.cpp index b650b65fb..33cb56877 100644 --- a/src/game/CreatureAI.cpp +++ b/src/game/CreatureAI.cpp @@ -36,7 +36,7 @@ CanCastResult CreatureAI::CanCastSpell(Unit* pTarget, const SpellEntry *pSpell, if (!isTriggered) { // State does not allow - if (m_creature->hasUnitState(UNIT_STAT_CAN_NOT_REACT)) + if (m_creature->hasUnitState(UNIT_STAT_CAN_NOT_REACT_OR_LOST_CONTROL)) return CAST_FAIL_STATE; if (pSpell->PreventionType == SPELL_PREVENTION_TYPE_SILENCE && m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SILENCED)) diff --git a/src/game/CreatureAISelector.cpp b/src/game/CreatureAISelector.cpp index 4b78c329d..87eb1fe97 100644 --- a/src/game/CreatureAISelector.cpp +++ b/src/game/CreatureAISelector.cpp @@ -90,7 +90,8 @@ namespace FactorySelector { MovementGeneratorRegistry &mv_registry(MovementGeneratorRepository::Instance()); ASSERT( creature->GetCreatureInfo() != NULL ); - const MovementGeneratorCreator *mv_factory = mv_registry.GetRegistryItem( creature->GetDefaultMovementType()); + MovementGeneratorCreator const * mv_factory = mv_registry.GetRegistryItem( + IS_PLAYER_GUID(creature->GetOwnerGUID()) ? FOLLOW_MOTION_TYPE : creature->GetDefaultMovementType()); /* if( mv_factory == NULL ) { diff --git a/src/game/CreatureEventAI.cpp b/src/game/CreatureEventAI.cpp index bbb12c602..c79611c31 100644 --- a/src/game/CreatureEventAI.cpp +++ b/src/game/CreatureEventAI.cpp @@ -1319,7 +1319,7 @@ bool CreatureEventAI::CanCast(Unit* Target, SpellEntry const *Spell, bool Trigge return false; //Silenced so we can't cast - if (!Triggered && (m_creature->hasUnitState(UNIT_STAT_CAN_NOT_REACT) || + if (!Triggered && (m_creature->hasUnitState(UNIT_STAT_CAN_NOT_REACT_OR_LOST_CONTROL) || m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PACIFIED))) return false; diff --git a/src/game/DestinationHolderImp.h b/src/game/DestinationHolderImp.h index b4932944b..32ca246b4 100644 --- a/src/game/DestinationHolderImp.h +++ b/src/game/DestinationHolderImp.h @@ -86,7 +86,12 @@ DestinationHolder::StartTravel(TRAVELLER &traveller, bool sendMove) i_totalTravelTime = traveller.GetTotalTrevelTimeTo(i_destX,i_destY,i_destZ); i_timeElapsed = 0; if(sendMove) - traveller.MoveTo(i_destX, i_destY, i_destZ, i_totalTravelTime); + { + if (i_totalTravelTime) + traveller.MoveTo(i_destX, i_destY, i_destZ, i_totalTravelTime); + else + traveller.Stop(); + } return i_totalTravelTime; } diff --git a/src/game/DynamicObject.cpp b/src/game/DynamicObject.cpp index 6a36f6dda..9c55c6b17 100644 --- a/src/game/DynamicObject.cpp +++ b/src/game/DynamicObject.cpp @@ -27,7 +27,7 @@ #include "GridNotifiersImpl.h" #include "SpellMgr.h" -DynamicObject::DynamicObject() : WorldObject(), m_isActiveObject(false) +DynamicObject::DynamicObject() : WorldObject() { m_objectType |= TYPEMASK_DYNAMICOBJECT; m_objectTypeId = TYPEID_DYNAMICOBJECT; @@ -50,7 +50,10 @@ void DynamicObject::RemoveFromWorld() { ///- Remove the dynamicObject from the accessor if(IsInWorld()) + { GetMap()->GetObjectsStore().erase(GetGUID(), (DynamicObject*)NULL); + GetViewPoint().Event_RemovedFromWorld(); + } Object::RemoveFromWorld(); } @@ -80,10 +83,6 @@ bool DynamicObject::Create( uint32 guidlow, Unit *caster, uint32 spellId, SpellE m_effIndex = effIndex; m_spellId = spellId; - // set to active for far sight case - if(SpellEntry const* spellEntry = sSpellStore.LookupEntry(spellId)) - m_isActiveObject = IsSpellHaveEffect(spellEntry,SPELL_EFFECT_ADD_FARSIGHT); - return true; } diff --git a/src/game/DynamicObject.h b/src/game/DynamicObject.h index fffdbec20..3dbcd66d5 100644 --- a/src/game/DynamicObject.h +++ b/src/game/DynamicObject.h @@ -61,7 +61,6 @@ class DynamicObject : public WorldObject GridReference &GetGridRef() { return m_gridRef; } - bool isActiveObject() const { return m_isActiveObject; } protected: uint32 m_spellId; SpellEffectIndex m_effIndex; @@ -70,6 +69,5 @@ class DynamicObject : public WorldObject AffectedSet m_affected; private: GridReference m_gridRef; - bool m_isActiveObject; }; #endif diff --git a/src/game/GameEventMgr.cpp b/src/game/GameEventMgr.cpp index 04275c311..2bcbbd1a8 100644 --- a/src/game/GameEventMgr.cpp +++ b/src/game/GameEventMgr.cpp @@ -171,6 +171,13 @@ void GameEventMgr::LoadFromDB() sLog.outString( ">> Loaded %u game events", count ); } + std::map pool2event; // for check unique spawn event associated with pool + std::map creature2event; // for check unique spawn event associated with creature + std::map go2event; // for check unique spawn event associated with gameobject + + // list only positive event top pools, filled at creature/gameobject loading + mGameEventSpawnPoolIds.resize(mGameEvent.size()); + mGameEventCreatureGuids.resize(mGameEvent.size()*2-1); // 1 2 result = WorldDatabase.Query("SELECT creature.guid, game_event_creature.event " @@ -198,6 +205,12 @@ void GameEventMgr::LoadFromDB() uint32 guid = fields[0].GetUInt32(); int16 event_id = fields[1].GetInt16(); + if (event_id == 0) + { + sLog.outErrorDb("`game_event_creature` game event id (%i) not allowed",event_id); + continue; + } + int32 internal_event_id = mGameEvent.size() + event_id - 1; if(internal_event_id < 0 || (size_t)internal_event_id >= mGameEventCreatureGuids.size()) @@ -207,6 +220,32 @@ void GameEventMgr::LoadFromDB() } ++count; + + // spawn objects at event can be grouped in pools and then affected pools have stricter requirements for this case + if (event_id > 0) + { + creature2event[guid] = event_id; + + // not list explicitly creatures from pools in event creature list + if (uint16 topPoolId = sPoolMgr.IsPartOfTopPool(guid)) + { + int16& eventRef = pool2event[topPoolId]; + if (eventRef != 0) + { + if (eventRef != event_id) + sLog.outErrorDb("`game_event_creature` have creature (GUID: %u) for event %i from pool or subpool of pool (ID: %u) but pool have already content from event %i. Pool don't must have content for different events!", guid, event_id, topPoolId, eventRef); + } + else + { + eventRef = event_id; + mGameEventSpawnPoolIds[event_id].push_back(topPoolId); + sPoolMgr.RemoveAutoSpawnForPool(topPoolId); + } + + continue; + } + } + GuidList& crelist = mGameEventCreatureGuids[internal_event_id]; crelist.push_back(guid); @@ -244,6 +283,12 @@ void GameEventMgr::LoadFromDB() uint32 guid = fields[0].GetUInt32(); int16 event_id = fields[1].GetInt16(); + if (event_id == 0) + { + sLog.outErrorDb("`game_event_gameobject` game event id (%i) not allowed",event_id); + continue; + } + int32 internal_event_id = mGameEvent.size() + event_id - 1; if(internal_event_id < 0 || (size_t)internal_event_id >= mGameEventGameobjectGuids.size()) @@ -253,6 +298,32 @@ void GameEventMgr::LoadFromDB() } ++count; + + // spawn objects at event can be grouped in pools and then affected pools have stricter requirements for this case + if (event_id > 0) + { + go2event[guid] = event_id; + + // not list explicitly gameobjects from pools in event gameobject list + if (uint16 topPoolId = sPoolMgr.IsPartOfTopPool(guid)) + { + int16& eventRef = pool2event[topPoolId]; + if (eventRef != 0) + { + if (eventRef != event_id) + sLog.outErrorDb("`game_event_gameobject` have gameobject (GUID: %u) for event %i from pool or subpool of pool (ID: %u) but pool have already content from event %i. Pool don't must have content for different events!", guid, event_id, topPoolId, eventRef); + } + else + { + eventRef = event_id; + mGameEventSpawnPoolIds[event_id].push_back(topPoolId); + sPoolMgr.RemoveAutoSpawnForPool(topPoolId); + } + + continue; + } + } + GuidList& golist = mGameEventGameobjectGuids[internal_event_id]; golist.push_back(guid); @@ -263,6 +334,15 @@ void GameEventMgr::LoadFromDB() sLog.outString( ">> Loaded %u gameobjects in game events", count ); } + // now recheck that all eventPools linked with events after our skip pools with parents + for(std::map::const_iterator itr = pool2event.begin(); itr != pool2event.end(); ++itr) + { + uint16 pool_id = itr->first; + int16 event_id = itr->second; + + sPoolMgr.CheckEventLinkAndReport(pool_id, event_id, creature2event, go2event); + } + mGameEventModelEquip.resize(mGameEvent.size()); // 0 1 2 result = WorldDatabase.Query("SELECT creature.guid, game_event_model_equip.event, game_event_model_equip.modelid," @@ -365,57 +445,6 @@ void GameEventMgr::LoadFromDB() sLog.outString(); sLog.outString( ">> Loaded %u quests additions in game events", count ); } - - mGameEventPoolIds.resize(mGameEvent.size()*2-1); - // 1 2 - result = WorldDatabase.Query("SELECT pool_template.entry, game_event_pool.event " - "FROM pool_template JOIN game_event_pool ON pool_template.entry = game_event_pool.pool_entry"); - - count = 0; - if( !result ) - { - barGoLink bar2(1); - bar2.step(); - - sLog.outString(); - sLog.outString(">> Loaded %u pools in game events", count ); - } - else - { - - barGoLink bar2( (int)result->GetRowCount() ); - do - { - Field *fields = result->Fetch(); - - bar2.step(); - - uint32 entry = fields[0].GetUInt16(); - int16 event_id = fields[1].GetInt16(); - - int32 internal_event_id = mGameEvent.size() + event_id - 1; - - if (internal_event_id < 0 || (size_t)internal_event_id >= mGameEventPoolIds.size()) - { - sLog.outErrorDb("`game_event_pool` game event id (%i) is out of range compared to max event id in `game_event`",event_id); - continue; - } - - if (!sPoolMgr.CheckPool(entry)) - { - sLog.outErrorDb("Pool Id (%u) has all creatures or gameobjects with explicit chance sum <>100 and no equal chance defined. The pool system cannot pick one to spawn.", entry); - continue; - } - - ++count; - IdList& poollist = mGameEventPoolIds[internal_event_id]; - poollist.push_back(entry); - - } while( result->NextRow() ); - sLog.outString(); - sLog.outString( ">> Loaded %u pools in game events", count ); - delete result; - } } uint32 GameEventMgr::Initialize() // return the next event delay in ms @@ -516,6 +545,18 @@ void GameEventMgr::GameEventSpawn(int16 event_id) CreatureData const* data = sObjectMgr.GetCreatureData(*itr); if (data) { + // negative event id for pool element meaning allow be used in next pool spawn + if (event_id < 0) + { + if (uint16 pool_id = sPoolMgr.IsPartOfAPool(*itr)) + { + // will have chance at next pool update + sPoolMgr.SetExcludeObject(pool_id, *itr, false); + sPoolMgr.UpdatePool(pool_id); + continue; + } + } + sObjectMgr.AddCreatureToGrid(*itr, data); // Spawn if necessary (loaded grids only) @@ -549,7 +590,20 @@ void GameEventMgr::GameEventSpawn(int16 event_id) GameObjectData const* data = sObjectMgr.GetGOData(*itr); if (data) { + // negative event id for pool element meaning allow be used in next pool spawn + if (event_id < 0) + { + if (uint16 pool_id = sPoolMgr.IsPartOfAPool(*itr)) + { + // will have chance at next pool update + sPoolMgr.SetExcludeObject(pool_id, *itr, false); + sPoolMgr.UpdatePool(pool_id); + continue; + } + } + sObjectMgr.AddGameobjectToGrid(*itr, data); + // Spawn if necessary (loaded grids only) // this base map checked as non-instanced and then only existed Map* map = const_cast(sMapMgr.CreateBaseMap(data->mapid)); @@ -571,14 +625,17 @@ void GameEventMgr::GameEventSpawn(int16 event_id) } } - if (internal_event_id < 0 || (size_t)internal_event_id >= mGameEventPoolIds.size()) + if (event_id > 0) { - sLog.outError("GameEventMgr::GameEventSpawn attempt access to out of range mGameEventPoolIds element %i (size: " SIZEFMTD ")",internal_event_id,mGameEventPoolIds.size()); - return; - } + if((size_t)event_id >= mGameEventSpawnPoolIds.size()) + { + sLog.outError("GameEventMgr::GameEventSpawn attempt access to out of range mGameEventSpawnPoolIds element %i (size: " SIZEFMTD ")", event_id, mGameEventSpawnPoolIds.size()); + return; + } - for (IdList::iterator itr = mGameEventPoolIds[internal_event_id].begin();itr != mGameEventPoolIds[internal_event_id].end();++itr) - sPoolMgr.SpawnPool(*itr, true); + for (IdList::iterator itr = mGameEventSpawnPoolIds[event_id].begin();itr != mGameEventSpawnPoolIds[event_id].end();++itr) + sPoolMgr.SpawnPool(*itr, true); + } } void GameEventMgr::GameEventUnspawn(int16 event_id) @@ -596,6 +653,17 @@ void GameEventMgr::GameEventUnspawn(int16 event_id) // Remove the creature from grid if( CreatureData const* data = sObjectMgr.GetCreatureData(*itr) ) { + // negative event id for pool element meaning unspawn in pool and exclude for next spawns + if (event_id < 0) + { + if (uint16 poolid = sPoolMgr.IsPartOfAPool(*itr)) + { + sPoolMgr.SetExcludeObject(poolid, *itr, true); + sPoolMgr.UpdatePool(poolid, *itr); + continue; + } + } + sObjectMgr.RemoveCreatureFromGrid(*itr, data); if (Creature* pCreature = ObjectAccessor::GetCreatureInWorld(ObjectGuid(HIGHGUID_UNIT, data->id, *itr))) @@ -614,21 +682,36 @@ void GameEventMgr::GameEventUnspawn(int16 event_id) // Remove the gameobject from grid if(GameObjectData const* data = sObjectMgr.GetGOData(*itr)) { + // negative event id for pool element meaning unspawn in pool and exclude for next spawns + if (event_id < 0) + { + if (uint16 poolid = sPoolMgr.IsPartOfAPool(*itr)) + { + sPoolMgr.SetExcludeObject(poolid, *itr, true); + sPoolMgr.UpdatePool(poolid, *itr); + continue; + } + } + sObjectMgr.RemoveGameobjectFromGrid(*itr, data); if( GameObject* pGameobject = ObjectAccessor::GetGameObjectInWorld(ObjectGuid(HIGHGUID_GAMEOBJECT, data->id, *itr)) ) pGameobject->AddObjectToRemoveList(); } } - if (internal_event_id < 0 || (size_t)internal_event_id >= mGameEventPoolIds.size()) - { - sLog.outError("GameEventMgr::GameEventUnspawn attempt access to out of range mGameEventPoolIds element %i (size: " SIZEFMTD ")",internal_event_id,mGameEventPoolIds.size()); - return; - } - for (IdList::iterator itr = mGameEventPoolIds[internal_event_id].begin();itr != mGameEventPoolIds[internal_event_id].end();++itr) + if (event_id > 0) { - sPoolMgr.DespawnPool(*itr); + if ((size_t)event_id >= mGameEventSpawnPoolIds.size()) + { + sLog.outError("GameEventMgr::GameEventUnspawn attempt access to out of range mGameEventSpawnPoolIds element %i (size: " SIZEFMTD ")", event_id, mGameEventSpawnPoolIds.size()); + return; + } + + for (IdList::iterator itr = mGameEventSpawnPoolIds[event_id].begin();itr != mGameEventSpawnPoolIds[event_id].end();++itr) + { + sPoolMgr.DespawnPool(*itr); + } } } diff --git a/src/game/GameEventMgr.h b/src/game/GameEventMgr.h index 39480a9f4..e236768bb 100644 --- a/src/game/GameEventMgr.h +++ b/src/game/GameEventMgr.h @@ -88,11 +88,11 @@ class GameEventMgr typedef std::pair QuestRelation; typedef std::list QuestRelList; typedef std::vector GameEventQuestMap; - GameEventQuestMap mGameEventQuests; - GameEventModelEquipMap mGameEventModelEquip; - GameEventGuidMap mGameEventCreatureGuids; - GameEventGuidMap mGameEventGameobjectGuids; - GameEventIdMap mGameEventPoolIds; + GameEventQuestMap mGameEventQuests; // events*2-1 + GameEventModelEquipMap mGameEventModelEquip; // events*2-1 + GameEventGuidMap mGameEventCreatureGuids; // events*2-1 + GameEventGuidMap mGameEventGameobjectGuids; // events*2-1 + GameEventIdMap mGameEventSpawnPoolIds; // events size, only positive event case GameEventDataMap mGameEvent; ActiveEvents m_ActiveEvents; bool m_IsGameEventsInit; diff --git a/src/game/GameObject.h b/src/game/GameObject.h index 0e48cb722..657dad3df 100644 --- a/src/game/GameObject.h +++ b/src/game/GameObject.h @@ -703,7 +703,6 @@ class MANGOS_DLL_SPEC GameObject : public WorldObject GridReference &GetGridRef() { return m_gridRef; } - bool isActiveObject() const { return false; } uint64 GetRotation() const { return m_rotation; } protected: uint32 m_spellId; diff --git a/src/game/GridDefines.h b/src/game/GridDefines.h index 0f737decc..da5abba03 100644 --- a/src/game/GridDefines.h +++ b/src/game/GridDefines.h @@ -31,6 +31,7 @@ class DynamicObject; class GameObject; class Pet; class Player; +class Camera; #define MAX_NUMBER_OF_GRIDS 64 @@ -56,10 +57,12 @@ class Player; #define MAP_HALFSIZE (MAP_SIZE/2) // Creature used instead pet to simplify *::Visit templates (not required duplicate code for Creature->Pet case) -typedef TYPELIST_3(Player, Creature/*pets*/, Corpse/*resurrectable*/) AllWorldObjectTypes; +// Cameras in world list just because linked with Player objects +typedef TYPELIST_4(Player, Creature/*pets*/, Corpse/*resurrectable*/, Camera) AllWorldObjectTypes; typedef TYPELIST_4(GameObject, Creature/*except pets*/, DynamicObject, Corpse/*Bones*/) AllGridObjectTypes; typedef TYPELIST_5(Creature, Pet, Vehicle, GameObject, DynamicObject) AllMapStoredObjectTypes; +typedef GridRefManager CameraMapType; typedef GridRefManager CorpseMapType; typedef GridRefManager CreatureMapType; typedef GridRefManager DynamicObjectMapType; diff --git a/src/game/GridMap.cpp b/src/game/GridMap.cpp index 4df4083b6..501ad807d 100644 --- a/src/game/GridMap.cpp +++ b/src/game/GridMap.cpp @@ -21,7 +21,6 @@ #include "GridStates.h" #include "CellImpl.h" #include "Map.h" -#include "Config/ConfigEnv.h" #include "DBCEnums.h" #include "DBCStores.h" #include "GridMap.h" diff --git a/src/game/GridNotifiers.cpp b/src/game/GridNotifiers.cpp index 30d977c40..da6aa90ea 100644 --- a/src/game/GridNotifiers.cpp +++ b/src/game/GridNotifiers.cpp @@ -28,32 +28,29 @@ using namespace MaNGOS; void -VisibleChangesNotifier::Visit(PlayerMapType &m) +VisibleChangesNotifier::Visit(CameraMapType &m) { - for(PlayerMapType::iterator iter=m.begin(); iter != m.end(); ++iter) + for(CameraMapType::iterator iter=m.begin(); iter != m.end(); ++iter) { - Player* player = iter->getSource(); - if(player == &i_object) - continue; - - player->UpdateVisibilityOf(player->GetViewPoint(),&i_object); + iter->getSource()->UpdateVisibilityOf(&i_object); } } void VisibleNotifier::Notify() { + Player& player = *i_camera.GetOwner(); // at this moment i_clientGUIDs have guids that not iterate at grid level checks // but exist one case when this possible and object not out of range: transports - if(Transport* transport = i_player.GetTransport()) + if(Transport* transport = player.GetTransport()) { for(Transport::PlayerSet::const_iterator itr = transport->GetPassengers().begin();itr!=transport->GetPassengers().end();++itr) { - if(i_clientGUIDs.find((*itr)->GetGUID())!=i_clientGUIDs.end()) + if (i_clientGUIDs.find((*itr)->GetGUID()) != i_clientGUIDs.end()) { // ignore far sight case - (*itr)->UpdateVisibilityOf((*itr),&i_player); - i_player.UpdateVisibilityOf(&i_player,(*itr),i_data,i_visibleNow); + (*itr)->UpdateVisibilityOf(*itr, &player); + player.UpdateVisibilityOf(&player, *itr, i_data, i_visibleNow); i_clientGUIDs.erase((*itr)->GetGUID()); } } @@ -63,27 +60,28 @@ VisibleNotifier::Notify() i_data.AddOutOfRangeGUID(i_clientGUIDs); for(ObjectGuidSet::iterator itr = i_clientGUIDs.begin();itr!=i_clientGUIDs.end();++itr) { - i_player.m_clientGUIDs.erase(*itr); + player.m_clientGUIDs.erase(*itr); - DEBUG_FILTER_LOG(LOG_FILTER_VISIBILITY_CHANGES, "%s is out of range (no in active cells set) now for player %u",itr->GetString().c_str(),i_player.GetGUIDLow()); + DEBUG_FILTER_LOG(LOG_FILTER_VISIBILITY_CHANGES, "%s is out of range (no in active cells set) now for %s", + itr->GetString().c_str(), player.GetObjectGuid().GetString().c_str()); } - if( i_data.HasData() ) + if (i_data.HasData()) { // send create/outofrange packet to player (except player create updates that already sent using SendUpdateToPlayer) WorldPacket packet; i_data.BuildPacket(&packet); - i_player.GetSession()->SendPacket(&packet); + player.GetSession()->SendPacket(&packet); // send out of range to other players if need ObjectGuidSet const& oor = i_data.GetOutOfRangeGUIDs(); for(ObjectGuidSet::const_iterator iter = oor.begin(); iter != oor.end(); ++iter) { - if(!iter->IsPlayer()) + if (!iter->IsPlayer()) continue; if (Player* plr = ObjectAccessor::FindPlayer(*iter)) - plr->UpdateVisibilityOf(plr->GetViewPoint(),&i_player); + plr->UpdateVisibilityOf(plr->GetCamera().GetBody(), &player); } } @@ -93,87 +91,92 @@ VisibleNotifier::Notify() for(std::set::const_iterator vItr = i_visibleNow.begin(); vItr != i_visibleNow.end(); ++vItr) { // target aura duration for caster show only if target exist at caster client - if((*vItr)!=&i_player && (*vItr)->isType(TYPEMASK_UNIT)) - i_player.SendAurasForTarget((Unit*)(*vItr)); + if ((*vItr) != &player && (*vItr)->isType(TYPEMASK_UNIT)) + player.SendAurasForTarget((Unit*)(*vItr)); // non finished movements show to player - if((*vItr)->GetTypeId()==TYPEID_UNIT && ((Creature*)(*vItr))->isAlive()) - ((Creature*)(*vItr))->SendMonsterMoveWithSpeedToCurrentDestination(&i_player); + if ((*vItr)->GetTypeId()==TYPEID_UNIT && ((Creature*)(*vItr))->isAlive()) + ((Creature*)(*vItr))->SendMonsterMoveWithSpeedToCurrentDestination(&player); } } void -MessageDeliverer::Visit(PlayerMapType &m) +MessageDeliverer::Visit(CameraMapType &m) { - for(PlayerMapType::iterator iter=m.begin(); iter != m.end(); ++iter) + for(CameraMapType::iterator iter = m.begin(); iter != m.end(); ++iter) { - if (i_toSelf || iter->getSource() != &i_player) + Player* owner = iter->getSource()->GetOwner(); + + if (i_toSelf || owner != &i_player) { - if (!i_player.InSamePhase(iter->getSource())) + if (!i_player.InSamePhase(iter->getSource()->GetBody())) continue; - if(WorldSession* session = iter->getSource()->GetSession()) + if (WorldSession* session = owner->GetSession()) session->SendPacket(i_message); } } } -void MessageDelivererExcept::Visit(PlayerMapType &m) +void MessageDelivererExcept::Visit(CameraMapType &m) { - for(PlayerMapType::iterator it = m.begin(); it!= m.end(); ++it) + for(CameraMapType::iterator iter = m.begin(); iter != m.end(); ++iter) { - Player* player = it->getSource(); - if(!player->InSamePhase(i_phaseMask) || player == i_skipped_receiver) + Player* owner = iter->getSource()->GetOwner(); + + if (!owner->InSamePhase(i_phaseMask) || owner == i_skipped_receiver) continue; - if (WorldSession* session = player->GetSession()) + if (WorldSession* session = owner->GetSession()) session->SendPacket(i_message); } } void -ObjectMessageDeliverer::Visit(PlayerMapType &m) +ObjectMessageDeliverer::Visit(CameraMapType &m) { - for(PlayerMapType::iterator iter=m.begin(); iter != m.end(); ++iter) + for(CameraMapType::iterator iter = m.begin(); iter != m.end(); ++iter) { - if(!iter->getSource()->InSamePhase(i_phaseMask)) + if(!iter->getSource()->GetBody()->InSamePhase(i_phaseMask)) continue; - if(WorldSession* session = iter->getSource()->GetSession()) + if(WorldSession* session = iter->getSource()->GetOwner()->GetSession()) session->SendPacket(i_message); } } void -MessageDistDeliverer::Visit(PlayerMapType &m) +MessageDistDeliverer::Visit(CameraMapType &m) { - for(PlayerMapType::iterator iter=m.begin(); iter != m.end(); ++iter) + for(CameraMapType::iterator iter=m.begin(); iter != m.end(); ++iter) { - if ((i_toSelf || iter->getSource() != &i_player ) && - (!i_ownTeamOnly || iter->getSource()->GetTeam() == i_player.GetTeam() ) && - (!i_dist || iter->getSource()->IsWithinDist(&i_player,i_dist))) + Player * owner = iter->getSource()->GetOwner(); + + if ((i_toSelf || owner != &i_player) && + (!i_ownTeamOnly || owner->GetTeam() == i_player.GetTeam()) && + (!i_dist || iter->getSource()->GetBody()->IsWithinDist(&i_player,i_dist))) { - if (!i_player.InSamePhase(iter->getSource())) + if (!i_player.InSamePhase(iter->getSource()->GetBody())) continue; - if (WorldSession* session = iter->getSource()->GetSession()) + if (WorldSession* session = owner->GetSession()) session->SendPacket(i_message); } } } void -ObjectMessageDistDeliverer::Visit(PlayerMapType &m) +ObjectMessageDistDeliverer::Visit(CameraMapType &m) { - for(PlayerMapType::iterator iter=m.begin(); iter != m.end(); ++iter) + for(CameraMapType::iterator iter=m.begin(); iter != m.end(); ++iter) { - if (!i_dist || iter->getSource()->IsWithinDist(&i_object,i_dist)) + if (!i_dist || iter->getSource()->GetBody()->IsWithinDist(&i_object,i_dist)) { - if (!i_object.InSamePhase(iter->getSource())) + if (!i_object.InSamePhase(iter->getSource()->GetBody())) continue; - if (WorldSession* session = iter->getSource()->GetSession()) + if (WorldSession* session = iter->getSource()->GetOwner()->GetSession()) session->SendPacket(i_message); } } diff --git a/src/game/GridNotifiers.h b/src/game/GridNotifiers.h index cd7614352..d2449085f 100644 --- a/src/game/GridNotifiers.h +++ b/src/game/GridNotifiers.h @@ -38,13 +38,14 @@ namespace MaNGOS { struct MANGOS_DLL_DECL VisibleNotifier { - Player &i_player; + Camera& i_camera; UpdateData i_data; ObjectGuidSet i_clientGUIDs; std::set i_visibleNow; - explicit VisibleNotifier(Player &player) : i_player(player),i_clientGUIDs(player.m_clientGUIDs) {} + explicit VisibleNotifier(Camera &c) : i_camera(c), i_clientGUIDs(c.GetOwner()->m_clientGUIDs) {} template void Visit(GridRefManager &m); + void Visit(CameraMapType &m) {} void Notify(void); }; @@ -54,7 +55,7 @@ namespace MaNGOS explicit VisibleChangesNotifier(WorldObject &object) : i_object(object) {} template void Visit(GridRefManager &) {} - void Visit(PlayerMapType &); + void Visit(CameraMapType &); }; struct MANGOS_DLL_DECL GridUpdater @@ -82,7 +83,7 @@ namespace MaNGOS WorldPacket *i_message; bool i_toSelf; MessageDeliverer(Player &pl, WorldPacket *msg, bool to_self) : i_player(pl), i_message(msg), i_toSelf(to_self) {} - void Visit(PlayerMapType &m); + void Visit(CameraMapType &m); template void Visit(GridRefManager &) {} }; @@ -95,7 +96,7 @@ namespace MaNGOS MessageDelivererExcept(WorldObject const* obj, WorldPacket *msg, Player const* skipped) : i_phaseMask(obj->GetPhaseMask()), i_message(msg), i_skipped_receiver(skipped) {} - void Visit(PlayerMapType &m); + void Visit(CameraMapType &m); template void Visit(GridRefManager &) {} }; @@ -105,7 +106,7 @@ namespace MaNGOS WorldPacket *i_message; explicit ObjectMessageDeliverer(WorldObject& obj, WorldPacket *msg) : i_phaseMask(obj.GetPhaseMask()), i_message(msg) {} - void Visit(PlayerMapType &m); + void Visit(CameraMapType &m); template void Visit(GridRefManager &) {} }; @@ -119,7 +120,7 @@ namespace MaNGOS MessageDistDeliverer(Player &pl, WorldPacket *msg, float dist, bool to_self, bool ownTeamOnly) : i_player(pl), i_message(msg), i_toSelf(to_self), i_ownTeamOnly(ownTeamOnly), i_dist(dist) {} - void Visit(PlayerMapType &m); + void Visit(CameraMapType &m); template void Visit(GridRefManager &) {} }; @@ -129,7 +130,7 @@ namespace MaNGOS WorldPacket *i_message; float i_dist; ObjectMessageDistDeliverer(WorldObject &obj, WorldPacket *msg, float dist) : i_object(obj), i_message(msg), i_dist(dist) {} - void Visit(PlayerMapType &m); + void Visit(CameraMapType &m); template void Visit(GridRefManager &) {} }; @@ -140,6 +141,7 @@ namespace MaNGOS template void Visit(GridRefManager &m); void Visit(PlayerMapType &) {} void Visit(CorpseMapType &) {} + void Visit(CameraMapType &) {} void Visit(CreatureMapType &); }; @@ -476,22 +478,21 @@ namespace MaNGOS }; template - struct MANGOS_DLL_DECL PlayerDistWorker + struct MANGOS_DLL_DECL CameraDistWorker { WorldObject const* i_searcher; float i_dist; Do& i_do; - PlayerDistWorker(WorldObject const* searcher, float _dist, Do& _do) + CameraDistWorker(WorldObject const* searcher, float _dist, Do& _do) : i_searcher(searcher), i_dist(_dist), i_do(_do) {} - void Visit(PlayerMapType &m) + void Visit(CameraMapType &m) { - for(PlayerMapType::iterator itr=m.begin(); itr != m.end(); ++itr) - if (itr->getSource()->InSamePhase(i_searcher) && itr->getSource()->IsWithinDist(i_searcher,i_dist)) - i_do(itr->getSource()); + for(CameraMapType::iterator itr=m.begin(); itr != m.end(); ++itr) + if (itr->getSource()->GetBody()->InSamePhase(i_searcher) && itr->getSource()->GetBody()->IsWithinDist(i_searcher,i_dist)) + i_do(itr->getSource()->GetOwner()); } - template void Visit(GridRefManager &) {} }; diff --git a/src/game/GridNotifiersImpl.h b/src/game/GridNotifiersImpl.h index 192d52f5d..b1cda7ecf 100644 --- a/src/game/GridNotifiersImpl.h +++ b/src/game/GridNotifiersImpl.h @@ -31,11 +31,9 @@ template inline void MaNGOS::VisibleNotifier::Visit(GridRefManager &m) { - WorldObject const* viewPoint = i_player.GetViewPoint(); - for(typename GridRefManager::iterator iter = m.begin(); iter != m.end(); ++iter) { - i_player.UpdateVisibilityOf(viewPoint,iter->getSource(), i_data, i_visibleNow); + i_camera.UpdateVisibilityOf(iter->getSource(), i_data, i_visibleNow); i_clientGUIDs.erase(iter->getSource()->GetGUID()); } } @@ -69,7 +67,7 @@ inline void PlayerCreatureRelocationWorker(Player* pl, WorldObject const* viewPo pl->UpdateVisibilityOf(viewPoint,c); // Creature AI reaction - if (!c->hasUnitState(UNIT_STAT_FLEEING)) + if (!c->hasUnitState(UNIT_STAT_LOST_CONTROL)) { if (c->AI() && c->AI()->IsVisible(pl) && !c->IsInEvadeMode()) c->AI()->MoveInLineOfSight(pl); @@ -78,13 +76,13 @@ inline void PlayerCreatureRelocationWorker(Player* pl, WorldObject const* viewPo inline void CreatureCreatureRelocationWorker(Creature* c1, Creature* c2) { - if (!c1->hasUnitState(UNIT_STAT_FLEEING)) + if (!c1->hasUnitState(UNIT_STAT_LOST_CONTROL)) { if (c1->AI() && c1->AI()->IsVisible(c2) && !c1->IsInEvadeMode()) c1->AI()->MoveInLineOfSight(c2); } - if (!c2->hasUnitState(UNIT_STAT_FLEEING)) + if (!c2->hasUnitState(UNIT_STAT_LOST_CONTROL)) { if (c2->AI() && c2->AI()->IsVisible(c1) && !c2->IsInEvadeMode()) c2->AI()->MoveInLineOfSight(c1); @@ -96,7 +94,7 @@ inline void MaNGOS::PlayerRelocationNotifier::Visit(CreatureMapType &m) if (!i_player.isAlive() || i_player.isInFlight()) return; - WorldObject const* viewPoint = i_player.GetViewPoint(); + WorldObject const* viewPoint = i_player.GetCamera().GetBody(); for(CreatureMapType::iterator iter = m.begin(); iter != m.end(); ++iter) if (iter->getSource()->isAlive()) @@ -106,13 +104,13 @@ inline void MaNGOS::PlayerRelocationNotifier::Visit(CreatureMapType &m) template<> inline void MaNGOS::CreatureRelocationNotifier::Visit(PlayerMapType &m) { - if(!i_creature.isAlive()) + if (!i_creature.isAlive()) return; for(PlayerMapType::iterator iter=m.begin(); iter != m.end(); ++iter) if (Player* player = iter->getSource()) if (player->isAlive() && !player->isInFlight()) - PlayerCreatureRelocationWorker(player, player->GetViewPoint(), &i_creature); + PlayerCreatureRelocationWorker(player, player->GetCamera().GetBody(), &i_creature); } template<> diff --git a/src/game/Group.cpp b/src/game/Group.cpp index 7aa97e10b..e6db94f59 100644 --- a/src/game/Group.cpp +++ b/src/game/Group.cpp @@ -771,7 +771,7 @@ void Group::CountTheRoll(Rolls::iterator& rollI) if (itr->second != ROLL_NEED) continue; - uint8 randomN = urand(1, 99); + uint8 randomN = urand(1, 100); SendLootRoll(itr->first, randomN, ROLL_NEED, *roll); if (maxresul < randomN) { @@ -819,7 +819,7 @@ void Group::CountTheRoll(Rolls::iterator& rollI) if (itr->second != ROLL_GREED && itr->second != ROLL_DISENCHANT) continue; - uint8 randomN = urand(1, 99); + uint8 randomN = urand(1, 100); SendLootRoll(itr->first, randomN, itr->second, *roll); if (maxresul < randomN) { diff --git a/src/game/InstanceSaveMgr.cpp b/src/game/InstanceSaveMgr.cpp index 81ebb0106..14befab57 100644 --- a/src/game/InstanceSaveMgr.cpp +++ b/src/game/InstanceSaveMgr.cpp @@ -30,7 +30,6 @@ #include "InstanceSaveMgr.h" #include "Timer.h" #include "GridNotifiersImpl.h" -#include "Config/ConfigEnv.h" #include "Transports.h" #include "ObjectMgr.h" #include "World.h" diff --git a/src/game/Level1.cpp b/src/game/Level1.cpp index 603032f13..a19c7ed7c 100644 --- a/src/game/Level1.cpp +++ b/src/game/Level1.cpp @@ -2226,6 +2226,51 @@ bool ChatHandler::HandleGroupgoCommand(const char* args) return true; } +bool ChatHandler::HandleGoHelper( Player* player, uint32 mapid, float x, float y, float const* zPtr ) +{ + float z; + + if (zPtr) + { + z = *zPtr; + + // check full provided coordinates + if(!MapManager::IsValidMapCoord(mapid,x,y,z)) + { + PSendSysMessage(LANG_INVALID_TARGET_COORD,x,y,mapid); + SetSentErrorMessage(true); + return false; + } + } + else + { + // we need check x,y before ask Z or can crash at invalide coordinates + if(!MapManager::IsValidMapCoord(mapid,x,y)) + { + PSendSysMessage(LANG_INVALID_TARGET_COORD,x,y,mapid); + SetSentErrorMessage(true); + return false; + } + + Map const *map = sMapMgr.CreateBaseMap(mapid); + z = std::max(map->GetHeight(x, y, MAX_HEIGHT), map->GetWaterLevel(x, y)); + } + + // stop flight if need + if(player->isInFlight()) + { + player->GetMotionMaster()->MovementExpired(); + player->m_taxi.ClearTaxiDestinations(); + } + // save only in non-flight case + else + player->SaveRecallPosition(); + + player->TeleportTo(mapid, x, y, z, player->GetOrientation()); + + return true; +} + bool ChatHandler::HandleGoTaxinodeCommand(const char* args) { Player* _player = m_session->GetPlayer(); @@ -2249,28 +2294,55 @@ bool ChatHandler::HandleGoTaxinodeCommand(const char* args) return false; } - if ((node->x == 0.0f && node->y == 0.0f && node->z == 0.0f) || - !MapManager::IsValidMapCoord(node->map_id,node->x,node->y,node->z)) + if (node->x == 0.0f && node->y == 0.0f && node->z == 0.0f) { PSendSysMessage(LANG_INVALID_TARGET_COORD,node->x,node->y,node->map_id); SetSentErrorMessage(true); return false; } - // stop flight if need - if (_player->isInFlight()) - { - _player->GetMotionMaster()->MovementExpired(); - _player->m_taxi.ClearTaxiDestinations(); - } - // save only in non-flight case - else - _player->SaveRecallPosition(); - - _player->TeleportTo(node->map_id, node->x, node->y, node->z, _player->GetOrientation()); - return true; + return HandleGoHelper(_player, node->map_id, node->x, node->y, &node->z); } +bool ChatHandler::HandleGoCommand(const char* args) +{ + if(!*args) + return false; + + Player* _player = m_session->GetPlayer(); + + uint32 mapid; + float x, y, z; + + // raw coordinates case + if (isNumeric(args[0])) + { + char* px = strtok((char*)args, " "); + char* py = strtok(NULL, " "); + char* pz = strtok(NULL, " "); + char* pmapid = strtok(NULL, " "); + + if (!px || !py || !pz) + return false; + + x = (float)atof(px); + y = (float)atof(py); + z = (float)atof(pz); + if (pmapid) + mapid = (uint32)atoi(pmapid); + else + mapid = _player->GetMapId(); + + } + // link case + else if (!extractLocationFromLink((char*)args, mapid, x, y, z)) + return false; + + return HandleGoHelper(_player, mapid, x, y, &z); +} + + + //teleport at coordinates bool ChatHandler::HandleGoXYCommand(const char* args) { @@ -2293,29 +2365,7 @@ bool ChatHandler::HandleGoXYCommand(const char* args) mapid = (uint32)atoi(pmapid); else mapid = _player->GetMapId(); - if(!MapManager::IsValidMapCoord(mapid,x,y)) - { - PSendSysMessage(LANG_INVALID_TARGET_COORD,x,y,mapid); - SetSentErrorMessage(true); - return false; - } - - // stop flight if need - if(_player->isInFlight()) - { - _player->GetMotionMaster()->MovementExpired(); - _player->m_taxi.ClearTaxiDestinations(); - } - // save only in non-flight case - else - _player->SaveRecallPosition(); - - Map const *map = sMapMgr.CreateBaseMap(mapid); - float z = std::max(map->GetHeight(x, y, MAX_HEIGHT), map->GetWaterLevel(x, y)); - - _player->TeleportTo(mapid, x, y, z, _player->GetOrientation()); - - return true; + return HandleGoHelper(_player, mapid, x, y); } //teleport at coordinates, including Z @@ -2343,26 +2393,7 @@ bool ChatHandler::HandleGoXYZCommand(const char* args) else mapid = _player->GetMapId(); - if(!MapManager::IsValidMapCoord(mapid,x,y,z)) - { - PSendSysMessage(LANG_INVALID_TARGET_COORD,x,y,mapid); - SetSentErrorMessage(true); - return false; - } - - // stop flight if need - if(_player->isInFlight()) - { - _player->GetMotionMaster()->MovementExpired(); - _player->m_taxi.ClearTaxiDestinations(); - } - // save only in non-flight case - else - _player->SaveRecallPosition(); - - _player->TeleportTo(mapid, x, y, z, _player->GetOrientation()); - - return true; + return HandleGoHelper(_player, mapid, x, y, &z); } //teleport at coordinates @@ -2403,49 +2434,33 @@ bool ChatHandler::HandleGoZoneXYCommand(const char* args) // update to parent zone if exist (client map show only zones without parents) AreaTableEntry const* zoneEntry = areaEntry->zone ? GetAreaEntryByAreaID(areaEntry->zone) : areaEntry; - Map const *map = sMapMgr.CreateBaseMap(zoneEntry->mapid); + MapEntry const *mapEntry = sMapStore.LookupEntry(zoneEntry->mapid); - if(map->Instanceable()) + if (mapEntry->Instanceable()) { - PSendSysMessage(LANG_INVALID_ZONE_MAP,areaEntry->ID,areaEntry->area_name[GetSessionDbcLocale()],map->GetId(),map->GetMapName()); + PSendSysMessage(LANG_INVALID_ZONE_MAP, areaEntry->ID, areaEntry->area_name[GetSessionDbcLocale()], + mapEntry->MapID, mapEntry->name[GetSessionDbcLocale()]); SetSentErrorMessage(true); return false; } if (!Zone2MapCoordinates(x,y,zoneEntry->ID)) { - PSendSysMessage(LANG_INVALID_ZONE_MAP,areaEntry->ID,areaEntry->area_name[GetSessionDbcLocale()],map->GetId(),map->GetMapName()); + PSendSysMessage(LANG_INVALID_ZONE_MAP, areaEntry->ID, areaEntry->area_name[GetSessionDbcLocale()], + mapEntry->MapID, mapEntry->name[GetSessionDbcLocale()]); SetSentErrorMessage(true); return false; } - if(!MapManager::IsValidMapCoord(zoneEntry->mapid,x,y)) - { - PSendSysMessage(LANG_INVALID_TARGET_COORD,x,y,zoneEntry->mapid); - SetSentErrorMessage(true); - return false; - } - - // stop flight if need - if(_player->isInFlight()) - { - _player->GetMotionMaster()->MovementExpired(); - _player->m_taxi.ClearTaxiDestinations(); - } - // save only in non-flight case - else - _player->SaveRecallPosition(); - - float z = std::max(map->GetHeight(x, y, MAX_HEIGHT), map->GetWaterLevel(x, y)); - _player->TeleportTo(zoneEntry->mapid, x, y, z, _player->GetOrientation()); - - return true; + return HandleGoHelper(_player, mapEntry->MapID, x, y); } //teleport to grid bool ChatHandler::HandleGoGridCommand(const char* args) { - if(!*args) return false; + if (!*args) + return false; + Player* _player = m_session->GetPlayer(); char* px = strtok((char*)args, " "); @@ -2457,37 +2472,13 @@ bool ChatHandler::HandleGoGridCommand(const char* args) float grid_x = (float)atof(px); float grid_y = (float)atof(py); - uint32 mapid; - if (pmapid) - mapid = (uint32)atoi(pmapid); - else mapid = _player->GetMapId(); + uint32 mapid = pmapid ? (uint32)atoi(pmapid) : _player->GetMapId(); // center of grid float x = (grid_x-CENTER_GRID_ID+0.5f)*SIZE_OF_GRIDS; float y = (grid_y-CENTER_GRID_ID+0.5f)*SIZE_OF_GRIDS; - if(!MapManager::IsValidMapCoord(mapid,x,y)) - { - PSendSysMessage(LANG_INVALID_TARGET_COORD,x,y,mapid); - SetSentErrorMessage(true); - return false; - } - - // stop flight if need - if(_player->isInFlight()) - { - _player->GetMotionMaster()->MovementExpired(); - _player->m_taxi.ClearTaxiDestinations(); - } - // save only in non-flight case - else - _player->SaveRecallPosition(); - - Map const *map = sMapMgr.CreateBaseMap(mapid); - float z = std::max(map->GetHeight(x, y, MAX_HEIGHT), map->GetWaterLevel(x, y)); - _player->TeleportTo(mapid, x, y, z, _player->GetOrientation()); - - return true; + return HandleGoHelper(_player, mapid, x, y); } bool ChatHandler::HandleModifyDrunkCommand(const char* args) diff --git a/src/game/Level3.cpp b/src/game/Level3.cpp index 6ed7809e3..e6abfb8b2 100644 --- a/src/game/Level3.cpp +++ b/src/game/Level3.cpp @@ -43,7 +43,7 @@ #include "SkillDiscovery.h" #include "SkillExtraItems.h" #include "SystemConfig.h" -#include "Config/ConfigEnv.h" +#include "Config/Config.h" #include "Mail.h" #include "Util.h" #include "ItemEnchantmentMgr.h" @@ -2832,7 +2832,7 @@ void ChatHandler::ShowSpellListHelper(Player* target, SpellEntry const* spellInf uint32 talentCost = GetTalentSpellCost(id); bool talent = (talentCost > 0); - bool passive = IsPassiveSpell(id); + bool passive = IsPassiveSpell(spellInfo); bool active = target && target->HasAura(id); // unit32 used to prevent interpreting uint8 as char at output diff --git a/src/game/Makefile.am b/src/game/Makefile.am index f4ef7892f..575b4c04b 100644 --- a/src/game/Makefile.am +++ b/src/game/Makefile.am @@ -76,6 +76,8 @@ libmangosgame_a_SOURCES = \ Calendar.cpp \ Calendar.h \ CalendarHandler.cpp \ + Camera.cpp \ + Camera.h \ Cell.h \ CellImpl.h \ Channel.cpp \ diff --git a/src/game/Map.cpp b/src/game/Map.cpp index bca4cca36..57f09ce13 100644 --- a/src/game/Map.cpp +++ b/src/game/Map.cpp @@ -26,7 +26,6 @@ #include "InstanceData.h" #include "Map.h" #include "GridNotifiersImpl.h" -#include "Config/ConfigEnv.h" #include "Transports.h" #include "ObjectAccessor.h" #include "ObjectMgr.h" @@ -367,8 +366,9 @@ bool Map::Add(Player *player) SendInitSelf(player); SendInitTransports(player); + NGridType* grid = getNGrid(cell.GridX(), cell.GridY()); + player->GetViewPoint().Event_AddedToWorld(&(*grid)(cell.CellX(), cell.CellY())); UpdateObjectVisibility(player,cell,p); - UpdateObjectsVisibilityFor(player,cell,p); AddNotifier(player,cell,p); return true; @@ -406,6 +406,7 @@ Map::Add(T *obj) DEBUG_LOG("Object %u enters grid[%u,%u]", GUID_LOPART(obj->GetGUID()), cell.GridX(), cell.GridY()); + obj->GetViewPoint().Event_AddedToWorld(&(*grid)(cell.CellX(), cell.CellY())); UpdateObjectVisibility(obj,cell,p); AddNotifier(obj,cell,p); @@ -682,7 +683,6 @@ void Map::Remove(Player *player, bool remove) SendRemoveTransports(player); UpdateObjectVisibility(player,cell,p); - UpdateObjectsVisibilityFor(player,cell,p); player->ResetMap(); if( remove ) @@ -716,10 +716,9 @@ Map::Remove(T *obj, bool remove) else obj->RemoveFromWorld(); + UpdateObjectVisibility(obj,cell,p); // i think will be better to call this function while object still in grid, this changes nothing but logically is better(as for me) RemoveFromGrid(obj,grid,cell); - UpdateObjectVisibility(obj,cell,p); - obj->ResetMap(); if( remove ) { @@ -759,10 +758,13 @@ Map::PlayerRelocation(Player *player, float x, float y, float z, float orientati AddToGrid(player, oldGrid,new_cell); else EnsureGridLoadedAtEnter(new_cell, player); + + NGridType* newGrid = getNGrid(new_cell.GridX(), new_cell.GridY()); + player->GetViewPoint().Event_GridChanged(&(*newGrid)(new_cell.CellX(),new_cell.CellY())); } + player->GetViewPoint().Call_UpdateVisibilityForOwner(); // if move then update what player see and who seen - UpdateObjectsVisibilityFor(player,new_cell,new_val); UpdateObjectVisibility(player, new_cell, new_val); PlayerRelocationNotify(player,new_cell,new_val); @@ -816,6 +818,7 @@ Map::CreatureRelocation(Creature *creature, float x, float y, float z, float ang creature->SetNeedNotify(); } + creature->GetViewPoint().Call_UpdateVisibilityForOwner(); ASSERT(CheckGridIntegrity(creature,true)); } @@ -829,12 +832,12 @@ bool Map::CreatureCellRelocation(Creature *c, Cell new_cell) { DEBUG_FILTER_LOG(LOG_FILTER_CREATURE_MOVES, "Creature (GUID: %u Entry: %u) moved in grid[%u,%u] from cell[%u,%u] to cell[%u,%u].", c->GetGUIDLow(), c->GetEntry(), old_cell.GridX(), old_cell.GridY(), old_cell.CellX(), old_cell.CellY(), new_cell.CellX(), new_cell.CellY()); - if( !old_cell.DiffGrid(new_cell) ) - { - RemoveFromGrid(c,getNGrid(old_cell.GridX(), old_cell.GridY()),old_cell); - AddToGrid(c,getNGrid(new_cell.GridX(), new_cell.GridY()),new_cell); - c->SetCurrentCell(new_cell); - } + RemoveFromGrid(c,getNGrid(old_cell.GridX(), old_cell.GridY()),old_cell); + + NGridType* new_grid = getNGrid(new_cell.GridX(), new_cell.GridY()); + AddToGrid(c,new_grid,new_cell); + + c->GetViewPoint().Event_GridChanged( &(*new_grid)(new_cell.CellX(),new_cell.CellY()) ); } else { @@ -852,7 +855,10 @@ bool Map::CreatureCellRelocation(Creature *c, Cell new_cell) DEBUG_FILTER_LOG(LOG_FILTER_CREATURE_MOVES, "Active creature (GUID: %u Entry: %u) moved from grid[%u,%u]cell[%u,%u] to grid[%u,%u]cell[%u,%u].", c->GetGUIDLow(), c->GetEntry(), old_cell.GridX(), old_cell.GridY(), old_cell.CellX(), old_cell.CellY(), new_cell.GridX(), new_cell.GridY(), new_cell.CellX(), new_cell.CellY()); RemoveFromGrid(c,getNGrid(old_cell.GridX(), old_cell.GridY()),old_cell); - AddToGrid(c,getNGrid(new_cell.GridX(), new_cell.GridY()),new_cell); + + NGridType* new_grid = getNGrid(new_cell.GridX(), new_cell.GridY()); + AddToGrid(c,new_grid,new_cell); + c->GetViewPoint().Event_GridChanged( &(*new_grid)(new_cell.CellX(),new_cell.CellY()) ); return true; } @@ -865,7 +871,9 @@ bool Map::CreatureCellRelocation(Creature *c, Cell new_cell) RemoveFromGrid(c,getNGrid(old_cell.GridX(), old_cell.GridY()),old_cell); { EnsureGridCreated(GridPair(new_cell.GridX(), new_cell.GridY())); - AddToGrid(c,getNGrid(new_cell.GridX(), new_cell.GridY()),new_cell); + NGridType* new_grid = getNGrid(new_cell.GridX(), new_cell.GridY()); + AddToGrid(c,new_grid,new_cell); + c->GetViewPoint().Event_GridChanged( &(*new_grid)(new_cell.CellX(),new_cell.CellY()) ); } return true; @@ -1420,21 +1428,6 @@ void Map::UpdateObjectVisibility( WorldObject* obj, Cell cell, CellPair cellpair cell.Visit(cellpair, player_notifier, *this, *obj, GetVisibilityDistance()); } -void Map::UpdateObjectsVisibilityFor( Player* player, Cell cell, CellPair cellpair ) -{ - MaNGOS::VisibleNotifier notifier(*player); - - cell.data.Part.reserved = ALL_DISTRICT; - //cell.SetNoCreate(); need trigger cell loading around the player - TypeContainerVisitor world_notifier(notifier); - TypeContainerVisitor grid_notifier(notifier); - cell.Visit(cellpair, world_notifier, *this, *player, GetVisibilityDistance()); - cell.Visit(cellpair, grid_notifier, *this, *player, GetVisibilityDistance()); - - // send data - notifier.Notify(); -} - void Map::PlayerRelocationNotify( Player* player, Cell cell, CellPair cellpair ) { MaNGOS::PlayerRelocationNotifier relocationNotifier(*player); @@ -1646,44 +1639,63 @@ bool Map::ActiveObjectsNearGrid(uint32 x, uint32 y) const return false; } -void Map::AddToActive( Creature* c ) +void Map::AddToActive( WorldObject* obj ) { - AddToActiveHelper(c); + m_activeNonPlayers.insert(obj); // also not allow unloading spawn grid to prevent creating creature clone at load - if(!c->isPet() && c->GetDBTableGUIDLow()) + if (obj->GetTypeId()==TYPEID_UNIT) { - float x,y,z; - c->GetRespawnCoord(x,y,z); - GridPair p = MaNGOS::ComputeGridPair(x, y); - if(getNGrid(p.x_coord, p.y_coord)) - getNGrid(p.x_coord, p.y_coord)->incUnloadActiveLock(); - else + Creature* c= (Creature*)obj; + + if (!c->isPet() && c->GetDBTableGUIDLow()) { - GridPair p2 = MaNGOS::ComputeGridPair(c->GetPositionX(), c->GetPositionY()); - sLog.outError("Active creature (GUID: %u Entry: %u) added to grid[%u,%u] but spawn grid[%u,%u] not loaded.", - c->GetGUIDLow(), c->GetEntry(), p.x_coord, p.y_coord, p2.x_coord, p2.y_coord); + float x,y,z; + c->GetRespawnCoord(x,y,z); + GridPair p = MaNGOS::ComputeGridPair(x, y); + if(getNGrid(p.x_coord, p.y_coord)) + getNGrid(p.x_coord, p.y_coord)->incUnloadActiveLock(); + else + { + GridPair p2 = MaNGOS::ComputeGridPair(c->GetPositionX(), c->GetPositionY()); + sLog.outError("Active creature (GUID: %u Entry: %u) added to grid[%u,%u] but spawn grid[%u,%u] not loaded.", + c->GetGUIDLow(), c->GetEntry(), p.x_coord, p.y_coord, p2.x_coord, p2.y_coord); + } } } } -void Map::RemoveFromActive( Creature* c ) +void Map::RemoveFromActive( WorldObject* obj ) { - RemoveFromActiveHelper(c); + // Map::Update for active object in proccess + if(m_activeNonPlayersIter != m_activeNonPlayers.end()) + { + ActiveNonPlayers::iterator itr = m_activeNonPlayers.find(obj); + if(itr==m_activeNonPlayersIter) + ++m_activeNonPlayersIter; + m_activeNonPlayers.erase(itr); + } + else + m_activeNonPlayers.erase(obj); // also allow unloading spawn grid - if(!c->isPet() && c->GetDBTableGUIDLow()) + if (obj->GetTypeId()==TYPEID_UNIT) { - float x,y,z; - c->GetRespawnCoord(x,y,z); - GridPair p = MaNGOS::ComputeGridPair(x, y); - if(getNGrid(p.x_coord, p.y_coord)) - getNGrid(p.x_coord, p.y_coord)->decUnloadActiveLock(); - else + Creature* c= (Creature*)obj; + + if(!c->isPet() && c->GetDBTableGUIDLow()) { - GridPair p2 = MaNGOS::ComputeGridPair(c->GetPositionX(), c->GetPositionY()); - sLog.outError("Active creature (GUID: %u Entry: %u) removed from grid[%u,%u] but spawn grid[%u,%u] not loaded.", - c->GetGUIDLow(), c->GetEntry(), p.x_coord, p.y_coord, p2.x_coord, p2.y_coord); + float x,y,z; + c->GetRespawnCoord(x,y,z); + GridPair p = MaNGOS::ComputeGridPair(x, y); + if(getNGrid(p.x_coord, p.y_coord)) + getNGrid(p.x_coord, p.y_coord)->decUnloadActiveLock(); + else + { + GridPair p2 = MaNGOS::ComputeGridPair(c->GetPositionX(), c->GetPositionY()); + sLog.outError("Active creature (GUID: %u Entry: %u) removed from grid[%u,%u] but spawn grid[%u,%u] not loaded.", + c->GetGUIDLow(), c->GetEntry(), p.x_coord, p.y_coord, p2.x_coord, p2.y_coord); + } } } } diff --git a/src/game/Map.h b/src/game/Map.h index 5193d2c7b..1a2efe97a 100644 --- a/src/game/Map.h +++ b/src/game/Map.h @@ -84,6 +84,8 @@ enum LevelRequirementVsMode class MANGOS_DLL_SPEC Map : public GridRefManager, public MaNGOS::ObjectLevelLockable { friend class MapReference; + friend class ObjectGridLoader; + friend class ObjectWorldLoader; public: Map(uint32 id, time_t, uint32 InstanceId, uint8 SpawnMode, Map* _parent = NULL); virtual ~Map(); @@ -211,7 +213,6 @@ class MANGOS_DLL_SPEC Map : public GridRefManager, public MaNGOS::Obj void AddObjectToRemoveList(WorldObject *obj); void UpdateObjectVisibility(WorldObject* obj, Cell cell, CellPair cellpair); - void UpdateObjectsVisibilityFor(Player* player, Cell cell, CellPair cellpair); void resetMarkedCells() { marked_cells.reset(); } bool isCellMarked(uint32 pCellId) { return marked_cells.test(pCellId); } @@ -231,16 +232,9 @@ class MANGOS_DLL_SPEC Map : public GridRefManager, public MaNGOS::Obj void ScriptCommandStart(ScriptInfo const& script, uint32 delay, Object* source, Object* target); // must called with AddToWorld - template - void AddToActive(T* obj) { AddToActiveHelper(obj); } - - void AddToActive(Creature* obj); - + void AddToActive(WorldObject* obj); // must called with RemoveFromWorld - template - void RemoveFromActive(T* obj) { RemoveFromActiveHelper(obj); } - - void RemoveFromActive(Creature* obj); + void RemoveFromActive(WorldObject* obj); Creature* GetCreature(ObjectGuid guid); Vehicle* GetVehicle(ObjectGuid guid); @@ -357,27 +351,6 @@ class MANGOS_DLL_SPEC Map : public GridRefManager, public MaNGOS::Obj template void DeleteFromWorld(T*); - - template - void AddToActiveHelper(T* obj) - { - m_activeNonPlayers.insert(obj); - } - - template - void RemoveFromActiveHelper(T* obj) - { - // Map::Update for active object in proccess - if(m_activeNonPlayersIter != m_activeNonPlayers.end()) - { - ActiveNonPlayers::iterator itr = m_activeNonPlayers.find(obj); - if(itr==m_activeNonPlayersIter) - ++m_activeNonPlayersIter; - m_activeNonPlayers.erase(itr); - } - else - m_activeNonPlayers.erase(obj); - } }; enum InstanceResetMethod diff --git a/src/game/MiscHandler.cpp b/src/game/MiscHandler.cpp index 8a1738796..ff1a71224 100644 --- a/src/game/MiscHandler.cpp +++ b/src/game/MiscHandler.cpp @@ -1293,10 +1293,10 @@ void WorldSession::HandleFarSightOpcode( WorldPacket & recv_data ) //WorldPacket data(SMSG_CLEAR_FAR_SIGHT_IMMEDIATE, 0) //SendPacket(&data); //_player->SetUInt64Value(PLAYER_FARSIGHT, 0); - DEBUG_LOG("Removed FarSight from player %u", _player->GetGUIDLow()); + DEBUG_LOG("Removed FarSight from %s", _player->GetObjectGuid().GetString().c_str()); break; case 1: - DEBUG_LOG("Added FarSight (GUID:%u TypeId:%u) to player %u", GUID_LOPART(_player->GetFarSight()), GuidHigh2TypeId(GUID_HIPART(_player->GetFarSight())), _player->GetGUIDLow()); + DEBUG_LOG("Added FarSight %s to %s", _player->GetFarSightGuid().GetString().c_str(), _player->GetObjectGuid().GetString().c_str()); break; } } diff --git a/src/game/MotionMaster.cpp b/src/game/MotionMaster.cpp index c43ce0f4f..58e242564 100644 --- a/src/game/MotionMaster.cpp +++ b/src/game/MotionMaster.cpp @@ -40,11 +40,15 @@ inline bool isStatic(MovementGenerator *mv) void MotionMaster::Initialize() { + // stop current move + if (!i_owner->IsStopped()) + i_owner->StopMoving(); + // clear ALL movement generators (including default) Clear(false,true); // set new default movement generator - if (i_owner->GetTypeId() == TYPEID_UNIT) + if (i_owner->GetTypeId() == TYPEID_UNIT && !i_owner->hasUnitState(UNIT_STAT_CONTROLLED)) { MovementGenerator* movement = FactorySelector::selectMovementGenerator((Creature*)i_owner); push(movement == NULL ? &si_idleMovement : movement); @@ -226,7 +230,7 @@ void MotionMaster::MoveRandom() void MotionMaster::MoveTargetedHome() { - if(i_owner->hasUnitState(UNIT_STAT_FLEEING)) + if(i_owner->hasUnitState(UNIT_STAT_LOST_CONTROL)) return; Clear(false); @@ -281,6 +285,9 @@ MotionMaster::MoveChase(Unit* target, float dist, float angle) void MotionMaster::MoveFollow(Unit* target, float dist, float angle) { + if(i_owner->hasUnitState(UNIT_STAT_LOST_CONTROL)) + return; + Clear(); // ignore movement request if target not exist diff --git a/src/game/MovementHandler.cpp b/src/game/MovementHandler.cpp index b4601e9b5..9c9377673 100644 --- a/src/game/MovementHandler.cpp +++ b/src/game/MovementHandler.cpp @@ -181,7 +181,7 @@ void WorldSession::HandleMoveTeleportAck(WorldPacket& recv_data) DEBUG_LOG("Guid: %s", guid.GetString().c_str()); DEBUG_LOG("Flags %u, time %u", flags, time/IN_MILLISECONDS); - Unit *mover = _player->m_mover; + Unit *mover = _player->GetMover(); Player *plMover = mover->GetTypeId() == TYPEID_PLAYER ? (Player*)mover : NULL; if(!plMover || !plMover->IsBeingTeleportedNear()) @@ -223,7 +223,7 @@ void WorldSession::HandleMovementOpcodes( WorldPacket & recv_data ) DEBUG_LOG("WORLD: Recvd %s (%u, 0x%X) opcode", LookupOpcodeName(opcode), opcode, opcode); recv_data.hexlike(); - Unit *mover = _player->m_mover; + Unit *mover = _player->GetMover(); Player *plMover = mover->GetTypeId() == TYPEID_PLAYER ? (Player*)mover : NULL; // ignore, waiting processing in WorldSession::HandleMoveWorldportAckOpcode and WorldSession::HandleMoveTeleportAck @@ -335,7 +335,7 @@ void WorldSession::HandleMovementOpcodes( WorldPacket & recv_data ) // TODO: discard movement packets after the player is rooted if(plMover->isAlive()) { - plMover->EnvironmentalDamage(DAMAGE_FALL_TO_VOID, GetPlayer()->GetMaxHealth()); + plMover->EnvironmentalDamage(DAMAGE_FALL_TO_VOID, plMover->GetMaxHealth()); // pl can be alive if GM/etc if(!plMover->isAlive()) { @@ -434,12 +434,13 @@ void WorldSession::HandleSetActiveMoverOpcode(WorldPacket &recv_data) DEBUG_LOG("WORLD: Recvd CMSG_SET_ACTIVE_MOVER"); recv_data.hexlike(); - uint64 guid; + ObjectGuid guid; recv_data >> guid; - if(_player->m_mover->GetGUID() != guid) + if(_player->GetMover()->GetObjectGuid() != guid) { - sLog.outError("HandleSetActiveMoverOpcode: incorrect mover guid: mover is " I64FMT " and should be " I64FMT, _player->m_mover->GetGUID(), guid); + sLog.outError("HandleSetActiveMoverOpcode: incorrect mover guid: mover is %s and should be %s", + _player->GetMover()->GetObjectGuid().GetString().c_str(), guid.GetString().c_str()); return; } } @@ -455,9 +456,12 @@ void WorldSession::HandleMoveNotActiveMover(WorldPacket &recv_data) recv_data >> old_mover_guid.ReadAsPacked(); recv_data >> mi; - if(_player->m_mover->GetObjectGuid() == old_mover_guid) + if(_player->GetMover()->GetObjectGuid() == old_mover_guid) { - sLog.outError("HandleMoveNotActiveMover: incorrect mover guid: mover is " I64FMT " and should be " I64FMT " instead of " UI64FMTD, _player->m_mover->GetGUID(), _player->GetGUID(), old_mover_guid.GetRawValue()); + sLog.outError("HandleMoveNotActiveMover: incorrect mover guid: mover is %s and should be %s instead of %s", + _player->GetMover()->GetObjectGuid().GetString().c_str(), + _player->GetObjectGuid().GetString().c_str(), + old_mover_guid.GetString().c_str()); recv_data.rpos(recv_data.wpos()); // prevent warnings spam return; } diff --git a/src/game/NPCHandler.cpp b/src/game/NPCHandler.cpp index 95a869d88..749b5161b 100644 --- a/src/game/NPCHandler.cpp +++ b/src/game/NPCHandler.cpp @@ -397,11 +397,17 @@ void WorldSession::SendSpiritResurrect() _player->TeleportTo(corpseGrave->map_id, corpseGrave->x, corpseGrave->y, corpseGrave->z, _player->GetOrientation()); // or update at original position else - _player->UpdateVisibilityForPlayer(); + { + _player->GetCamera().UpdateVisibilityForOwner(); + _player->UpdateObjectVisibility(); + } } // or update at original position else - _player->UpdateVisibilityForPlayer(); + { + _player->GetCamera().UpdateVisibilityForOwner(); + _player->UpdateObjectVisibility(); + } } void WorldSession::HandleBinderActivateOpcode( WorldPacket & recv_data ) diff --git a/src/game/Object.cpp b/src/game/Object.cpp index 55fc2d08a..5a6492a80 100644 --- a/src/game/Object.cpp +++ b/src/game/Object.cpp @@ -1084,7 +1084,7 @@ void Object::BuildUpdateData( UpdateDataMapType& /*update_players */) } WorldObject::WorldObject() - : m_currMap(NULL), m_mapId(0), m_InstanceId(0), m_phaseMask(PHASEMASK_NORMAL), + : m_isActiveObject(false), m_currMap(NULL), m_mapId(0), m_InstanceId(0), m_phaseMask(PHASEMASK_NORMAL), m_positionX(0.0f), m_positionY(0.0f), m_positionZ(0.0f), m_orientation(0.0f) { } @@ -1496,7 +1496,7 @@ void WorldObject::MonsterSay(int32 textId, uint32 language, uint64 TargetGuid) { MaNGOS::MonsterChatBuilder say_build(*this, CHAT_MSG_MONSTER_SAY, textId,language,TargetGuid); MaNGOS::LocalizedPacketDo say_do(say_build); - MaNGOS::PlayerDistWorker > say_worker(this,sWorld.getConfig(CONFIG_FLOAT_LISTEN_RANGE_SAY),say_do); + MaNGOS::CameraDistWorker > say_worker(this,sWorld.getConfig(CONFIG_FLOAT_LISTEN_RANGE_SAY),say_do); Cell::VisitWorldObjects(this, say_worker, sWorld.getConfig(CONFIG_FLOAT_LISTEN_RANGE_SAY)); } @@ -1507,7 +1507,7 @@ void WorldObject::MonsterYell(int32 textId, uint32 language, uint64 TargetGuid) MaNGOS::MonsterChatBuilder say_build(*this, CHAT_MSG_MONSTER_YELL, textId,language,TargetGuid); MaNGOS::LocalizedPacketDo say_do(say_build); - MaNGOS::PlayerDistWorker > say_worker(this,range,say_do); + MaNGOS::CameraDistWorker > say_worker(this,range,say_do); Cell::VisitWorldObjects(this, say_worker, sWorld.getConfig(CONFIG_FLOAT_LISTEN_RANGE_YELL)); } @@ -1530,7 +1530,7 @@ void WorldObject::MonsterTextEmote(int32 textId, uint64 TargetGuid, bool IsBossE MaNGOS::MonsterChatBuilder say_build(*this, IsBossEmote ? CHAT_MSG_RAID_BOSS_EMOTE : CHAT_MSG_MONSTER_EMOTE, textId,LANG_UNIVERSAL,TargetGuid); MaNGOS::LocalizedPacketDo say_do(say_build); - MaNGOS::PlayerDistWorker > say_worker(this,range,say_do); + MaNGOS::CameraDistWorker > say_worker(this,range,say_do); Cell::VisitWorldObjects(this, say_worker, range); } @@ -1864,7 +1864,10 @@ void WorldObject::SetPhaseMask(uint32 newPhaseMask, bool update) m_phaseMask = newPhaseMask; if(update && IsInWorld()) + { UpdateObjectVisibility(); + GetViewPoint().Event_ViewPointVisibilityChanged(); + } } void WorldObject::PlayDistanceSound( uint32 sound_id, Player* target /*= NULL*/ ) @@ -1910,12 +1913,22 @@ struct WorldObjectChangeAccumulator { UpdateDataMapType &i_updateDatas; WorldObject &i_object; - WorldObjectChangeAccumulator(WorldObject &obj, UpdateDataMapType &d) : i_updateDatas(d), i_object(obj) {} - void Visit(PlayerMapType &m) + WorldObjectChangeAccumulator(WorldObject &obj, UpdateDataMapType &d) : i_updateDatas(d), i_object(obj) { - for(PlayerMapType::iterator iter = m.begin(); iter != m.end(); ++iter) - if(iter->getSource()->HaveAtClient(&i_object)) - i_object.BuildUpdateDataForPlayer(iter->getSource(), i_updateDatas); + // send self fields changes in another way, otherwise + // with new camera system when player's camera too far from player, camera wouldn't receive packets and changes from player + if(i_object.isType(TYPEMASK_PLAYER)) + i_object.BuildUpdateDataForPlayer((Player*)&i_object, i_updateDatas); + } + + void Visit(CameraMapType &m) + { + for(CameraMapType::iterator iter = m.begin(); iter != m.end(); ++iter) + { + Player* owner = iter->getSource()->GetOwner(); + if(owner != &i_object && owner->HaveAtClient(&i_object)) + i_object.BuildUpdateDataForPlayer(owner, i_updateDatas); + } } template void Visit(GridRefManager &) {} diff --git a/src/game/Object.h b/src/game/Object.h index 04c31f0f5..5ae719791 100644 --- a/src/game/Object.h +++ b/src/game/Object.h @@ -23,8 +23,8 @@ #include "ByteBuffer.h" #include "UpdateFields.h" #include "UpdateData.h" -#include "GameSystem/GridReference.h" #include "ObjectGuid.h" +#include "Camera.h" #include #include @@ -108,11 +108,11 @@ class MANGOS_DLL_SPEC Object m_inWorld = false; } - ObjectGuid const& GetObjectGuid() const { return *reinterpret_cast(&GetUInt64Value(0)); } - - const uint64& GetGUID() const { return GetUInt64Value(0); } - uint32 GetGUIDLow() const { return GUID_LOPART(GetUInt64Value(0)); } + ObjectGuid const& GetObjectGuid() const { return GetGuidValue(OBJECT_FIELD_GUID); } + const uint64& GetGUID() const { return GetUInt64Value(OBJECT_FIELD_GUID); } + uint32 GetGUIDLow() const { return GUID_LOPART(GetUInt64Value(OBJECT_FIELD_GUID)); } PackedGuid const& GetPackGUID() const { return m_PackGUID; } + uint32 GetEntry() const { return GetUInt32Value(OBJECT_FIELD_ENTRY); } void SetEntry(uint32 entry) { SetUInt32Value(OBJECT_FIELD_ENTRY, entry); } @@ -171,6 +171,8 @@ class MANGOS_DLL_SPEC Object return *(((uint16*)&m_uint32Values[ index ])+offset); } + ObjectGuid const& GetGuidValue( uint16 index ) const { return *reinterpret_cast(&GetUInt64Value(index)); } + void SetInt32Value( uint16 index, int32 value ); void SetUInt32Value( uint16 index, uint32 value ); void SetUInt64Value( uint16 index, const uint64 &value ); @@ -178,6 +180,7 @@ class MANGOS_DLL_SPEC Object void SetByteValue( uint16 index, uint8 offset, uint8 value ); void SetUInt16Value( uint16 index, uint8 offset, uint16 value ); void SetInt16Value( uint16 index, uint8 offset, int16 value ) { SetUInt16Value(index,offset,(uint16)value); } + void SetGuidValue( uint16 index, ObjectGuid const& value ) { SetUInt64Value(index, value.GetRawValue()); } void SetStatFloatValue( uint16 index, float value); void SetStatInt32Value( uint16 index, int32 value); @@ -476,6 +479,10 @@ class MANGOS_DLL_SPEC WorldObject : public Object void BuildUpdateData(UpdateDataMapType &); Creature* SummonCreature(uint32 id, float x, float y, float z, float ang,TempSummonType spwtype,uint32 despwtime); + + bool isActiveObject() const { return m_isActiveObject || m_viewPoint.hasViewers(); } + + ViewPoint& GetViewPoint() { return m_viewPoint; } protected: explicit WorldObject(); @@ -487,6 +494,7 @@ class MANGOS_DLL_SPEC WorldObject : public Object std::string m_name; + bool m_isActiveObject; private: Map * m_currMap; //current object's Map location @@ -498,6 +506,8 @@ class MANGOS_DLL_SPEC WorldObject : public Object float m_positionY; float m_positionZ; float m_orientation; + + ViewPoint m_viewPoint; }; #endif diff --git a/src/game/ObjectGridLoader.cpp b/src/game/ObjectGridLoader.cpp index 415c7ac6f..8df5d4632 100644 --- a/src/game/ObjectGridLoader.cpp +++ b/src/game/ObjectGridLoader.cpp @@ -25,6 +25,7 @@ #include "Corpse.h" #include "World.h" #include "CellImpl.h" +#include "GridDefines.h" class MANGOS_DLL_DECL ObjectGridRespawnMover { @@ -105,7 +106,7 @@ template<> void addUnitState(Creature *obj, CellPair const& cell_pair) } template -void LoadHelper(CellGuidSet const& guid_set, CellPair &cell, GridRefManager &m, uint32 &count, Map* map) +void LoadHelper(CellGuidSet const& guid_set, CellPair &cell, GridRefManager &m, uint32 &count, Map* map, GridType& grid) { BattleGround* bg = map->IsBattleGroundOrArena() ? ((BattleGroundMap*)map)->GetBG() : NULL; @@ -121,13 +122,16 @@ void LoadHelper(CellGuidSet const& guid_set, CellPair &cell, GridRefManager & continue; } - obj->GetGridRef().link(&m, obj); + grid.AddGridObject(obj); addUnitState(obj,cell); obj->SetMap(map); obj->AddToWorld(); if(obj->isActiveObject()) map->AddToActive(obj); + + obj->GetViewPoint().Event_AddedToWorld(&grid); + if (bg) bg->OnObjectDBLoad(obj); @@ -135,7 +139,7 @@ void LoadHelper(CellGuidSet const& guid_set, CellPair &cell, GridRefManager & } } -void LoadHelper(CellCorpseSet const& cell_corpses, CellPair &cell, CorpseMapType &m, uint32 &count, Map* map) +void LoadHelper(CellCorpseSet const& cell_corpses, CellPair &cell, CorpseMapType &m, uint32 &count, Map* map, GridType& grid) { if(cell_corpses.empty()) return; @@ -151,7 +155,7 @@ void LoadHelper(CellCorpseSet const& cell_corpses, CellPair &cell, CorpseMapType if(!obj) continue; - obj->GetGridRef().link(&m, obj); + grid.AddWorldObject(obj); addUnitState(obj,cell); obj->SetMap(map); @@ -173,7 +177,8 @@ ObjectGridLoader::Visit(GameObjectMapType &m) CellObjectGuids const& cell_guids = sObjectMgr.GetCellObjectGuids(i_map->GetId(), i_map->GetSpawnMode(), cell_id); - LoadHelper(cell_guids.gameobjects, cell_pair, m, i_gameObjects, i_map); + GridType& grid = (*i_map->getNGrid(i_cell.GridX(),i_cell.GridY())) (i_cell.CellX(),i_cell.CellY()); + LoadHelper(cell_guids.gameobjects, cell_pair, m, i_gameObjects, i_map, grid); } void @@ -186,7 +191,8 @@ ObjectGridLoader::Visit(CreatureMapType &m) CellObjectGuids const& cell_guids = sObjectMgr.GetCellObjectGuids(i_map->GetId(), i_map->GetSpawnMode(), cell_id); - LoadHelper(cell_guids.creatures, cell_pair, m, i_creatures, i_map); + GridType& grid = (*i_map->getNGrid(i_cell.GridX(),i_cell.GridY())) (i_cell.CellX(),i_cell.CellY()); + LoadHelper(cell_guids.creatures, cell_pair, m, i_creatures, i_map, grid); } void @@ -199,7 +205,8 @@ ObjectWorldLoader::Visit(CorpseMapType &m) // corpses are always added to spawn mode 0 and they are spawned by their instance id CellObjectGuids const& cell_guids = sObjectMgr.GetCellObjectGuids(i_map->GetId(), 0, cell_id); - LoadHelper(cell_guids.corpses, cell_pair, m, i_corpses, i_map); + GridType& grid = (*i_map->getNGrid(i_cell.GridX(),i_cell.GridY())) (i_cell.CellX(),i_cell.CellY()); + LoadHelper(cell_guids.corpses, cell_pair, m, i_corpses, i_map, grid); } void diff --git a/src/game/ObjectMgr.cpp b/src/game/ObjectMgr.cpp index dad541015..9874aece3 100644 --- a/src/game/ObjectMgr.cpp +++ b/src/game/ObjectMgr.cpp @@ -929,7 +929,8 @@ void ObjectMgr::LoadEquipmentTemplates() dbcitem->InventoryType != INVTYPE_WEAPONOFFHAND && dbcitem->InventoryType != INVTYPE_HOLDABLE && dbcitem->InventoryType != INVTYPE_THROWN && - dbcitem->InventoryType != INVTYPE_RANGEDRIGHT) + dbcitem->InventoryType != INVTYPE_RANGEDRIGHT && + dbcitem->InventoryType != INVTYPE_RELIC) { sLog.outErrorDb("Item (entry=%u) in creature_equip_template.equipentry%u for entry = %u is not equipable in a hand, forced to 0.", eqInfo->equipentry[j], j+1, i); const_cast(eqInfo)->equipentry[j] = 0; diff --git a/src/game/Opcodes.cpp b/src/game/Opcodes.cpp index e1c0c7ddb..6c26ded59 100644 --- a/src/game/Opcodes.cpp +++ b/src/game/Opcodes.cpp @@ -359,7 +359,7 @@ OpcodeHandler opcodeTable[NUM_MSG_TYPES] = /*0x14A*/ { "SMSG_ATTACKERSTATEUPDATE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, /*0x14B*/ { "SMSG_BATTLEFIELD_PORT_DENIED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, /*0x14C*/ { "SMSG_DAMAGE_DONE_OBSOLETE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x14D*/ { "SMSG_DAMAGE_TAKEN_OBSOLETE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x14D*/ { "SMSG_UNIT_SPELLCAST_START", STATUS_NEVER, &WorldSession::Handle_ServerSide }, /*0x14E*/ { "SMSG_CANCEL_COMBAT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, /*0x14F*/ { "SMSG_SPELLBREAKLOG", STATUS_NEVER, &WorldSession::Handle_ServerSide }, /*0x150*/ { "SMSG_SPELLHEALLOG", STATUS_NEVER, &WorldSession::Handle_ServerSide }, @@ -568,7 +568,7 @@ OpcodeHandler opcodeTable[NUM_MSG_TYPES] = /*0x21B*/ { "SMSG_GMTICKET_SYSTEMSTATUS", STATUS_NEVER, &WorldSession::Handle_ServerSide }, /*0x21C*/ { "CMSG_SPIRIT_HEALER_ACTIVATE", STATUS_LOGGEDIN, &WorldSession::HandleSpiritHealerActivateOpcode}, /*0x21D*/ { "CMSG_SET_STAT_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x21E*/ { "SMSG_SET_REST_START_OBSOLETE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x21E*/ { "SMSG_QUEST_FORCE_REMOVE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, /*0x21F*/ { "CMSG_SKILL_BUY_STEP", STATUS_NEVER, &WorldSession::Handle_NULL }, /*0x220*/ { "CMSG_SKILL_BUY_RANK", STATUS_NEVER, &WorldSession::Handle_NULL }, /*0x221*/ { "CMSG_XP_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL }, @@ -1146,8 +1146,8 @@ OpcodeHandler opcodeTable[NUM_MSG_TYPES] = /*0x45D*/ { "CMSG_FORCE_PITCH_RATE_CHANGE_ACK", STATUS_NEVER, &WorldSession::Handle_NULL }, /*0x45E*/ { "SMSG_SPLINE_SET_PITCH_RATE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, /*0x45F*/ { "SMSG_MOVE_ABANDON_TRANSPORT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x460*/ { "MSG_MOVE_ABANDON_TRANSPORT", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x461*/ { "CMSG_MOVE_ABANDON_TRANSPORT_ACK", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x460*/ { "SMSG_CALENDAR_UPDATE_INVITE_LIST", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x461*/ { "SMSG_CALENDAR_UPDATE_INVITE_LIST2", STATUS_NEVER, &WorldSession::Handle_NULL }, /*0x462*/ { "CMSG_UPDATE_MISSILE_TRAJECTORY", STATUS_NEVER, &WorldSession::Handle_NULL }, /*0x463*/ { "SMSG_UPDATE_ACCOUNT_DATA_COMPLETE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, /*0x464*/ { "SMSG_TRIGGER_MOVIE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, @@ -1163,7 +1163,7 @@ OpcodeHandler opcodeTable[NUM_MSG_TYPES] = /*0x46E*/ { "CMSG_COMPLETE_ACHIEVEMENT_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL }, /*0x46F*/ { "SMSG_QUESTUPDATE_ADD_PVP_KILL", STATUS_NEVER, &WorldSession::Handle_ServerSide }, /*0x470*/ { "CMSG_SET_CRITERIA_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x471*/ { "SMSG_GROUP_SWAP_FAILED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x471*/ { "SMSG_CALENDAR_UPDATE_INVITE_LIST3", STATUS_NEVER, &WorldSession::Handle_ServerSide }, /*0x472*/ { "CMSG_UNITANIMTIER_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL }, /*0x473*/ { "CMSG_CHAR_CUSTOMIZE", STATUS_AUTHED, &WorldSession::HandleCharCustomize }, /*0x474*/ { "SMSG_CHAR_CUSTOMIZE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, @@ -1256,13 +1256,13 @@ OpcodeHandler opcodeTable[NUM_MSG_TYPES] = /*0x4CB*/ { "UMSG_UNKNOWN_1227", STATUS_NEVER, &WorldSession::Handle_NULL }, /*0x4CC*/ { "UMSG_UNKNOWN_1228", STATUS_NEVER, &WorldSession::Handle_NULL }, /*0x4CD*/ { "SMSG_MULTIPLE_PACKETS", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x4CE*/ { "SMSG_UNKNOWN_1230", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x4CF*/ { "CMSG_UNKNOWN_1231_ACK", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x4D0*/ { "SMSG_UNKNOWN_1232", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x4D1*/ { "CMSG_UNKNOWN_1233_ACK", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x4D2*/ { "SMSG_UNKNOWN_1234", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x4D3*/ { "SMSG_UNKNOWN_1235", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x4D4*/ { "SMSG_UNKNOWN_1236", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x4CE*/ { "SMSG_FORCE_UNK1_SPEED_CHANGE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x4CF*/ { "CMSG_FORCE_UNK1_SPEED_CHANGE_ACK", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x4D0*/ { "SMSG_FORCE_UNK2_SPEED_CHANGE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x4D1*/ { "CMSG_FORCE_UNK2_SPEED_CHANGE_ACK", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x4D2*/ { "MSG_MOVE_UNKNOWN_1234", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x4D3*/ { "SMSG_SPLINE_MOVE_UNKNOWN_1235", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x4D4*/ { "SMSG_SPLINE_MOVE_UNKNOWN_1236", STATUS_NEVER, &WorldSession::Handle_ServerSide }, /*0x4D5*/ { "CMSG_EQUIPMENT_SET_USE", STATUS_LOGGEDIN, &WorldSession::HandleEquipmentSetUse }, /*0x4D6*/ { "SMSG_EQUIPMENT_SET_USE_RESULT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, /*0x4D7*/ { "UMSG_UNKNOWN_1239", STATUS_NEVER, &WorldSession::Handle_NULL }, @@ -1273,7 +1273,7 @@ OpcodeHandler opcodeTable[NUM_MSG_TYPES] = /*0x4DC*/ { "UMSG_UNKNOWN_1244", STATUS_NEVER, &WorldSession::Handle_NULL }, /*0x4DD*/ { "UMSG_UNKNOWN_1245", STATUS_NEVER, &WorldSession::Handle_NULL }, /*0x4DE*/ { "SMSG_BATTLEFIELD_MGR_ENTRY_INVITE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x4DF*/ { "CMSG_BATTLEFIELD_MGR_ENTRY_INVITE_RESPONS", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x4DF*/ { "CMSG_BATTLEFIELD_MGR_ENTRY_INVITE_RESPONSE", STATUS_NEVER, &WorldSession::Handle_NULL }, /*0x4E0*/ { "SMSG_BATTLEFIELD_MGR_ENTERED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, /*0x4E1*/ { "SMSG_BATTLEFIELD_MGR_QUEUE_INVITE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, /*0x4E2*/ { "CMSG_BATTLEFIELD_MGR_QUEUE_INVITE_RESPONSE", STATUS_NEVER, &WorldSession::Handle_NULL }, diff --git a/src/game/Opcodes.h b/src/game/Opcodes.h index 1aacba866..8de6e166c 100644 --- a/src/game/Opcodes.h +++ b/src/game/Opcodes.h @@ -1242,7 +1242,7 @@ enum Opcodes SMSG_ITEM_REFUND_RESULT = 0x4B5, // refund item result CMSG_CORPSE_MAP_POSITION_QUERY = 0x4B6, // CMSG, uint32 SMSG_CORPSE_MAP_POSITION_QUERY_RESPONSE = 0x4B7, // SMSG, 3*float+float - UMSG_UNKNOWN_1208 = 0x4B8, // not found + CMSG_LFG_SET_ROLES_2 = 0x4B8, // not found UMSG_UNKNOWN_1209 = 0x4B9, // not found CMSG_CALENDAR_CONTEXT_EVENT_SIGNUP = 0x4BA, // CMSG, uint64, lua: CalendarContextEventSignUp SMSG_CALENDAR_ACTION_PENDING = 0x4BB, // SMSG, calendar related EVENT_CALENDAR_ACTION_PENDING diff --git a/src/game/Pet.cpp b/src/game/Pet.cpp index c077d0a4b..395ea51ed 100644 --- a/src/game/Pet.cpp +++ b/src/game/Pet.cpp @@ -1313,7 +1313,7 @@ bool Pet::addSpell(uint32 spell_id,ActiveStates active /*= ACT_DECIDE*/, PetSpel if(active == ACT_DECIDE) //active was not used before, so we save it's autocast/passive state here { - if(IsPassiveSpell(spell_id)) + if(IsPassiveSpell(spellInfo)) newspell.active = ACT_PASSIVE; else newspell.active = ACT_DISABLED; @@ -1369,7 +1369,7 @@ bool Pet::addSpell(uint32 spell_id,ActiveStates active /*= ACT_DECIDE*/, PetSpel m_spells[spell_id] = newspell; - if (IsPassiveSpell(spell_id)) + if (IsPassiveSpell(spellInfo)) CastSpell(this, spell_id, true); else m_charmInfo->AddSpellToActionBar(spell_id, ActiveStates(newspell.active)); diff --git a/src/game/PetHandler.cpp b/src/game/PetHandler.cpp index e306f8078..57356b38a 100644 --- a/src/game/PetHandler.cpp +++ b/src/game/PetHandler.cpp @@ -86,7 +86,7 @@ void WorldSession::HandlePetAction( WorldPacket & recv_data ) { case COMMAND_STAY: //flat=1792 //STAY pet->StopMoving(); - pet->GetMotionMaster()->Clear(); + pet->GetMotionMaster()->Clear(false); pet->GetMotionMaster()->MoveIdle(); charmInfo->SetCommandState( COMMAND_STAY ); break; @@ -191,7 +191,7 @@ void WorldSession::HandlePetAction( WorldPacket & recv_data ) } // do not cast not learned spells - if(!pet->HasSpell(spellid) || IsPassiveSpell(spellid)) + if(!pet->HasSpell(spellid) || IsPassiveSpell(spellInfo)) return; pet->clearUnitState(UNIT_STAT_MOVING); @@ -626,7 +626,7 @@ void WorldSession::HandlePetCastSpellOpcode( WorldPacket& recvPacket ) } // do not cast not learned spells - if (!pet->HasSpell(spellid) || IsPassiveSpell(spellid)) + if (!pet->HasSpell(spellid) || IsPassiveSpell(spellInfo)) return; SpellCastTargets targets; diff --git a/src/game/Player.cpp b/src/game/Player.cpp index 53706be37..fe43768f4 100644 --- a/src/game/Player.cpp +++ b/src/game/Player.cpp @@ -405,7 +405,7 @@ void TradeData::SetAccepted(bool state, bool crosssend /*= false*/) UpdateMask Player::updateVisualBits; -Player::Player (WorldSession *session): Unit(), m_achievementMgr(this), m_reputationMgr(this) +Player::Player (WorldSession *session): Unit(), m_achievementMgr(this), m_reputationMgr(this), m_mover(this), m_camera(this) { m_transport = 0; @@ -417,6 +417,8 @@ Player::Player (WorldSession *session): Unit(), m_achievementMgr(this), m_reputa m_valuesCount = PLAYER_END; + m_isActiveObject = true; // player is always active object + m_session = session; m_divider = 0; @@ -478,6 +480,7 @@ Player::Player (WorldSession *session): Unit(), m_achievementMgr(this), m_reputa m_DelayedOperations = 0; m_bCanDelayTeleport = false; m_bHasDelayedTeleport = false; + m_bHasBeenAliveAtDelayedTeleport = true; // overwrite always at setup teleport data, so not used infact m_teleport_options = 0; m_trade = NULL; @@ -584,8 +587,6 @@ Player::Player (WorldSession *session): Unit(), m_achievementMgr(this), m_reputa m_summon_y = 0.0f; m_summon_z = 0.0f; - m_mover = this; - m_miniPet = 0; m_contestedPvPTimer = 0; @@ -1474,9 +1475,7 @@ void Player::Update( uint32 p_time ) RemovePet(pet, PET_SAVE_NOT_IN_SLOT, true); } - //we should execute delayed teleports only for alive(!) players - //because we don't want player's ghost teleported from graveyard - if(IsHasDelayedTeleport() && isAlive()) + if (IsHasDelayedTeleport()) TeleportTo(m_teleport_dest, m_teleport_options); } @@ -1775,10 +1774,9 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati //lets reset far teleport flag if it wasn't reset during chained teleports SetSemaphoreTeleportFar(false); //setup delayed teleport flag - SetDelayedTeleportFlag(IsCanDelayTeleport()); //if teleport spell is casted in Unit::Update() func //then we need to delay it until update process will be finished - if(IsHasDelayedTeleport()) + if (SetDelayedTeleportFlagIfCan()) { SetSemaphoreTeleportNear(true); //lets save teleport destination for player @@ -1794,7 +1792,7 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati UnsummonPetTemporaryIfAny(); } - if(!(options & TELE_TO_NOT_LEAVE_COMBAT)) + if (!(options & TELE_TO_NOT_LEAVE_COMBAT)) CombatStop(); // this will be used instead of the current location in SaveToDB @@ -1831,10 +1829,9 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati //lets reset near teleport flag if it wasn't reset during chained teleports SetSemaphoreTeleportNear(false); //setup delayed teleport flag - SetDelayedTeleportFlag(IsCanDelayTeleport()); //if teleport spell is casted in Unit::Update() func //then we need to delay it until update process will be finished - if(IsHasDelayedTeleport()) + if (SetDelayedTeleportFlagIfCan()) { SetSemaphoreTeleportFar(true); //lets save teleport destination for player @@ -1850,7 +1847,7 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati ResetContestedPvP(); // remove player from battleground on far teleport (when changing maps) - if(BattleGround const* bg = GetBattleGround()) + if (BattleGround const* bg = GetBattleGround()) { // Note: at battleground join battleground id set before teleport // and we already will found "current" battleground @@ -1868,14 +1865,14 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati // stop spellcasting // not attempt interrupt teleportation spell at caster teleport - if(!(options & TELE_TO_SPELL)) - if(IsNonMeleeSpellCasted(true)) + if (!(options & TELE_TO_SPELL)) + if (IsNonMeleeSpellCasted(true)) InterruptNonMeleeSpells(true); //remove auras before removing from map... RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_CHANGE_MAP | AURA_INTERRUPT_FLAG_MOVE | AURA_INTERRUPT_FLAG_TURNING); - if(!GetSession()->PlayerLogout()) + if (!GetSession()->PlayerLogout()) { // send transfer packets WorldPacket data(SMSG_TRANSFER_PENDING, (4+4+4)); @@ -1909,7 +1906,7 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati } // remove from old map now - if(oldmap) + if (oldmap) oldmap->Remove(this, false); // new final coordinates @@ -1918,7 +1915,7 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati float final_z = z; float final_o = orientation; - if(m_transport) + if (m_transport) { final_x += m_movementInfo.GetTransportPos()->x; final_y += m_movementInfo.GetTransportPos()->y; @@ -2236,7 +2233,7 @@ Creature* Player::GetNPCIfCanInteractWith(ObjectGuid guid, uint32 npcflagmask) return NULL; // not in interactive state - if (hasUnitState(UNIT_STAT_CAN_NOT_REACT)) + if (hasUnitState(UNIT_STAT_CAN_NOT_REACT_OR_LOST_CONTROL)) return NULL; // exist (we need look pets also for some interaction (quest/etc) @@ -2290,7 +2287,7 @@ GameObject* Player::GetGameObjectIfCanInteractWith(ObjectGuid guid, uint32 gameo return NULL; // not in interactive state - if (hasUnitState(UNIT_STAT_CAN_NOT_REACT)) + if (hasUnitState(UNIT_STAT_CAN_NOT_REACT_OR_LOST_CONTROL)) return NULL; if (GameObject *go = GetMap()->GetGameObject(guid)) @@ -2409,7 +2406,8 @@ void Player::SetGameMaster(bool on) getHostileRefManager().setOnlineOfflineState(true); } - UpdateVisibilityForPlayer(); + m_camera.UpdateVisibilityForOwner(); + UpdateObjectVisibility(); } void Player::SetGMVisible(bool on) @@ -3062,7 +3060,7 @@ bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool dependen if(active) { - if (IsPassiveSpell(spell_id) && IsNeedCastPassiveSpellAtLearn(spellInfo)) + if (IsPassiveSpell(spellInfo) && IsNeedCastPassiveSpellAtLearn(spellInfo)) CastSpell (this, spell_id, true); } else if(IsInWorld()) @@ -3253,7 +3251,7 @@ bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool dependen CastSpell(this, spell_id, true); } // also cast passive spells (including all talents without SPELL_EFFECT_LEARN_SPELL) with additional checks - else if (IsPassiveSpell(spell_id)) + else if (IsPassiveSpell(spellInfo)) { if (IsNeedCastPassiveSpellAtLearn(spellInfo)) CastSpell(this, spell_id, true); @@ -4490,8 +4488,10 @@ void Player::ResurrectPlayer(float restore_percent, bool applySickness) GetZoneAndAreaId(newzone,newarea); UpdateZone(newzone,newarea); - // update visibility - UpdateVisibilityForPlayer(); + // update visibility of world around viewpoint + m_camera.UpdateVisibilityForOwner(); + // update visibility of player for nearby cameras + UpdateObjectVisibility(); if(!applySickness) return; @@ -6073,42 +6073,30 @@ void Player::SaveRecallPosition() void Player::SendMessageToSet(WorldPacket *data, bool self) { - Map * _map = IsInWorld() ? GetMap() : sMapMgr.FindMap(GetMapId(), GetInstanceId()); - if(_map) - { - _map->MessageBroadcast(this, data, self); - return; - } + if (Map * _map = IsInWorld() ? GetMap() : sMapMgr.FindMap(GetMapId(), GetInstanceId())) + _map->MessageBroadcast(this, data, false); //if player is not in world and map in not created/already destroyed //no need to create one, just send packet for itself! - if(self) + if (self) GetSession()->SendPacket(data); } void Player::SendMessageToSetInRange(WorldPacket *data, float dist, bool self) { - Map * _map = IsInWorld() ? GetMap() : sMapMgr.FindMap(GetMapId(), GetInstanceId()); - if(_map) - { - _map->MessageDistBroadcast(this, data, dist, self); - return; - } + if (Map * _map = IsInWorld() ? GetMap() : sMapMgr.FindMap(GetMapId(), GetInstanceId())) + _map->MessageDistBroadcast(this, data, dist, false); - if(self) + if (self) GetSession()->SendPacket(data); } void Player::SendMessageToSetInRange(WorldPacket *data, float dist, bool self, bool own_team_only) { - Map * _map = IsInWorld() ? GetMap() : sMapMgr.FindMap(GetMapId(), GetInstanceId()); - if(_map) - { - _map->MessageDistBroadcast(this, data, dist, self, own_team_only); - return; - } + if (Map * _map = IsInWorld() ? GetMap() : sMapMgr.FindMap(GetMapId(), GetInstanceId())) + _map->MessageDistBroadcast(this, data, dist, false, own_team_only); - if(self) + if (self) GetSession()->SendPacket(data); } @@ -13547,10 +13535,6 @@ void Player::IncompleteQuest( uint32 quest_id ) void Player::RewardQuest( Quest const *pQuest, uint32 reward, Object* questGiver, bool announce ) { - //this THING should be here to protect code from quest, which cast on player far teleport as a reward - //should work fine, cause far teleport will be executed in Player::Update() - SetCanDelayTeleport(true); - uint32 quest_id = pQuest->GetQuestId(); for (int i = 0; i < QUEST_ITEM_OBJECTIVES_COUNT; ++i ) @@ -13702,9 +13686,6 @@ void Player::RewardQuest( Quest const *pQuest, uint32 reward, Object* questGiver if (!HasAura(itr->second->spellId, EFFECT_INDEX_0)) CastSpell(this,itr->second->spellId,true); } - - //lets remove flag for delayed teleports - SetCanDelayTeleport(false); } void Player::FailQuest(uint32 questId) @@ -15322,7 +15303,8 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder ) SetCreatorGUID(0); // reset some aura modifiers before aura apply - SetFarSightGUID(0); + + SetUInt64Value(PLAYER_FARSIGHT, 0); SetUInt32Value(PLAYER_TRACK_CREATURES, 0 ); SetUInt32Value(PLAYER_TRACK_RESOURCES, 0 ); @@ -17605,7 +17587,7 @@ void Player::RemoveMiniPet() } } -Pet* Player::GetMiniPet() +Pet* Player::GetMiniPet() const { if (!m_miniPet) return NULL; @@ -18058,7 +18040,7 @@ void Player::HandleStealthedUnitsDetection() MaNGOS::UnitListSearcher searcher(this,stealthedUnits, u_check); Cell::VisitAllObjects(this, searcher, MAX_PLAYER_STEALTH_DETECT_RANGE); - WorldObject const* viewPoint = GetViewPoint(); + WorldObject const* viewPoint = GetCamera().GetBody(); for (std::list::const_iterator i = stealthedUnits.begin(); i != stealthedUnits.end(); ++i) { @@ -19154,17 +19136,6 @@ void Player::ReportedAfkBy(Player* reporter) } } -WorldObject const* Player::GetViewPoint() const -{ - if(uint64 far_sight = GetFarSight()) - { - WorldObject const* viewPoint = GetMap()->GetWorldObject(far_sight); - return viewPoint ? viewPoint : this; // always expected not NULL - } - else - return this; -} - bool Player::IsVisibleInGridForPlayer( Player* pl ) const { // gamemaster in GM mode see all, including ghosts @@ -19461,7 +19432,7 @@ void Player::SendInitialPacketsBeforeAddToMap() if(HasAuraType(SPELL_AURA_MOD_FLIGHT_SPEED_MOUNTED) || HasAuraType(SPELL_AURA_FLY) || isInFlight()) m_movementInfo.AddMovementFlag(MOVEFLAG_FLYING); - m_mover = this; + SetMover(this); } void Player::SendInitialPacketsAfterAddToMap() @@ -20736,7 +20707,7 @@ void Player::EnterVehicle(Vehicle *vehicle) vehicle->setFaction(getFaction()); SetCharm(vehicle); // charm - SetFarSightGUID(vehicle->GetGUID()); // set view + m_camera.SetView(vehicle); // set view SetClientControl(vehicle, 1); // redirect controls to vehicle SetMover(vehicle); @@ -20788,7 +20759,7 @@ void Player::ExitVehicle(Vehicle *vehicle) vehicle->setFaction((GetTeam() == ALLIANCE) ? vehicle->GetCreatureInfo()->faction_A : vehicle->GetCreatureInfo()->faction_H); SetCharm(NULL); - SetFarSightGUID(0); + m_camera.ResetView(); SetClientControl(vehicle, 0); SetMover(NULL); @@ -21230,6 +21201,23 @@ void Player::UpdateAchievementCriteria( AchievementCriteriaTypes type, uint32 mi GetAchievementMgr().UpdateAchievementCriteria(type, miscvalue1,miscvalue2,unit,time); } +PlayerTalent const* Player::GetKnownTalentById(int32 talentId) const +{ + PlayerTalentMap::const_iterator itr = m_talents[m_activeSpec].find(talentId); + if (itr != m_talents[m_activeSpec].end() && itr->second.state != PLAYERSPELL_REMOVED) + return &itr->second; + else + return NULL; +} + +SpellEntry const* Player::GetKnownTalentRankById(int32 talentId) const +{ + if (PlayerTalent const* talent = GetKnownTalentById(talentId)) + return sSpellStore.LookupEntry(talent->m_talentEntry->RankID[talent->currentRank]); + else + return NULL; +} + void Player::LearnTalent(uint32 talentId, uint32 talentRank) { uint32 CurTalentPoints = GetFreeTalentPoints(); @@ -21256,9 +21244,8 @@ void Player::LearnTalent(uint32 talentId, uint32 talentRank) // find current max talent rank uint32 curtalent_maxrank = 0; - PlayerTalentMap::iterator itr = m_talents[m_activeSpec].find(talentId); - if (itr != m_talents[m_activeSpec].end() && itr->second.state != PLAYERSPELL_REMOVED) - curtalent_maxrank = itr->second.currentRank + 1; + if (PlayerTalent const* talent = GetKnownTalentById(talentId)) + curtalent_maxrank = talent->currentRank + 1; // we already have same or higher talent rank learned if(curtalent_maxrank >= (talentRank + 1)) @@ -21894,17 +21881,16 @@ void Player::ActivateSpec(uint8 specNum) // learn talent spells if they not in new spec (old spec copy) // and if they have different rank - PlayerTalentMap::iterator specIter = m_talents[m_activeSpec].find(tempIter->first); - if (specIter != m_talents[m_activeSpec].end() && specIter->second.state != PLAYERSPELL_REMOVED) + if (PlayerTalent const* cur_talent = GetKnownTalentById(tempIter->first)) { - if ((*specIter).second.currentRank != talent.currentRank) + if (cur_talent->currentRank != talent.currentRank) learnSpell(talentSpellId, false); } else learnSpell(talentSpellId, false); // sync states - original state is changed in addSpell that learnSpell calls - specIter = m_talents[m_activeSpec].find(tempIter->first); + PlayerTalentMap::iterator specIter = m_talents[m_activeSpec].find(tempIter->first); if (specIter != m_talents[m_activeSpec].end()) (*specIter).second.state = talent.state; else @@ -21925,11 +21911,20 @@ void Player::ActivateSpec(uint8 specNum) // recheck action buttons (not checked at loading/spec copy) ActionButtonList const& currentActionButtonList = m_actionButtons[m_activeSpec]; - for(ActionButtonList::const_iterator itr = currentActionButtonList.begin(); itr != currentActionButtonList.end(); ++itr) + for(ActionButtonList::const_iterator itr = currentActionButtonList.begin(); itr != currentActionButtonList.end(); ) + { if (itr->second.uState != ACTIONBUTTON_DELETED) + { // remove broken without any output (it can be not correct because talents not copied at spec creating) if (!IsActionButtonDataValid(itr->first,itr->second.GetAction(),itr->second.GetType(), this, false)) + { removeActionButton(m_activeSpec,itr->first); + itr = currentActionButtonList.begin(); + continue; + } + } + ++itr; + } ResummonPetTemporaryUnSummonedIfAny(); @@ -22022,38 +22017,6 @@ bool Player::HasMovementFlag( MovementFlags f ) const return m_movementInfo.HasMovementFlag(f); } -void Player::SetFarSightGUID( uint64 guid ) -{ - if(GetFarSight() == guid) - return; - - SetUInt64Value(PLAYER_FARSIGHT, guid); - - // need triggering load grids around new view point - UpdateVisibilityForPlayer(); -} - -void Player::UpdateVisibilityForPlayer() -{ - WorldObject const* viewPoint = GetViewPoint(); - Map* m = GetMap(); - - CellPair p(MaNGOS::ComputeCellPair(GetPositionX(), GetPositionY())); - Cell cell(p); - - m->UpdateObjectVisibility(this, cell, p); - - if (this != viewPoint) - { - CellPair pView(MaNGOS::ComputeCellPair(viewPoint->GetPositionX(), viewPoint->GetPositionY())); - Cell cellView(pView); - - m->UpdateObjectsVisibilityFor(this, cellView, pView); - } - else - m->UpdateObjectsVisibilityFor(this, cell, p); -} - void Player::ResetTimeSync() { m_timeSyncCounter = 0; diff --git a/src/game/Player.h b/src/game/Player.h index bdaa39991..548d4645f 100644 --- a/src/game/Player.h +++ b/src/game/Player.h @@ -1128,8 +1128,6 @@ class MANGOS_DLL_SPEC Player : public Unit Creature* GetNPCIfCanInteractWith(ObjectGuid guid, uint32 npcflagmask); GameObject* GetGameObjectIfCanInteractWith(ObjectGuid guid, uint32 gameobject_type = MAX_GAMEOBJECT_TYPE) const; - void UpdateVisibilityForPlayer(); - bool ToggleAFK(); bool ToggleDND(); bool isAFK() const { return HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_AFK); } @@ -1191,7 +1189,7 @@ class MANGOS_DLL_SPEC Player : public Unit void RemovePet(Pet* pet, PetSaveMode mode, bool returnreagent = false); void RemoveMiniPet(); - Pet* GetMiniPet(); + Pet* GetMiniPet() const; void SetMiniPet(Pet* pet) { m_miniPet = pet->GetGUID(); } template @@ -1666,6 +1664,9 @@ class MANGOS_DLL_SPEC Player : public Unit SpellCooldowns const& GetSpellCooldownMap() const { return m_spellCooldowns; } + PlayerTalent const* GetKnownTalentById(int32 talentId) const; + SpellEntry const* GetKnownTalentRankById(int32 talentId) const; + void AddSpellMod(SpellModifier* mod, bool apply); bool IsAffectedBySpellmod(SpellEntry const *spellInfo, SpellModifier *mod, Spell const* spell = NULL); template T ApplySpellMod(uint32 spellId, SpellModOp op, T &basevalue, Spell const* spell = NULL); @@ -2191,7 +2192,6 @@ class MANGOS_DLL_SPEC Player : public Unit /*********************************************************/ bool HasMovementFlag(MovementFlags f) const; // for script access to m_movementInfo.HasMovementFlag void UpdateFallInformationIfNeed(MovementInfo const& minfo,uint16 opcode); - Unit *m_mover; void SetFallInformation(uint32 time, float z) { m_lastFallTime = time; @@ -2210,12 +2210,13 @@ class MANGOS_DLL_SPEC Player : public Unit void SetClientControl(Unit* target, uint8 allowMove); void SetMover(Unit* target) { m_mover = target ? target : this; } + Unit* GetMover() const { return m_mover; } + bool IsSelfMover() const { return m_mover == this; }// normal case for player not controlling other unit void EnterVehicle(Vehicle *vehicle); void ExitVehicle(Vehicle *vehicle); - uint64 GetFarSight() const { return GetUInt64Value(PLAYER_FARSIGHT); } - void SetFarSightGUID(uint64 guid); + ObjectGuid const& GetFarSightGuid() const { return GetGuidValue(PLAYER_FARSIGHT); } // Transports Transport * GetTransport() const { return m_transport; } @@ -2250,7 +2251,6 @@ class MANGOS_DLL_SPEC Player : public Unit bool HaveAtClient(WorldObject const* u) { return u==this || m_clientGUIDs.find(u->GetGUID())!=m_clientGUIDs.end(); } - WorldObject const* GetViewPoint() const; bool IsVisibleInGridForPlayer(Player* pl) const; bool IsVisibleGloballyFor(Player* pl) const; @@ -2262,6 +2262,8 @@ class MANGOS_DLL_SPEC Player : public Unit // Stealth detection system void HandleStealthedUnitsDetection(); + Camera& GetCamera() { return m_camera; } + uint8 m_forced_speed_changes[MAX_MOVE_TYPE]; bool HasAtLoginFlag(AtLoginFlags f) const { return m_atLoginFlags & f; } @@ -2353,7 +2355,6 @@ class MANGOS_DLL_SPEC Player : public Unit bool HasTitle(CharTitlesEntry const* title) { return HasTitle(title->bit_index); } void SetTitle(CharTitlesEntry const* title, bool lost = false); - bool isActiveObject() const { return true; } bool canSeeSpellClickOn(Creature const* creature) const; protected: @@ -2592,17 +2593,30 @@ class MANGOS_DLL_SPEC Player : public Unit int32 CalculateReputationGain(uint32 creatureOrQuestLevel, int32 rep, int32 faction, bool for_quest); void AdjustQuestReqItemCount( Quest const* pQuest, QuestStatusData& questStatusData ); - bool IsCanDelayTeleport() const { return m_bCanDelayTeleport; } void SetCanDelayTeleport(bool setting) { m_bCanDelayTeleport = setting; } - bool IsHasDelayedTeleport() const { return m_bHasDelayedTeleport; } - void SetDelayedTeleportFlag(bool setting) { m_bHasDelayedTeleport = setting; } + bool IsHasDelayedTeleport() const + { + // we should not execute delayed teleports for now dead players but has been alive at teleport + // because we don't want player's ghost teleported from graveyard + return m_bHasDelayedTeleport && (isAlive() || !m_bHasBeenAliveAtDelayedTeleport); + } + + bool SetDelayedTeleportFlagIfCan() + { + m_bHasDelayedTeleport = m_bCanDelayTeleport; + m_bHasBeenAliveAtDelayedTeleport = isAlive(); + return m_bHasDelayedTeleport; + } void ScheduleDelayedOperation(uint32 operation) { - if(operation < DELAYED_END) + if (operation < DELAYED_END) m_DelayedOperations |= operation; } + Unit *m_mover; + Camera m_camera; + GridReference m_gridRef; MapReference m_mapRef; @@ -2630,6 +2644,7 @@ class MANGOS_DLL_SPEC Player : public Unit uint32 m_DelayedOperations; bool m_bCanDelayTeleport; bool m_bHasDelayedTeleport; + bool m_bHasBeenAliveAtDelayedTeleport; uint32 m_DetectInvTimer; @@ -2710,7 +2725,7 @@ template bool Player::CheckAllControlledUnits(Func const& func, bool withTotems, bool withGuardians, bool withCharms, bool withMiniPet) const { if (withMiniPet) - if(Unit* mini = GetMiniPet()) + if(Unit const* mini = GetMiniPet()) if (func(mini)) return true; diff --git a/src/game/PoolManager.cpp b/src/game/PoolManager.cpp index b0b30308b..ba8c76897 100644 --- a/src/game/PoolManager.cpp +++ b/src/game/PoolManager.cpp @@ -106,6 +106,30 @@ void SpawnedPoolData::RemoveSpawn(uint32 sub_pool_id, uint32 pool_id) --val; } +//////////////////////////////////////////////////////////// +// Methods of class PoolObject +template<> +void PoolObject::CheckEventLinkAndReport(uint32 poolId, int16 event_id, std::map const& creature2event, std::map const& /*go2event*/) const +{ + std::map::const_iterator itr = creature2event.find(guid); + if (itr == creature2event.end() || itr->second != event_id) + sLog.outErrorDb("Creature (GUID: %u) expected to be listed in `game_event_creature` for event %u as part pool %u", guid, event_id, poolId); +} + +template<> +void PoolObject::CheckEventLinkAndReport(uint32 poolId, int16 event_id, std::map const& /*creature2event*/, std::map const& go2event) const +{ + std::map::const_iterator itr = go2event.find(guid); + if (itr == go2event.end() || itr->second != event_id) + sLog.outErrorDb("Gameobject (GUID: %u) expected to be listed in `game_event_gameobject` for event %u as part pool %u", guid, event_id, poolId); +} + +template<> +void PoolObject::CheckEventLinkAndReport(uint32 poolId, int16 event_id, std::map const& creature2event, std::map const& go2event) const +{ + sPoolMgr.CheckEventLinkAndReport(guid, event_id, creature2event, go2event); +} + //////////////////////////////////////////////////////////// // Methods of template class PoolGroup @@ -134,6 +158,40 @@ bool PoolGroup::CheckPool() const return true; } +// Method to check event linking +template +void PoolGroup::CheckEventLinkAndReport(int16 event_id, std::map const& creature2event, std::map const& go2event) const +{ + for (uint32 i=0; i < EqualChanced.size(); ++i) + EqualChanced[i].CheckEventLinkAndReport(poolId, event_id, creature2event, go2event); + + for (uint32 i=0; i(poolId, event_id, creature2event, go2event); +} + +template +void PoolGroup::SetExcludeObject(uint32 guid, bool state) +{ + for (uint32 i=0; i < EqualChanced.size(); ++i) + { + if (EqualChanced[i].guid == guid) + { + EqualChanced[i].exclude = state; + return; + } + } + + for (uint32 i=0; i PoolObject* PoolGroup::RollOne(SpawnedPoolData& spawns, uint32 triggerFrom) { @@ -146,7 +204,7 @@ PoolObject* PoolGroup::RollOne(SpawnedPoolData& spawns, uint32 triggerFrom) roll -= ExplicitlyChanced[i].chance; // Triggering object is marked as spawned at this time and can be also rolled (respawn case) // so this need explicit check for this case - if (roll < 0 && (ExplicitlyChanced[i].guid == triggerFrom || !spawns.IsSpawnedObject(ExplicitlyChanced[i].guid))) + if (roll < 0 && !ExplicitlyChanced[i].exclude && (ExplicitlyChanced[i].guid == triggerFrom || !spawns.IsSpawnedObject(ExplicitlyChanced[i].guid))) return &ExplicitlyChanced[i]; } } @@ -156,7 +214,7 @@ PoolObject* PoolGroup::RollOne(SpawnedPoolData& spawns, uint32 triggerFrom) int32 index = irand(0, EqualChanced.size()-1); // Triggering object is marked as spawned at this time and can be also rolled (respawn case) // so this need explicit check for this case - if (EqualChanced[index].guid == triggerFrom || !spawns.IsSpawnedObject(EqualChanced[index].guid)) + if (!EqualChanced[index].exclude && (EqualChanced[index].guid == triggerFrom || !spawns.IsSpawnedObject(EqualChanced[index].guid))) return &EqualChanced[index]; } @@ -263,7 +321,12 @@ void PoolGroup::SpawnObject(SpawnedPoolData& spawns, uint32 limit, uint32 tri // and also counted into m_SpawnedPoolAmount so we need increase count to be // spawned by 1 if (triggerFrom) - ++count; + { + if (spawns.IsSpawnedObject(triggerFrom)) + ++count; + else + triggerFrom = 0; + } // This will try to spawn the rest of pool, not guaranteed for (int i = 0; i < count; ++i) @@ -462,6 +525,7 @@ void PoolManager::LoadFromDB() PoolTemplateData& pPoolTemplate = mPoolTemplate[pool_id]; pPoolTemplate.MaxLimit = fields[1].GetUInt32(); + pPoolTemplate.AutoSpawn = true; // will update and later data loading } while (result->NextRow()); @@ -661,6 +725,9 @@ void PoolManager::LoadFromDB() SearchPair p(child_pool_id, mother_pool_id); mPoolSearchMap.insert(p); + // update top independent pool flag + mPoolTemplate[child_pool_id].AutoSpawn = false; + } while( result->NextRow() ); // Now check for circular reference @@ -692,17 +759,15 @@ void PoolManager::LoadFromDB() } } -// The initialize method will spawn all pools not in an event and not in another pool, this is why there is 2 left joins with 2 null checks +// The initialize method will spawn all pools not in an event and not in another pool void PoolManager::Initialize() { - QueryResult *result = WorldDatabase.Query("SELECT DISTINCT pool_template.entry FROM pool_template LEFT JOIN game_event_pool ON pool_template.entry=game_event_pool.pool_entry LEFT JOIN pool_pool ON pool_template.entry=pool_pool.pool_id WHERE game_event_pool.pool_entry IS NULL AND pool_pool.pool_id IS NULL"); - uint32 count=0; - if (result) + uint32 count = 0; + + for(uint16 pool_entry = 0; pool_entry < mPoolTemplate.size(); ++pool_entry) { - do + if (mPoolTemplate[pool_entry].AutoSpawn) { - Field *fields = result->Fetch(); - uint16 pool_entry = fields[0].GetUInt16(); if (!CheckPool(pool_entry)) { sLog.outErrorDb("Pool Id (%u) has all creatures or gameobjects with explicit chance sum <>100 and no equal chance defined. The pool system cannot pick one to spawn.", pool_entry); @@ -710,8 +775,7 @@ void PoolManager::Initialize() } SpawnPool(pool_entry, true); count++; - } while (result->NextRow()); - delete result; + } } BASIC_LOG("Pool handling system initialized, %u pools spawned.", count); @@ -775,6 +839,27 @@ bool PoolManager::CheckPool(uint16 pool_id) const mPoolPoolGroups[pool_id].CheckPool(); } +// Method that check linking all elements to event +void PoolManager::CheckEventLinkAndReport(uint16 pool_id, int16 event_id, std::map const& creature2event, std::map const& go2event) const +{ + mPoolGameobjectGroups[pool_id].CheckEventLinkAndReport(event_id, creature2event, go2event); + mPoolCreatureGroups[pool_id].CheckEventLinkAndReport(event_id, creature2event, go2event); + mPoolPoolGroups[pool_id].CheckEventLinkAndReport(event_id, creature2event, go2event); +} + +// Method that exclude some elements from next spawn +template<> +void PoolManager::SetExcludeObject(uint16 pool_id, uint32 db_guid_or_pool_id, bool state) +{ + mPoolCreatureGroups[pool_id].SetExcludeObject(db_guid_or_pool_id, state); +} + +template<> +void PoolManager::SetExcludeObject(uint16 pool_id, uint32 db_guid_or_pool_id, bool state) +{ + mPoolGameobjectGroups[pool_id].SetExcludeObject(db_guid_or_pool_id, state); +} + // Call to update the pool when a gameobject/creature part of pool [pool_id] is ready to respawn // Here we cache only the creature/gameobject whose guid is passed as parameter // Then the spawn pool call will use this cache to decide diff --git a/src/game/PoolManager.h b/src/game/PoolManager.h index 5cdeeda7d..278cdd701 100644 --- a/src/game/PoolManager.h +++ b/src/game/PoolManager.h @@ -27,13 +27,19 @@ struct PoolTemplateData { uint32 MaxLimit; + bool AutoSpawn; // spawn at pool system start (not part of another pool and not part of event spawn) }; struct PoolObject { uint32 guid; float chance; - PoolObject(uint32 _guid, float _chance): guid(_guid), chance(fabs(_chance)) {} + bool exclude; + + PoolObject(uint32 _guid, float _chance): guid(_guid), chance(fabs(_chance)), exclude(false) {} + + template + void CheckEventLinkAndReport(uint32 poolId, int16 event_id, std::map const& creature2event, std::map const& go2event) const; }; class Pool // for Pool of Pool case @@ -73,10 +79,12 @@ class PoolGroup bool isEmpty() const { return ExplicitlyChanced.empty() && EqualChanced.empty(); } void AddEntry(PoolObject& poolitem, uint32 maxentries); bool CheckPool() const; + void CheckEventLinkAndReport(int16 event_id, std::map const& creature2event, std::map const& go2event) const; PoolObject* RollOne(SpawnedPoolData& spawns, uint32 triggerFrom); void DespawnObject(SpawnedPoolData& spawns, uint32 guid=0); void Despawn1Object(uint32 guid); void SpawnObject(SpawnedPoolData& spawns, uint32 limit, uint32 triggerFrom, bool instantly); + void SetExcludeObject(uint32 guid, bool state); void Spawn1Object(PoolObject* obj, bool instantly); void ReSpawn1Object(PoolObject* obj); @@ -99,17 +107,37 @@ class PoolManager template uint16 IsPartOfAPool(uint32 db_guid_or_pool_id) const; + // Method that tell if the creature/gameobject/pool is part of top level pool and return the pool id if yes + template + uint16 IsPartOfTopPool(uint32 db_guid_or_pool_id) const + { + if (uint16 pool_id = IsPartOfAPool(db_guid_or_pool_id)) + { + if (uint16 top_pool_id = IsPartOfTopPool(pool_id)) + return top_pool_id; + + return pool_id; + } + + return 0; + } + template bool IsSpawnedObject(uint32 db_guid_or_pool_id) const { return mSpawnedData.IsSpawnedObject(db_guid_or_pool_id); } + template + void SetExcludeObject(uint16 pool_id, uint32 db_guid_or_pool_id, bool state); + bool CheckPool(uint16 pool_id) const; + void CheckEventLinkAndReport(uint16 pool_id, int16 event_id, std::map const& creature2event, std::map const& go2event) const; void SpawnPool(uint16 pool_id, bool instantly); void DespawnPool(uint16 pool_id); template - void UpdatePool(uint16 pool_id, uint32 db_guid_or_pool_id); + void UpdatePool(uint16 pool_id, uint32 db_guid_or_pool_id = 0); + void RemoveAutoSpawnForPool(uint16 pool_id) { mPoolTemplate[pool_id].AutoSpawn = false; } protected: template void SpawnPoolGroup(uint16 pool_id, uint32 db_guid_or_pool_id, bool instantly); diff --git a/src/game/Spell.cpp b/src/game/Spell.cpp index 6597d88e4..3a8abf1be 100644 --- a/src/game/Spell.cpp +++ b/src/game/Spell.cpp @@ -4253,21 +4253,11 @@ SpellCastResult Spell::CheckCast(bool strict) // auto selection spell rank implemented in WorldSession::HandleCastSpellOpcode // this case can be triggered if rank not found (too low-level target for first rank) - if (m_caster->GetTypeId() == TYPEID_PLAYER && !IsPassiveSpell(m_spellInfo->Id) && !m_CastItem) + if (m_caster->GetTypeId() == TYPEID_PLAYER && !m_CastItem && !m_IsTriggeredSpell) { - for(int i = 0; i < MAX_EFFECT_INDEX; ++i) - { - // check only spell that apply positive auras - if (m_spellInfo->Effect[i] == SPELL_EFFECT_APPLY_AURA && - IsPositiveEffect(m_spellInfo->Id, SpellEffectIndex(i)) && - // at not self target - !IsCasterSourceTarget(m_spellInfo->EffectImplicitTargetA[i]) && - // and target low level - target->getLevel() + 10 < m_spellInfo->spellLevel) - { - return SPELL_FAILED_LOWLEVEL; - } - } + // spell expected to be auto-downranking in cast handle, so must be same + if (m_spellInfo != sSpellMgr.SelectAuraRankForLevel(m_spellInfo, target->getLevel())) + return SPELL_FAILED_LOWLEVEL; } } else if (m_caster == target) @@ -4448,7 +4438,7 @@ SpellCastResult Spell::CheckCast(bool strict) // not let players cast spells at mount (and let do it to creatures) if (m_caster->IsMounted() && m_caster->GetTypeId()==TYPEID_PLAYER && !m_IsTriggeredSpell && - !IsPassiveSpell(m_spellInfo->Id) && !(m_spellInfo->Attributes & SPELL_ATTR_CASTABLE_WHILE_MOUNTED)) + !IsPassiveSpell(m_spellInfo) && !(m_spellInfo->Attributes & SPELL_ATTR_CASTABLE_WHILE_MOUNTED)) { if (m_caster->isInFlight()) return SPELL_FAILED_NOT_ON_TAXI; @@ -4457,7 +4447,7 @@ SpellCastResult Spell::CheckCast(bool strict) } // always (except passive spells) check items (focus object can be required for any type casts) - if (!IsPassiveSpell(m_spellInfo->Id)) + if (!IsPassiveSpell(m_spellInfo)) { SpellCastResult castResult = CheckItems(); if(castResult != SPELL_CAST_OK) diff --git a/src/game/Spell.h b/src/game/Spell.h index cea75be8b..27aaf4dd8 100644 --- a/src/game/Spell.h +++ b/src/game/Spell.h @@ -23,11 +23,14 @@ #include "SharedDefines.h" #include "DBCEnums.h" #include "ObjectGuid.h" +#include "LootMgr.h" +#include "Unit.h" +#include "Player.h" class WorldSession; -class Unit; +class WorldPacket; class DynamicObj; -class Player; +class Item; class GameObject; class Group; class Aura; @@ -808,6 +811,7 @@ namespace MaNGOS template<> inline void Visit(CorpseMapType & ) {} template<> inline void Visit(GameObjectMapType & ) {} template<> inline void Visit(DynamicObjectMapType & ) {} + template<> inline void Visit(CameraMapType & ) {} #endif }; @@ -815,6 +819,7 @@ namespace MaNGOS template<> inline void SpellNotifierCreatureAndPlayer::Visit(CorpseMapType& ) {} template<> inline void SpellNotifierCreatureAndPlayer::Visit(GameObjectMapType& ) {} template<> inline void SpellNotifierCreatureAndPlayer::Visit(DynamicObjectMapType& ) {} + template<> inline void SpellNotifierCreatureAndPlayer::Visit(CameraMapType& ) {} #endif } diff --git a/src/game/SpellAuras.cpp b/src/game/SpellAuras.cpp index f6badb486..263e473b3 100644 --- a/src/game/SpellAuras.cpp +++ b/src/game/SpellAuras.cpp @@ -386,7 +386,7 @@ m_isRemovedOnShapeLost(true), m_in_use(0), m_deleted(false) m_currentBasePoints = currentBasePoints ? *currentBasePoints : m_spellProto->CalculateSimpleValue(eff); - m_isPassive = IsPassiveSpell(GetId()); + m_isPassive = IsPassiveSpell(GetSpellProto()); m_positive = IsPositiveEffect(GetId(), m_effIndex); m_isSingleTargetAura = IsSingleTargetSpell(m_spellProto); @@ -633,7 +633,7 @@ void Aura::Update(uint32 diff) Unit* caster = GetCaster(); if(!caster) { - m_target->RemoveAura(GetId(), GetEffIndex()); + m_target->RemoveAurasByCasterSpell(GetId(), GetEffIndex(), GetCasterGUID()); return; } @@ -648,7 +648,7 @@ void Aura::Update(uint32 diff) if(!caster->IsWithinDistInMap(m_target, max_range)) { - m_target->RemoveAura(GetId(), GetEffIndex()); + m_target->RemoveAurasByCasterSpell(GetId(), GetEffIndex(), GetCasterGUID()); return; } } @@ -813,7 +813,7 @@ void AreaAura::Update(uint32 diff) if(!apply) continue; - if(SpellEntry const *actualSpellInfo = sSpellMgr.SelectAuraRankForPlayerLevel(GetSpellProto(), (*tIter)->getLevel())) + if(SpellEntry const *actualSpellInfo = sSpellMgr.SelectAuraRankForLevel(GetSpellProto(), (*tIter)->getLevel())) { int32 actualBasePoints = m_currentBasePoints; // recalculate basepoints for lower rank (all AreaAura spell not use custom basepoints?) @@ -2380,7 +2380,7 @@ void Aura::HandleAuraDummy(bool apply, bool Real) (GetSpellProto()->EffectApplyAuraName[EFFECT_INDEX_0] == 1 || GetSpellProto()->EffectApplyAuraName[EFFECT_INDEX_0] == 128))) { // spells with SpellEffect=72 and aura=4: 6196, 6197, 21171, 21425 - ((Player*)target)->SetFarSightGUID(0); + ((Player*)target)->GetCamera().ResetView(); WorldPacket data(SMSG_CLEAR_FAR_SIGHT_IMMEDIATE, 0); ((Player*)target)->GetSession()->SendPacket(&data); return; @@ -3543,7 +3543,11 @@ void Aura::HandleBindSight(bool apply, bool /*Real*/) if(!caster || caster->GetTypeId() != TYPEID_PLAYER) return; - ((Player*)caster)->SetFarSightGUID(apply ? GetTarget()->GetGUID() : 0); + Camera& camera = ((Player*)caster)->GetCamera(); + if (apply) + camera.SetView(m_target); + else + camera.ResetView(); } void Aura::HandleFarSight(bool apply, bool /*Real*/) @@ -3552,7 +3556,11 @@ void Aura::HandleFarSight(bool apply, bool /*Real*/) if(!caster || caster->GetTypeId() != TYPEID_PLAYER) return; - ((Player*)caster)->SetFarSightGUID(apply ? GetTarget()->GetGUID() : 0); + Camera& camera = ((Player*)caster)->GetCamera(); + if (apply) + camera.SetView(GetTarget()); + else + camera.ResetView(); } void Aura::HandleAuraTrackCreatures(bool apply, bool /*Real*/) @@ -3607,10 +3615,12 @@ void Aura::HandleModPossess(bool apply, bool Real) return; Player* p_caster = (Player*)caster; - + Camera& camera = p_caster->GetCamera(); if( apply ) { + target->addUnitState(UNIT_STAT_CONTROLLED); + target->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED); target->SetCharmerGUID(p_caster->GetGUID()); @@ -3618,35 +3628,39 @@ void Aura::HandleModPossess(bool apply, bool Real) p_caster->SetCharm(target); - p_caster->SetFarSightGUID(target->GetGUID()); + camera.SetView(target); p_caster->SetClientControl(target, 1); p_caster->SetMover(target); - target->CombatStop(); + target->CombatStop(true); target->DeleteThreatList(); + target->getHostileRefManager().deleteReferences(); + + if(CharmInfo *charmInfo = target->InitCharmInfo(target)) + { + charmInfo->InitPossessCreateSpells(); + charmInfo->SetReactState(REACT_PASSIVE); + charmInfo->SetCommandState(COMMAND_STAY); + } + + p_caster->PossessSpellInitialize(); if(target->GetTypeId() == TYPEID_UNIT) { - target->StopMoving(); - target->GetMotionMaster()->Clear(); - target->GetMotionMaster()->MoveIdle(); + ((Creature*)target)->AIM_Initialize(); } else if(target->GetTypeId() == TYPEID_PLAYER) { ((Player*)target)->SetClientControl(target, 0); } - if(CharmInfo *charmInfo = target->InitCharmInfo(target)) - charmInfo->InitPossessCreateSpells(); - - p_caster->PossessSpellInitialize(); } else { p_caster->InterruptSpell(CURRENT_CHANNELED_SPELL); // the spell is not automatically canceled when interrupted, do it now p_caster->SetCharm(NULL); - p_caster->SetFarSightGUID(0); + camera.ResetView(); p_caster->SetClientControl(target, 0); p_caster->SetMover(NULL); @@ -3656,6 +3670,12 @@ void Aura::HandleModPossess(bool apply, bool Real) if(m_removeMode == AURA_REMOVE_BY_DELETE) return; + target->clearUnitState(UNIT_STAT_CONTROLLED); + + target->CombatStop(true); + target->DeleteThreatList(); + target->getHostileRefManager().deleteReferences(); + target->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED); target->SetCharmerGUID(0); @@ -3690,30 +3710,40 @@ void Aura::HandleModPossessPet(bool apply, bool Real) if(!caster || caster->GetTypeId() != TYPEID_PLAYER) return; - Pet *pet = caster->GetPet(); - if(!pet || pet != GetTarget()) + Unit* target = GetTarget(); + if (target->GetTypeId() != TYPEID_UNIT) return; + Creature* pet = (Creature*)target; // not need more stricted type check Player* p_caster = (Player*)caster; + Camera& camera = p_caster->GetCamera(); - if(apply) - pet->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED); - else - pet->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED); - - p_caster->SetFarSightGUID(apply ? pet->GetGUID() : 0); - p_caster->SetCharm(apply ? pet : NULL); - p_caster->SetClientControl(pet, apply ? 1 : 0); - ((Player*)caster)->SetMover(apply ? pet : NULL); - - if(apply) + if (apply) { + camera.SetView(pet); + p_caster->SetCharm(pet); + p_caster->SetClientControl(pet, 1); + ((Player*)caster)->SetMover(pet); + + pet->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED); + pet->StopMoving(); - pet->GetMotionMaster()->Clear(); + pet->GetMotionMaster()->Clear(false); pet->GetMotionMaster()->MoveIdle(); } else { + camera.ResetView(); + p_caster->SetCharm(NULL); + p_caster->SetClientControl(pet, 0); + p_caster->SetMover(NULL); + + // on delete only do caster related effects + if(m_removeMode == AURA_REMOVE_BY_DELETE) + return; + + pet->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED); + pet->AttackStop(); pet->GetMotionMaster()->MoveFollow(caster, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE); pet->AddSplineFlag(SPLINEFLAG_WALKMODE); @@ -3758,8 +3788,9 @@ void Aura::HandleModCharm(bool apply, bool Real) target->CastStop(target == caster ? GetId() : 0); caster->SetCharm(target); - target->CombatStop(); + target->CombatStop(true); target->DeleteThreatList(); + target->getHostileRefManager().deleteReferences(); if(target->GetTypeId() == TYPEID_UNIT) { @@ -3834,6 +3865,10 @@ void Aura::HandleModCharm(bool apply, bool Real) if(caster->GetTypeId() == TYPEID_PLAYER) ((Player*)caster)->RemovePetActionBar(); + target->CombatStop(true); + target->DeleteThreatList(); + target->getHostileRefManager().deleteReferences(); + if(target->GetTypeId() == TYPEID_UNIT) { ((Creature*)target)->AIM_Initialize(); @@ -4182,7 +4217,7 @@ void Aura::HandleInvisibilityDetect(bool apply, bool Real) target->m_detectInvisibilityMask |= (1 << m_modifier.m_miscvalue); } if(Real && target->GetTypeId()==TYPEID_PLAYER) - ((Player*)target)->UpdateVisibilityForPlayer(); + ((Player*)target)->GetCamera().UpdateVisibilityForOwner(); } void Aura::HandleAuraModRoot(bool apply, bool Real) @@ -4924,16 +4959,6 @@ void Aura::HandlePeriodicDamage(bool apply, bool Real) } break; } - case SPELLFAMILY_WARLOCK: - { - // Drain Soul - if (spellProto->SpellFamilyFlags & UI64LIT(0x0000000000004000)) - { - if (target->GetHealth() * 100 / target->GetMaxHealth() <= 25) - m_modifier.m_amount *= 4; - } - break; - } case SPELLFAMILY_DRUID: { // Rake @@ -8241,9 +8266,13 @@ void Aura::HandleAuraControlVehicle(bool apply, bool Real) if(!Real) return; + Unit* target = GetTarget(); + if (target->GetTypeId() != TYPEID_UNIT || !((Creature*)target)->isVehicle()) + return; + Vehicle* vehicle = (Vehicle*)target; + Unit *player = GetCaster(); - Vehicle *vehicle = dynamic_cast(GetTarget()); - if(!player || player->GetTypeId() != TYPEID_PLAYER || !vehicle) + if(!player || player->GetTypeId() != TYPEID_PLAYER) return; if (apply) diff --git a/src/game/SpellEffects.cpp b/src/game/SpellEffects.cpp index f0c6fcf44..d8f6aac3a 100644 --- a/src/game/SpellEffects.cpp +++ b/src/game/SpellEffects.cpp @@ -4244,7 +4244,8 @@ void Spell::EffectAddFarsight(SpellEffectIndex eff_idx) dynObj->SetUInt32Value(DYNAMICOBJECT_BYTES, 0x80000002); m_caster->AddDynObject(dynObj); m_caster->GetMap()->Add(dynObj); - ((Player*)m_caster)->SetFarSightGUID(dynObj->GetGUID()); + + ((Player*)m_caster)->GetCamera().SetView(dynObj); } void Spell::DoSummonWild(SpellEffectIndex eff_idx, uint32 forceFaction) diff --git a/src/game/SpellHandler.cpp b/src/game/SpellHandler.cpp index 86ca9c7ba..4a901c579 100644 --- a/src/game/SpellHandler.cpp +++ b/src/game/SpellHandler.cpp @@ -31,13 +31,6 @@ void WorldSession::HandleUseItemOpcode(WorldPacket& recvPacket) { - // TODO: add targets.read() check - Player* pUser = _player; - - // ignore for remote control state - if(pUser->m_mover != pUser) - return; - uint8 bagIndex, slot; uint8 unk_flags; // flags (if 0x02 - some additional data are received) uint8 cast_count; // next cast if exists (single or not) @@ -47,9 +40,20 @@ void WorldSession::HandleUseItemOpcode(WorldPacket& recvPacket) recvPacket >> bagIndex >> slot >> cast_count >> spellid >> item_guid >> glyphIndex >> unk_flags; + // TODO: add targets.read() check + Player* pUser = _player; + + // ignore for remote control state + if (!pUser->IsSelfMover()) + { + recvPacket.rpos(recvPacket.wpos()); // prevent spam at not read packet tail + return; + } + // reject fake data if (glyphIndex >= MAX_GLYPH_SLOT_INDEX) { + recvPacket.rpos(recvPacket.wpos()); // prevent spam at not read packet tail pUser->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL ); return; } @@ -57,12 +61,14 @@ void WorldSession::HandleUseItemOpcode(WorldPacket& recvPacket) Item *pItem = pUser->GetItemByPos(bagIndex, slot); if (!pItem) { + recvPacket.rpos(recvPacket.wpos()); // prevent spam at not read packet tail pUser->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL ); return; } if (pItem->GetGUID() != item_guid) { + recvPacket.rpos(recvPacket.wpos()); // prevent spam at not read packet tail pUser->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL ); return; } @@ -72,6 +78,7 @@ void WorldSession::HandleUseItemOpcode(WorldPacket& recvPacket) ItemPrototype const *proto = pItem->GetProto(); if (!proto) { + recvPacket.rpos(recvPacket.wpos()); // prevent spam at not read packet tail pUser->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, pItem, NULL ); return; } @@ -79,6 +86,7 @@ void WorldSession::HandleUseItemOpcode(WorldPacket& recvPacket) // some item classes can be used only in equipped state if (proto->InventoryType != INVTYPE_NON_EQUIP && !pItem->IsEquipped()) { + recvPacket.rpos(recvPacket.wpos()); // prevent spam at not read packet tail pUser->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, pItem, NULL ); return; } @@ -86,6 +94,7 @@ void WorldSession::HandleUseItemOpcode(WorldPacket& recvPacket) uint8 msg = pUser->CanUseItem(pItem); if (msg != EQUIP_ERR_OK) { + recvPacket.rpos(recvPacket.wpos()); // prevent spam at not read packet tail pUser->SendEquipError( msg, pItem, NULL ); return; } @@ -95,6 +104,7 @@ void WorldSession::HandleUseItemOpcode(WorldPacket& recvPacket) !(proto->Flags & ITEM_FLAGS_USEABLE_IN_ARENA) && pUser->InArena()) { + recvPacket.rpos(recvPacket.wpos()); // prevent spam at not read packet tail pUser->SendEquipError(EQUIP_ERR_NOT_DURING_ARENA_MATCH,pItem,NULL); return; } @@ -107,6 +117,7 @@ void WorldSession::HandleUseItemOpcode(WorldPacket& recvPacket) { if (IsNonCombatSpell(spellInfo)) { + recvPacket.rpos(recvPacket.wpos()); // prevent spam at not read packet tail pUser->SendEquipError(EQUIP_ERR_NOT_IN_COMBAT,pItem,NULL); return; } @@ -116,6 +127,7 @@ void WorldSession::HandleUseItemOpcode(WorldPacket& recvPacket) // Prevent potion drink if another potion in processing (client have potions disabled in like case) if (pItem->IsPotion() && pUser->GetLastPotionId()) { + recvPacket.rpos(recvPacket.wpos()); // prevent spam at not read packet tail pUser->SendEquipError(EQUIP_ERR_OBJECT_IS_BUSY,pItem,NULL); return; } @@ -174,18 +186,18 @@ void WorldSession::HandleOpenItemOpcode(WorldPacket& recvPacket) { DETAIL_LOG("WORLD: CMSG_OPEN_ITEM packet, data length = %i",(uint32)recvPacket.size()); - Player* pUser = _player; - - // ignore for remote control state - if(pUser->m_mover != pUser) - return; - uint8 bagIndex, slot; recvPacket >> bagIndex >> slot; DETAIL_LOG("bagIndex: %u, slot: %u",bagIndex,slot); + Player* pUser = _player; + + // ignore for remote control state + if (!pUser->IsSelfMover()) + return; + Item *pItem = pUser->GetItemByPos(bagIndex, slot); if(!pItem) { @@ -257,7 +269,7 @@ void WorldSession::HandleGameObjectUseOpcode( WorldPacket & recv_data ) DEBUG_LOG( "WORLD: Recvd CMSG_GAMEOBJ_USE Message [guid=%u]", GUID_LOPART(guid)); // ignore for remote control state - if(_player->m_mover != _player) + if (!_player->IsSelfMover()) return; GameObject *obj = GetPlayer()->GetMap()->GetGameObject(guid); @@ -276,7 +288,7 @@ void WorldSession::HandleGameobjectReportUse(WorldPacket& recvPacket) DEBUG_LOG( "WORLD: Recvd CMSG_GAMEOBJ_REPORT_USE Message [in game guid: %u]", GUID_LOPART(guid)); // ignore for remote control state - if(_player->m_mover != _player) + if (!_player->IsSelfMover()) return; GameObject* go = GetPlayer()->GetMap()->GetGameObject(guid); @@ -298,8 +310,8 @@ void WorldSession::HandleCastSpellOpcode(WorldPacket& recvPacket) recvPacket >> unk_flags; // flags (if 0x02 - some additional data are received) // ignore for remote control state (for player case) - Unit* mover = _player->m_mover; - if(mover != _player && mover->GetTypeId()==TYPEID_PLAYER) + Unit* mover = _player->GetMover(); + if (mover != _player && mover->GetTypeId()==TYPEID_PLAYER) { recvPacket.rpos(recvPacket.wpos()); // prevent spam at ignore packet return; @@ -317,10 +329,10 @@ void WorldSession::HandleCastSpellOpcode(WorldPacket& recvPacket) return; } - if(mover->GetTypeId()==TYPEID_PLAYER) + if (mover->GetTypeId()==TYPEID_PLAYER) { // not have spell in spellbook or spell passive and not casted by client - if (!((Player*)mover)->HasActiveSpell (spellId) || IsPassiveSpell(spellId) ) + if (!((Player*)mover)->HasActiveSpell (spellId) || IsPassiveSpell(spellInfo)) { sLog.outError("World: Player %u casts spell %u which he shouldn't have", mover->GetGUIDLow(), spellId); //cheater? kick? ban? @@ -331,7 +343,7 @@ void WorldSession::HandleCastSpellOpcode(WorldPacket& recvPacket) else { // not have spell in spellbook or spell passive and not casted by client - if (!((Creature*)mover)->HasSpell(spellId) || IsPassiveSpell(spellId) ) + if (!((Creature*)mover)->HasSpell(spellId) || IsPassiveSpell(spellInfo)) { //cheater? kick? ban? recvPacket.rpos(recvPacket.wpos()); // prevent spam at ignore packet @@ -364,12 +376,10 @@ void WorldSession::HandleCastSpellOpcode(WorldPacket& recvPacket) } // auto-selection buff level base at target level (in spellInfo) - if(targets.getUnitTarget()) + if (Unit* target = targets.getUnitTarget()) { - SpellEntry const *actualSpellInfo = sSpellMgr.SelectAuraRankForPlayerLevel(spellInfo,targets.getUnitTarget()->getLevel()); - // if rank not found then function return NULL but in explicit cast case original spell can be casted and later failed with appropriate error message - if(actualSpellInfo) + if (SpellEntry const *actualSpellInfo = sSpellMgr.SelectAuraRankForLevel(spellInfo, target->getLevel())) spellInfo = actualSpellInfo; } @@ -380,16 +390,16 @@ void WorldSession::HandleCastSpellOpcode(WorldPacket& recvPacket) void WorldSession::HandleCancelCastOpcode(WorldPacket& recvPacket) { - // ignore for remote control state (for player case) - Unit* mover = _player->m_mover; - if(mover != _player && mover->GetTypeId()==TYPEID_PLAYER) - return; - uint32 spellId; recvPacket.read_skip(); // counter, increments with every CANCEL packet, don't use for now recvPacket >> spellId; + // ignore for remote control state (for player case) + Unit* mover = _player->GetMover(); + if (mover != _player && mover->GetTypeId()==TYPEID_PLAYER) + return; + //FIXME: hack, ignore unexpected client cancel Deadly Throw cast if(spellId==26679) return; @@ -410,10 +420,13 @@ void WorldSession::HandleCancelAuraOpcode( WorldPacket& recvPacket) if (spellInfo->Attributes & SPELL_ATTR_CANT_CANCEL) return; - if(!IsPositiveSpell(spellId)) + if (IsPassiveSpell(spellInfo)) + return; + + if (!IsPositiveSpell(spellId)) { // ignore for remote control state - if (_player->m_mover != _player) + if (!_player->IsSelfMover()) { // except own aura spells bool allow = false; @@ -450,16 +463,16 @@ void WorldSession::HandleCancelAuraOpcode( WorldPacket& recvPacket) void WorldSession::HandlePetCancelAuraOpcode( WorldPacket& recvPacket) { - // ignore for remote control state - if(_player->m_mover != _player) - return; - uint64 guid; uint32 spellId; recvPacket >> guid; recvPacket >> spellId; + // ignore for remote control state + if (!_player->IsSelfMover()) + return; + SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId ); if(!spellInfo) { @@ -501,7 +514,7 @@ void WorldSession::HandleCancelAutoRepeatSpellOpcode( WorldPacket& /*recvPacket* { // cancel and prepare for deleting // do not send SMSG_CANCEL_AUTO_REPEAT! client will send this Opcode again (loop) - _player->m_mover->InterruptSpell(CURRENT_AUTOREPEAT_SPELL, true, false); + _player->GetMover()->InterruptSpell(CURRENT_AUTOREPEAT_SPELL, true, false); } void WorldSession::HandleCancelChanneling( WorldPacket & recv_data) @@ -509,8 +522,8 @@ void WorldSession::HandleCancelChanneling( WorldPacket & recv_data) recv_data.read_skip(); // spellid, not used // ignore for remote control state (for player case) - Unit* mover = _player->m_mover; - if(mover != _player && mover->GetTypeId()==TYPEID_PLAYER) + Unit* mover = _player->GetMover(); + if (mover != _player && mover->GetTypeId()==TYPEID_PLAYER) return; mover->InterruptSpell(CURRENT_CHANNELED_SPELL); @@ -518,14 +531,14 @@ void WorldSession::HandleCancelChanneling( WorldPacket & recv_data) void WorldSession::HandleTotemDestroyed( WorldPacket& recvPacket) { - // ignore for remote control state - if(_player->m_mover != _player) - return; - uint8 slotId; recvPacket >> slotId; + // ignore for remote control state + if (!_player->IsSelfMover()) + return; + if (int(slotId) >= MAX_TOTEM_SLOT) return; diff --git a/src/game/SpellMgr.cpp b/src/game/SpellMgr.cpp index a4c9651ae..008c21cde 100644 --- a/src/game/SpellMgr.cpp +++ b/src/game/SpellMgr.cpp @@ -283,6 +283,11 @@ bool IsPassiveSpell(uint32 spellId) SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId); if (!spellInfo) return false; + return IsPassiveSpell(spellInfo); +} + +bool IsPassiveSpell(SpellEntry const *spellInfo) +{ return (spellInfo->Attributes & SPELL_ATTR_PASSIVE) != 0; } @@ -1607,7 +1612,7 @@ bool SpellMgr::IsRankSpellDueToSpell(SpellEntry const *spellInfo_1,uint32 spellI bool SpellMgr::canStackSpellRanks(SpellEntry const *spellInfo) { - if(IsPassiveSpell(spellInfo->Id)) // ranked passive spell + if(IsPassiveSpell(spellInfo)) // ranked passive spell return false; if(spellInfo->powerType != POWER_MANA && spellInfo->powerType != POWER_HEALTH) return false; @@ -2211,37 +2216,44 @@ bool SpellMgr::IsSkillBonusSpell(uint32 spellId) const return false; } -SpellEntry const* SpellMgr::SelectAuraRankForPlayerLevel(SpellEntry const* spellInfo, uint32 playerLevel) const +SpellEntry const* SpellMgr::SelectAuraRankForLevel(SpellEntry const* spellInfo, uint32 level) const { - // ignore passive spells - if(IsPassiveSpell(spellInfo->Id)) + // fast case + if (level + 10 >= spellInfo->spellLevel) + return spellInfo; + + // ignore selection for passive spells + if (IsPassiveSpell(spellInfo)) return spellInfo; bool needRankSelection = false; for(int i = 0; i < MAX_EFFECT_INDEX; ++i) { - if (IsPositiveEffect(spellInfo->Id, SpellEffectIndex(i)) && ( - spellInfo->Effect[i] == SPELL_EFFECT_APPLY_AURA || + // for simple aura in check apply to any non caster based targets, in rank search mode to any explicit targets + if (((spellInfo->Effect[i] == SPELL_EFFECT_APPLY_AURA && + (IsExplicitPositiveTarget(spellInfo->EffectImplicitTargetA[i]) || + IsAreaEffectPossitiveTarget(Targets(spellInfo->EffectImplicitTargetA[i])))) || spellInfo->Effect[i] == SPELL_EFFECT_APPLY_AREA_AURA_PARTY || - spellInfo->Effect[i] == SPELL_EFFECT_APPLY_AREA_AURA_RAID)) + spellInfo->Effect[i] == SPELL_EFFECT_APPLY_AREA_AURA_RAID) && + IsPositiveEffect(spellInfo->Id, SpellEffectIndex(i))) { needRankSelection = true; break; } } - // not required - if(!needRankSelection) + // not required (rank check more slow so check it here) + if (!needRankSelection || GetSpellRank(spellInfo->Id) == 0) return spellInfo; for(uint32 nextSpellId = spellInfo->Id; nextSpellId != 0; nextSpellId = GetPrevSpellInChain(nextSpellId)) { SpellEntry const *nextSpellInfo = sSpellStore.LookupEntry(nextSpellId); - if(!nextSpellInfo) + if (!nextSpellInfo) break; // if found appropriate level - if(playerLevel + 10 >= nextSpellInfo->spellLevel) + if (level + 10 >= spellInfo->spellLevel) return nextSpellInfo; // one rank less then @@ -2588,7 +2600,7 @@ void SpellMgr::LoadSpellLearnSpells() // talent or passive spells or skill-step spells auto-casted and not need dependent learning, // pet teaching spells don't must be dependent learning (casted) // other required explicit dependent learning - dbc_node.autoLearned = entry->EffectImplicitTargetA[i]==TARGET_PET || GetTalentSpellCost(spell) > 0 || IsPassiveSpell(spell) || IsSpellHaveEffect(entry,SPELL_EFFECT_SKILL_STEP); + dbc_node.autoLearned = entry->EffectImplicitTargetA[i]==TARGET_PET || GetTalentSpellCost(spell) > 0 || IsPassiveSpell(entry) || IsSpellHaveEffect(entry,SPELL_EFFECT_SKILL_STEP); SpellLearnSpellMapBounds db_node_bounds = GetSpellLearnSpellMapBounds(spell); @@ -3974,4 +3986,4 @@ SpellEntry const* GetSpellEntryByDifficulty(uint32 id, Difficulty difficulty) SpellEntry const* spellEntry = sSpellStore.LookupEntry(spellDiff->spellId[difficulty]); return spellEntry; -} +} \ No newline at end of file diff --git a/src/game/SpellMgr.h b/src/game/SpellMgr.h index 0108e78d3..6c5b5508a 100644 --- a/src/game/SpellMgr.h +++ b/src/game/SpellMgr.h @@ -210,10 +210,11 @@ bool IsSingleFromSpellSpecificSpellRanksPerTarget(SpellSpecific spellSpec1,Spell bool IsSingleFromSpellSpecificPerTarget(SpellSpecific spellSpec1,SpellSpecific spellSpec2); bool IsPassiveSpell(uint32 spellId); +bool IsPassiveSpell(SpellEntry const* spellProto); inline bool IsPassiveSpellStackableWithRanks(SpellEntry const* spellProto) { - if(!IsPassiveSpell(spellProto->Id)) + if(!IsPassiveSpell(spellProto)) return false; return !IsSpellHaveEffect(spellProto,SPELL_EFFECT_APPLY_AURA); @@ -319,6 +320,25 @@ inline bool IsPointEffectTarget( Targets target ) return false; } +inline bool IsAreaEffectPossitiveTarget( Targets target ) +{ + switch (target ) + { + case TARGET_ALL_PARTY_AROUND_CASTER: + case TARGET_ALL_FRIENDLY_UNITS_AROUND_CASTER: + case TARGET_ALL_FRIENDLY_UNITS_IN_AREA: + case TARGET_ALL_PARTY: + case TARGET_ALL_PARTY_AROUND_CASTER_2: + case TARGET_AREAEFFECT_PARTY: + case TARGET_ALL_RAID_AROUND_CASTER: + case TARGET_AREAEFFECT_PARTY_AND_CLASS: + return true; + default: + break; + } + return false; +} + inline bool IsAreaEffectTarget( Targets target ) { switch (target ) @@ -371,12 +391,9 @@ inline bool IsAreaAuraEffect(uint32 effect) inline bool IsDispelSpell(SpellEntry const *spellInfo) { - if (spellInfo->Effect[EFFECT_INDEX_0] == SPELL_EFFECT_DISPEL || - spellInfo->Effect[EFFECT_INDEX_1] == SPELL_EFFECT_DISPEL || - spellInfo->Effect[EFFECT_INDEX_2] == SPELL_EFFECT_DISPEL ) - return true; - return false; + return IsSpellHaveEffect(spellInfo, SPELL_EFFECT_DISPEL); } + inline bool isSpellBreakStealth(SpellEntry const* spellInfo) { return !(spellInfo->AttributesEx & SPELL_ATTR_EX_NOT_BREAK_STEALTH); @@ -906,7 +923,7 @@ class SpellMgr static bool canStackSpellRanks(SpellEntry const *spellInfo); bool IsNoStackSpellDueToSpell(uint32 spellId_1, uint32 spellId_2) const; - SpellEntry const* SelectAuraRankForPlayerLevel(SpellEntry const* spellInfo, uint32 playerLevel) const; + SpellEntry const* SelectAuraRankForLevel(SpellEntry const* spellInfo, uint32 Level) const; // Spell learning SpellLearnSkillNode const* GetSpellLearnSkill(uint32 spell_id) const @@ -1064,4 +1081,4 @@ class SpellMgr }; #define sSpellMgr SpellMgr::Instance() -#endif +#endif \ No newline at end of file diff --git a/src/game/TargetedMovementGenerator.cpp b/src/game/TargetedMovementGenerator.cpp index b59e6c8f1..efc52bfc8 100644 --- a/src/game/TargetedMovementGenerator.cpp +++ b/src/game/TargetedMovementGenerator.cpp @@ -37,12 +37,17 @@ void TargetedMovementGeneratorMedium::_setTargetLocation(T &owner) if (owner.hasUnitState(UNIT_STAT_NOT_MOVE)) return; + float x, y, z; + // prevent redundant micro-movement for pets, other followers. if (i_offset && i_target->IsWithinDistInMap(&owner,2*i_offset)) - return; + { + if (i_destinationHolder.HasDestination()) + return; - float x, y, z; - if (!i_offset) + owner.GetPosition(x, y, z); + } + else if (!i_offset) { // to nearest contact position i_target->GetContactPoint( &owner, x, y, z ); diff --git a/src/game/Traveller.h b/src/game/Traveller.h index dd5fad5a0..d854f3294 100644 --- a/src/game/Traveller.h +++ b/src/game/Traveller.h @@ -55,6 +55,7 @@ struct MANGOS_DLL_DECL Traveller void Relocation(float x, float y, float z, float orientation) {} void Relocation(float x, float y, float z) { Relocation(x, y, z, i_traveller.GetOrientation()); } void MoveTo(float x, float y, float z, uint32 t) {} + void Stop() {} }; template @@ -102,7 +103,13 @@ inline float Traveller::GetMoveDestinationTo(float x, float y, float z template<> inline void Traveller::MoveTo(float x, float y, float z, uint32 t) { - i_traveller.AI_SendMoveToPacket(x, y, z, t, i_traveller.GetSplineFlags(), SPLINETYPE_NORMAL); + i_traveller.SendMonsterMove(x, y, z, SPLINETYPE_NORMAL, i_traveller.GetSplineFlags(), t); +} + +template<> +inline void Traveller::Stop() +{ + i_traveller.SendMonsterMove(i_traveller.GetPositionX(), i_traveller.GetPositionY(), i_traveller.GetPositionZ(), SPLINETYPE_STOP, i_traveller.GetSplineFlags(), 0); } // specialization for players @@ -141,6 +148,13 @@ inline void Traveller::MoveTo(float x, float y, float z, uint32 t) i_traveller.SendMonsterMove(x, y, z, SPLINETYPE_NORMAL, SPLINEFLAG_WALKMODE, t); } +template<> +inline void Traveller::Stop() +{ + //Only send SPLINEFLAG_WALKMODE, client has strange issues with other move flags + i_traveller.SendMonsterMove(i_traveller.GetPositionX(), i_traveller.GetPositionY(), i_traveller.GetPositionZ(), SPLINETYPE_STOP, SPLINEFLAG_WALKMODE, 0); +} + typedef Traveller CreatureTraveller; typedef Traveller PlayerTraveller; #endif diff --git a/src/game/Unit.cpp b/src/game/Unit.cpp index ae03a34e5..a280dd8d6 100644 --- a/src/game/Unit.cpp +++ b/src/game/Unit.cpp @@ -382,12 +382,7 @@ void Unit::SendMonsterMove(float NewPosX, float NewPosY, float NewPosZ, SplineTy break; } - data << uint32(flags); - - // enable me if things goes wrong or looks ugly, it is however an old hack - // if(flags & SPLINEFLAG_WALKMODE) - // moveTime *= 1.05f; - + data << uint32(flags); // splineflags data << uint32(moveTime); // Time in between points data << uint32(1); // 1 single waypoint data << NewPosX << NewPosY << NewPosZ; // the single waypoint Point B @@ -4011,7 +4006,7 @@ bool Unit::RemoveNoStackAurasDueToAura(Aura *Aur) SpellEffectIndex effIndex = Aur->GetEffIndex(); // passive spell special case (only non stackable with ranks) - if(IsPassiveSpell(spellId)) + if(IsPassiveSpell(spellProto)) { if(IsPassiveSpellStackableWithRanks(spellProto)) return true; @@ -4034,7 +4029,7 @@ bool Unit::RemoveNoStackAurasDueToAura(Aura *Aur) uint32 i_spellId = i_spellProto->Id; // early checks that spellId is passive non stackable spell - if(IsPassiveSpell(i_spellId)) + if(IsPassiveSpell(i_spellProto)) { // passive non-stackable spells not stackable only for same caster if(Aur->GetCasterGUID()!=i->second->GetCasterGUID()) @@ -4516,7 +4511,20 @@ void Unit::RemoveAura(AuraMap::iterator &i, AuraRemoveMode mode) DEBUG_FILTER_LOG(LOG_FILTER_SPELL_CAST, "Aura %u now is remove mode %d",Aur->GetModifier()->m_auraname, mode); // some auras also need to apply modifier (on caster) on remove - if (mode != AURA_REMOVE_BY_DELETE || Aur->GetModifier()->m_auraname == SPELL_AURA_MOD_POSSESS) + if (mode == AURA_REMOVE_BY_DELETE) + { + switch (Aur->GetModifier()->m_auraname) + { + // need properly undo any auras with player-caster mover set (or will crash at next caster move packet) + case SPELL_AURA_MOD_POSSESS: + case SPELL_AURA_MOD_POSSESS_PET: + case SPELL_AURA_CONTROL_VEHICLE: + Aur->ApplyModifier(false,true); + break; + default: break; + } + } + else Aur->ApplyModifier(false,true); if (Aur->_RemoveAura()) @@ -8549,7 +8557,7 @@ void Unit::CombatStopWithPets(bool includingCast) struct IsAttackingPlayerHelper { explicit IsAttackingPlayerHelper() {} - bool operator()(Unit* unit) const { return unit->isAttackingPlayer(); } + bool operator()(Unit const* unit) const { return unit->isAttackingPlayer(); } }; bool Unit::isAttackingPlayer() const @@ -8615,7 +8623,7 @@ void Unit::ModifyAuraState(AuraState flag, bool apply) { if(itr->second.state == PLAYERSPELL_REMOVED) continue; SpellEntry const *spellInfo = sSpellStore.LookupEntry(itr->first); - if (!spellInfo || !IsPassiveSpell(itr->first)) continue; + if (!spellInfo || !IsPassiveSpell(spellInfo)) continue; if (spellInfo->CasterAuraState == flag) CastSpell(this, itr->first, true, NULL); } @@ -8925,7 +8933,18 @@ int32 Unit::SpellBonusWithCoeffs(SpellEntry const *spellProto, int32 total, int3 // apply ap bonus at done part calculation only (it flat total mod so common with taken) if (donePart && bonus->ap_bonus) - total += int32(bonus->ap_bonus * (GetTotalAttackPowerValue(BASE_ATTACK) + ap_benefit)); + { + float ap_bonus = bonus->ap_bonus; + + // Impurity + if (GetTypeId() == TYPEID_PLAYER && spellProto->SpellFamilyName == SPELLFAMILY_DEATHKNIGHT) + { + if (SpellEntry const* spell = ((Player*)this)->GetKnownTalentRankById(2005)) + ap_bonus += ((spell->CalculateSimpleValue(EFFECT_INDEX_0) * ap_bonus) / 100.0f); + } + + total += int32(ap_bonus * (GetTotalAttackPowerValue(BASE_ATTACK) + ap_benefit)); + } } // Default calculation else if (benefit) @@ -9158,7 +9177,15 @@ uint32 Unit::SpellDamageBonusDone(Unit *pVictim, SpellEntry const *spellProto, u break; } case SPELLFAMILY_WARLOCK: + { + // Drain Soul + if (spellProto->SpellFamilyFlags & UI64LIT(0x0000000000004000)) + { + if (pVictim->GetHealth() * 100 / pVictim->GetMaxHealth() <= 25) + DoneTotalMod *= 4; + } break; + } case SPELLFAMILY_PRIEST: { // Glyph of Smite @@ -10579,10 +10606,6 @@ bool Unit::isVisibleForOrDetect(Unit const* u, WorldObject const* viewPoint, boo return false; } - // always seen by far sight caster - if (u->GetTypeId()==TYPEID_PLAYER && ((Player*)u)->GetFarSight()==GetGUID()) - return true; - // different visible distance checks if (u->isInFlight()) // what see player in flight { @@ -10781,12 +10804,41 @@ void Unit::SetVisibility(UnitVisibility x) if(IsInWorld()) { + // some auras requires visible target + if(m_Visibility == VISIBILITY_GROUP_NO_DETECT || m_Visibility == VISIBILITY_OFF) + { + static const AuraType auratypes[] = {SPELL_AURA_BIND_SIGHT, SPELL_AURA_FAR_SIGHT, SPELL_AURA_NONE}; + for (AuraType const* type = &auratypes[0]; *type != SPELL_AURA_NONE; ++type) + { + AuraList& alist = m_modAuras[*type]; + if(alist.empty()) + continue; + + for (AuraList::iterator it = alist.begin(); it != alist.end();) + { + Aura* aura = (*it); + Unit* owner = aura->GetCaster(); + + if (!owner || !isVisibleForOrDetect(owner,this,false)) + { + alist.erase(it); + RemoveAura(aura); + it = alist.begin(); + } + else + ++it; + } + } + } + Map *m = GetMap(); if(GetTypeId()==TYPEID_PLAYER) m->PlayerRelocation((Player*)this,GetPositionX(),GetPositionY(),GetPositionZ(),GetOrientation()); else m->CreatureRelocation((Creature*)this,GetPositionX(),GetPositionY(),GetPositionZ(),GetOrientation()); + + GetViewPoint().Event_ViewPointVisibilityChanged(); } } @@ -12039,6 +12091,7 @@ void Unit::RemoveFromWorld() RemoveAllGameObjects(); RemoveAllDynObjects(); CleanupDeletedAuras(); + GetViewPoint().Event_RemovedFromWorld(); } Object::RemoveFromWorld(); @@ -12740,9 +12793,13 @@ void Unit::StopMoving() { clearUnitState(UNIT_STAT_MOVING); + // not need send any packets if not in world + if (!IsInWorld()) + return; + // send explicit stop packet // player expected for correct work SPLINEFLAG_WALKMODE - SendMonsterMove(GetPositionX(), GetPositionY(), GetPositionZ(), SPLINETYPE_NORMAL, GetTypeId() == TYPEID_PLAYER ? SPLINEFLAG_WALKMODE : SPLINEFLAG_NONE, 0); + SendMonsterMove(GetPositionX(), GetPositionY(), GetPositionZ(), SPLINETYPE_STOP, GetTypeId() == TYPEID_PLAYER ? SPLINEFLAG_WALKMODE : SPLINEFLAG_NONE, 0); // update position and orientation for near players WorldPacket data; @@ -13710,4 +13767,4 @@ bool Unit::CheckAndIncreaseCastCounter() ++m_castCounter; return true; -} +} \ No newline at end of file diff --git a/src/game/Unit.h b/src/game/Unit.h index b4b407727..76533ffcb 100644 --- a/src/game/Unit.h +++ b/src/game/Unit.h @@ -420,24 +420,25 @@ enum UnitState UNIT_STAT_STUNNED = 0x00000008, // Aura::HandleAuraModStun UNIT_STAT_ROOT = 0x00000010, // Aura::HandleAuraModRoot UNIT_STAT_ISOLATED = 0x00000020, // area auras do not affect other players, Aura::HandleAuraModSchoolImmunity + UNIT_STAT_CONTROLLED = 0x00000040, // Aura::HandleAuraModPossess // persistent movement generator state (all time while movement generator applied to unit (independent from top state of movegen) - UNIT_STAT_IN_FLIGHT = 0x00000040, // player is in flight mode (in fact interrupted at far teleport until next map telport landing) - UNIT_STAT_DISTRACTED = 0x00000080, // DistractedMovementGenerator active + UNIT_STAT_IN_FLIGHT = 0x00000080, // player is in flight mode (in fact interrupted at far teleport until next map telport landing) + UNIT_STAT_DISTRACTED = 0x00000100, // DistractedMovementGenerator active // persistent movement generator state with non-persistent mirror states for stop support // (can be removed temporary by stop command or another movement generator apply) // not use _MOVE versions for generic movegen state, it can be removed temporary for unit stop and etc - UNIT_STAT_CONFUSED = 0x00000100, // ConfusedMovementGenerator active/onstack - UNIT_STAT_CONFUSED_MOVE = 0x00000200, - UNIT_STAT_ROAMING = 0x00000400, // RandomMovementGenerator/PointMovementGenerator/WaypointMovementGenerator active (now always set) - UNIT_STAT_ROAMING_MOVE = 0x00000800, - UNIT_STAT_CHASE = 0x00001000, // ChaseMovementGenerator active - UNIT_STAT_CHASE_MOVE = 0x00002000, - UNIT_STAT_FOLLOW = 0x00004000, // FollowMovementGenerator active - UNIT_STAT_FOLLOW_MOVE = 0x00008000, - UNIT_STAT_FLEEING = 0x00010000, // FleeMovementGenerator/TimedFleeingMovementGenerator active/onstack - UNIT_STAT_FLEEING_MOVE = 0x00020000, + UNIT_STAT_CONFUSED = 0x00000200, // ConfusedMovementGenerator active/onstack + UNIT_STAT_CONFUSED_MOVE = 0x00000400, + UNIT_STAT_ROAMING = 0x00000800, // RandomMovementGenerator/PointMovementGenerator/WaypointMovementGenerator active (now always set) + UNIT_STAT_ROAMING_MOVE = 0x00001000, + UNIT_STAT_CHASE = 0x00002000, // ChaseMovementGenerator active + UNIT_STAT_CHASE_MOVE = 0x00004000, + UNIT_STAT_FOLLOW = 0x00008000, // FollowMovementGenerator active + UNIT_STAT_FOLLOW_MOVE = 0x00010000, + UNIT_STAT_FLEEING = 0x00020000, // FleeMovementGenerator/TimedFleeingMovementGenerator active/onstack + UNIT_STAT_FLEEING_MOVE = 0x00040000, // masks (only for check) @@ -457,6 +458,12 @@ enum UnitState UNIT_STAT_CAN_NOT_REACT = UNIT_STAT_STUNNED | UNIT_STAT_DIED | UNIT_STAT_CONFUSED | UNIT_STAT_FLEEING, + // AI disabled by some reason + UNIT_STAT_LOST_CONTROL = UNIT_STAT_FLEEING | UNIT_STAT_CONTROLLED, + + // above 2 state cases + UNIT_STAT_CAN_NOT_REACT_OR_LOST_CONTROL = UNIT_STAT_CAN_NOT_REACT | UNIT_STAT_LOST_CONTROL, + // masks (for check or reset) // for real move using movegen check and stop (except unstoppable flight) @@ -1943,14 +1950,14 @@ void Unit::CallForAllControlledUnits(Func const& func, bool withTotems, bool wit template bool Unit::CheckAllControlledUnits(Func const& func, bool withTotems, bool withGuardians, bool withCharms) const { - if (Pet* pet = GetPet()) + if (Pet const* pet = GetPet()) if (func(pet)) return true; if (withGuardians) { for(GuardianPetList::const_iterator itr = m_guardianPets.begin(); itr != m_guardianPets.end(); ++itr) - if (Unit* guardian = Unit::GetUnit(*this,*itr)) + if (Unit const* guardian = Unit::GetUnit(*this,*itr)) if (func(guardian)) return true; @@ -1959,13 +1966,13 @@ bool Unit::CheckAllControlledUnits(Func const& func, bool withTotems, bool withG if (withTotems) { for (int i = 0; i < MAX_TOTEM_SLOT; ++i) - if (Unit *totem = _GetTotem(TotemSlot(i))) + if (Unit const* totem = _GetTotem(TotemSlot(i))) if (func(totem)) return true; } if (withCharms) - if(Unit* charm = GetCharm()) + if(Unit const* charm = GetCharm()) if (func(charm)) return true; diff --git a/src/game/World.cpp b/src/game/World.cpp index abf273dce..9a0071b8c 100644 --- a/src/game/World.cpp +++ b/src/game/World.cpp @@ -22,7 +22,7 @@ #include "Common.h" #include "Database/DatabaseEnv.h" -#include "Config/ConfigEnv.h" +#include "Config/Config.h" #include "SystemConfig.h" #include "Log.h" #include "Opcodes.h" @@ -402,9 +402,9 @@ Weather* World::AddWeather(uint32 zone_id) /// Initialize config values void World::LoadConfigSettings(bool reload) { - if(reload) + if (reload) { - if(!sConfig.Reload()) + if (!sConfig.Reload()) { sLog.outError("World settings reload fail: can't read settings from %s.",sConfig.GetFilename().c_str()); return; @@ -413,7 +413,7 @@ void World::LoadConfigSettings(bool reload) ///- Read the version of the configuration file and warn the user in case of emptiness or mismatch uint32 confVersion = sConfig.GetIntDefault("ConfVersion", 0); - if(!confVersion) + if (!confVersion) { sLog.outError("*****************************************************************************"); sLog.outError(" WARNING: mangosd.conf does not include a ConfVersion variable."); @@ -1032,7 +1032,7 @@ void World::SetInitialWorldSettings() sLog.outString( "Loading Objects Pooling Data..."); sPoolMgr.LoadFromDB(); - sLog.outString( "Loading Game Event Data..."); + sLog.outString( "Loading Game Event Data..."); // must be after sPoolMgr.LoadFromDB for proper load pool events sLog.outString(); sGameEventMgr.LoadFromDB(); sLog.outString( ">>> Game Event Data loaded" ); diff --git a/src/game/WorldSession.cpp b/src/game/WorldSession.cpp index 273cf088e..8a8b3831d 100644 --- a/src/game/WorldSession.cpp +++ b/src/game/WorldSession.cpp @@ -171,7 +171,7 @@ bool WorldSession::Update(uint32 /*diff*/) packet->GetOpcode()); #endif*/ - OpcodeHandler& opHandle = opcodeTable[packet->GetOpcode()]; + OpcodeHandler const& opHandle = opcodeTable[packet->GetOpcode()]; try { switch (opHandle.status) @@ -184,11 +184,8 @@ bool WorldSession::Update(uint32 /*diff*/) LogUnexpectedOpcode(packet, "the player has not logged in yet"); } else if(_player->IsInWorld()) - { - (this->*opHandle.handler)(*packet); - if (packet->rpos() < packet->wpos() && sLog.HasLogLevelOrHigher(LOG_LVL_DEBUG)) - LogUnprocessedTail(packet); - } + ExecuteOpcode(opHandle, packet); + // lag can cause STATUS_LOGGEDIN opcodes to arrive after the player started a transfer break; case STATUS_LOGGEDIN_OR_RECENTLY_LOGGEDOUT: @@ -197,12 +194,8 @@ bool WorldSession::Update(uint32 /*diff*/) LogUnexpectedOpcode(packet, "the player has not logged in yet and not recently logout"); } else - { // not expected _player or must checked in packet hanlder - (this->*opHandle.handler)(*packet); - if (packet->rpos() < packet->wpos() && sLog.HasLogLevelOrHigher(LOG_LVL_DEBUG)) - LogUnprocessedTail(packet); - } + ExecuteOpcode(opHandle, packet); break; case STATUS_TRANSFER: if(!_player) @@ -210,11 +203,7 @@ bool WorldSession::Update(uint32 /*diff*/) else if(_player->IsInWorld()) LogUnexpectedOpcode(packet, "the player is still in world"); else - { - (this->*opHandle.handler)(*packet); - if (packet->rpos() < packet->wpos() && sLog.HasLogLevelOrHigher(LOG_LVL_DEBUG)) - LogUnprocessedTail(packet); - } + ExecuteOpcode(opHandle, packet); break; case STATUS_AUTHED: // prevent cheating with skip queue wait @@ -229,9 +218,7 @@ bool WorldSession::Update(uint32 /*diff*/) if (packet->GetOpcode() != CMSG_SET_ACTIVE_VOICE_CHANNEL) m_playerRecentlyLogout = false; - (this->*opHandle.handler)(*packet); - if (packet->rpos() < packet->wpos() && sLog.HasLogLevelOrHigher(LOG_LVL_DEBUG)) - LogUnprocessedTail(packet); + ExecuteOpcode(opHandle, packet); break; case STATUS_NEVER: sLog.outError( "SESSION: received not allowed opcode %s (0x%.4X)", @@ -872,3 +859,27 @@ void WorldSession::SendRedirectClient(std::string& ip, uint16 port) SendPacket(&pkt); } + +void WorldSession::ExecuteOpcode( OpcodeHandler const& opHandle, WorldPacket* packet ) +{ + // need prevent do internal far teleports in handlers because some handlers do lot steps + // or call code that can do far teleports in some conditions unexpectedly for generic way work code + if (_player) + _player->SetCanDelayTeleport(true); + + (this->*opHandle.handler)(*packet); + + if (_player) + { + // can be not set in fact for login opcode, but this not create porblems. + _player->SetCanDelayTeleport(false); + + //we should execute delayed teleports only for alive(!) players + //because we don't want player's ghost teleported from graveyard + if (_player->IsHasDelayedTeleport()) + _player->TeleportTo(_player->m_teleport_dest, _player->m_teleport_options); + } + + if (packet->rpos() < packet->wpos() && sLog.HasLogLevelOrHigher(LOG_LVL_DEBUG)) + LogUnprocessedTail(packet); +} \ No newline at end of file diff --git a/src/game/WorldSession.h b/src/game/WorldSession.h index 8aa6ba959..af857e236 100644 --- a/src/game/WorldSession.h +++ b/src/game/WorldSession.h @@ -43,6 +43,8 @@ class LoginQueryHolder; class CharacterHandler; class GMTicket; +struct OpcodeHandler; + enum AccountDataType { GLOBAL_CONFIG_CACHE = 0, // 0x01 g @@ -773,6 +775,8 @@ class MANGOS_DLL_SPEC WorldSession // private trade methods void moveItems(Item* myItems[], Item* hisItems[]); + void ExecuteOpcode( OpcodeHandler const& opHandle, WorldPacket* packet ); + // logging helper void LogUnexpectedOpcode(WorldPacket *packet, const char * reason); void LogUnprocessedTail(WorldPacket *packet); diff --git a/src/game/WorldSocketMgr.cpp b/src/game/WorldSocketMgr.cpp index 9f1927ecc..25ff79b10 100644 --- a/src/game/WorldSocketMgr.cpp +++ b/src/game/WorldSocketMgr.cpp @@ -40,7 +40,7 @@ #include "Log.h" #include "Common.h" -#include "Config/ConfigEnv.h" +#include "Config/Config.h" #include "Database/DatabaseEnv.h" #include "WorldSocket.h" diff --git a/src/mangosd/CliRunnable.cpp b/src/mangosd/CliRunnable.cpp index 0f23f71e9..5aa82edb8 100644 --- a/src/mangosd/CliRunnable.cpp +++ b/src/mangosd/CliRunnable.cpp @@ -27,7 +27,7 @@ #include "ScriptCalls.h" #include "ObjectMgr.h" #include "WorldSession.h" -#include "Config/ConfigEnv.h" +#include "Config/Config.h" #include "Util.h" #include "AccountMgr.h" #include "CliRunnable.h" @@ -593,7 +593,7 @@ bool ChatHandler::HandleServerLogLevelCommand(const char *args) { if(!*args) { - PSendSysMessage("Log level: %u"); + PSendSysMessage("Log level: %u", sLog.GetLogLevel()); return true; } @@ -629,7 +629,7 @@ void CliRunnable::run() ///- Display the list of available CLI functions then beep sLog.outString(); - if(sConfig.GetBoolDefault("BeepAtStart", true)) + if (sConfig.GetBoolDefault("BeepAtStart", true)) printf("\a"); // \a = Alert // print this here the first time diff --git a/src/mangosd/Main.cpp b/src/mangosd/Main.cpp index af5daf420..abd5daebd 100644 --- a/src/mangosd/Main.cpp +++ b/src/mangosd/Main.cpp @@ -22,7 +22,7 @@ #include "Common.h" #include "Database/DatabaseEnv.h" -#include "Config/ConfigEnv.h" +#include "Config/Config.h" #include "Log.h" #include "Master.h" #include "SystemConfig.h" @@ -31,6 +31,7 @@ #include #include #include +#include #ifdef WIN32 #include "ServiceWin32.h" @@ -56,11 +57,11 @@ uint32 realmID; ///< Id of the realm void usage(const char *prog) { sLog.outString("Usage: \n %s []\n" - " --version print version and exist\n\r" + " -v, --version print version and exist\n\r" " -c config_file use config_file as configuration file\n\r" #ifdef WIN32 " Running as service functions:\n\r" - " --service run as service\n\r" + " -s run run as service\n\r" " -s install install service\n\r" " -s uninstall uninstall service\n\r" #endif @@ -75,69 +76,69 @@ extern int main(int argc, char **argv) //char *leak = new char[1000]; // test leak detection - ///- Command line parsing to get the configuration file name + ///- Command line parsing char const* cfg_file = _MANGOSD_CONFIG; - int c=1; - while( c < argc ) + +#ifdef WIN32 + char const *options = ":c:s:"; +#else + char const *options = ":c:"; +#endif + + ACE_Get_Opt cmd_opts(argc, argv, options); + cmd_opts.long_option("version", 'v'); + + int option; + while ((option = cmd_opts()) != EOF) { - if( strcmp(argv[c],"-c") == 0) + switch (option) { - if( ++c >= argc ) + case 'c': + cfg_file = cmd_opts.opt_arg(); + break; + case 'v': + printf("%s\n", _FULLVERSION(REVISION_DATE,REVISION_TIME,REVISION_NR,REVISION_ID)); + return 0; +#ifdef WIN32 + case 's': { - sLog.outError("Runtime-Error: -c option requires an input argument"); - usage(argv[0]); - return 1; + const char *mode = cmd_opts.opt_arg(); + + if (!strcmp(mode, "install")) + { + if (WinServiceInstall()) + sLog.outString("Installing service"); + return 1; + } + else if (!strcmp(mode, "uninstall")) + { + if (WinServiceUninstall()) + sLog.outString("Uninstalling service"); + return 1; + } + else if (!strcmp(mode, "run")) + WinServiceRun(); + else + { + sLog.outError("Runtime-Error: -%c unsupported argument %s", cmd_opts.opt_opt(), mode); + usage(argv[0]); + Log::WaitBeforeContinueIfNeed(); + return 1; + } + break; } - else - cfg_file = argv[c]; - } - - if( strcmp(argv[c],"--version") == 0) - { - printf("%s\n", _FULLVERSION(REVISION_DATE,REVISION_TIME,REVISION_NR,REVISION_ID)); - return 0; - } - - #ifdef WIN32 - //////////// - //Services// - //////////// - if( strcmp(argv[c],"-s") == 0) - { - if( ++c >= argc ) - { - sLog.outError("Runtime-Error: -s option requires an input argument"); +#endif + case ':': + sLog.outError("Runtime-Error: -%c option requires an input argument", cmd_opts.opt_opt()); usage(argv[0]); Log::WaitBeforeContinueIfNeed(); return 1; - } - if( strcmp(argv[c],"install") == 0) - { - if (WinServiceInstall()) - sLog.outString("Installing service"); - return 1; - } - else if( strcmp(argv[c],"uninstall") == 0) - { - if(WinServiceUninstall()) - sLog.outString("Uninstalling service"); - return 1; - } - else - { - sLog.outError("Runtime-Error: unsupported option %s",argv[c]); + default: + sLog.outError("Runtime-Error: bad format of commandline arguments"); usage(argv[0]); Log::WaitBeforeContinueIfNeed(); return 1; - } } - if( strcmp(argv[c],"--service") == 0) - { - WinServiceRun(); - } - //// - #endif - ++c; } if (!sConfig.SetSource(cfg_file)) diff --git a/src/mangosd/Master.cpp b/src/mangosd/Master.cpp index 9478a8d9d..2d9eca5b3 100644 --- a/src/mangosd/Master.cpp +++ b/src/mangosd/Master.cpp @@ -30,7 +30,7 @@ #include "Timer.h" #include "Policies/SingletonImp.h" #include "SystemConfig.h" -#include "Config/ConfigEnv.h" +#include "Config/Config.h" #include "Database/DatabaseEnv.h" #include "CliRunnable.h" #include "RASocket.h" diff --git a/src/mangosd/RASocket.cpp b/src/mangosd/RASocket.cpp index 15952fb97..1d291c23a 100644 --- a/src/mangosd/RASocket.cpp +++ b/src/mangosd/RASocket.cpp @@ -25,7 +25,7 @@ #include "Log.h" #include "RASocket.h" #include "World.h" -#include "Config/ConfigEnv.h" +#include "Config/Config.h" #include "Util.h" #include "AccountMgr.h" #include "Language.h" diff --git a/src/mangosd/mangosd.conf.dist.in b/src/mangosd/mangosd.conf.dist.in index f5ba807ed..58d337a00 100644 --- a/src/mangosd/mangosd.conf.dist.in +++ b/src/mangosd/mangosd.conf.dist.in @@ -1,7 +1,9 @@ ##################################### # MaNGOS Configuration file # ##################################### -ConfVersion=2010051901 + +[MangosdConf] +ConfVersion=2010062001 ################################################################################################################### # CONNECTIONS AND DIRECTORIES diff --git a/src/realmd/AuthSocket.cpp b/src/realmd/AuthSocket.cpp index 848579b97..8465eb381 100644 --- a/src/realmd/AuthSocket.cpp +++ b/src/realmd/AuthSocket.cpp @@ -22,7 +22,7 @@ #include "Common.h" #include "Database/DatabaseEnv.h" -#include "Config/ConfigEnv.h" +#include "Config/Config.h" #include "Log.h" #include "RealmList.h" #include "AuthSocket.h" diff --git a/src/realmd/Main.cpp b/src/realmd/Main.cpp index 1807b165f..e83fe15e6 100644 --- a/src/realmd/Main.cpp +++ b/src/realmd/Main.cpp @@ -24,7 +24,7 @@ #include "Database/DatabaseEnv.h" #include "RealmList.h" -#include "Config/ConfigEnv.h" +#include "Config/Config.h" #include "Log.h" #include "AuthSocket.h" #include "SystemConfig.h" @@ -35,6 +35,7 @@ #include #include +#include #include #include #include @@ -67,11 +68,11 @@ DatabaseType loginDatabase; ///< Accessor to the void usage(const char *prog) { sLog.outString("Usage: \n %s []\n" - " --version print version and exist\n\r" + " -v, --version print version and exist\n\r" " -c config_file use config_file as configuration file\n\r" #ifdef WIN32 " Running as service functions:\n\r" - " --service run as service\n\r" + " -s run run as service\n\r" " -s install install service\n\r" " -s uninstall uninstall service\n\r" #endif @@ -81,70 +82,69 @@ void usage(const char *prog) /// Launch the realm server extern int main(int argc, char **argv) { - ///- Command line parsing to get the configuration file name + ///- Command line parsing char const* cfg_file = _REALMD_CONFIG; - int c=1; - while( c < argc ) + +#ifdef WIN32 + char const *options = ":c:s:"; +#else + char const *options = ":c:"; +#endif + + ACE_Get_Opt cmd_opts(argc, argv, options); + cmd_opts.long_option("version", 'v'); + + int option; + while ((option = cmd_opts()) != EOF) { - if( strcmp(argv[c],"-c") == 0) + switch (option) { - if( ++c >= argc ) + case 'c': + cfg_file = cmd_opts.opt_arg(); + break; + case 'v': + printf("%s\n", _FULLVERSION(REVISION_DATE,REVISION_TIME,REVISION_NR,REVISION_ID)); + return 0; +#ifdef WIN32 + case 's': { - sLog.outError("Runtime-Error: -c option requires an input argument"); - usage(argv[0]); - Log::WaitBeforeContinueIfNeed(); - return 1; - } - else - cfg_file = argv[c]; - } + const char *mode = cmd_opts.opt_arg(); - if( strcmp(argv[c],"--version") == 0) - { - printf("%s\n", _FULLVERSION(REVISION_DATE,REVISION_TIME,REVISION_NR,REVISION_ID)); - return 0; - } - - #ifdef WIN32 - //////////// - //Services// - //////////// - if( strcmp(argv[c],"-s") == 0) - { - if( ++c >= argc ) - { - sLog.outError("Runtime-Error: -s option requires an input argument"); + if (!strcmp(mode, "install")) + { + if (WinServiceInstall()) + sLog.outString("Installing service"); + return 1; + } + else if (!strcmp(mode, "uninstall")) + { + if (WinServiceUninstall()) + sLog.outString("Uninstalling service"); + return 1; + } + else if (!strcmp(mode, "run")) + WinServiceRun(); + else + { + sLog.outError("Runtime-Error: -%c unsupported argument %s", cmd_opts.opt_opt(), mode); + usage(argv[0]); + Log::WaitBeforeContinueIfNeed(); + return 1; + } + break; + } +#endif + case ':': + sLog.outError("Runtime-Error: -%c option requires an input argument", cmd_opts.opt_opt()); usage(argv[0]); Log::WaitBeforeContinueIfNeed(); return 1; - } - if( strcmp(argv[c],"install") == 0) - { - if (WinServiceInstall()) - sLog.outString("Installing service"); - return 1; - } - else if( strcmp(argv[c],"uninstall") == 0) - { - if(WinServiceUninstall()) - sLog.outString("Uninstalling service"); - return 1; - } - else - { - sLog.outError("Runtime-Error: unsupported option %s",argv[c]); + default: + sLog.outError("Runtime-Error: bad format of commandline arguments"); usage(argv[0]); Log::WaitBeforeContinueIfNeed(); return 1; - } } - if( strcmp(argv[c],"--service") == 0) - { - WinServiceRun(); - } - //// - #endif - ++c; } if (!sConfig.SetSource(cfg_file)) diff --git a/src/realmd/realmd.conf.dist.in b/src/realmd/realmd.conf.dist.in index 20e179217..99ada0219 100644 --- a/src/realmd/realmd.conf.dist.in +++ b/src/realmd/realmd.conf.dist.in @@ -1,7 +1,9 @@ ############################################ # MaNGOS realmd configuration file # ############################################ -ConfVersion=2007062001 + +[RealmdConf] +ConfVersion=2010062001 ################################################################################################################### # REALMD SETTINGS diff --git a/src/shared/Config/Config.cpp b/src/shared/Config/Config.cpp index b4eeacd2c..515a5f367 100644 --- a/src/shared/Config/Config.cpp +++ b/src/shared/Config/Config.cpp @@ -16,13 +16,36 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "ConfigEnv.h" +#include "Config.h" +#include "ace/Configuration_Import_Export.h" + #include "Policies/SingletonImp.h" INSTANTIATE_SINGLETON_1(Config); +static bool GetValueHelper(ACE_Configuration_Heap *mConf, const char *name, ACE_TString &result) +{ + if (!mConf) + return false; + + ACE_TString section_name; + ACE_Configuration_Section_Key section_key; + ACE_Configuration_Section_Key root_key = mConf->root_section(); + + int i = 0; + while (mConf->enumerate_sections(root_key, i, section_name) == 0) + { + mConf->open_section(root_key, section_name.c_str(), 0, section_key); + if (mConf->get_string_value(section_key, name, result) == 0) + return true; + ++i; + } + + return false; +} + Config::Config() -: mIgnoreCase(true), mConf(NULL) +: mConf(NULL) { } @@ -31,9 +54,8 @@ Config::~Config() delete mConf; } -bool Config::SetSource(const char *file, bool ignorecase) +bool Config::SetSource(const char *file) { - mIgnoreCase = ignorecase; mFilename = file; return Reload(); @@ -42,43 +64,33 @@ bool Config::SetSource(const char *file, bool ignorecase) bool Config::Reload() { delete mConf; + mConf = new ACE_Configuration_Heap; - mConf = new DOTCONFDocument(mIgnoreCase ? - DOTCONFDocument::CASEINSENSETIVE : - DOTCONFDocument::CASESENSITIVE); - - if (mConf->setContent(mFilename.c_str()) == -1) + if (mConf->open() == 0) { - delete mConf; - mConf = NULL; - return false; + ACE_Ini_ImpExp config_importer(*mConf); + if (config_importer.import_config(mFilename.c_str()) == 0) + return true; } - return true; + delete mConf; + mConf = NULL; + return false; } std::string Config::GetStringDefault(const char* name, const char* def) { - if (!mConf) - return std::string(def); - - DOTCONFDocumentNode const *node = mConf->findNode(name); - if (!node || !node->getValue()) - return std::string(def); - - return std::string(node->getValue()); + ACE_TString val; + return GetValueHelper(mConf, name, val) ? val.c_str() : def; } bool Config::GetBoolDefault(const char* name, bool def) { - if (!mConf) + ACE_TString val; + if (!GetValueHelper(mConf, name, val)) return def; - DOTCONFDocumentNode const *node = mConf->findNode(name); - if (!node || !node->getValue()) - return def; - - const char* str = node->getValue(); + const char* str = val.c_str(); if (strcmp(str, "true") == 0 || strcmp(str, "TRUE") == 0 || strcmp(str, "yes") == 0 || strcmp(str, "YES") == 0 || strcmp(str, "1") == 0) @@ -90,25 +102,13 @@ bool Config::GetBoolDefault(const char* name, bool def) int32 Config::GetIntDefault(const char* name, int32 def) { - if (!mConf) - return def; - - DOTCONFDocumentNode const *node = mConf->findNode(name); - if (!node || !node->getValue()) - return def; - - return atoi(node->getValue()); + ACE_TString val; + return GetValueHelper(mConf, name, val) ? atoi(val.c_str()) : def; } float Config::GetFloatDefault(const char* name, float def) { - if (!mConf) - return def; - - DOTCONFDocumentNode const *node = mConf->findNode(name); - if (!node || !node->getValue()) - return def; - - return (float)atof(node->getValue()); + ACE_TString val; + return GetValueHelper(mConf, name, val) ? (float)atof(val.c_str()) : def; } diff --git a/src/shared/Config/Config.h b/src/shared/Config/Config.h index 296018408..29a524bfd 100644 --- a/src/shared/Config/Config.h +++ b/src/shared/Config/Config.h @@ -19,10 +19,11 @@ #ifndef CONFIG_H #define CONFIG_H +#include "Common.h" #include #include "Platform/Define.h" -class DOTCONFDocument; +class ACE_Configuration_Heap; class MANGOS_DLL_SPEC Config { @@ -31,7 +32,7 @@ class MANGOS_DLL_SPEC Config Config(); ~Config(); - bool SetSource(const char *file, bool ignorecase = true); + bool SetSource(const char *file); bool Reload(); std::string GetStringDefault(const char* name, const char* def); @@ -44,8 +45,7 @@ class MANGOS_DLL_SPEC Config private: std::string mFilename; - bool mIgnoreCase; - DOTCONFDocument *mConf; + ACE_Configuration_Heap *mConf; }; #define sConfig MaNGOS::Singleton::Instance() diff --git a/src/shared/Config/ConfigEnv.h b/src/shared/Config/ConfigEnv.h deleted file mode 100644 index e9801b641..000000000 --- a/src/shared/Config/ConfigEnv.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (C) 2005-2010 MaNGOS - * - * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#if !defined(CONFIGENVIRONMENT_H) - -#define CONFIGENVIRONMENT_H - -#include "Common.h" -#include "dotconfpp/dotconfpp.h" -#include "Config.h" - -#endif diff --git a/src/shared/Config/ConfigLibrary.vcproj b/src/shared/Config/ConfigLibrary.vcproj deleted file mode 100644 index a8f1fc322..000000000 --- a/src/shared/Config/ConfigLibrary.vcproj +++ /dev/null @@ -1,137 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/shared/Config/Makefile.am b/src/shared/Config/Makefile.am index 7d670af90..77ea62b36 100644 --- a/src/shared/Config/Makefile.am +++ b/src/shared/Config/Makefile.am @@ -19,7 +19,7 @@ ## Sub-directories to parse ## CPP flags for includes, defines, etc. -AM_CPPFLAGS = $(MANGOS_INCLUDES) -I$(top_builddir)/src/shared -I$(srcdir) -I$(srcdir)/../../../dep/include -I$(srcdir)/../../framework -I$(srcdir)/../../shared -I$(srcdir)/../../../dep/include/g3dlite +AM_CPPFLAGS = $(MANGOS_INCLUDES) -I$(top_builddir)/src/shared -I$(srcdir) -I$(srcdir)/../../../dep/include -I$(srcdir)/../../framework -I$(srcdir)/../../shared ## Build MaNGOS shared library and its parts as convenience library. # All libraries will be convenience libraries. Might be changed to shared @@ -27,14 +27,5 @@ AM_CPPFLAGS = $(MANGOS_INCLUDES) -I$(top_builddir)/src/shared -I$(srcdir) -I$(sr noinst_LIBRARIES = libmangosconfig.a libmangosconfig_a_SOURCES = \ - dotconfpp/dotconfpp.cpp \ - dotconfpp/dotconfpp.h \ - dotconfpp/mempool.cpp \ - dotconfpp/mempool.h \ Config.cpp \ - Config.h \ - ConfigEnv.h - -# VC++ project workspace for dotconfpp -EXTRA_DIST = \ - ConfigLibrary.vcproj + Config.h diff --git a/src/shared/Config/dotconfpp/dotconfpp.cpp b/src/shared/Config/dotconfpp/dotconfpp.cpp deleted file mode 100644 index 85b515032..000000000 --- a/src/shared/Config/dotconfpp/dotconfpp.cpp +++ /dev/null @@ -1,703 +0,0 @@ -#include "Common.h" -#include "dotconfpp.h" -#include - -#ifdef WIN32 -# define strcasecmp stricmp -# include -#else -# include -# include -# include -# include -#endif - -#if !defined(R_OK) -# define R_OK 04 -#endif - -DOTCONFDocumentNode::DOTCONFDocumentNode() -: previousNode(NULL), nextNode(NULL), parentNode(NULL), childNode(NULL), -values(NULL), valuesCount(0), name(NULL), lineNum(0), -fileName(NULL), closed(true) -{ -} - -DOTCONFDocumentNode::~DOTCONFDocumentNode() -{ - free(name); - - if (values != NULL) - { - for (int i = 0; i < valuesCount; ++i) - free(values[i]); - - free(values); - } -} - -void DOTCONFDocumentNode::pushValue(char* _value) -{ - ++valuesCount; - values = (char**)realloc(values, valuesCount * sizeof(char*)); - values[valuesCount - 1] = strdup(_value); -} - -const char* DOTCONFDocumentNode::getValue(int index) const -{ - if (index >= valuesCount) - return NULL; - - return values[index]; -} - -DOTCONFDocument::DOTCONFDocument(DOTCONFDocument::CaseSensitive caseSensitivity) -: mempool(NULL), curParent(NULL), curPrev(NULL), curLine(0), file(NULL), fileName(NULL) -{ - switch (caseSensitivity) - { - case CASESENSITIVE: - cmp_func = strcmp; - break; - case CASEINSENSETIVE: - cmp_func = strcasecmp; - break; - } - - mempool = new AsyncDNSMemPool(1024); - mempool->initialize(); -} - -DOTCONFDocument::~DOTCONFDocument() -{ - for (NodeList::iterator i = nodeTree.begin(); i != nodeTree.end(); ++i) - delete(*i); - - for (CharList::iterator i = requiredOptions.begin(); i != requiredOptions.end(); ++i) - free(*i); - - for (CharList::iterator i = processedFiles.begin(); i != processedFiles.end(); ++i) - free(*i); - - free(fileName); - delete mempool; -} - -int DOTCONFDocument::cleanupLine(char* line) -{ - char* start = line; - char* bg = line; - bool multiline = false; - bool concat = false; - char* word = NULL; - - if (!words.empty() && quoted) - concat = true; - - while (*line) - { - if ((*line == '#' || *line == ';') && !quoted) - { - *bg = 0; - if (strlen(start)) - { - if (concat) - { - word = (char*)mempool->Alloc(strlen(words.back()) + strlen(start) + 1); - strcpy(word, words.back()); - strcat(word, start); - words.pop_back(); - concat = false; - } - else - word = mempool->Strdup(start); - - words.push_back(word); - } - - break; - } - - if (*line == '=' && !quoted) - { - *line = ' '; - continue; - } - - // Allowing \" in there causes problems with directory paths - // like "C:\MaNGOS\" - //if(*line == '\\' && (*(line+1) == '"' || *(line+1) == '\'')){ - if (*line == '\\' && (*(line + 1) == '\'')) - { - *bg++ = *(line + 1); - line += 2; - continue; - } - - if (*line == '\\' && *(line + 1) == 'n') - { - *bg++ = '\n'; - line += 2; - continue; - } - - if (*line == '\\' && *(line + 1) == 'r') - { - *bg++ = '\r'; - line += 2; - continue; - } - - if (*line == '\\' && (*(line + 1) == '\n' || *(line + 1) == '\r')) - { - *bg = 0; - if (strlen(start)) - { - if (concat) - { - word = (char*)mempool->Alloc(strlen(words.back()) + strlen(start) + 1); - strcpy(word, words.back()); - strcat(word, start); - words.pop_back(); - concat = false; - } - else - word = mempool->Strdup(start); - - words.push_back(word); - } - - multiline = true; - break; - } - - if (*line == '"' || *line == '\'') - { - quoted = !quoted; - ++line; - continue; - } - - if (isspace((unsigned char)*line) && !quoted) - { - *bg++ = 0; - if (strlen(start)) - { - if (concat) - { - word = (char*)mempool->Alloc(strlen(words.back()) + strlen(start) + 1); - strcpy(word, words.back()); - strcat(word, start); - words.pop_back(); - concat = false; - } - else - word = mempool->Strdup(start); - - words.push_back(word); - } - - start = bg; - while (isspace((unsigned char)*++line)) - { - } - - continue; - } - - *bg++ = *line++; - } - - if (quoted && !multiline) - { - error(curLine, fileName, "unterminated quote"); - return -1; - } - - return multiline ? 1 : 0; -} - -int DOTCONFDocument::parseLine() -{ - char* word = NULL; - char* nodeName = NULL; - char* nodeValue = NULL; - DOTCONFDocumentNode* tagNode = NULL; - bool newNode = false; - - for (CharList::iterator i = words.begin(); i != words.end(); ++i) - { - word = *i; - - if (*word == '<') - newNode = true; - - if (newNode) - { - nodeValue = NULL; - nodeName = NULL; - newNode = false; - } - - size_t wordLen = strlen(word); - if (word[wordLen - 1] == '>') - { - word[wordLen - 1] = 0; - newNode = true; - } - - if (nodeName == NULL) - { - nodeName = word; - bool closed = true; - if (*nodeName == '<') - { - if (*(nodeName + 1) != '/') - { - ++nodeName; - closed = false; - } - else - { - NodeList::reverse_iterator itr = nodeTree.rbegin(); - nodeName += 2; - for (; itr != nodeTree.rend(); ++itr) - { - if (!cmp_func(nodeName, (*itr)->name) && !(*itr)->closed) - { - (*itr)->closed = true; - curParent = (*itr)->parentNode; - curPrev = *itr; - break; - } - } - - if(itr == nodeTree.rend()) - { - error(curLine, fileName, "not matched closing tag ", nodeName); - return -1; - } - - continue; - } - } - - tagNode = new DOTCONFDocumentNode; - tagNode->name = strdup(nodeName); - tagNode->document = this; - tagNode->fileName = processedFiles.back(); - tagNode->lineNum = curLine; - tagNode->closed = closed; - - if(!nodeTree.empty()) - { - DOTCONFDocumentNode* prev = nodeTree.back(); - if (prev->closed) - { - curPrev->nextNode = tagNode; - tagNode->previousNode = curPrev; - tagNode->parentNode = curParent; - } - else - { - prev->childNode = tagNode; - tagNode->parentNode = prev; - curParent = prev; - } - } - - nodeTree.push_back(tagNode); - curPrev = tagNode; - } - else - { - nodeValue = word; - tagNode->pushValue(nodeValue); - } - } - - return 0; -} - -int DOTCONFDocument::parseFile(DOTCONFDocumentNode* _parent) -{ - char str[512]; - int ret = 0; - curLine = 0; - curParent = _parent; - - quoted = false; - size_t slen = 0; - - while (fgets(str, 511, file)) - { - ++curLine; - slen = strlen(str); - if (slen >= 510) - error(curLine, fileName, "warning: line too long"); - - if (str[slen - 1] != '\n') - { - str[slen] = '\n'; - str[slen + 1] = 0; - } - - if ((ret = cleanupLine(str)) == -1) - break; - - if (ret == 0) - { - if (!words.empty()) - { - ret = parseLine(); - mempool->Free(); - words.clear(); - - if(ret == -1) - break; - } - } - } - - return ret; -} - -int DOTCONFDocument::checkConfig(const NodeList::iterator& from) -{ - int ret = 0; - - DOTCONFDocumentNode* tagNode = NULL; - int vi = 0; - for (NodeList::iterator i = from; i != nodeTree.end(); ++i) - { - tagNode = *i; - if (!tagNode->closed) - { - error(tagNode->lineNum, tagNode->fileName, "unclosed tag %s", tagNode->name); - ret = -1; - break; - } - - vi = 0; - while (vi < tagNode->valuesCount) - { - if (strstr(tagNode->values[vi], "${") && strchr(tagNode->values[vi], '}')) - { - ret = macroSubstitute(tagNode, vi); - mempool->Free(); - if (ret == -1) - break; - } - - ++vi; - } - - if (ret == -1) - break; - } - - return ret; -} - -int DOTCONFDocument::setContent(const char* _fileName) -{ - int ret = 0; - char realpathBuf[MANGOS_PATH_MAX]; - - if (ACE_OS::realpath(_fileName, realpathBuf) == NULL) - { - error(0, NULL, "realpath (%s) failed: %s", _fileName, strerror(errno)); - return -1; - } - - fileName = strdup(realpathBuf); - - processedFiles.push_back(strdup(realpathBuf)); - - if ((file = fopen(fileName, "r")) == NULL) - { - error(0, NULL, "failed to open file '%s': %s", fileName, strerror(errno)); - return -1; - } - - // Try read utf8 header and skip it if exist - unsigned int utf8header = 0; - fgets((char*)&utf8header, 4, file); // Try read header - if (utf8header != 0x00BFBBEF) // If not exist - fseek(file, 0, SEEK_SET); // Reset read position - - ret = parseFile(); - - fclose(file); - - if (!ret) - { - if ((ret = checkConfig(nodeTree.begin())) == -1) - return -1; - - NodeList::iterator from; - DOTCONFDocumentNode* tagNode = NULL; - int vi = 0; - for (NodeList::iterator i = nodeTree.begin(); i != nodeTree.end(); ++i) - { - tagNode = *i; - if (!cmp_func("DOTCONFPPIncludeFile", tagNode->name)) - { - vi = 0; - while (vi < tagNode->valuesCount) - { - if (access(tagNode->values[vi], R_OK) == -1) - { - error(tagNode->lineNum, tagNode->fileName, "%s: %s", tagNode->values[vi], strerror(errno)); - return -1; - } - - if (ACE_OS::realpath(tagNode->values[vi], realpathBuf) == NULL) - { - error(tagNode->lineNum, tagNode->fileName, "realpath (%s) failed: %s", tagNode->values[vi], strerror(errno)); - return -1; - } - - bool processed = false; - for (CharList::const_iterator itInode = processedFiles.begin(); itInode != processedFiles.end(); ++itInode) - { - if (!strcmp(*itInode, realpathBuf)) - { - processed = true; - break; - } - } - - if(processed) - break; - - processedFiles.push_back(strdup(realpathBuf)); - - file = fopen(tagNode->values[vi], "r"); - if(file == NULL) - { - error(tagNode->lineNum, fileName, "failed to open file '%s': %s", tagNode->values[vi], strerror(errno)); - return -1; - } - - fileName = strdup(realpathBuf); - from = nodeTree.end(); - --from; - - ret = parseFile(); - fclose(file); - - if (ret == -1) - return -1; - if (checkConfig(++from) == -1) - return -1; - - ++vi; - } - } - } - - if (!requiredOptions.empty()) - ret = checkRequiredOptions(); - } - - return ret; -} - -int DOTCONFDocument::checkRequiredOptions() -{ - for (CharList::const_iterator ci = requiredOptions.begin(); ci != requiredOptions.end(); ++ci) - { - bool matched = false; - for (NodeList::iterator i = nodeTree.begin(); i != nodeTree.end(); ++i) - { - if (!cmp_func((*i)->name, *ci)) - { - matched = true; - break; - } - } - - if(!matched) - { - error(0, NULL, "required option '%s' not specified", *ci); - return -1; - } - } - - return 0; -} - -void DOTCONFDocument::error(int lineNum, const char* fileName_, const char* fmt, ...) -{ - va_list args; - va_start(args, fmt); - - size_t len = (lineNum != 0 ? strlen(fileName_) : 0) + strlen(fmt) + 50; - char* buf = (char*)mempool->Alloc(len); - - if (lineNum) - snprintf(buf, len, "DOTCONF++: file '%s', line %d: %s\n", fileName_, lineNum, fmt); - else - snprintf(buf, len, "DOTCONF++: %s\n", fmt); - - vfprintf(stderr, buf, args); - - va_end(args); -} - -char* DOTCONFDocument::getSubstitution(char* macro, int lineNum) -{ - char* buf = NULL; - char* variable = macro + 2; - - char* endBr = strchr(macro, '}'); - - if (!endBr) - { - error(lineNum, fileName, "unterminated '{'"); - return NULL; - } - - *endBr = 0; - - char* defaultValue = strchr(variable, ':'); - - if (defaultValue) - { - *defaultValue++ = 0; - if (*defaultValue != '-') - { - error(lineNum, fileName, "incorrect macro substitution syntax"); - return NULL; - } - - ++defaultValue; - if (*defaultValue == '"' || *defaultValue == '\'') - { - ++defaultValue; - defaultValue[strlen(defaultValue) - 1] = 0; - } - } - else - defaultValue = NULL; - - char* subs = getenv(variable); - if (subs) - buf = mempool->Strdup(subs); - else - { - NodeList::iterator i = nodeTree.begin(); - DOTCONFDocumentNode* tagNode = NULL; - for (; i != nodeTree.end(); ++i) - { - tagNode = *i; - if (!cmp_func(tagNode->name, variable)) - { - if (tagNode->valuesCount != 0) - { - buf = mempool->Strdup(tagNode->values[0]); - break; - } - } - } - - if (i == nodeTree.end()) - { - if (defaultValue) - buf = mempool->Strdup(defaultValue); - else - { - error(lineNum, fileName, "substitution not found and default value not given"); - return NULL; - } - } - } - - return buf; -} - -int DOTCONFDocument::macroSubstitute(DOTCONFDocumentNode* tagNode, int valueIndex) -{ - int ret = 0; - char* macro = tagNode->values[valueIndex]; - size_t valueLen = strlen(tagNode->values[valueIndex]) + 1; - char* value = (char*)mempool->Alloc(valueLen); - char* v = value; - char* subs = NULL; - - while (*macro) - { - if (*macro == '$' && *(macro + 1) == '{') - { - char* m = strchr(macro, '}'); - subs = getSubstitution(macro, tagNode->lineNum); - if(subs == NULL) - { - ret = -1; - break; - } - - macro = m + 1; - *v = 0; - v = (char*)mempool->Alloc(strlen(value) + strlen(subs) + valueLen); - strcpy(v, value); - value = strcat(v, subs); - v = value + strlen(value); - continue; - } - - *v++ = *macro++; - } - - *v = 0; - - free(tagNode->values[valueIndex]); - tagNode->values[valueIndex] = strdup(value); - return ret; -} - -const DOTCONFDocumentNode* DOTCONFDocument::getFirstNode() const -{ - if (!nodeTree.empty()) - return *nodeTree.begin(); - else - return NULL; -} - -const DOTCONFDocumentNode* DOTCONFDocument::findNode(const char* nodeName, const DOTCONFDocumentNode* parentNode, const DOTCONFDocumentNode* startNode) const -{ - NodeList::const_iterator i = nodeTree.begin(); - - if (startNode == NULL) - startNode = parentNode; - - if (startNode != NULL) - { - while (i != nodeTree.end() && (*i) != startNode) - ++i; - - if (i != nodeTree.end()) - ++i; - } - - for (; i != nodeTree.end(); ++i) - { - if ((*i)->parentNode != parentNode) - continue; - - if (!cmp_func(nodeName, (*i)->name)) - return *i; - } - - return NULL; -} - -void DOTCONFDocument::setRequiredOptionNames(const char** requiredOptionNames) -{ - while (*requiredOptionNames) - { - requiredOptions.push_back(strdup(*requiredOptionNames)); - ++requiredOptionNames; - } -} diff --git a/src/shared/Config/dotconfpp/dotconfpp.h b/src/shared/Config/dotconfpp/dotconfpp.h deleted file mode 100644 index 55e6dd75d..000000000 --- a/src/shared/Config/dotconfpp/dotconfpp.h +++ /dev/null @@ -1,111 +0,0 @@ -#ifndef DOTCONFPP_H -#define DOTCONFPP_H - -#include - -#include -#include -#include -#include -#include - -#include -#include - -#include "mempool.h" - -class DOTCONFDocument; - -class DOTCONFDocumentNode -{ - friend class DOTCONFDocument; - - private: - - DOTCONFDocumentNode* previousNode; - DOTCONFDocumentNode* nextNode; - DOTCONFDocumentNode* parentNode; - DOTCONFDocumentNode* childNode; - char** values; - int valuesCount; - char* name; - const DOTCONFDocument* document; - int lineNum; - char* fileName; - bool closed; - - void pushValue(char* _value); - - public: - - DOTCONFDocumentNode(); - ~DOTCONFDocumentNode(); - - const char* getConfigurationFileName() const { return fileName; } - int getConfigurationLineNumber() const { return lineNum; } - - const DOTCONFDocumentNode* getNextNode() const { return nextNode; } - const DOTCONFDocumentNode* getPreviuosNode() const { return previousNode; } - const DOTCONFDocumentNode* getParentNode() const { return parentNode; } - const DOTCONFDocumentNode* getChildNode() const { return childNode; } - const char* getValue(int index = 0) const; - const char* getName() const { return name; } - const DOTCONFDocument * getDocument() const { return document; } -}; - -class DOTCONFDocument -{ - public: - - enum CaseSensitive - { - CASESENSITIVE, - CASEINSENSETIVE - }; - - protected: - - AsyncDNSMemPool* mempool; - - private: - - typedef std::list CharList; - typedef std::list NodeList; - - DOTCONFDocumentNode* curParent; - DOTCONFDocumentNode* curPrev; - int curLine; - bool quoted; - NodeList nodeTree; - CharList requiredOptions; - CharList processedFiles; - FILE* file; - char* fileName; - CharList words; - int (*cmp_func)(const char*, const char*); - - int checkRequiredOptions(); - int parseLine(); - int parseFile(DOTCONFDocumentNode* _parent = NULL); - int checkConfig(const NodeList::iterator& from); - int cleanupLine(char* line); - char* getSubstitution(char* macro, int lineNum); - int macroSubstitute(DOTCONFDocumentNode* tagNode, int valueIndex); - - protected: - - virtual void error(int lineNum, const char* fileName, const char* fmt, ...) ATTR_PRINTF(4,5); - - public: - - DOTCONFDocument(CaseSensitive caseSensitivity = CASESENSITIVE); - virtual ~DOTCONFDocument(); - - int setContent(const char* _fileName); - - void setRequiredOptionNames(const char** requiredOptionNames); - const DOTCONFDocumentNode * getFirstNode() const; - const DOTCONFDocumentNode * findNode(const char* nodeName, const DOTCONFDocumentNode* parentNode = NULL, const DOTCONFDocumentNode* startNode = NULL) const; -}; - -#endif diff --git a/src/shared/Config/dotconfpp/mempool.cpp b/src/shared/Config/dotconfpp/mempool.cpp deleted file mode 100644 index 45bdee24c..000000000 --- a/src/shared/Config/dotconfpp/mempool.cpp +++ /dev/null @@ -1,106 +0,0 @@ -#include "mempool.h" - -AsyncDNSMemPool::PoolChunk::PoolChunk(size_t _size) -: pool(NULL), pos(0), size(_size) -{ - pool = malloc(size); -} - -AsyncDNSMemPool::PoolChunk::~PoolChunk() -{ - ::free(pool); -} - -AsyncDNSMemPool::AsyncDNSMemPool(size_t _defaultSize) -: chunks(NULL), chunksCount(0), defaultSize(_defaultSize), -poolUsage(0), poolUsageCounter(0) -{ -} - -AsyncDNSMemPool::~AsyncDNSMemPool() -{ - for (size_t i = 0; i < chunksCount; ++i) - delete chunks[i]; - - ::free(chunks); -} - -bool AsyncDNSMemPool::initialize() -{ - chunksCount = 1; - chunks = (PoolChunk**)malloc(sizeof(PoolChunk*)); - if (chunks == NULL) - return false; - - chunks[chunksCount - 1] = new PoolChunk(defaultSize); - - return true; -} - -void AsyncDNSMemPool::addNewChunk(size_t size) -{ - ++chunksCount; - - chunks = (PoolChunk**)realloc(chunks, chunksCount * sizeof(PoolChunk*)); - if (size <= defaultSize) - chunks[chunksCount - 1] = new PoolChunk(defaultSize); - else - chunks[chunksCount - 1] = new PoolChunk(size); -} - -void* AsyncDNSMemPool::Alloc(size_t size) -{ - PoolChunk* chunk = NULL; - for (size_t i = 0; i < chunksCount; ++i) - { - chunk = chunks[i]; - if ((chunk->size - chunk->pos) >= size) - { - chunk->pos += size; - return ((char*)chunk->pool) + chunk->pos - size; - } - } - - addNewChunk(size); - chunks[chunksCount - 1]->pos = size; - return chunks[chunksCount - 1]->pool; -} - -void AsyncDNSMemPool::Free() -{ - size_t pu = 0; - size_t psz = 0; - ++poolUsageCounter; - - for (size_t i = 0; i < chunksCount; ++i) - { - pu += chunks[i]->pos; - psz += chunks[i]->size; - chunks[i]->pos = 0; - } - - poolUsage = poolUsage > pu ? poolUsage : pu; - - if (poolUsageCounter >= 10 && chunksCount > 1) - { - psz -= chunks[chunksCount - 1]->size; - if (poolUsage < psz) - { - --chunksCount; - delete chunks[chunksCount]; - } - - poolUsage = 0; - poolUsageCounter = 0; - } -} - -void* AsyncDNSMemPool::Calloc(size_t size) -{ - return ::memset(Alloc(size), 0, size); -} - -char* AsyncDNSMemPool::Strdup(const char *str) -{ - return ::strcpy((char*)Alloc(strlen(str) + 1), str); -} diff --git a/src/shared/Config/dotconfpp/mempool.h b/src/shared/Config/dotconfpp/mempool.h deleted file mode 100644 index 44b789551..000000000 --- a/src/shared/Config/dotconfpp/mempool.h +++ /dev/null @@ -1,43 +0,0 @@ -#ifndef ASYNC_DNS_MEMPOOL_H -#define ASYNC_DNS_MEMPOOL_H - -#include -#include -#include - -class AsyncDNSMemPool -{ - private: - - struct PoolChunk - { - void* pool; - size_t pos; - size_t size; - - PoolChunk(size_t _size); - ~PoolChunk(); - }; - - PoolChunk** chunks; - size_t chunksCount; - size_t defaultSize; - - size_t poolUsage; - size_t poolUsageCounter; - - void addNewChunk(size_t size); - - public: - - AsyncDNSMemPool(size_t _defaultSize = 4096); - virtual ~AsyncDNSMemPool(); - - bool initialize(); - void Free(); - void* Alloc(size_t size); - void* Calloc(size_t size); - char* Strdup(const char *str); -}; - -#endif diff --git a/src/shared/Database/Database.cpp b/src/shared/Database/Database.cpp index 8bb729745..a0d9cc8b8 100644 --- a/src/shared/Database/Database.cpp +++ b/src/shared/Database/Database.cpp @@ -17,7 +17,7 @@ */ #include "DatabaseEnv.h" -#include "Config/ConfigEnv.h" +#include "Config/Config.h" #include #include diff --git a/src/shared/Errors.h b/src/shared/Errors.h index 16ffff9b5..6764c1858 100644 --- a/src/shared/Errors.h +++ b/src/shared/Errors.h @@ -62,7 +62,6 @@ if (!(CONDITION)) \ #define WPWarning(CONDITION) \ if (!(CONDITION)) \ { \ - ACE_Stack_Trace st; \ printf("%s:%i: Warning: Assertion in %s failed: %s",\ __FILE__, __LINE__, __FUNCTION__, STRINGIZE(CONDITION)); \ } diff --git a/src/shared/Log.cpp b/src/shared/Log.cpp index ebeee267d..c64199e4c 100644 --- a/src/shared/Log.cpp +++ b/src/shared/Log.cpp @@ -19,7 +19,7 @@ #include "Common.h" #include "Log.h" #include "Policies/SingletonImp.h" -#include "Config/ConfigEnv.h" +#include "Config/Config.h" #include "Util.h" #include "ByteBuffer.h" #include "ProgressBar.h" diff --git a/src/shared/ServiceWin32.cpp b/src/shared/ServiceWin32.cpp index 843b6b074..36ba014f6 100644 --- a/src/shared/ServiceWin32.cpp +++ b/src/shared/ServiceWin32.cpp @@ -57,7 +57,7 @@ bool WinServiceInstall() if (GetModuleFileName( 0, path, sizeof(path)/sizeof(path[0]) ) > 0) { SC_HANDLE service; - std::strcat(path, " --service"); + std::strcat(path, " -s run"); service = CreateService(serviceControlManager, serviceName, // name of service serviceLongName, // service name to display diff --git a/src/shared/SystemConfig.h.in b/src/shared/SystemConfig.h.in index 57f7e0b89..85edbc023 100644 --- a/src/shared/SystemConfig.h.in +++ b/src/shared/SystemConfig.h.in @@ -36,10 +36,10 @@ // Format is YYYYMMDDRR where RR is the change in the conf file // for that day. #ifndef _MANGOSDCONFVERSION -# define _MANGOSDCONFVERSION 2010051901 +# define _MANGOSDCONFVERSION 2010062001 #endif #ifndef _REALMDCONFVERSION -# define _REALMDCONFVERSION 2007062001 +# define _REALMDCONFVERSION 2010062001 #endif #if MANGOS_ENDIAN == MANGOS_BIGENDIAN diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index 5c22b2fa3..d1f9f0c75 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "10051" + #define REVISION_NR "10091" #endif // __REVISION_NR_H__ diff --git a/src/shared/revision_sql.h b/src/shared/revision_sql.h index 7e2003649..eb8a6c0c2 100644 --- a/src/shared/revision_sql.h +++ b/src/shared/revision_sql.h @@ -1,6 +1,6 @@ #ifndef __REVISION_SQL_H__ #define __REVISION_SQL_H__ #define REVISION_DB_CHARACTERS "required_10051_01_characters_character_aura" - #define REVISION_DB_MANGOS "required_10045_01_mangos_spell_proc_event" + #define REVISION_DB_MANGOS "required_10089_01_mangos_game_event_pool" #define REVISION_DB_REALMD "required_10008_01_realmd_realmd_db_version" #endif // __REVISION_SQL_H__ diff --git a/win/VC100/game.vcxproj b/win/VC100/game.vcxproj index 575fef41e..44858d500 100644 --- a/win/VC100/game.vcxproj +++ b/win/VC100/game.vcxproj @@ -370,6 +370,7 @@ + @@ -517,6 +518,7 @@ + diff --git a/win/VC100/game.vcxproj.filters b/win/VC100/game.vcxproj.filters index 44940f527..804e66778 100644 --- a/win/VC100/game.vcxproj.filters +++ b/win/VC100/game.vcxproj.filters @@ -442,6 +442,9 @@ Tool + + Object + @@ -832,5 +835,8 @@ Tool + + Object + \ No newline at end of file diff --git a/win/VC100/shared.vcxproj b/win/VC100/shared.vcxproj index c67029dd2..6d1e05f74 100644 --- a/win/VC100/shared.vcxproj +++ b/win/VC100/shared.vcxproj @@ -437,8 +437,6 @@ - - @@ -475,9 +473,6 @@ - - - diff --git a/win/VC100/shared.vcxproj.filters b/win/VC100/shared.vcxproj.filters index a72367461..8733657b2 100644 --- a/win/VC100/shared.vcxproj.filters +++ b/win/VC100/shared.vcxproj.filters @@ -16,9 +16,6 @@ {adb98dec-d22a-40b3-84be-51eaf2974a15} - - {dff0e90b-cab5-4d0b-bd5d-3cacbb638630} - {e35fd108-bd39-46ae-83f9-09cf1ebf4ea8} @@ -66,12 +63,6 @@ Config - - Config\dotconfpp - - - Config\dotconfpp - Auth @@ -194,15 +185,6 @@ Config - - Config - - - Config\dotconfpp - - - Config\dotconfpp - Auth diff --git a/win/VC80/game.vcproj b/win/VC80/game.vcproj index 409c26ffa..8f1c431a6 100644 --- a/win/VC80/game.vcproj +++ b/win/VC80/game.vcproj @@ -669,6 +669,14 @@ RelativePath="..\..\src\game\CalendarHandler.cpp" > + + + + diff --git a/win/VC80/shared.vcproj b/win/VC80/shared.vcproj index f23732b84..fbba29694 100644 --- a/win/VC80/shared.vcproj +++ b/win/VC80/shared.vcproj @@ -672,30 +672,6 @@ RelativePath="..\..\src\shared\Config\Config.h" > - - - - - - - - - - - - + + + + diff --git a/win/VC90/shared.vcproj b/win/VC90/shared.vcproj index b2e8e3dfa..b26e8ba90 100644 --- a/win/VC90/shared.vcproj +++ b/win/VC90/shared.vcproj @@ -678,30 +678,6 @@ RelativePath="..\..\src\shared\Config\Config.h" > - - - - - - - - - - - -