diff --git a/contrib/git_id/git_id.cpp b/contrib/git_id/git_id.cpp index 14bdf9165..332202c7c 100644 --- a/contrib/git_id/git_id.cpp +++ b/contrib/git_id/git_id.cpp @@ -875,6 +875,13 @@ int main(int argc, char *argv[]) } } + if (local && do_sql) + { + printf("Options -l/--local and -s/--sql can't be used in same time currently.\n"); + printf("FAILED\n"); + return 1; + } + DO( find_path() ); if(!local) { diff --git a/sql/mangos.sql b/sql/mangos.sql index f8aad173b..ce17d1036 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_8549_03_mangos_battleground_events` bit(1) default NULL + `required_8573_01_mangos_mangos_string` bit(1) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Used DB version notes'; -- @@ -178,6 +178,87 @@ LOCK TABLES `areatrigger_teleport` WRITE; /*!40000 ALTER TABLE `areatrigger_teleport` ENABLE KEYS */; UNLOCK TABLES; +-- +-- Table structure for table `battleground_events` +-- + +DROP TABLE IF EXISTS `battleground_events`; +CREATE TABLE `battleground_events` ( + `map` smallint(5) NOT NULL, + `event1` tinyint(3) unsigned NOT NULL, + `event2` tinyint(3) unsigned NOT NULL, + `description` varchar(255) NOT NULL, + PRIMARY KEY (`map`,`event1`,`event2`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +-- +-- Dumping data for table `battleground_events` +-- + +LOCK TABLES `battleground_events` WRITE; +/*!40000 ALTER TABLE `battleground_events` DISABLE KEYS */; +INSERT INTO battleground_events (map, event1, event2, description) VALUES +-- WS +(489, 0, 0, 'Alliance Flag'), +(489, 1, 0, 'Horde Flag'), +(489, 2, 0, 'Spirit Guides'), +(489, 254, 0, 'Doors'), +-- AB +(529, 0, 0, 'Stables - neutral'), +(529, 0, 1, 'Stables - alliance contested'), +(529, 0, 2, 'Stables - horde contested'), +(529, 0, 3, 'Stables - alliance owned'), +(529, 0, 4, 'Stables - horde owned'), +(529, 1, 0, 'Blacksmith - neutral'), +(529, 1, 1, 'Blacksmith - alliance contested'), +(529, 1, 2, 'Blacksmith - horde contested'), +(529, 1, 3, 'Blacksmith - alliance owned'), +(529, 1, 4, 'Blacksmith - horde owned'), +(529, 2, 0, 'Farm - neutral'), +(529, 2, 1, 'Farm - alliance contested'), +(529, 2, 2, 'Farm - horde contested'), +(529, 2, 3, 'Farm - alliance owned'), +(529, 2, 4, 'Farm - horde owned'), +(529, 3, 0, 'Lumber Mill - neutral'), +(529, 3, 1, 'Lumber Mill - alliance contested'), +(529, 3, 2, 'Lumber Mill - horde contested'), +(529, 3, 3, 'Lumber Mill - alliance owned'), +(529, 3, 4, 'Lumber Mill - horde owned'), +(529, 4, 0, 'Gold Mine - neutral'), +(529, 4, 1, 'Gold Mine - alliance contested'), +(529, 4, 2, 'Gold Mine - horde contested'), +(529, 4, 3, 'Gold Mine - alliance owned'), +(529, 4, 4, 'Gold Mine - horde owned'), +(529, 254, 0, 'doors'), +-- EY +(566, 0, 0, 'Fel Reaver - alliance'), +(566, 0, 1, 'Fel Reaver - horde'), +(566, 0, 2, 'Fel Reaver - neutral'), +(566, 1, 0, 'Blood Elf - alliance'), +(566, 1, 1, 'Blood Elf - horde'), +(566, 1, 2, 'Blood Elf - neutral'), +(566, 2, 0, 'Draenei Ruins - alliance'), +(566, 2, 1, 'Draenei Ruins - horde'), +(566, 2, 2, 'Draenei Ruins - neutral'), +(566, 3, 0, 'Mage Tower - alliance'), +(566, 3, 1, 'Mage Tower - horde'), +(566, 3, 2, 'Mage Tower - neutral'), +(566, 4, 0, 'capture flag - Fel Reaver'), +(566, 4, 1, 'capture flag - Blood Elf'), +(566, 4, 2, 'capture flag - Draenei Ruins'), +(566, 4, 3, 'capture flag - Mage Tower'), +(566, 4, 4, 'capture flag - center'), +(566, 254, 0, 'doors'), +-- arenas +(559, 253, 0, 'buffs'), +(559, 254, 0, 'doors'), +(572, 253, 0, 'buffs'), +(572, 254, 0, 'doors'), +(562, 253, 0, 'buffs'), +(562, 254, 0, 'doors'); +/*!40000 ALTER TABLE `battleground_events` ENABLE KEYS */; +UNLOCK TABLES; + -- -- Table structure for table `battleground_template` -- @@ -583,6 +664,27 @@ LOCK TABLES `creature_addon` WRITE; /*!40000 ALTER TABLE `creature_addon` ENABLE KEYS */; UNLOCK TABLES; +-- +-- Table structure for table `creature_battleground` +-- + +DROP TABLE IF EXISTS `creature_battleground`; +CREATE TABLE `creature_battleground` ( + `guid` int(10) unsigned NOT NULL COMMENT 'Creature\'s GUID', + `event1` tinyint(3) unsigned NOT NULL COMMENT 'main event', + `event2` tinyint(3) unsigned NOT NULL COMMENT 'sub event', + PRIMARY KEY (`guid`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='Creature battleground indexing system'; + +-- +-- Dumping data for table `creature_battleground` +-- + +LOCK TABLES `creature_battleground` WRITE; +/*!40000 ALTER TABLE `creature_battleground` DISABLE KEYS */; +/*!40000 ALTER TABLE `creature_battleground` ENABLE KEYS */; +UNLOCK TABLES; + -- -- Table structure for table `creature_equip_template` -- @@ -1422,6 +1524,27 @@ LOCK TABLES `gameobject` WRITE; /*!40000 ALTER TABLE `gameobject` ENABLE KEYS */; UNLOCK TABLES; +-- +-- Table structure for table `gameobject_battleground` +-- + +DROP TABLE IF EXISTS `gameobject_battleground`; +CREATE TABLE `gameobject_battleground` ( + `guid` int(10) unsigned NOT NULL COMMENT 'GameObject\'s GUID', + `event1` tinyint(3) unsigned NOT NULL COMMENT 'main event', + `event2` tinyint(3) unsigned NOT NULL COMMENT 'sub event', + PRIMARY KEY (`guid`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='GameObject battleground indexing system'; + +-- +-- Dumping data for table `gameobject_battleground` +-- + +LOCK TABLES `gameobject_battleground` WRITE; +/*!40000 ALTER TABLE `gameobject_battleground` DISABLE KEYS */; +/*!40000 ALTER TABLE `gameobject_battleground` ENABLE KEYS */; +UNLOCK TABLES; + -- -- Table structure for table `gameobject_involvedrelation` -- @@ -2893,8 +3016,6 @@ INSERT INTO `mangos_string` VALUES (570,'The uint32 value of %u in %u is: %u',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), (571,'Get %u float Value:[OPCODE]:%u [VALUE]:%f',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), (572,'The float of %u value in %u is: %f',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), -(573,'.Set32Bit:[OPCODE]:%u [VALUE]:%u',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), -(574,'You set Bit of Field:%u to Value: %u',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), (575,'.Mod32Value:[OPCODE]:%u [VALUE]:%i',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), (576,'You modified the value of Field:%u to Value: %u',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), (577,'You are now invisible.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), diff --git a/sql/updates/8549_03_mangos_battleground_events.sql b/sql/updates/8549_03_mangos_battleground_events.sql index 63bedd54d..f310af3ad 100644 --- a/sql/updates/8549_03_mangos_battleground_events.sql +++ b/sql/updates/8549_03_mangos_battleground_events.sql @@ -89,4 +89,4 @@ INSERT INTO battleground_events (map, event1, event2, description) VALUES (@RL_MAP, 254, 0, 'doors'), (@BE_MAP, 253, 0, 'buffs'), - (@BE_MAP, 254, 0, 'doors') + (@BE_MAP, 254, 0, 'doors'); diff --git a/sql/updates/8573_01_mangos_mangos_string.sql b/sql/updates/8573_01_mangos_mangos_string.sql new file mode 100644 index 000000000..6c0b820e8 --- /dev/null +++ b/sql/updates/8573_01_mangos_mangos_string.sql @@ -0,0 +1,4 @@ +ALTER TABLE db_version CHANGE COLUMN required_8549_03_mangos_battleground_events required_8573_01_mangos_mangos_string bit; + +DELETE FROM mangos_string WHERE entry IN(573,574); + diff --git a/sql/updates/Makefile.am b/sql/updates/Makefile.am index 5387117fa..457efe5b4 100644 --- a/sql/updates/Makefile.am +++ b/sql/updates/Makefile.am @@ -116,6 +116,7 @@ pkgdata_DATA = \ 8548_01_mangos_creature_battleground.sql \ 8548_02_mangos_gameobject_battleground.sql \ 8549_03_mangos_battleground_events.sql \ + 8573_01_mangos_mangos_string.sql \ README ## Additional files to include when running 'make dist' @@ -212,4 +213,5 @@ EXTRA_DIST = \ 8548_01_mangos_creature_battleground.sql \ 8548_02_mangos_gameobject_battleground.sql \ 8549_03_mangos_battleground_events.sql \ + 8573_01_mangos_mangos_string.sql \ README diff --git a/src/game/ArenaTeam.cpp b/src/game/ArenaTeam.cpp index 51302179a..b9615a57c 100644 --- a/src/game/ArenaTeam.cpp +++ b/src/game/ArenaTeam.cpp @@ -161,90 +161,90 @@ bool ArenaTeam::AddMember(const uint64& PlayerGuid) return true; } -bool ArenaTeam::LoadArenaTeamFromDB(uint32 ArenaTeamId) +bool ArenaTeam::LoadArenaTeamFromDB(QueryResult *arenaTeamDataResult) { - QueryResult *result = CharacterDatabase.PQuery("SELECT arenateamid,name,captainguid,type,BackgroundColor,EmblemStyle,EmblemColor,BorderStyle,BorderColor FROM arena_team WHERE arenateamid = '%u'", ArenaTeamId); - - if(!result) + if(!arenaTeamDataResult) return false; - Field *fields = result->Fetch(); + Field *fields = arenaTeamDataResult->Fetch(); - m_TeamId = fields[0].GetUInt32(); - m_Name = fields[1].GetCppString(); - m_CaptainGuid = MAKE_NEW_GUID(fields[2].GetUInt32(), 0, HIGHGUID_PLAYER); - m_Type = fields[3].GetUInt32(); - m_BackgroundColor = fields[4].GetUInt32(); - m_EmblemStyle = fields[5].GetUInt32(); - m_EmblemColor = fields[6].GetUInt32(); - m_BorderStyle = fields[7].GetUInt32(); - m_BorderColor = fields[8].GetUInt32(); - - delete result; - - // only load here, so additional checks can be made - LoadStatsFromDB(ArenaTeamId); - LoadMembersFromDB(ArenaTeamId); - - if(Empty()) - { - // arena team is empty, delete from db - CharacterDatabase.BeginTransaction(); - CharacterDatabase.PExecute("DELETE FROM arena_team WHERE arenateamid = '%u'", ArenaTeamId); - CharacterDatabase.PExecute("DELETE FROM arena_team_member WHERE arenateamid = '%u'", ArenaTeamId); - CharacterDatabase.PExecute("DELETE FROM arena_team_stats WHERE arenateamid = '%u'", ArenaTeamId); - CharacterDatabase.CommitTransaction(); - return false; - } + m_TeamId = fields[0].GetUInt32(); + m_Name = fields[1].GetCppString(); + m_CaptainGuid = MAKE_NEW_GUID(fields[2].GetUInt32(), 0, HIGHGUID_PLAYER); + m_Type = fields[3].GetUInt32(); + m_BackgroundColor = fields[4].GetUInt32(); + m_EmblemStyle = fields[5].GetUInt32(); + m_EmblemColor = fields[6].GetUInt32(); + m_BorderStyle = fields[7].GetUInt32(); + m_BorderColor = fields[8].GetUInt32(); + //load team stats + m_stats.rating = fields[9].GetUInt32(); + m_stats.games_week = fields[10].GetUInt32(); + m_stats.wins_week = fields[11].GetUInt32(); + m_stats.games_season = fields[12].GetUInt32(); + m_stats.wins_season = fields[13].GetUInt32(); + m_stats.rank = fields[14].GetUInt32(); return true; } -void ArenaTeam::LoadStatsFromDB(uint32 ArenaTeamId) +bool ArenaTeam::LoadMembersFromDB(QueryResult *arenaTeamMembersResult) { - // 0 1 2 3 4 5 - QueryResult *result = CharacterDatabase.PQuery("SELECT rating,games,wins,played,wins2,rank FROM arena_team_stats WHERE arenateamid = '%u'", ArenaTeamId); + if(!arenaTeamMembersResult) + return false; - if(!result) - return; - - Field *fields = result->Fetch(); - - m_stats.rating = fields[0].GetUInt32(); - m_stats.games_week = fields[1].GetUInt32(); - m_stats.wins_week = fields[2].GetUInt32(); - m_stats.games_season = fields[3].GetUInt32(); - m_stats.wins_season = fields[4].GetUInt32(); - m_stats.rank = fields[5].GetUInt32(); - - delete result; -} - -void ArenaTeam::LoadMembersFromDB(uint32 ArenaTeamId) -{ - // 0 1 2 3 4 5 6 7 - QueryResult *result = CharacterDatabase.PQuery("SELECT member.guid,played_week,wons_week,played_season,wons_season,personal_rating,name,class " - "FROM arena_team_member member " - "INNER JOIN characters chars on member.guid = chars.guid " - "WHERE member.arenateamid = '%u'", ArenaTeamId); - if(!result) - return; + bool captainPresentInTeam = false; do { - Field *fields = result->Fetch(); + Field *fields = arenaTeamMembersResult->Fetch(); + //prevent crash if db records are broken, when all members in result are already processed and current team hasn't got any members + if (!fields) + break; + uint32 arenaTeamId = fields[0].GetUInt32(); + if (arenaTeamId < m_TeamId) + { + //there is in table arena_team_member record which doesn't have arenateamid in arena_team table, report error + sLog.outErrorDb("ArenaTeam %u does not exist but it has record in arena_team_member table, deleting it!", arenaTeamId); + CharacterDatabase.PExecute("DELETE FROM arena_team_member WHERE arenateamid = '%u'", arenaTeamId); + continue; + } + + if (arenaTeamId > m_TeamId) + //we loaded all members for this arena_team already, break cycle + break; + ArenaTeamMember newmember; - newmember.guid = MAKE_NEW_GUID(fields[0].GetUInt32(), 0, HIGHGUID_PLAYER); - newmember.games_week = fields[1].GetUInt32(); - newmember.wins_week = fields[2].GetUInt32(); - newmember.games_season = fields[3].GetUInt32(); - newmember.wins_season = fields[4].GetUInt32(); - newmember.personal_rating = fields[5].GetUInt32(); - newmember.name = fields[6].GetCppString(); - newmember.Class = fields[7].GetUInt8(); + newmember.guid = MAKE_NEW_GUID(fields[1].GetUInt32(), 0, HIGHGUID_PLAYER); + newmember.games_week = fields[2].GetUInt32(); + newmember.wins_week = fields[3].GetUInt32(); + newmember.games_season = fields[4].GetUInt32(); + newmember.wins_season = fields[5].GetUInt32(); + newmember.personal_rating = fields[6].GetUInt32(); + newmember.name = fields[7].GetCppString(); + newmember.Class = fields[8].GetUInt8(); + + //check if member exists in characters table + if (newmember.name.empty()) + { + sLog.outErrorDb("ArenaTeam %u has member with empty name - probably player %u doesn't exist, deleting him from memberlist!", arenaTeamId, GUID_LOPART(newmember.guid)); + this->DelMember(newmember.guid); + continue; + } + if (newmember.guid == GetCaptain()) + captainPresentInTeam = true; + m_members.push_back(newmember); - }while( result->NextRow() ); - delete result; + }while (arenaTeamMembersResult->NextRow()); + + if(Empty() || !captainPresentInTeam) + { + // arena team is empty or captain is not in team, delete from db + sLog.outErrorDb("ArenaTeam %u does not have any members or its captain is not in team, disbanding it...", m_TeamId); + return false; + } + + return true; } void ArenaTeam::SetCaptain(const uint64& guid) @@ -291,9 +291,12 @@ void ArenaTeam::DelMember(uint64 guid) void ArenaTeam::Disband(WorldSession *session) { // event - WorldPacket data; - session->BuildArenaTeamEventPacket(&data, ERR_ARENA_TEAM_DISBANDED_S, 2, session->GetPlayerName(), GetName(), ""); - BroadcastPacket(&data); + if (session) + { + WorldPacket data; + session->BuildArenaTeamEventPacket(&data, ERR_ARENA_TEAM_DISBANDED_S, 2, session->GetPlayerName(), GetName(), ""); + BroadcastPacket(&data); + } while (!m_members.empty()) { diff --git a/src/game/ArenaTeam.h b/src/game/ArenaTeam.h index 3fabde337..822444b75 100644 --- a/src/game/ArenaTeam.h +++ b/src/game/ArenaTeam.h @@ -179,8 +179,8 @@ class ArenaTeam bool IsFighting() const; - bool LoadArenaTeamFromDB(uint32 ArenaTeamId); - void LoadMembersFromDB(uint32 ArenaTeamId); + bool LoadArenaTeamFromDB(QueryResult *arenaTeamDataResult); + bool LoadMembersFromDB(QueryResult *arenaTeamMembersResult); void LoadStatsFromDB(uint32 ArenaTeamId); void SaveToDB(); diff --git a/src/game/BattleGround.cpp b/src/game/BattleGround.cpp index 0667c5cea..7e3bc1cf8 100644 --- a/src/game/BattleGround.cpp +++ b/src/game/BattleGround.cpp @@ -152,6 +152,7 @@ BattleGround::BattleGround() m_MinPlayers = 0; m_MapId = 0; + m_Map = NULL; m_TeamStartLocX[BG_TEAM_ALLIANCE] = 0; m_TeamStartLocX[BG_TEAM_HORDE] = 0; @@ -214,10 +215,12 @@ BattleGround::~BattleGround() } sBattleGroundMgr.RemoveBattleGround(GetInstanceID(), GetTypeID()); + // unload map - if (Map * map = MapManager::Instance().FindMap(GetMapId(), GetInstanceID())) - if (map->IsBattleGroundOrArena()) - ((BattleGroundMap*)map)->SetUnload(); + // map can be null at bg destruction + if (m_Map) + m_Map->SetUnload(); + // remove from bg free slot queue this->RemoveFromBGFreeSlotQueue(); @@ -1292,15 +1295,11 @@ void BattleGround::UpdatePlayerScore(Player *Source, uint32 type, uint32 value) bool BattleGround::AddObject(uint32 type, uint32 entry, float x, float y, float z, float o, float rotation0, float rotation1, float rotation2, float rotation3, uint32 respawnTime) { - Map * map = MapManager::Instance().FindMap(GetMapId(),GetInstanceID()); - if (!map) - return false; - // must be created this way, adding to godatamap would add it to the base map of the instance // and when loading it (in go::LoadFromDB()), a new guid would be assigned to the object, and a new object would be created // so we must create it specific for this instance GameObject * go = new GameObject; - if(!go->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT),entry, map, + if(!go->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT),entry, GetBgMap(), PHASEMASK_NORMAL, x,y,z,o,rotation0,rotation1,rotation2,rotation3,100,GO_STATE_READY)) { sLog.outErrorDb("Gameobject template %u not found in database! BattleGround not created!", entry); @@ -1340,7 +1339,7 @@ bool BattleGround::AddObject(uint32 type, uint32 entry, float x, float y, float //it would be nice to correctly implement GO_ACTIVATED state and open/close doors in gameobject code void BattleGround::DoorClose(uint64 const& guid) { - GameObject *obj = HashMapHolder::Find(guid); + GameObject *obj = GetBgMap()->GetGameObject(guid); if (obj) { //if doors are open, close it @@ -1359,7 +1358,7 @@ void BattleGround::DoorClose(uint64 const& guid) void BattleGround::DoorOpen(uint64 const& guid) { - GameObject *obj = HashMapHolder::Find(guid); + GameObject *obj = GetBgMap()->GetGameObject(guid); if (obj) { //change state to be sure they will be opened @@ -1459,12 +1458,11 @@ void BattleGround::SpawnEvent(uint8 event1, uint8 event2, bool spawn) void BattleGround::SpawnBGObject(uint64 const& guid, uint32 respawntime) { - GameObject *obj = HashMapHolder::Find(guid); + Map* map = GetBgMap(); + + GameObject *obj = map->GetGameObject(guid); if(!obj) return; - Map * map = MapManager::Instance().FindMap(GetMapId(),GetInstanceID()); - if (!map) - return; if (respawntime == 0) { //we need to change state from GO_JUST_DEACTIVATED to GO_READY in case battleground is starting again @@ -1483,12 +1481,11 @@ void BattleGround::SpawnBGObject(uint64 const& guid, uint32 respawntime) void BattleGround::SpawnBGCreature(uint64 const& guid, uint32 respawntime) { - Creature* obj = HashMapHolder::Find(guid); + Map* map = GetBgMap(); + + Creature* obj = map->GetCreature(guid); if (!obj) return; - Map * map = MapManager::Instance().FindMap(GetMapId(),GetInstanceID()); - if (!map) - return; if (respawntime == 0) { obj->Respawn(); @@ -1508,12 +1505,13 @@ bool BattleGround::DelObject(uint32 type) if (!m_BgObjects[type]) return true; - GameObject *obj = HashMapHolder::Find(m_BgObjects[type]); + GameObject *obj = GetBgMap()->GetGameObject(m_BgObjects[type]); if (!obj) { sLog.outError("Can't find gobject guid: %u",GUID_LOPART(m_BgObjects[type])); return false; } + obj->SetRespawnTime(0); // not save respawn time obj->Delete(); m_BgObjects[type] = 0; @@ -1560,11 +1558,20 @@ buffs are in their positions when battleground starts */ void BattleGround::HandleTriggerBuff(uint64 const& go_guid) { - GameObject *obj = HashMapHolder::Find(go_guid); + GameObject *obj = GetBgMap()->GetGameObject(go_guid); if (!obj || obj->GetGoType() != GAMEOBJECT_TYPE_TRAP || !obj->isSpawned()) return; - //change buff type, when buff is used: + // static buffs are already handled just by database and don't need + // battleground code + if (!m_BuffChange) + { + obj->SetLootState(GO_JUST_DEACTIVATED); // can be despawned or destroyed + return; + } + + // change buff type, when buff is used: + // TODO this can be done when poolsystem works for instances int32 index = m_BgObjects.size() - 1; while (index >= 0 && m_BgObjects[index] != go_guid) index--; diff --git a/src/game/BattleGround.h b/src/game/BattleGround.h index fa26e69bd..6c24828ec 100644 --- a/src/game/BattleGround.h +++ b/src/game/BattleGround.h @@ -36,6 +36,7 @@ class GameObject; class Group; class Player; class WorldPacket; +class BattleGroundMap; struct WorldSafeLocsEntry; @@ -395,6 +396,14 @@ class BattleGround void SetMapId(uint32 MapID) { m_MapId = MapID; } uint32 GetMapId() const { return m_MapId; } + /* Map pointers */ + void SetBgMap(BattleGroundMap* map) { m_Map = map; } + BattleGroundMap* GetBgMap() + { + ASSERT(m_Map); + return m_Map; + } + void SetTeamStartLoc(uint32 TeamID, float X, float Y, float Z, float O); void GetTeamStartLoc(uint32 TeamID, float &X, float &Y, float &Z, float &O) const { @@ -619,6 +628,7 @@ class BattleGround /* Start location */ uint32 m_MapId; + BattleGroundMap* m_Map; float m_TeamStartLocX[BG_TEAMS_COUNT]; float m_TeamStartLocY[BG_TEAMS_COUNT]; float m_TeamStartLocZ[BG_TEAMS_COUNT]; diff --git a/src/game/BattleGroundAB.cpp b/src/game/BattleGroundAB.cpp index ea10e3dee..19d592ae1 100644 --- a/src/game/BattleGroundAB.cpp +++ b/src/game/BattleGroundAB.cpp @@ -469,7 +469,7 @@ void BattleGroundAB::Reset() } m_IsInformedNearVictory = false; - bool isBGWeekend = sBattleGroundMgr.IsBGWeekend(GetTypeID()); + bool isBGWeekend = BattleGroundMgr::IsBGWeekend(GetTypeID()); m_HonorTics = (isBGWeekend) ? BG_AB_ABBGWeekendHonorTicks : BG_AB_NotABBGWeekendHonorTicks; m_ReputationTics = (isBGWeekend) ? BG_AB_ABBGWeekendReputationTicks : BG_AB_NotABBGWeekendReputationTicks; diff --git a/src/game/BattleGroundEY.cpp b/src/game/BattleGroundEY.cpp index d9855e150..f3ef573f2 100644 --- a/src/game/BattleGroundEY.cpp +++ b/src/game/BattleGroundEY.cpp @@ -430,7 +430,7 @@ void BattleGroundEY::Reset() m_DroppedFlagGUID = 0; m_PointAddingTimer = 0; m_TowerCapCheckTimer = 0; - bool isBGWeekend = sBattleGroundMgr.IsBGWeekend(GetTypeID()); + bool isBGWeekend = BattleGroundMgr::IsBGWeekend(GetTypeID()); m_HonorTics = (isBGWeekend) ? BG_EY_EYWeekendHonorTicks : BG_EY_NotEYWeekendHonorTicks; for(uint8 i = 0; i < BG_EY_NODES_MAX; ++i) @@ -468,7 +468,7 @@ void BattleGroundEY::RespawnFlagAfterDrop() { RespawnFlag(true); - GameObject *obj = HashMapHolder::Find(GetDroppedFlagGUID()); + GameObject *obj = GetBgMap()->GetGameObject(GetDroppedFlagGUID()); if (obj) obj->Delete(); else diff --git a/src/game/BattleGroundHandler.cpp b/src/game/BattleGroundHandler.cpp index 21be23200..8b02bb6e5 100644 --- a/src/game/BattleGroundHandler.cpp +++ b/src/game/BattleGroundHandler.cpp @@ -23,7 +23,6 @@ #include "Player.h" #include "ObjectMgr.h" #include "WorldSession.h" -#include "ObjectAccessor.h" #include "Object.h" #include "Chat.h" #include "BattleGroundMgr.h" diff --git a/src/game/BattleGroundMgr.h b/src/game/BattleGroundMgr.h index 45199d8b6..5fb3668c0 100644 --- a/src/game/BattleGroundMgr.h +++ b/src/game/BattleGroundMgr.h @@ -21,6 +21,7 @@ #include "Common.h" #include "Policies/Singleton.h" +#include "Utilities/EventProcessor.h" #include "BattleGround.h" typedef std::map BattleGroundSet; diff --git a/src/game/BattleGroundWS.cpp b/src/game/BattleGroundWS.cpp index 0816d689a..296e79875 100644 --- a/src/game/BattleGroundWS.cpp +++ b/src/game/BattleGroundWS.cpp @@ -98,6 +98,7 @@ void BattleGroundWS::StartingEventOpenDoors() // TODO implement timer to despawn doors after a short while + SpawnEvent(WS_EVENT_SPIRITGUIDES_SPAWN, 0, true); SpawnEvent(WS_EVENT_FLAG_A, 0, true); SpawnEvent(WS_EVENT_FLAG_H, 0, true); } @@ -149,7 +150,7 @@ void BattleGroundWS::RespawnFlagAfterDrop(uint32 team) PlaySoundToAll(BG_WS_SOUND_FLAGS_RESPAWNED); - GameObject *obj = HashMapHolder::Find(GetDroppedFlagGUID(team)); + GameObject *obj = GetBgMap()->GetGameObject(GetDroppedFlagGUID(team)); if (obj) obj->Delete(); else @@ -533,7 +534,7 @@ void BattleGroundWS::Reset() m_FlagState[i] = BG_WS_FLAG_STATE_ON_BASE; m_TeamScores[i] = 0; } - bool isBGWeekend = sBattleGroundMgr.IsBGWeekend(GetTypeID()); + bool isBGWeekend = BattleGroundMgr::IsBGWeekend(GetTypeID()); m_ReputationCapture = (isBGWeekend) ? 45 : 35; m_HonorWinKills = (isBGWeekend) ? 3 : 1; m_HonorEndKills = (isBGWeekend) ? 4 : 2; diff --git a/src/game/Chat.h b/src/game/Chat.h index f5e2c2a38..45a029346 100644 --- a/src/game/Chat.h +++ b/src/game/Chat.h @@ -492,7 +492,6 @@ class ChatHandler bool HandleWaterwalkCommand(const char* args); //! Development Commands - bool HandleSet32Bit(const char* args); bool HandleSaveAllCommand(const char* args); Player* getSelectedPlayer(); diff --git a/src/game/Creature.cpp b/src/game/Creature.cpp index 0df39018f..4872e282d 100644 --- a/src/game/Creature.cpp +++ b/src/game/Creature.cpp @@ -159,7 +159,7 @@ void Creature::RemoveCorpse() m_deathTimer = 0; setDeathState(DEAD); - ObjectAccessor::UpdateObjectVisibility(this); + UpdateObjectVisibility(); loot.clear(); uint32 respawnDelay = m_respawnDelay; if (AI()) @@ -1585,9 +1585,9 @@ void Creature::Respawn() // forced recreate creature object at clients UnitVisibility currentVis = GetVisibility(); SetVisibility(VISIBILITY_RESPAWN); - ObjectAccessor::UpdateObjectVisibility(this); + UpdateObjectVisibility(); SetVisibility(currentVis); // restore visibility state - ObjectAccessor::UpdateObjectVisibility(this); + UpdateObjectVisibility(); if(getDeathState()==DEAD) { diff --git a/src/game/GameObject.cpp b/src/game/GameObject.cpp index 995940ebf..c0e0299c4 100644 --- a/src/game/GameObject.cpp +++ b/src/game/GameObject.cpp @@ -449,7 +449,7 @@ void GameObject::Update(uint32 /*p_time*/) if(sWorld.getConfig(CONFIG_SAVE_RESPAWN_TIME_IMMEDIATLY)) SaveRespawnTime(); - ObjectAccessor::UpdateObjectVisibility(this); + UpdateObjectVisibility(); break; } @@ -602,7 +602,7 @@ bool GameObject::LoadFromDB(uint32 guid, Map *map) if (!Create(guid,entry, map, phaseMask, x, y, z, ang, rotation0, rotation1, rotation2, rotation3, animprogress, go_state) ) return false; - if(!GetGOInfo()->GetDespawnPossibility() && !GetGOInfo()->IsDespawnAtAction()) + if (!GetGOInfo()->GetDespawnPossibility() && !GetGOInfo()->IsDespawnAtAction() && data->spawntimesecs >= 0) { SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_NODESPAWN); m_spawnedByDefault = true; diff --git a/src/game/Guild.cpp b/src/game/Guild.cpp index 48c258647..15f642c7e 100644 --- a/src/game/Guild.cpp +++ b/src/game/Guild.cpp @@ -208,62 +208,43 @@ void Guild::SetGINFO(std::string ginfo) CharacterDatabase.PExecute("UPDATE guild SET info='%s' WHERE guildid='%u'", ginfo.c_str(), m_Id); } -bool Guild::LoadGuildFromDB(uint32 GuildId) +bool Guild::LoadGuildFromDB(QueryResult *guildDataResult) { - //set m_Id in case guild data are broken in DB and Guild will be Disbanded (deleted from DB) - m_Id = GuildId; - - QueryResult *result = CharacterDatabase.PQuery("SELECT COUNT(TabId) FROM guild_bank_tab WHERE guildid='%u'", GuildId); - if (result) - { - Field *fields = result->Fetch(); - m_PurchasedTabs = fields[0].GetUInt32(); - if (m_PurchasedTabs > GUILD_BANK_MAX_TABS) - m_PurchasedTabs = GUILD_BANK_MAX_TABS; - delete result; - } - - if (!LoadRanksFromDB(GuildId)) + if (!guildDataResult) return false; - if (!LoadMembersFromDB(GuildId)) - return false; + Field *fields = guildDataResult->Fetch(); - LoadBankRightsFromDB(GuildId); // Must be after LoadRanksFromDB because it populates rank struct + m_Id = fields[0].GetUInt32(); + m_Name = fields[1].GetCppString(); + m_LeaderGuid = MAKE_NEW_GUID(fields[2].GetUInt32(), 0, HIGHGUID_PLAYER); + m_EmblemStyle = fields[3].GetUInt32(); + m_EmblemColor = fields[4].GetUInt32(); + m_BorderStyle = fields[5].GetUInt32(); + m_BorderColor = fields[6].GetUInt32(); + m_BackgroundColor = fields[7].GetUInt32(); + GINFO = fields[8].GetCppString(); + MOTD = fields[9].GetCppString(); + time_t time = fields[10].GetUInt64(); + m_GuildBankMoney = fields[11].GetUInt64(); + m_PurchasedTabs = fields[12].GetUInt32(); - // 0 1 2 3 4 5 - result = CharacterDatabase.PQuery("SELECT name, leaderguid, EmblemStyle, EmblemColor, BorderStyle, BorderColor," - // 6 7 8 9 10 - "BackgroundColor, info, motd, createdate, BankMoney FROM guild WHERE guildid = '%u'", GuildId); - - if (!result) - return false; - - Field *fields = result->Fetch(); - - m_Name = fields[0].GetCppString(); - m_LeaderGuid = MAKE_NEW_GUID(fields[1].GetUInt32(), 0, HIGHGUID_PLAYER); - - m_EmblemStyle = fields[2].GetUInt32(); - m_EmblemColor = fields[3].GetUInt32(); - m_BorderStyle = fields[4].GetUInt32(); - m_BorderColor = fields[5].GetUInt32(); - m_BackgroundColor = fields[6].GetUInt32(); - GINFO = fields[7].GetCppString(); - MOTD = fields[8].GetCppString(); - time_t time = fields[9].GetUInt64(); - m_GuildBankMoney = fields[10].GetUInt64(); - - delete result; + if (m_PurchasedTabs > GUILD_BANK_MAX_TABS) + m_PurchasedTabs = GUILD_BANK_MAX_TABS; if (time > 0) { - tm local = *(localtime(&time)); // dereference and assign + tm local = *(localtime(&time)); // dereference and assign m_CreatedDay = local.tm_mday; m_CreatedMonth = local.tm_mon + 1; m_CreatedYear = local.tm_year + 1900; } + return true; +} + +bool Guild::CheckGuildStructure() +{ // Repair the structure of guild // If the guildmaster doesn't exist or isn't the member of guild // attempt to promote another member @@ -286,24 +267,19 @@ bool Guild::LoadGuildFromDB(uint32 GuildId) ChangeRank(itr->first, GR_OFFICER); } - sLog.outDebug("Guild %u Creation time Loaded day: %u, month: %u, year: %u", GuildId, m_CreatedDay, m_CreatedMonth, m_CreatedYear); - return true; } -bool Guild::LoadRanksFromDB(uint32 GuildId) +bool Guild::LoadRanksFromDB(QueryResult *guildRanksResult) { - Field *fields; - // 0 1 2 3 - QueryResult *result = CharacterDatabase.PQuery("SELECT rid,rname,rights,BankMoneyPerDay FROM guild_rank WHERE guildid = '%u' ORDER BY rid ASC", GuildId); - - if (!result) + if (!guildRanksResult) { - sLog.outError("Guild %u has broken `guild_rank` data, creating new...",GuildId); + sLog.outError("Guild %u has broken `guild_rank` data, creating new...",m_Id); CreateDefaultGuildRanks(0); return true; } + Field *fields; bool broken_ranks = false; //GUILD RANKS are sequence starting from 0 = GUILD_MASTER (ALL PRIVILEGES) to max 9 (lowest privileges) @@ -313,12 +289,27 @@ bool Guild::LoadRanksFromDB(uint32 GuildId) do { - fields = result->Fetch(); + fields = guildRanksResult->Fetch(); + //condition that would be true when all ranks in QueryResult will be processed and guild without ranks is being processed + if (!fields) + break; - uint32 rankID = fields[0].GetUInt32(); - std::string rankName = fields[1].GetCppString(); - uint32 rankRights = fields[2].GetUInt32(); - uint32 rankMoney = fields[3].GetUInt32(); + uint32 guildId = fields[0].GetUInt32(); + if (guildId < m_Id) + { + //there is in table guild_rank record which doesn't have guildid in guild table, report error + sLog.outErrorDb("Guild %u does not exist but it has a record in guild_rank table, deleting it!", guildId); + CharacterDatabase.PExecute("DELETE FROM guild_rank WHERE guildid = '%u'", guildId); + continue; + } + + if (guildId > m_Id) + //we loaded all ranks for this guild already, break cycle + break; + uint32 rankID = fields[1].GetUInt32(); + std::string rankName = fields[2].GetCppString(); + uint32 rankRights = fields[3].GetUInt32(); + uint32 rankMoney = fields[4].GetUInt32(); if (rankID != m_Ranks.size()) // guild_rank.ids are sequence 0,1,2,3.. broken_ranks = true; @@ -328,28 +319,27 @@ bool Guild::LoadRanksFromDB(uint32 GuildId) rankRights |= GR_RIGHT_ALL; AddRank(rankName,rankRights,rankMoney); - }while( result->NextRow() ); - delete result; + }while( guildRanksResult->NextRow() ); if (m_Ranks.size() < GUILD_RANKS_MIN_COUNT) // if too few ranks, renew them { m_Ranks.clear(); - sLog.outError("Guild %u has broken `guild_rank` data, creating new...",GuildId); + sLog.outError("Guild %u has broken `guild_rank` data, creating new...", m_Id); CreateDefaultGuildRanks(0); // 0 is default locale_idx broken_ranks = false; } // guild_rank have wrong numbered ranks, repair if (broken_ranks) { - sLog.outError("Guild %u has broken `guild_rank` data, repairing...",GuildId); + sLog.outError("Guild %u has broken `guild_rank` data, repairing...", m_Id); CharacterDatabase.BeginTransaction(); - CharacterDatabase.PExecute("DELETE FROM guild_rank WHERE guildid='%u'", GuildId); + CharacterDatabase.PExecute("DELETE FROM guild_rank WHERE guildid='%u'", m_Id); for(size_t i = 0; i < m_Ranks.size(); ++i) { std::string name = m_Ranks[i].Name; uint32 rights = m_Ranks[i].Rights; CharacterDatabase.escape_string(name); - CharacterDatabase.PExecute( "INSERT INTO guild_rank (guildid,rid,rname,rights) VALUES ('%u', '%u', '%s', '%u')", GuildId, uint32(i), name.c_str(), rights); + CharacterDatabase.PExecute( "INSERT INTO guild_rank (guildid,rid,rname,rights) VALUES ('%u', '%u', '%s', '%u')", m_Id, uint32(i), name.c_str(), rights); } CharacterDatabase.CommitTransaction(); } @@ -357,46 +347,52 @@ bool Guild::LoadRanksFromDB(uint32 GuildId) return true; } -bool Guild::LoadMembersFromDB(uint32 GuildId) +bool Guild::LoadMembersFromDB(QueryResult *guildMembersResult) { - // 0 1 2 3 4 5 - QueryResult *result = CharacterDatabase.PQuery("SELECT guild_member.guid,rank, pnote, offnote, BankResetTimeMoney,BankRemMoney," - // 6 7 8 9 10 11 - "BankResetTimeTab0, BankRemSlotsTab0, BankResetTimeTab1, BankRemSlotsTab1, BankResetTimeTab2, BankRemSlotsTab2," - // 12 13 14 15 16 17 - "BankResetTimeTab3, BankRemSlotsTab3, BankResetTimeTab4, BankRemSlotsTab4, BankResetTimeTab5, BankRemSlotsTab5," - // 18 19 20 21 22 - "characters.name, characters.level, characters.class, characters.zone, characters.logout_time " - "FROM guild_member LEFT JOIN characters ON characters.guid = guild_member.guid WHERE guildid = '%u'", GuildId); - - if (!result) + if (!guildMembersResult) return false; do { - Field *fields = result->Fetch(); + Field *fields = guildMembersResult->Fetch(); + //this condition will be true when all rows in QueryResult are processed and new guild without members is going to be loaded - prevent crash + if (!fields) + break; + uint32 guildId = fields[0].GetUInt32(); + if (guildId < m_Id) + { + //there is in table guild_member record which doesn't have guildid in guild table, report error + sLog.outErrorDb("Guild %u does not exist but it has a record in guild_member table, deleting it!", guildId); + CharacterDatabase.PExecute("DELETE FROM guild_member WHERE guildid = '%u'", guildId); + continue; + } + + if (guildId > m_Id) + //we loaded all members for this guild already, break cycle + break; + MemberSlot newmember; - uint64 guid = MAKE_NEW_GUID(fields[0].GetUInt32(), 0, HIGHGUID_PLAYER); - newmember.RankId = fields[1].GetUInt32(); + uint64 guid = MAKE_NEW_GUID(fields[1].GetUInt32(), 0, HIGHGUID_PLAYER); + newmember.RankId = fields[2].GetUInt32(); //don't allow member to have not existing rank! if (newmember.RankId >= m_Ranks.size()) newmember.RankId = GetLowestRank(); - newmember.Pnote = fields[2].GetCppString(); - newmember.OFFnote = fields[3].GetCppString(); - newmember.BankResetTimeMoney = fields[4].GetUInt32(); - newmember.BankRemMoney = fields[5].GetUInt32(); + newmember.Pnote = fields[3].GetCppString(); + newmember.OFFnote = fields[4].GetCppString(); + newmember.BankResetTimeMoney = fields[5].GetUInt32(); + newmember.BankRemMoney = fields[6].GetUInt32(); for (int i = 0; i < GUILD_BANK_MAX_TABS; ++i) { - newmember.BankResetTimeTab[i] = fields[6+(2*i)].GetUInt32(); - newmember.BankRemSlotsTab[i] = fields[7+(2*i)].GetUInt32(); + newmember.BankResetTimeTab[i] = fields[7+(2*i)].GetUInt32(); + newmember.BankRemSlotsTab[i] = fields[8+(2*i)].GetUInt32(); } - newmember.Name = fields[18].GetCppString(); - newmember.Level = fields[19].GetUInt8(); - newmember.Class = fields[20].GetUInt8(); - newmember.ZoneId = fields[21].GetUInt32(); - newmember.LogoutTime = fields[22].GetUInt64(); + newmember.Name = fields[19].GetCppString(); + newmember.Level = fields[20].GetUInt8(); + newmember.Class = fields[21].GetUInt8(); + newmember.ZoneId = fields[22].GetUInt32(); + newmember.LogoutTime = fields[23].GetUInt64(); //this code will remove unexisting character guids from guild if (newmember.Level < 1 || newmember.Level > STRONG_MAX_LEVEL) // can be at broken `data` field @@ -421,8 +417,7 @@ bool Guild::LoadMembersFromDB(uint32 GuildId) members[GUID_LOPART(guid)] = newmember; - }while( result->NextRow() ); - delete result; + }while (guildMembersResult->NextRow()); if (members.empty()) return false; @@ -1464,28 +1459,39 @@ uint32 Guild::GetBankSlotPerDay(uint32 rankId, uint8 TabId) // ************************************************* // Rights per day related -void Guild::LoadBankRightsFromDB(uint32 GuildId) +bool Guild::LoadBankRightsFromDB(QueryResult *guildBankTabRightsResult) { - // 0 1 2 3 - QueryResult *result = CharacterDatabase.PQuery("SELECT TabId, rid, gbright, SlotPerDay FROM guild_bank_right WHERE guildid = '%u' ORDER BY TabId", GuildId); - - if (!result) - return; + if (!guildBankTabRightsResult) + return true; do { - Field *fields = result->Fetch(); - uint8 TabId = fields[0].GetUInt8(); - uint32 rankId = fields[1].GetUInt32(); - uint16 right = fields[2].GetUInt16(); - uint16 SlotPerDay = fields[3].GetUInt16(); + Field *fields = guildBankTabRightsResult->Fetch(); + //prevent crash when all rights in result are already processed + if (!fields) + break; + uint32 guildId = fields[0].GetUInt32(); + if (guildId < m_Id) + { + //there is in table guild_bank_right record which doesn't have guildid in guild table, report error + sLog.outErrorDb("Guild %u does not exist but it has a record in guild_bank_right table, deleting it!", guildId); + CharacterDatabase.PExecute("DELETE FROM guild_bank_right WHERE guildid = '%u'", guildId); + continue; + } + + if (guildId > m_Id) + //we loaded all ranks for this guild bank already, break cycle + break; + uint8 TabId = fields[1].GetUInt8(); + uint32 rankId = fields[2].GetUInt32(); + uint16 right = fields[3].GetUInt16(); + uint16 SlotPerDay = fields[4].GetUInt16(); SetBankRightsAndSlots(rankId, TabId, right, SlotPerDay, false); - } while (result->NextRow()); - delete result; + } while (guildBankTabRightsResult->NextRow()); - return; + return true; } // ************************************************* diff --git a/src/game/Guild.h b/src/game/Guild.h index 2836a245a..4ef904536 100644 --- a/src/game/Guild.h +++ b/src/game/Guild.h @@ -324,9 +324,10 @@ class Guild uint32 GetMemberSize() const { return members.size(); } - bool LoadGuildFromDB(uint32 GuildId); - bool LoadRanksFromDB(uint32 GuildId); - bool LoadMembersFromDB(uint32 GuildId); + bool LoadGuildFromDB(QueryResult *guildDataResult); + bool CheckGuildStructure(); + bool LoadRanksFromDB(QueryResult *guildRanksResult); + bool LoadMembersFromDB(QueryResult *guildMembersResult); void SetMemberStats(uint64 guid); @@ -422,7 +423,7 @@ class Guild uint32 GetBankMoneyPerDay(uint32 rankId); uint32 GetBankSlotPerDay(uint32 rankId, uint8 TabId); // rights per day - void LoadBankRightsFromDB(uint32 GuildId); + bool LoadBankRightsFromDB(QueryResult *guildBankTabRightsResult); // Guild Bank Event Logs void LoadGuildBankEventLogFromDB(); void UnloadGuildBankEventLog(); diff --git a/src/game/ItemHandler.cpp b/src/game/ItemHandler.cpp index 77a841bdc..3a5606b88 100644 --- a/src/game/ItemHandler.cpp +++ b/src/game/ItemHandler.cpp @@ -25,7 +25,6 @@ #include "Player.h" #include "Item.h" #include "UpdateData.h" -#include "ObjectAccessor.h" void WorldSession::HandleSplitItemOpcode( WorldPacket & recv_data ) { @@ -1300,7 +1299,7 @@ void WorldSession::HandleSocketOpcode(WorldPacket& recv_data) _player->ApplyEnchantment(itemTarget, EnchantmentSlot(enchant_slot), true); bool SocketBonusToBeActivated = itemTarget->GemsFitSockets();// current socketbonus state - if(SocketBonusActivated ^ SocketBonusToBeActivated) // if there was a change... + if(SocketBonusActivated != SocketBonusToBeActivated) // if there was a change... { _player->ApplyEnchantment(itemTarget,BONUS_ENCHANTMENT_SLOT, false); itemTarget->SetEnchantment(BONUS_ENCHANTMENT_SLOT, (SocketBonusToBeActivated ? itemTarget->GetProto()->socketBonus : 0), 0, 0); diff --git a/src/game/Language.h b/src/game/Language.h index 1f2d24b73..ae3c251d2 100644 --- a/src/game/Language.h +++ b/src/game/Language.h @@ -533,8 +533,8 @@ enum MangosStrings LANG_GET_UINT_FIELD = 570, LANG_GET_FLOAT = 571, //log LANG_GET_FLOAT_FIELD = 572, - LANG_SET_32BIT = 573, //log - LANG_SET_32BIT_FIELD = 574, + // 573, //not used + // 574, //not used LANG_CHANGE_32BIT = 575, //log LANG_CHANGE_32BIT_FIELD = 576, diff --git a/src/game/Level3.cpp b/src/game/Level3.cpp index e13609401..ec69567c0 100644 --- a/src/game/Level3.cpp +++ b/src/game/Level3.cpp @@ -70,7 +70,6 @@ bool ChatHandler::HandleReloadAllCommand(const char*) HandleReloadReservedNameCommand(""); HandleReloadMangosStringCommand(""); HandleReloadGameTeleCommand(""); - HandleReloadBattleEventCommand(""); return true; } @@ -4144,30 +4143,6 @@ bool ChatHandler::HandleChangeWeather(const char* args) return true; } -bool ChatHandler::HandleSet32Bit(const char* args) -{ - if(!*args) - return false; - - char* px = strtok((char*)args, " "); - char* py = strtok(NULL, " "); - - if (!px || !py) - return false; - - uint32 Opcode = (uint32)atoi(px); - uint32 Value = (uint32)atoi(py); - if (Value > 32) //uint32 = 32 bits - return false; - - sLog.outDebug(GetMangosString(LANG_SET_32BIT), Opcode, Value); - - m_session->GetPlayer( )->SetUInt32Value( Opcode , 2^Value ); - - PSendSysMessage(LANG_SET_32BIT_FIELD, Opcode,1); - return true; -} - bool ChatHandler::HandleTeleAddCommand(const char * args) { if(!*args) diff --git a/src/game/MapInstanced.cpp b/src/game/MapInstanced.cpp index 4105bba80..85bd15da1 100644 --- a/src/game/MapInstanced.cpp +++ b/src/game/MapInstanced.cpp @@ -218,6 +218,7 @@ BattleGroundMap* MapInstanced::CreateBattleGroundMap(uint32 InstanceId, BattleGr BattleGroundMap *map = new BattleGroundMap(GetId(), GetGridExpiry(), InstanceId, this); ASSERT(map->IsBattleGroundOrArena()); map->SetBG(bg); + bg->SetBgMap(map); m_InstancedMaps[InstanceId] = map; return map; diff --git a/src/game/NPCHandler.cpp b/src/game/NPCHandler.cpp index 8bb0be9b9..33ba8538d 100644 --- a/src/game/NPCHandler.cpp +++ b/src/game/NPCHandler.cpp @@ -372,11 +372,11 @@ void WorldSession::SendSpiritResurrect() _player->TeleportTo(corpseGrave->map_id, corpseGrave->x, corpseGrave->y, corpseGrave->z, _player->GetOrientation()); // or update at original position else - ObjectAccessor::UpdateVisibilityForPlayer(_player); + _player->UpdateVisibilityForPlayer(); } // or update at original position else - ObjectAccessor::UpdateVisibilityForPlayer(_player); + _player->UpdateVisibilityForPlayer(); _player->SaveToDB(); } diff --git a/src/game/Object.cpp b/src/game/Object.cpp index 589cfc9f1..222b8efad 100644 --- a/src/game/Object.cpp +++ b/src/game/Object.cpp @@ -1427,7 +1427,7 @@ void WorldObject::MonsterTextEmote(const char* text, uint64 TargetGuid, bool IsB { WorldPacket data(SMSG_MESSAGECHAT, 200); BuildMonsterChat(&data,IsBossEmote ? CHAT_MSG_RAID_BOSS_EMOTE : CHAT_MSG_MONSTER_EMOTE,text,LANG_UNIVERSAL,GetName(),TargetGuid); - SendMessageToSetInRange(&data,sWorld.getConfig(CONFIG_LISTEN_RANGE_TEXTEMOTE),true); + SendMessageToSetInRange(&data,sWorld.getConfig(IsBossEmote ? CONFIG_LISTEN_RANGE_YELL : CONFIG_LISTEN_RANGE_TEXTEMOTE),true); } void WorldObject::MonsterWhisper(const char* text, uint64 receiver, bool IsBossWhisper) @@ -1524,7 +1524,7 @@ void WorldObject::MonsterTextEmote(int32 textId, uint64 TargetGuid, bool IsBossE MaNGOS::PlayerDistWorker > say_worker(this,sWorld.getConfig(CONFIG_LISTEN_RANGE_TEXTEMOTE),say_do); TypeContainerVisitor >, WorldTypeMapContainer > message(say_worker); CellLock cell_lock(cell, p); - cell_lock->Visit(cell_lock, message, *GetMap(), *this, sWorld.getConfig(CONFIG_LISTEN_RANGE_TEXTEMOTE)); + cell_lock->Visit(cell_lock, message, *GetMap(), *this, sWorld.getConfig(IsBossEmote ? CONFIG_LISTEN_RANGE_YELL : CONFIG_LISTEN_RANGE_TEXTEMOTE)); } void WorldObject::MonsterWhisper(int32 textId, uint64 receiver, bool IsBossWhisper) @@ -1849,7 +1849,7 @@ void WorldObject::SetPhaseMask(uint32 newPhaseMask, bool update) m_phaseMask = newPhaseMask; if(update && IsInWorld()) - ObjectAccessor::UpdateObjectVisibility(this); + UpdateObjectVisibility(); } void WorldObject::PlayDistanceSound( uint32 sound_id, Player* target /*= NULL*/ ) @@ -1872,3 +1872,12 @@ void WorldObject::PlayDirectSound( uint32 sound_id, Player* target /*= NULL*/ ) else SendMessageToSet( &data, true ); } + +void WorldObject::UpdateObjectVisibility() +{ + CellPair p = MaNGOS::ComputeCellPair(GetPositionX(), GetPositionY()); + Cell cell(p); + + GetMap()->UpdateObjectVisibility(this, cell, p); +} + diff --git a/src/game/Object.h b/src/game/Object.h index adb23924c..80044ef76 100644 --- a/src/game/Object.h +++ b/src/game/Object.h @@ -474,6 +474,8 @@ class MANGOS_DLL_SPEC WorldObject : public Object virtual void SaveRespawnTime() {} void AddObjectToRemoveList(); + void UpdateObjectVisibility(); + // main visibility check function in normal case (ignore grey zone distance check) bool isVisibleFor(Player const* u, WorldObject const* viewPoint) const { return isVisibleForInState(u,viewPoint,false); } diff --git a/src/game/ObjectAccessor.cpp b/src/game/ObjectAccessor.cpp index 1ceb156ce..cd6a3ffb3 100644 --- a/src/game/ObjectAccessor.cpp +++ b/src/game/ObjectAccessor.cpp @@ -442,36 +442,6 @@ ObjectAccessor::WorldObjectChangeAccumulator::Visit(PlayerMapType &m) ObjectAccessor::_buildPacket(iter->getSource(), &i_object, i_updateDatas); } -void -ObjectAccessor::UpdateObjectVisibility(WorldObject *obj) -{ - CellPair p = MaNGOS::ComputeCellPair(obj->GetPositionX(), obj->GetPositionY()); - Cell cell(p); - - obj->GetMap()->UpdateObjectVisibility(obj, cell, p); -} - -void ObjectAccessor::UpdateVisibilityForPlayer( Player* player ) -{ - WorldObject const* viewPoint = player->GetViewPoint(); - Map* m = player->GetMap(); - - CellPair p(MaNGOS::ComputeCellPair(player->GetPositionX(), player->GetPositionY())); - Cell cell(p); - - m->UpdatePlayerVisibility(player, cell, p); - - if (player!=viewPoint) - { - CellPair pView(MaNGOS::ComputeCellPair(viewPoint->GetPositionX(), viewPoint->GetPositionY())); - Cell cellView(pView); - - m->UpdateObjectsVisibilityFor(player, cellView, pView); - } - else - m->UpdateObjectsVisibilityFor(player, cell, p); -} - /// Define the static member of HashMapHolder template UNORDERED_MAP< uint64, T* > HashMapHolder::m_objectMap; diff --git a/src/game/ObjectAccessor.h b/src/game/ObjectAccessor.h index 14154817a..fb42d97a1 100644 --- a/src/game/ObjectAccessor.h +++ b/src/game/ObjectAccessor.h @@ -202,8 +202,6 @@ class MANGOS_DLL_DECL ObjectAccessor : public MaNGOS::SingletonGetRowCount() ); do { - Field *fields = result->Fetch(); + //Field *fields = result->Fetch(); bar.step(); ++count; - newguild = new Guild; - if(!newguild->LoadGuildFromDB(fields[0].GetUInt32())) + newGuild = new Guild; + if (!newGuild->LoadGuildFromDB(result) || + !newGuild->LoadRanksFromDB(guildRanksResult) || + !newGuild->LoadMembersFromDB(guildMembersResult) || + !newGuild->LoadBankRightsFromDB(guildBankTabRightsResult) || + !newGuild->CheckGuildStructure() + ) { - newguild->Disband(); - delete newguild; + newGuild->Disband(); + delete newGuild; continue; } - AddGuild(newguild); + AddGuild(newGuild); }while( result->NextRow() ); delete result; + delete guildRanksResult; + delete guildMembersResult; + delete guildBankTabRightsResult; //delete unused LogGuid records in guild_eventlog and guild_bank_eventlog table //you can comment these lines if you don't plan to change CONFIG_GUILD_EVENT_LOG_COUNT and CONFIG_GUILD_BANK_EVENT_LOG_COUNT @@ -2925,7 +2956,11 @@ void ObjectMgr::LoadArenaTeams() { uint32 count = 0; - QueryResult *result = CharacterDatabase.Query( "SELECT arenateamid FROM arena_team" ); + // 0 1 2 3 4 5 + QueryResult *result = CharacterDatabase.Query( "SELECT arena_team.arenateamid,name,captainguid,type,BackgroundColor,EmblemStyle," + // 6 7 8 9 10 11 12 13 14 + "EmblemColor,BorderStyle,BorderColor, rating,games,wins,played,wins2,rank " + "FROM arena_team LEFT JOIN arena_team_stats ON arena_team.arenateamid = arena_team_stats.arenateamid ORDER BY arena_team.arenateamid ASC" ); if( !result ) { @@ -2939,6 +2974,12 @@ void ObjectMgr::LoadArenaTeams() return; } + // load arena_team members + QueryResult *arenaTeamMembersResult = CharacterDatabase.Query( + // 0 1 2 3 4 5 6 7 8 + "SELECT arenateamid,member.guid,played_week,wons_week,played_season,wons_season,personal_rating,name,class " + "FROM arena_team_member member LEFT JOIN characters chars on member.guid = chars.guid ORDER BY member.arenateamid ASC"); + barGoLink bar( result->GetRowCount() ); do @@ -2948,16 +2989,19 @@ void ObjectMgr::LoadArenaTeams() bar.step(); ++count; - ArenaTeam *newarenateam = new ArenaTeam; - if(!newarenateam->LoadArenaTeamFromDB(fields[0].GetUInt32())) + ArenaTeam *newArenaTeam = new ArenaTeam; + if (!newArenaTeam->LoadArenaTeamFromDB(result) || + !newArenaTeam->LoadMembersFromDB(arenaTeamMembersResult)) { - delete newarenateam; + newArenaTeam->Disband(NULL); + delete newArenaTeam; continue; } - AddArenaTeam(newarenateam); + AddArenaTeam(newArenaTeam); }while( result->NextRow() ); delete result; + delete arenaTeamMembersResult; sLog.outString(); sLog.outString( ">> Loaded %u arenateam definitions", count ); diff --git a/src/game/Player.cpp b/src/game/Player.cpp index 4d2790ca7..919e88137 100644 --- a/src/game/Player.cpp +++ b/src/game/Player.cpp @@ -2239,7 +2239,7 @@ void Player::SetGameMaster(bool on) getHostilRefManager().setOnlineOfflineState(true); } - ObjectAccessor::UpdateVisibilityForPlayer(this); + UpdateVisibilityForPlayer(); } void Player::SetGMVisible(bool on) @@ -4152,7 +4152,7 @@ void Player::ResurrectPlayer(float restore_percent, bool applySickness) UpdateZone(newzone,newarea); // update visibility - ObjectAccessor::UpdateVisibilityForPlayer(this); + UpdateVisibilityForPlayer(); if(!applySickness) return; @@ -4205,7 +4205,7 @@ void Player::KillPlayer() // don't create corpse at this moment, player might be falling // update visibility - ObjectAccessor::UpdateObjectVisibility(this); + UpdateObjectVisibility(); } void Player::CreateCorpse() @@ -10122,10 +10122,42 @@ uint8 Player::CanUseItem( Item *pItem, bool not_loading ) const if ((pProto->AllowableClass & getClassMask()) == 0 || (pProto->AllowableRace & getRaceMask()) == 0) return EQUIP_ERR_YOU_CAN_NEVER_USE_THAT_ITEM; - if (pItem->GetSkill() != 0) + if (uint32 item_use_skill = pItem->GetSkill()) { - if (GetSkillValue( pItem->GetSkill() ) == 0) - return EQUIP_ERR_NO_REQUIRED_PROFICIENCY; + if (GetSkillValue(item_use_skill) == 0) + { + // armor items with scaling stats can downgrade armor skill reqs if related class can learn armor use at some level + if (pProto->Class != ITEM_CLASS_ARMOR) + return EQUIP_ERR_NO_REQUIRED_PROFICIENCY; + + ScalingStatDistributionEntry const *ssd = pProto->ScalingStatDistribution ? sScalingStatDistributionStore.LookupEntry(pProto->ScalingStatDistribution) : NULL; + if (!ssd) + return EQUIP_ERR_NO_REQUIRED_PROFICIENCY; + + bool allowScaleSkill = false; + for (uint32 i = 0; i < sSkillLineAbilityStore.GetNumRows(); ++i) + { + SkillLineAbilityEntry const *skillInfo = sSkillLineAbilityStore.LookupEntry(i); + if (!skillInfo) + continue; + + if (skillInfo->skillId != item_use_skill) + continue; + + // can't learn + if (skillInfo->classmask && (skillInfo->classmask & getClassMask()) == 0) + continue; + + if (skillInfo->racemask && (skillInfo->racemask & getRaceMask()) == 0) + continue; + + allowScaleSkill = true; + break; + } + + if (!allowScaleSkill) + return EQUIP_ERR_NO_REQUIRED_PROFICIENCY; + } } if (pProto->RequiredSkill != 0) @@ -15136,7 +15168,7 @@ void Player::_LoadQuestStatus(QueryResult *result) ((questStatusData.m_status == QUEST_STATUS_INCOMPLETE || questStatusData.m_status == QUEST_STATUS_COMPLETE || questStatusData.m_status == QUEST_STATUS_FAILED) && - (!questStatusData.m_rewarded || pQuest->IsDaily()))) + (!questStatusData.m_rewarded || pQuest->IsRepeatable()))) { SetQuestSlot(slot, quest_id, quest_time); @@ -17759,7 +17791,7 @@ void Player::CorrectMetaGemEnchants(uint8 exceptslot, bool apply) //was enchant active with/without item? bool wasactive = EnchantmentFitsRequirements(condition, apply ? exceptslot : -1); //should it now be? - if(wasactive ^ EnchantmentFitsRequirements(condition, apply ? -1 : exceptslot)) + if(wasactive != EnchantmentFitsRequirements(condition, apply ? -1 : exceptslot)) { // ignore item gem conditions //if state changed, (dis)apply enchant @@ -20646,7 +20678,28 @@ void Player::SetFarSightGUID( uint64 guid ) SetUInt64Value(PLAYER_FARSIGHT, guid); // need triggering load grids around new view point - ObjectAccessor::UpdateVisibilityForPlayer(this); + UpdateVisibilityForPlayer(); +} + +void Player::UpdateVisibilityForPlayer() +{ + WorldObject const* viewPoint = GetViewPoint(); + Map* m = GetMap(); + + CellPair p(MaNGOS::ComputeCellPair(GetPositionX(), GetPositionY())); + Cell cell(p); + + m->UpdatePlayerVisibility(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::SendDuelCountdown(uint32 counter) diff --git a/src/game/Player.h b/src/game/Player.h index 62a4bd839..5c75c6231 100644 --- a/src/game/Player.h +++ b/src/game/Player.h @@ -1045,6 +1045,8 @@ class MANGOS_DLL_SPEC Player : public Unit bool CanInteractWithNPCs(bool alive = true) const; GameObject* GetGameObjectIfCanInteractWith(uint64 guid, GameobjectTypes type) const; + void UpdateVisibilityForPlayer(); + bool ToggleAFK(); bool ToggleDND(); bool isAFK() const { return HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_AFK); } diff --git a/src/game/SharedDefines.h b/src/game/SharedDefines.h index c19e29d8f..60a9253b3 100644 --- a/src/game/SharedDefines.h +++ b/src/game/SharedDefines.h @@ -1033,6 +1033,7 @@ enum Targets TARGET_ALL_PARTY = 33, TARGET_ALL_PARTY_AROUND_CASTER_2 = 34, // used in Tranquility TARGET_SINGLE_PARTY = 35, + TARGET_ALL_HOSTILE_UNITS_AROUND_CASTER = 36, TARGET_AREAEFFECT_PARTY = 37, TARGET_SCRIPT = 38, TARGET_SELF_FISHING = 39, diff --git a/src/game/SkillHandler.cpp b/src/game/SkillHandler.cpp index 970406f79..9c97d9844 100644 --- a/src/game/SkillHandler.cpp +++ b/src/game/SkillHandler.cpp @@ -23,7 +23,6 @@ #include "Player.h" #include "WorldPacket.h" #include "WorldSession.h" -#include "ObjectAccessor.h" #include "UpdateMask.h" void WorldSession::HandleLearnTalentOpcode( WorldPacket & recv_data ) diff --git a/src/game/Spell.cpp b/src/game/Spell.cpp index 7cd115731..ee99c01ed 100644 --- a/src/game/Spell.cpp +++ b/src/game/Spell.cpp @@ -1220,7 +1220,8 @@ bool Spell::IsAliveUnitPresentInTargetList() { Unit *unit = m_caster->GetGUID() == ihit->targetGUID ? m_caster : ObjectAccessor::GetUnit(*m_caster, ihit->targetGUID); - if (unit && (unit->isAlive() ^ IsDeathOnlySpell(m_spellInfo))) + // either unit is alive and normal spell, or unit dead and deathonly-spell + if (unit && (unit->isAlive() != IsDeathOnlySpell(m_spellInfo))) needAliveTargetMask &= ~ihit->effectMask; // remove from need alive mask effect that have alive target } } @@ -1359,9 +1360,8 @@ void Spell::SetTargetMap(uint32 effIndex,uint32 targetMode,UnitList& TagUnitMap) case TARGET_RANDOM_CIRCUMFERENCE_POINT: { float angle = 2.0 * M_PI * rand_norm(); - float dest_x = m_caster->GetPositionX() + cos(angle) * radius; - float dest_y = m_caster->GetPositionY() + sin(angle) * radius; - float dest_z = m_caster->GetMap()->GetHeight(dest_x, dest_y, MAX_HEIGHT); + float dest_x, dest_y, dest_z; + m_caster->GetClosePoint(dest_x, dest_y, dest_z, 0.0f, radius, angle); m_targets.setDestination(dest_x, dest_y, dest_z); TagUnitMap.push_back(m_caster); @@ -1371,9 +1371,8 @@ void Spell::SetTargetMap(uint32 effIndex,uint32 targetMode,UnitList& TagUnitMap) { radius *= sqrt(rand_norm()); // Get a random point in circle. Use sqrt(rand) to correct distribution when converting polar to Cartesian coordinates. float angle = 2.0 * M_PI * rand_norm(); - float dest_x = m_targets.m_destX + cos(angle) * radius; - float dest_y = m_targets.m_destY + sin(angle) * radius; - float dest_z = m_caster->GetMap()->GetHeight(dest_x, dest_y, MAX_HEIGHT); + float dest_x, dest_y, dest_z; + m_caster->GetClosePoint(dest_x, dest_y, dest_z, 0.0f, radius, angle); m_targets.setDestination(dest_x, dest_y, dest_z); if (radius > 0.0f) @@ -1700,13 +1699,24 @@ void Spell::SetTargetMap(uint32 effIndex,uint32 targetMode,UnitList& TagUnitMap) m_targets.setDestination(caster->GetPositionX(), caster->GetPositionY(), caster->GetPositionZ()); break; } + case TARGET_ALL_HOSTILE_UNITS_AROUND_CASTER: + FillAreaTargets(TagUnitMap, m_targets.m_destX, m_targets.m_destY, radius, PUSH_SELF_CENTER, SPELL_TARGETS_HOSTILE); + break; case TARGET_ALL_FRIENDLY_UNITS_AROUND_CASTER: - // special target order - if (m_spellInfo->Id==64904) // Hymn of Hope - // target amount stored in parent spell dummy effect but hard for access - FillRaidOrPartyManaPriorityTargets(TagUnitMap, m_caster, m_caster, radius, 3, true, false, false); - else - FillAreaTargets(TagUnitMap, m_targets.m_destX, m_targets.m_destY, radius, PUSH_SELF_CENTER, SPELL_TARGETS_FRIENDLY); + switch (m_spellInfo->Id) + { + case 64844: // Divine Hymn + // target amount stored in parent spell dummy effect but hard to access + FillRaidOrPartyHealthPriorityTargets(TagUnitMap, m_caster, m_caster, radius, 3, true, false, false); + break; + case 64904: // Hymn of Hope + // target amount stored in parent spell dummy effect but hard to access + FillRaidOrPartyManaPriorityTargets(TagUnitMap, m_caster, m_caster, radius, 3, true, false, false); + break; + default: + FillAreaTargets(TagUnitMap, m_targets.m_destX, m_targets.m_destY, radius, PUSH_SELF_CENTER, SPELL_TARGETS_FRIENDLY); + break; + } break; case TARGET_ALL_FRIENDLY_UNITS_IN_AREA: // Wild Growth diff --git a/src/game/SpellAuras.cpp b/src/game/SpellAuras.cpp index f12885b80..b6618c936 100644 --- a/src/game/SpellAuras.cpp +++ b/src/game/SpellAuras.cpp @@ -3922,7 +3922,7 @@ void Aura::HandleInvisibilityDetect(bool apply, bool Real) m_target->m_detectInvisibilityMask |= (1 << m_modifier.m_miscvalue); } if(Real && m_target->GetTypeId()==TYPEID_PLAYER) - ObjectAccessor::UpdateVisibilityForPlayer((Player*)m_target); + ((Player*)m_target)->UpdateVisibilityForPlayer(); } void Aura::HandleAuraModRoot(bool apply, bool Real) @@ -6271,7 +6271,7 @@ void Aura::HandleSchoolAbsorb(bool apply, bool Real) void Aura::PeriodicTick() { - if (!m_target->isAlive() ^ IsDeathOnlySpell(GetSpellProto())) + if (!m_target->isAlive() != IsDeathOnlySpell(GetSpellProto())) return; switch(m_modifier.m_auraname) @@ -6771,229 +6771,243 @@ void Aura::PeriodicTick() void Aura::PeriodicDummyTick() { - Unit *caster = GetCaster(); SpellEntry const* spell = GetSpellProto(); switch (spell->SpellFamilyName) { case SPELLFAMILY_GENERIC: - switch (spell->Id) - { - // Drink - case 430: - case 431: - case 432: - case 1133: - case 1135: - case 1137: - case 10250: - case 22734: - case 27089: - case 34291: - case 43182: - case 43183: - case 43706: - case 46755: - case 49472: // Drink Coffee - case 57073: - case 61830: + switch (spell->Id) { - if (m_target->GetTypeId() != TYPEID_PLAYER) - return; - // Search SPELL_AURA_MOD_POWER_REGEN aura for this spell and add bonus - Unit::AuraList const& aura = m_target->GetAurasByType(SPELL_AURA_MOD_POWER_REGEN); - for(Unit::AuraList::const_iterator i = aura.begin(); i != aura.end(); ++i) + // Drink + case 430: + case 431: + case 432: + case 1133: + case 1135: + case 1137: + case 10250: + case 22734: + case 27089: + case 34291: + case 43182: + case 43183: + case 43706: + case 46755: + case 49472: // Drink Coffee + case 57073: + case 61830: { - if ((*i)->GetId() == GetId()) - { - (*i)->GetModifier()->m_amount = m_modifier.m_amount; - ((Player*)m_target)->UpdateManaRegen(); - // Disable continue - m_isPeriodic = false; + if (m_target->GetTypeId() != TYPEID_PLAYER) return; + // Search SPELL_AURA_MOD_POWER_REGEN aura for this spell and add bonus + Unit::AuraList const& aura = m_target->GetAurasByType(SPELL_AURA_MOD_POWER_REGEN); + for(Unit::AuraList::const_iterator i = aura.begin(); i != aura.end(); ++i) + { + if ((*i)->GetId() == GetId()) + { + (*i)->GetModifier()->m_amount = m_modifier.m_amount; + ((Player*)m_target)->UpdateManaRegen(); + // Disable continue + m_isPeriodic = false; + return; + } + } + return; + } + // Forsaken Skills + case 7054: + { + // Possibly need cast one of them (but + // 7038 Forsaken Skill: Swords + // 7039 Forsaken Skill: Axes + // 7040 Forsaken Skill: Daggers + // 7041 Forsaken Skill: Maces + // 7042 Forsaken Skill: Staves + // 7043 Forsaken Skill: Bows + // 7044 Forsaken Skill: Guns + // 7045 Forsaken Skill: 2H Axes + // 7046 Forsaken Skill: 2H Maces + // 7047 Forsaken Skill: 2H Swords + // 7048 Forsaken Skill: Defense + // 7049 Forsaken Skill: Fire + // 7050 Forsaken Skill: Frost + // 7051 Forsaken Skill: Holy + // 7053 Forsaken Skill: Shadow + return; + } +// // Panda +// case 19230: break; +// // Gossip NPC Periodic - Talk +// case 33208: break; +// // Gossip NPC Periodic - Despawn +// case 33209: break; +// // Steal Weapon +// case 36207: break; +// // Simon Game START timer, (DND) +// case 39993: break; +// // Knockdown Fel Cannon: break; The Aggro Burst +// case 40119: break; +// // Old Mount Spell +// case 40154: break; +// // Magnetic Pull +// case 40581: break; +// // Ethereal Ring: break; The Bolt Burst +// case 40801: break; +// // Crystal Prison +// case 40846: break; +// // Copy Weapon +// case 41054: break; +// // Dementia +// case 41404: break; +// // Ethereal Ring Visual, Lightning Aura +// case 41477: break; +// // Ethereal Ring Visual, Lightning Aura (Fork) +// case 41525: break; +// // Ethereal Ring Visual, Lightning Jumper Aura +// case 41567: break; +// // No Man's Land +// case 41955: break; +// // Headless Horseman - Fire +// case 42074: break; +// // Headless Horseman - Visual - Large Fire +// case 42075: break; +// // Headless Horseman - Start Fire, Periodic Aura +// case 42140: break; +// // Ram Speed Boost +// case 42152: break; +// // Headless Horseman - Fires Out Victory Aura +// case 42235: break; +// // Pumpkin Life Cycle +// case 42280: break; +// // Brewfest Request Chick Chuck Mug Aura +// case 42537: break; +// // Squashling +// case 42596: break; +// // Headless Horseman Climax, Head: Periodic +// case 42603: break; +// // Fire Bomb +// case 42621: break; +// // Headless Horseman - Conflagrate, Periodic Aura +// case 42637: break; +// // Headless Horseman - Create Pumpkin Treats Aura +// case 42774: break; +// // Headless Horseman Climax - Summoning Rhyme Aura +// case 42879: break; +// // Tricky Treat +// case 42919: break; +// // Giddyup! +// case 42924: break; +// // Ram - Trot +// case 42992: break; +// // Ram - Canter +// case 42993: break; +// // Ram - Gallop +// case 42994: break; +// // Ram Level - Neutral +// case 43310: break; +// // Headless Horseman - Maniacal Laugh, Maniacal, Delayed 17 +// case 43884: break; +// // Wretched! +// case 43963: break; +// // Headless Horseman - Maniacal Laugh, Maniacal, other, Delayed 17 +// case 44000: break; +// // Energy Feedback +// case 44328: break; +// // Romantic Picnic +// case 45102: break; +// // Romantic Picnic +// case 45123: break; +// // Looking for Love +// case 45124: break; +// // Kite - Lightning Strike Kite Aura +// case 45197: break; +// // Rocket Chicken +// case 45202: break; +// // Copy Offhand Weapon +// case 45205: break; +// // Upper Deck - Kite - Lightning Periodic Aura +// case 45207: break; +// // Kite -Sky Lightning Strike Kite Aura +// case 45251: break; +// // Ribbon Pole Dancer Check Aura +// case 45390: break; +// // Holiday - Midsummer, Ribbon Pole Periodic Visual +// case 45406: break; +// // Parachute +// case 45472: break; +// // Alliance Flag, Extra Damage Debuff +// case 45898: break; +// // Horde Flag, Extra Damage Debuff +// case 45899: break; +// // Ahune - Summoning Rhyme Aura +// case 45926: break; +// // Ahune - Slippery Floor +// case 45945: break; +// // Ahune's Shield +// case 45954: break; +// // Nether Vapor Lightning +// case 45960: break; +// // Darkness +// case 45996: break; +// // Summon Blood Elves Periodic +// case 46041: break; +// // Transform Visual Missile Periodic +// case 46205: break; +// // Find Opening Beam End +// case 46333: break; +// // Ice Spear Control Aura +// case 46371: break; +// // Hailstone Chill +// case 46458: break; +// // Hailstone Chill, Internal +// case 46465: break; +// // Chill, Internal Shifter +// case 46549: break; +// // Summon Ice Spear Knockback Delayer +// case 46878: break; +// // Burninate Effect +// case 47214: break; +// // Fizzcrank Practice Parachute +// case 47228: break; +// // Send Mug Control Aura +// case 47369: break; +// // Direbrew's Disarm (precast) +// case 47407: break; +// // Mole Machine Port Schedule +// case 47489: break; +// case 47941: break; // Crystal Spike +// case 48200: break; // Healer Aura +// case 48630: break; // Summon Gauntlet Mobs Periodic +// case 49313: break; // Proximity Mine Area Aura +// // Mole Machine Portal Schedule +// case 49466: break; +// case 49555: break; // Corpse Explode +// case 49592: break; // Temporal Rift +// case 49957: break; // Cutting Laser +// case 50085: break; // Slow Fall +// // Listening to Music +// case 50493: break; +// // Love Rocket Barrage +// case 50530: break; +// Exist more after, need add later + default: + break; + } + // Prey on the Weak + if (spell->SpellIconID == 2983) + { + Unit *target=m_target->getVictim(); + if (target && (m_target->GetHealth() * 100 / m_target->GetMaxHealth() > target->GetHealth() * 100 / target->GetMaxHealth())) + { + if(!m_target->HasAura(58670)) + { + int32 basepoints = GetBasePoints(); + m_target->CastCustomSpell(m_target, 58670, &basepoints, 0, 0, true); } } - return; + else + m_target->RemoveAurasDueToSpell(58670); } - // Forsaken Skills - case 7054: - { - // Possibly need cast one of them (but - // 7038 Forsaken Skill: Swords - // 7039 Forsaken Skill: Axes - // 7040 Forsaken Skill: Daggers - // 7041 Forsaken Skill: Maces - // 7042 Forsaken Skill: Staves - // 7043 Forsaken Skill: Bows - // 7044 Forsaken Skill: Guns - // 7045 Forsaken Skill: 2H Axes - // 7046 Forsaken Skill: 2H Maces - // 7047 Forsaken Skill: 2H Swords - // 7048 Forsaken Skill: Defense - // 7049 Forsaken Skill: Fire - // 7050 Forsaken Skill: Frost - // 7051 Forsaken Skill: Holy - // 7053 Forsaken Skill: Shadow - return; - } -// // Panda -// case 19230: break; -// // Gossip NPC Periodic - Talk -// case 33208: break; -// // Gossip NPC Periodic - Despawn -// case 33209: break; -// // Steal Weapon -// case 36207: break; -// // Simon Game START timer, (DND) -// case 39993: break; -// // Knockdown Fel Cannon: break; The Aggro Burst -// case 40119: break; -// // Old Mount Spell -// case 40154: break; -// // Magnetic Pull -// case 40581: break; -// // Ethereal Ring: break; The Bolt Burst -// case 40801: break; -// // Crystal Prison -// case 40846: break; -// // Copy Weapon -// case 41054: break; -// // Dementia -// case 41404: break; -// // Ethereal Ring Visual, Lightning Aura -// case 41477: break; -// // Ethereal Ring Visual, Lightning Aura (Fork) -// case 41525: break; -// // Ethereal Ring Visual, Lightning Jumper Aura -// case 41567: break; -// // No Man's Land -// case 41955: break; -// // Headless Horseman - Fire -// case 42074: break; -// // Headless Horseman - Visual - Large Fire -// case 42075: break; -// // Headless Horseman - Start Fire, Periodic Aura -// case 42140: break; -// // Ram Speed Boost -// case 42152: break; -// // Headless Horseman - Fires Out Victory Aura -// case 42235: break; -// // Pumpkin Life Cycle -// case 42280: break; -// // Brewfest Request Chick Chuck Mug Aura -// case 42537: break; -// // Squashling -// case 42596: break; -// // Headless Horseman Climax, Head: Periodic -// case 42603: break; -// // Fire Bomb -// case 42621: break; -// // Headless Horseman - Conflagrate, Periodic Aura -// case 42637: break; -// // Headless Horseman - Create Pumpkin Treats Aura -// case 42774: break; -// // Headless Horseman Climax - Summoning Rhyme Aura -// case 42879: break; -// // Tricky Treat -// case 42919: break; -// // Giddyup! -// case 42924: break; -// // Ram - Trot -// case 42992: break; -// // Ram - Canter -// case 42993: break; -// // Ram - Gallop -// case 42994: break; -// // Ram Level - Neutral -// case 43310: break; -// // Headless Horseman - Maniacal Laugh, Maniacal, Delayed 17 -// case 43884: break; -// // Wretched! -// case 43963: break; -// // Headless Horseman - Maniacal Laugh, Maniacal, other, Delayed 17 -// case 44000: break; -// // Energy Feedback -// case 44328: break; -// // Romantic Picnic -// case 45102: break; -// // Romantic Picnic -// case 45123: break; -// // Looking for Love -// case 45124: break; -// // Kite - Lightning Strike Kite Aura -// case 45197: break; -// // Rocket Chicken -// case 45202: break; -// // Copy Offhand Weapon -// case 45205: break; -// // Upper Deck - Kite - Lightning Periodic Aura -// case 45207: break; -// // Kite -Sky Lightning Strike Kite Aura -// case 45251: break; -// // Ribbon Pole Dancer Check Aura -// case 45390: break; -// // Holiday - Midsummer, Ribbon Pole Periodic Visual -// case 45406: break; -// // Parachute -// case 45472: break; -// // Alliance Flag, Extra Damage Debuff -// case 45898: break; -// // Horde Flag, Extra Damage Debuff -// case 45899: break; -// // Ahune - Summoning Rhyme Aura -// case 45926: break; -// // Ahune - Slippery Floor -// case 45945: break; -// // Ahune's Shield -// case 45954: break; -// // Nether Vapor Lightning -// case 45960: break; -// // Darkness -// case 45996: break; -// // Summon Blood Elves Periodic -// case 46041: break; -// // Transform Visual Missile Periodic -// case 46205: break; -// // Find Opening Beam End -// case 46333: break; -// // Ice Spear Control Aura -// case 46371: break; -// // Hailstone Chill -// case 46458: break; -// // Hailstone Chill, Internal -// case 46465: break; -// // Chill, Internal Shifter -// case 46549: break; -// // Summon Ice Spear Knockback Delayer -// case 46878: break; -// // Burninate Effect -// case 47214: break; -// // Fizzcrank Practice Parachute -// case 47228: break; -// // Send Mug Control Aura -// case 47369: break; -// // Direbrew's Disarm (precast) -// case 47407: break; -// // Mole Machine Port Schedule -// case 47489: break; -// case 47941: break; // Crystal Spike -// case 48200: break; // Healer Aura -// case 48630: break; // Summon Gauntlet Mobs Periodic -// case 49313: break; // Proximity Mine Area Aura -// // Mole Machine Portal Schedule -// case 49466: break; -// case 49555: break; // Corpse Explode -// case 49592: break; // Temporal Rift -// case 49957: break; // Cutting Laser -// case 50085: break; // Slow Fall -// // Listening to Music -// case 50493: break; -// // Love Rocket Barrage -// case 50530: break; -// Exist more after, need add later - default: - break; - } - break; + break; case SPELLFAMILY_MAGE: { // Mirror Image @@ -7035,27 +7049,31 @@ void Aura::PeriodicDummyTick() { switch (spell->Id) { + // Killing Spree case 51690: { + if (m_target->hasUnitState(UNIT_STAT_STUNNED) || m_target->HasAuraType(SPELL_AURA_MOD_FEAR)) + return; + std::list targets; { // eff_radius ==0 float radius = GetSpellMaxRange(sSpellRangeStore.LookupEntry(spell->rangeIndex)); - CellPair p(MaNGOS::ComputeCellPair(caster->GetPositionX(),caster->GetPositionY())); + CellPair p(MaNGOS::ComputeCellPair(m_target->GetPositionX(),m_target->GetPositionY())); Cell cell(p); cell.data.Part.reserved = ALL_DISTRICT; - MaNGOS::AnyUnfriendlyVisibleUnitInObjectRangeCheck u_check(caster, caster, radius); - MaNGOS::UnitListSearcher checker(caster,targets, u_check); + MaNGOS::AnyUnfriendlyVisibleUnitInObjectRangeCheck u_check(m_target, m_target, radius); + MaNGOS::UnitListSearcher checker(m_target, targets, u_check); TypeContainerVisitor, GridTypeMapContainer > grid_object_checker(checker); TypeContainerVisitor, WorldTypeMapContainer > world_object_checker(checker); CellLock cell_lock(cell, p); - cell_lock->Visit(cell_lock, grid_object_checker, *caster->GetMap(), *caster, radius); - cell_lock->Visit(cell_lock, world_object_checker, *caster->GetMap(), *caster, radius); + cell_lock->Visit(cell_lock, grid_object_checker, *m_target->GetMap(), *m_target, radius); + cell_lock->Visit(cell_lock, world_object_checker, *m_target->GetMap(), *m_target, radius); } if(targets.empty()) @@ -7065,18 +7083,12 @@ void Aura::PeriodicDummyTick() std::advance(itr, rand()%targets.size()); Unit* target = *itr; - caster->CastSpell(target, 57840, true); - caster->CastSpell(target, 57841, true); + m_target->CastSpell(target, 57840, true); + m_target->CastSpell(target, 57841, true); return; } - // Master of Subtlety -// case 31666: break; - // Killing Spree -// case 51690: break; - // Overkill -// case 58428: break; -// default: -// break; + default: + break; } break; } @@ -7125,7 +7137,7 @@ void Aura::PeriodicDummyTick() // Death and Decay if (spell->SpellFamilyFlags & UI64LIT(0x0000000000000020)) { - if (caster) + if (Unit *caster = GetCaster()) caster->CastCustomSpell(m_target, 52212, &m_modifier.m_amount, NULL, NULL, true, NULL, this); return; } @@ -7412,6 +7424,17 @@ void Aura::HandleModTargetArmorPct(bool apply, bool Real) void Aura::HandleAuraModAllCritChance(bool apply, bool Real) { - this->HandleAuraModCritPercent(apply, Real); - this->HandleModSpellCritChance(apply, Real); + // spells required only Real aura add/remove + if(!Real) + return; + + if(m_target->GetTypeId() != TYPEID_PLAYER) + return; + + ((Player*)m_target)->HandleBaseModValue(CRIT_PERCENTAGE, FLAT_MOD, float (m_modifier.m_amount), apply); + ((Player*)m_target)->HandleBaseModValue(OFFHAND_CRIT_PERCENTAGE, FLAT_MOD, float (m_modifier.m_amount), apply); + ((Player*)m_target)->HandleBaseModValue(RANGED_CRIT_PERCENTAGE, FLAT_MOD, float (m_modifier.m_amount), apply); + + // included in Player::UpdateSpellCritChance calculation + ((Player*)m_target)->UpdateAllSpellCritChances(); } diff --git a/src/game/SpellMgr.cpp b/src/game/SpellMgr.cpp index 051404404..fa0cff155 100644 --- a/src/game/SpellMgr.cpp +++ b/src/game/SpellMgr.cpp @@ -2809,7 +2809,7 @@ SpellCastResult SpellMgr::GetSpellAllowedInLocationError(SpellEntry const *spell // - with greater than 15 min CD if ((spellInfo->AttributesEx4 & SPELL_ATTR_EX4_NOT_USABLE_IN_ARENA) || (GetSpellRecoveryTime(spellInfo) > 15 * MINUTE * IN_MILISECONDS && !(spellInfo->AttributesEx4 & SPELL_ATTR_EX4_USABLE_IN_ARENA))) - if (!player || !player->InArena()) + if (player && player->InArena()) return SPELL_FAILED_NOT_IN_ARENA; // Spell casted only on battleground diff --git a/src/game/Unit.cpp b/src/game/Unit.cpp index 5161df21a..7e30563b0 100644 --- a/src/game/Unit.cpp +++ b/src/game/Unit.cpp @@ -4067,9 +4067,9 @@ void Unit::RemoveArenaAuras(bool onleave) for(AuraMap::iterator iter = m_Auras.begin(); iter != m_Auras.end();) { if ( !(iter->second->GetSpellProto()->AttributesEx4 & (1<<21)) // don't remove stances, shadowform, pally/hunter auras - && !iter->second->IsPassive() // don't remove passive auras + && !iter->second->IsPassive() // don't remove passive auras && (!(iter->second->GetSpellProto()->Attributes & SPELL_ATTR_UNAFFECTED_BY_INVULNERABILITY) || !(iter->second->GetSpellProto()->Attributes & SPELL_ATTR_UNK8)) // not unaffected by invulnerability auras or not having that unknown flag (that seemed the most probable) - && (iter->second->IsPositive() ^ onleave)) // remove positive buffs on enter, negative buffs on leave + && (iter->second->IsPositive() != onleave)) // remove positive buffs on enter, negative buffs on leave RemoveAura(iter); else ++iter; @@ -5266,9 +5266,10 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu } switch(dummySpell->Id) { - // Nightfall + // Nightfall & Glyph of Corruption case 18094: case 18095: + case 56218: { target = this; triggered_spell_id = 17941; @@ -9428,7 +9429,7 @@ bool Unit::isTargetableForAttack(bool inverseAlive /*=false*/) const if (HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE)) return false; - if (!(isAlive() ^ inverseAlive)) + if (!(isAlive() != inverseAlive)) return false; return IsInWorld() && !hasUnitState(UNIT_STAT_DIED)&& !isInFlight() /*&& !isStealth()*/; diff --git a/src/game/WorldSession.cpp b/src/game/WorldSession.cpp index 04826959f..3a7c61181 100644 --- a/src/game/WorldSession.cpp +++ b/src/game/WorldSession.cpp @@ -32,7 +32,6 @@ #include "Group.h" #include "Guild.h" #include "World.h" -#include "ObjectAccessor.h" #include "BattleGroundMgr.h" #include "MapManager.h" #include "SocialMgr.h" diff --git a/src/mangosd/WorldRunnable.cpp b/src/mangosd/WorldRunnable.cpp index 1f783f4a2..b90cd4a72 100644 --- a/src/mangosd/WorldRunnable.cpp +++ b/src/mangosd/WorldRunnable.cpp @@ -25,7 +25,6 @@ #include "World.h" #include "WorldRunnable.h" #include "Timer.h" -#include "ObjectAccessor.h" #include "MapManager.h" #include "BattleGroundMgr.h" diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index 18b0ced5f..cfc2bbbf5 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 "8555" + #define REVISION_NR "8582" #endif // __REVISION_NR_H__ diff --git a/src/shared/revision_sql.h b/src/shared/revision_sql.h index 686c79b73..c04ff11f5 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_8505_01_characters_character_spell" - #define REVISION_DB_MANGOS "required_8521_01_mangos_spell_proc_event" + #define REVISION_DB_MANGOS "required_8573_01_mangos_mangos_string" #define REVISION_DB_REALMD "required_8332_01_realmd_realmcharacters" #endif // __REVISION_SQL_H__ diff --git a/win/mangosdVC80.sln b/win/mangosdVC80.sln index e6a220763..67c2d9734 100644 --- a/win/mangosdVC80.sln +++ b/win/mangosdVC80.sln @@ -177,13 +177,16 @@ Global {803F488E-4C5A-4866-8D5C-1E6C03C007C2}.Release|x64.Build.0 = Release|Win32 {AD537C9A-FECA-1BAD-6757-8A6348EA12C8}.Debug_NoPCH|Win32.ActiveCfg = Debug_NoPCH|Win32 {AD537C9A-FECA-1BAD-6757-8A6348EA12C8}.Debug_NoPCH|Win32.Build.0 = Debug_NoPCH|Win32 - {AD537C9A-FECA-1BAD-6757-8A6348EA12C8}.Debug_NoPCH|x64.ActiveCfg = Debug_NoPCH|Win32 + {AD537C9A-FECA-1BAD-6757-8A6348EA12C8}.Debug_NoPCH|x64.ActiveCfg = Debug_NoPCH|x64 + {AD537C9A-FECA-1BAD-6757-8A6348EA12C8}.Debug_NoPCH|x64.Build.0 = Debug_NoPCH|x64 {AD537C9A-FECA-1BAD-6757-8A6348EA12C8}.Debug|Win32.ActiveCfg = Debug|Win32 {AD537C9A-FECA-1BAD-6757-8A6348EA12C8}.Debug|Win32.Build.0 = Debug|Win32 - {AD537C9A-FECA-1BAD-6757-8A6348EA12C8}.Debug|x64.ActiveCfg = Debug|Win32 + {AD537C9A-FECA-1BAD-6757-8A6348EA12C8}.Debug|x64.ActiveCfg = Debug|x64 + {AD537C9A-FECA-1BAD-6757-8A6348EA12C8}.Debug|x64.Build.0 = Debug|x64 {AD537C9A-FECA-1BAD-6757-8A6348EA12C8}.Release|Win32.ActiveCfg = Release|Win32 {AD537C9A-FECA-1BAD-6757-8A6348EA12C8}.Release|Win32.Build.0 = Release|Win32 - {AD537C9A-FECA-1BAD-6757-8A6348EA12C8}.Release|x64.ActiveCfg = Release|Win32 + {AD537C9A-FECA-1BAD-6757-8A6348EA12C8}.Release|x64.ActiveCfg = Release|x64 + {AD537C9A-FECA-1BAD-6757-8A6348EA12C8}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE