diff options
Diffstat (limited to 'src')
126 files changed, 4864 insertions, 2792 deletions
diff --git a/src/bindings/scripts/scripts/eastern_kingdoms/stormwind_city.cpp b/src/bindings/scripts/scripts/eastern_kingdoms/stormwind_city.cpp index 6ea696e7ae3..7ee1ad34a6a 100644 --- a/src/bindings/scripts/scripts/eastern_kingdoms/stormwind_city.cpp +++ b/src/bindings/scripts/scripts/eastern_kingdoms/stormwind_city.cpp @@ -454,7 +454,7 @@ struct TRINITY_DLL_DECL npc_marzon_silent_bladeAI : public ScriptedAI { CAST_AI(npc_lord_gregor_lescovarAI, CAST_CRE(pSummoner)->AI())->uiTimer = 2000; CAST_AI(npc_lord_gregor_lescovarAI, CAST_CRE(pSummoner)->AI())->uiPhase = 5; - m_creature->ChangeOrient(0.0f, pSummoner); + //m_creature->ChangeOrient(0.0f, pSummoner); } } } @@ -514,8 +514,6 @@ struct TRINITY_DLL_DECL npc_tyrion_spybotAI : public npc_escortAI switch(uiPointId) { case 1: - if (pTyrion = m_creature->FindNearestCreature(NPC_TYRION, 10.0f, true)) - m_creature->ChangeOrient(0.0f, pTyrion); SetEscortPaused(true); uiTimer = 2000; uiPhase = 1; @@ -528,8 +526,6 @@ struct TRINITY_DLL_DECL npc_tyrion_spybotAI : public npc_escortAI break; case 17: SetEscortPaused(true); - if (pLescovar = m_creature->FindNearestCreature(NPC_LORD_GREGOR_LESCOVAR, 20.0f, true)) - pLescovar->ChangeOrient(0.0f, m_creature); DoScriptText(SAY_SPYBOT_3, m_creature); uiTimer = 3000; uiPhase = 8; diff --git a/src/game/AchievementMgr.cpp b/src/game/AchievementMgr.cpp index d03bb5f4211..afd51d1f55e 100644 --- a/src/game/AchievementMgr.cpp +++ b/src/game/AchievementMgr.cpp @@ -196,10 +196,10 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria) } return true; case ACHIEVEMENT_CRITERIA_DATA_TYPE_MAP_DIFFICULTY: - if (difficalty.difficalty >= TOTAL_DIFFICULTIES) + if (difficulty.difficulty >= MAX_DIFFICULTY) { sLog.outErrorDb( "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_MAP_DIFFICULTY (%u) have wrong difficulty in value1 (%u), ignore.", - criteria->ID, criteria->requiredType,dataType,difficalty.difficalty); + criteria->ID, criteria->requiredType,dataType,difficulty.difficulty); return false; } return true; @@ -294,7 +294,7 @@ bool AchievementCriteriaData::Meets(Player const* source, Unit const* target, ui case ACHIEVEMENT_CRITERIA_DATA_TYPE_DISABLED: return false; // always fail case ACHIEVEMENT_CRITERIA_DATA_TYPE_MAP_DIFFICULTY: - return source->GetMap()->GetSpawnMode()==difficalty.difficalty; + return source->GetMap()->GetSpawnMode()==difficulty.difficulty; case ACHIEVEMENT_CRITERIA_DATA_TYPE_MAP_PLAYER_COUNT: return source->GetMap()->GetPlayersCountExceptGMs() <= map_players.maxcount; case ACHIEVEMENT_CRITERIA_DATA_TYPE_T_TEAM: @@ -592,7 +592,8 @@ void AchievementMgr::SendAchievementEarned(AchievementEntry const* achievement) data << uint32(0); // 1=link supplied string as player name, 0=display plain string sWorld.SendGlobalMessage(&data); } - else + // if player is in world he can tell his friends about new achievement + else if (GetPlayer()->IsInWorld()) { CellPair p = MaNGOS::ComputeCellPair(GetPlayer()->GetPositionX(), GetPlayer()->GetPositionY()); @@ -902,7 +903,7 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui if(!achievIdForDangeon[j][2]) break; // for } - else if(GetPlayer()->GetDifficulty()==DIFFICULTY_NORMAL) + else if(GetPlayer()->GetDungeonDifficulty()==DUNGEON_DIFFICULTY_NORMAL) { // dungeon in normal mode accepted if(!achievIdForDangeon[j][1]) diff --git a/src/game/AchievementMgr.h b/src/game/AchievementMgr.h index d031672f2a5..ceaa4bde65b 100644 --- a/src/game/AchievementMgr.h +++ b/src/game/AchievementMgr.h @@ -125,8 +125,8 @@ struct AchievementCriteriaData // ACHIEVEMENT_CRITERIA_DATA_TYPE_MAP_DIFFICULTY = 12 struct { - uint32 difficalty; - } difficalty; + uint32 difficulty; + } difficulty; // ACHIEVEMENT_CRITERIA_DATA_TYPE_MAP_PLAYER_COUNT = 13 struct { diff --git a/src/game/ArenaTeam.cpp b/src/game/ArenaTeam.cpp index feeae849bae..1d9669007fc 100644 --- a/src/game/ArenaTeam.cpp +++ b/src/game/ArenaTeam.cpp @@ -24,11 +24,12 @@ void ArenaTeamMember::ModifyPersonalRating(Player* plr, int32 mod, uint32 slot) { - int32 memberRating = int32(personal_rating) + mod; - personal_rating = memberRating > 0 ? memberRating : 0; - if(plr) - plr->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (slot*6) + 5, personal_rating); - //sLog.outArena("Modify personal rating for player %s: personal rating %u, mod %d, rating %d", plr->GetName(), personal_rating, mod, rating); + if (int32(personal_rating) + mod < 0) + personal_rating = 0; + else + personal_rating += mod; + if(plr) + plr->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (slot * ARENA_TEAM_END) + ARENA_TEAM_PERSONAL_RATING, personal_rating); } ArenaTeam::ArenaTeam() @@ -109,7 +110,7 @@ bool ArenaTeam::AddMember(const uint64& PlayerGuid) return false; } - plClass = (uint8)pl->getClass(); + plClass = pl->getClass(); plName = pl->GetName(); } else @@ -146,7 +147,7 @@ bool ArenaTeam::AddMember(const uint64& PlayerGuid) if (sWorld.getConfig(CONFIG_ARENA_SEASON_ID) >= 6) { if (m_stats.rating < 1000) - newmember.personal_rating = m_stats.rating; + newmember.personal_rating = 0; else newmember.personal_rating = 1000; } @@ -160,13 +161,13 @@ bool ArenaTeam::AddMember(const uint64& PlayerGuid) if(pl) { - pl->SetInArenaTeam(m_TeamId, GetSlot()); + pl->SetInArenaTeam(m_TeamId, GetSlot(), GetType()); pl->SetArenaTeamIdInvited(0); - pl->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot()*6) + 5, newmember.personal_rating ); + pl->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot() * ARENA_TEAM_END) + ARENA_TEAM_PERSONAL_RATING, newmember.personal_rating ); // hide promote/remove buttons if(m_CaptainGuid != PlayerGuid) - pl->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot() * 6) + 1, 1); + pl->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot() * ARENA_TEAM_END) + ARENA_TEAM_MEMBER, 1); sLog.outArena("Player: %s [GUID: %u] joined arena team type: %u [Id: %u].", pl->GetName(), pl->GetGUIDLow(), GetType(), GetId()); } return true; @@ -263,7 +264,7 @@ void ArenaTeam::SetCaptain(const uint64& guid) // disable remove/promote buttons Player *oldcaptain = objmgr.GetPlayer(GetCaptain()); if(oldcaptain) - oldcaptain->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 1 + (GetSlot() * 6), 1); + oldcaptain->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot() * ARENA_TEAM_END) + ARENA_TEAM_MEMBER, 1); // set new captain m_CaptainGuid = guid; @@ -275,7 +276,7 @@ void ArenaTeam::SetCaptain(const uint64& guid) Player *newcaptain = objmgr.GetPlayer(guid); if(newcaptain) { - newcaptain->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 1 + (GetSlot() * 6), 0); + newcaptain->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot() * ARENA_TEAM_END) + ARENA_TEAM_MEMBER, 0); sLog.outArena("Player: %s [GUID: %u] promoted player: %s [GUID: %u] to leader of arena team [Id: %u] [Type: %u].", oldcaptain->GetName(), oldcaptain->GetGUIDLow(), newcaptain->GetName(), newcaptain->GetGUIDLow(), GetId(), GetType()); } } @@ -291,17 +292,12 @@ void ArenaTeam::DelMember(uint64 guid) } } - Player *player = objmgr.GetPlayer(guid); - - if(player) + if(Player *player = objmgr.GetPlayer(guid)) { - player->SetInArenaTeam(0, GetSlot()); player->GetSession()->SendArenaTeamCommandResult(ERR_ARENA_TEAM_QUIT_S, GetName(), "", 0); // delete all info regarding this team - for (uint8 i = 0; i < 6; ++i) - { - player->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot() * 6) + i, 0); - } + for(uint32 i = 0; i < ARENA_TEAM_END; ++i) + player->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot() * ARENA_TEAM_END) + i, 0); sLog.outArena("Player: %s [GUID: %u] left arena team type: %u [Id: %u].", player->GetName(), player->GetGUIDLow(), GetType(), GetId()); } CharacterDatabase.PExecute("DELETE FROM arena_team_member WHERE arenateamid = '%u' AND guid = '%u'", GetId(), GUID_LOPART(guid)); @@ -513,8 +509,7 @@ uint32 ArenaTeam::GetPoints(uint32 MemberRating) uint32 rating = MemberRating + 150 < m_stats.rating ? MemberRating : m_stats.rating; if(rating<=1500) - // points = (float)1500 * 0.22f + 14.0f; - points = 344.0f; // 3.1 change - teams with rating below 1500 get arena points for 1500 rating + points = (float)rating * 0.22f + 14.0f; else points = 1511.26f / (1.0f + 1639.28f * exp(-0.00412f * (float)rating)); @@ -533,8 +528,8 @@ float ArenaTeam::GetChanceAgainst(uint32 own_rating, uint32 enemy_rating) // ELO system if (sWorld.getConfig(CONFIG_ARENA_SEASON_ID) >= 6) - if (enemy_rating < 1300) - enemy_rating = 1300; + if (enemy_rating < 1000) + enemy_rating = 1000; return 1.0f/(1.0f+exp(log(10.0f)*(float)((float)enemy_rating - (float)own_rating)/400.0f)); } @@ -560,10 +555,12 @@ void ArenaTeam::FinishGame(int32 mod) int32 ArenaTeam::WonAgainst(uint32 againstRating) { // called when the team has won - //'chance' calculation - to beat the opponent + // 'chance' calculation - to beat the opponent float chance = GetChanceAgainst(m_stats.rating, againstRating); - // calculate the rating modification (ELO system with k=32) - int32 mod = (int32)floor(32.0f * (1.0f - chance)); + float K = (m_stats.rating < 1000) ? 48.0f : 32.0f; + // calculate the rating modification (ELO system with k=32 or k=48 if rating<1000) + int32 mod = (int32)floor(K* (1.0f - chance)); + // modify the team stats accordingly FinishGame(mod); m_stats.wins_week += 1; @@ -578,8 +575,9 @@ int32 ArenaTeam::LostAgainst(uint32 againstRating) // called when the team has lost //'chance' calculation - to loose to the opponent float chance = GetChanceAgainst(m_stats.rating, againstRating); - // calculate the rating modification (ELO system with k=32) - int32 mod = (int32)ceil(32.0f * (0.0f - chance)); + float K = (m_stats.rating < 1000) ? 48.0f : 32.0f; + // calculate the rating modification (ELO system with k=32 or k=48 if rating<1000) + int32 mod = (int32)ceil(K * (0.0f - chance)); // modify the team stats accordingly FinishGame(mod); @@ -596,14 +594,16 @@ void ArenaTeam::MemberLost(Player * plr, uint32 againstRating) { // update personal rating float chance = GetChanceAgainst(itr->personal_rating, againstRating); - int32 mod = (int32)ceil(32.0f * (0.0f - chance)); + float K = (itr->personal_rating < 1000) ? 48.0f : 32.0f; + // calculate the rating modification (ELO system with k=32 or k=48 if rating<1000) + int32 mod = (int32)ceil(K * (0.0f - chance)); itr->ModifyPersonalRating(plr, mod, GetSlot()); // update personal played stats itr->games_week +=1; itr->games_season +=1; // update the unit fields - plr->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 6 * GetSlot() + 2, itr->games_week); - plr->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 6 * GetSlot() + 3, itr->games_season); + plr->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot() * ARENA_TEAM_END) + ARENA_TEAM_GAMES_WEEK, itr->games_week); + plr->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot() * ARENA_TEAM_END) + ARENA_TEAM_GAMES_SEASON, itr->games_season); return; } } @@ -618,7 +618,9 @@ void ArenaTeam::OfflineMemberLost(uint64 guid, uint32 againstRating) { // update personal rating float chance = GetChanceAgainst(itr->personal_rating, againstRating); - int32 mod = (int32)ceil(32.0f * (0.0f - chance)); + float K = (itr->personal_rating < 1000) ? 48.0f : 32.0f; + // calculate the rating modification (ELO system with k=32 or k=48 if rating<1000) + int32 mod = (int32)ceil(K * (0.0f - chance)); if (int32(itr->personal_rating) + mod < 0) itr->personal_rating = 0; else @@ -640,7 +642,9 @@ void ArenaTeam::MemberWon(Player * plr, uint32 againstRating) { // update personal rating float chance = GetChanceAgainst(itr->personal_rating, againstRating); - int32 mod = (int32)floor(32.0f * (1.0f - chance)); + float K = (itr->personal_rating < 1000) ? 48.0f : 32.0f; + // calculate the rating modification (ELO system with k=32 or k=48 if rating<1000) + int32 mod = (int32)floor(K* (1.0f - chance)); itr->ModifyPersonalRating(plr, mod, GetSlot()); // update personal stats itr->games_week +=1; @@ -648,8 +652,8 @@ void ArenaTeam::MemberWon(Player * plr, uint32 againstRating) itr->wins_season += 1; itr->wins_week += 1; // update unit fields - plr->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 6 * GetSlot() + 2, itr->games_week); - plr->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 6 * GetSlot() + 3, itr->games_season); + plr->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot() * ARENA_TEAM_END) + ARENA_TEAM_GAMES_WEEK, itr->games_week); + plr->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot() * ARENA_TEAM_END) + ARENA_TEAM_GAMES_SEASON, itr->games_season); return; } } @@ -720,26 +724,3 @@ bool ArenaTeam::IsFighting() const } return false; } - -/* -arenateam fields (id from 2.3.3 client): -1414 - arena team id 2v2 -1415 - 0=captain, 1=member -1416 - played this week -1417 - played this season -1418 - unk - rank? -1419 - personal arena rating -1420 - arena team id 3v3 -1421 - 0=captain, 1=member -1422 - played this week -1423 - played this season -1424 - unk - rank? -1425 - personal arena rating -1426 - arena team id 5v5 -1427 - 0=captain, 1=member -1428 - played this week -1429 - played this season -1430 - unk - rank? -1431 - personal arena rating -*/ - diff --git a/src/game/ArenaTeamHandler.cpp b/src/game/ArenaTeamHandler.cpp index c7ecf5b1d80..edcfeed0f99 100644 --- a/src/game/ArenaTeamHandler.cpp +++ b/src/game/ArenaTeamHandler.cpp @@ -57,12 +57,11 @@ void WorldSession::HandleArenaTeamQueryOpcode(WorldPacket & recv_data) uint32 ArenaTeamId; recv_data >> ArenaTeamId; - ArenaTeam *arenateam = objmgr.GetArenaTeamById(ArenaTeamId); - if(!arenateam) // arena team not found - return; - - arenateam->Query(this); - arenateam->Stats(this); + if(ArenaTeam *arenateam = objmgr.GetArenaTeamById(ArenaTeamId)) + { + arenateam->Query(this); + arenateam->Stats(this); + } } void WorldSession::HandleArenaTeamRosterOpcode(WorldPacket & recv_data) @@ -72,11 +71,8 @@ void WorldSession::HandleArenaTeamRosterOpcode(WorldPacket & recv_data) uint32 ArenaTeamId; // arena team id recv_data >> ArenaTeamId; - ArenaTeam *arenateam = objmgr.GetArenaTeamById(ArenaTeamId); - if(!arenateam) - return; - - arenateam->Roster(this); + if(ArenaTeam *arenateam = objmgr.GetArenaTeamById(ArenaTeamId)) + arenateam->Roster(this); } void WorldSession::HandleArenaTeamInviteOpcode(WorldPacket & recv_data) @@ -206,12 +202,14 @@ void WorldSession::HandleArenaTeamLeaveOpcode(WorldPacket & recv_data) ArenaTeam *at = objmgr.GetArenaTeamById(ArenaTeamId); if(!at) return; + if(_player->GetGUID() == at->GetCaptain() && at->GetMembersSize() > 1) { // check for correctness SendArenaTeamCommandResult(ERR_ARENA_TEAM_QUIT_S, "", "", ERR_ARENA_TEAM_LEADER_LEAVE_S); return; } + // arena team has only one member (=captain) if(_player->GetGUID() == at->GetCaptain()) { @@ -238,18 +236,17 @@ void WorldSession::HandleArenaTeamDisbandOpcode(WorldPacket & recv_data) uint32 ArenaTeamId; // arena team id recv_data >> ArenaTeamId; - ArenaTeam *at = objmgr.GetArenaTeamById(ArenaTeamId); - if(!at) - return; - - if(at->GetCaptain() != _player->GetGUID()) - return; + if(ArenaTeam *at = objmgr.GetArenaTeamById(ArenaTeamId)) + { + if(at->GetCaptain() != _player->GetGUID()) + return; - if (at->IsFighting()) - return; + if(at->IsFighting()) + return; - at->Disband(this); - delete at; + at->Disband(this); + delete at; + } } void WorldSession::HandleArenaTeamRemoveOpcode(WorldPacket & recv_data) @@ -422,4 +419,3 @@ ERR_ARENA_TEAM_TOO_MANY_MEMBERS_S "%s is full" ERR_ARENA_TEAM_LEVEL_TOO_LOW_I "You must be level %d to form an arena team" */ - diff --git a/src/game/BattleGround.cpp b/src/game/BattleGround.cpp index d6558e3bb4f..bdbcfc63bac 100644 --- a/src/game/BattleGround.cpp +++ b/src/game/BattleGround.cpp @@ -156,6 +156,7 @@ BattleGround::BattleGround() m_MinPlayers = 0; m_MapId = 0; + m_Map = NULL; m_TeamStartLocX[BG_TEAM_ALLIANCE] = 0; m_TeamStartLocX[BG_TEAM_HORDE] = 0; @@ -224,9 +225,8 @@ BattleGround::~BattleGround() sBattleGroundMgr.RemoveBattleGround(GetInstanceID(), GetTypeID()); // unload map - if (Map * map = MapManager::Instance().FindMap(GetMapId(), GetInstanceID())) - if (map->IsBattleGroundOrArena()) - ((BattleGroundMap*)map)->SetUnload(); + if (m_Map) + m_Map->SetUnload(); // remove from bg free slot queue this->RemoveFromBGFreeSlotQueue(); @@ -784,6 +784,7 @@ void BattleGround::EndBattleGround(uint32 winner) else if(winner) RewardMark(plr,ITEM_LOSER_COUNT); + plr->SetHealth(plr->GetMaxHealth()); plr->SetPower(POWER_MANA, plr->GetMaxPower(POWER_MANA)); plr->CombatStopWithPets(true); @@ -1277,7 +1278,9 @@ void BattleGround::EventPlayerLoggedOut(Player* player) if (GetAlivePlayersCountByTeam(player->GetTeam()) <= 1 && GetPlayersCountByTeam(GetOtherTeam(player->GetTeam()))) EndBattleGround(GetOtherTeam(player->GetTeam())); } + return; } + player->LeaveBattleground(); } /* This method should be called only once ... it adds pointer to queue */ @@ -1445,15 +1448,14 @@ void BattleGround::RemovePlayerFromResurrectQueue(uint64 player_guid) 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()); + Map *map = GetBgMap(); 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); @@ -1493,7 +1495,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(uint32 type) { - GameObject *obj = HashMapHolder<GameObject>::Find(m_BgObjects[type]); + GameObject *obj = GetBgMap()->GetGameObject(m_BgObjects[type]); if (obj) { //if doors are open, close it @@ -1512,7 +1514,7 @@ void BattleGround::DoorClose(uint32 type) void BattleGround::DoorOpen(uint32 type) { - GameObject *obj = HashMapHolder<GameObject>::Find(m_BgObjects[type]); + GameObject *obj = GetBgMap()->GetGameObject(m_BgObjects[type]); if (obj) { //change state to be sure they will be opened @@ -1527,7 +1529,7 @@ void BattleGround::DoorOpen(uint32 type) GameObject* BattleGround::GetBGObject(uint32 type) { - GameObject *obj = HashMapHolder<GameObject>::Find(m_BgObjects[type]); + GameObject *obj = GetBgMap()->GetGameObject(m_BgObjects[type]); if(!obj) sLog.outError("couldn't get gameobject %i",type); return obj; @@ -1535,7 +1537,7 @@ GameObject* BattleGround::GetBGObject(uint32 type) Creature* BattleGround::GetBGCreature(uint32 type) { - Creature *creature = HashMapHolder<Creature>::Find(m_BgCreatures[type]); + Creature *creature = GetBgMap()->GetCreature(m_BgCreatures[type]); if(!creature) sLog.outError("couldn't get creature %i",type); return creature; @@ -1543,12 +1545,12 @@ Creature* BattleGround::GetBGCreature(uint32 type) void BattleGround::SpawnBGObject(uint32 type, uint32 respawntime) { - Map * map = MapManager::Instance().FindMap(GetMapId(),GetInstanceID()); + Map * map = GetBgMap(); if (!map) return; if (respawntime == 0) { - GameObject *obj = HashMapHolder<GameObject>::Find(m_BgObjects[type]); + GameObject *obj = map->GetGameObject(m_BgObjects[type]); if (obj) { //we need to change state from GO_JUST_DEACTIVATED to GO_READY in case battleground is starting again @@ -1560,7 +1562,7 @@ void BattleGround::SpawnBGObject(uint32 type, uint32 respawntime) } else { - GameObject *obj = HashMapHolder<GameObject>::Find(m_BgObjects[type]); + GameObject *obj = map->GetGameObject(m_BgObjects[type]); if (obj) { map->Add(obj); @@ -1572,7 +1574,7 @@ void BattleGround::SpawnBGObject(uint32 type, uint32 respawntime) Creature* BattleGround::AddCreature(uint32 entry, uint32 type, uint32 teamval, float x, float y, float z, float o, uint32 respawntime) { - Map * map = MapManager::Instance().FindMap(GetMapId(),GetInstanceID()); + Map * map = GetBgMap(); if (!map) return NULL; @@ -1628,7 +1630,7 @@ bool BattleGround::DelCreature(uint32 type) if (!m_BgCreatures[type]) return true; - Creature *cr = HashMapHolder<Creature>::Find(m_BgCreatures[type]); + Creature *cr = GetBgMap()->GetCreature(m_BgCreatures[type]); if (!cr) { sLog.outError("Can't find creature guid: %u",GUID_LOPART(m_BgCreatures[type])); @@ -1644,7 +1646,7 @@ bool BattleGround::DelObject(uint32 type) if (!m_BgObjects[type]) return true; - GameObject *obj = HashMapHolder<GameObject>::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])); @@ -1679,10 +1681,6 @@ bool BattleGround::AddSpiritGuide(uint32 type, float x, float y, float z, float // aura //TODO: Fix display here //pCreature->SetVisibleAura(0, SPELL_SPIRIT_HEAL_CHANNEL); - - //pCreature->SetUInt32Value(UNIT_FIELD_AURAFLAGS, 0x00000009); - //pCreature->SetUInt32Value(UNIT_FIELD_AURALEVELS, 0x0000003C); - //pCreature->SetUInt32Value(UNIT_FIELD_AURAAPPLICATIONS, 0x000000FF); // casting visual effect pCreature->SetUInt32Value(UNIT_CHANNEL_SPELL, SPELL_SPIRIT_HEAL_CHANNEL); // correct cast speed @@ -1740,7 +1738,7 @@ buffs are in their positions when battleground starts */ void BattleGround::HandleTriggerBuff(uint64 const& go_guid) { - GameObject *obj = HashMapHolder<GameObject>::Find(go_guid); + GameObject *obj = GetBgMap()->GetGameObject(go_guid); if (!obj || obj->GetGoType() != GAMEOBJECT_TYPE_TRAP || !obj->isSpawned()) return; @@ -1887,10 +1885,10 @@ void BattleGround::CheckArenaWinConditions() EndBattleGround(ALLIANCE); } -void BattleGround::UpdateArenaUnitWorldState() +void BattleGround::UpdateArenaWorldState() { - UpdateWorldState(HORDE_WORLD_STATE, GetAlivePlayersCountByTeam(HORDE)); - UpdateWorldState(ALLIANCE_WORLD_STATE, GetAlivePlayersCountByTeam(ALLIANCE)); + UpdateWorldState(0xe10, GetAlivePlayersCountByTeam(HORDE)); + UpdateWorldState(0xe11, GetAlivePlayersCountByTeam(ALLIANCE)); } void BattleGround::SetBgRaid( uint32 TeamID, Group *bg_raid ) diff --git a/src/game/BattleGround.h b/src/game/BattleGround.h index 275085f4ca7..7a1bcbc58ea 100644 --- a/src/game/BattleGround.h +++ b/src/game/BattleGround.h @@ -29,6 +29,7 @@ class GameObject; class Group; class Player; class WorldPacket; +class BattleGroundMap; struct WorldSafeLocsEntry; @@ -97,9 +98,9 @@ enum BattleGroundSpells enum BattleGroundTimeIntervals { RESURRECTION_INTERVAL = 30000, // ms - REMIND_INTERVAL = 30000, // ms - INVITATION_REMIND_TIME = 60000, // ms - INVITE_ACCEPT_WAIT_TIME = 80000, // ms + //REMIND_INTERVAL = 10000, // ms + INVITATION_REMIND_TIME = 20000, // ms + INVITE_ACCEPT_WAIT_TIME = 40000, // ms TIME_TO_AUTOREMOVE = 120000, // ms MAX_OFFLINE_TIME = 300, // secs RESPAWN_ONE_DAY = 86400, // secs @@ -158,11 +159,12 @@ enum BattleGroundQueueTypeId BATTLEGROUND_QUEUE_AB = 3, BATTLEGROUND_QUEUE_EY = 4, BATTLEGROUND_QUEUE_SA = 5, - BATTLEGROUND_QUEUE_2v2 = 6, - BATTLEGROUND_QUEUE_3v3 = 7, - BATTLEGROUND_QUEUE_5v5 = 8 + BATTLEGROUND_QUEUE_IC = 6, + BATTLEGROUND_QUEUE_2v2 = 7, + BATTLEGROUND_QUEUE_3v3 = 8, + BATTLEGROUND_QUEUE_5v5 = 9, + MAX_BATTLEGROUND_QUEUE_TYPES }; -#define MAX_BATTLEGROUND_QUEUE_TYPES 9 enum BGQueueIdBasedOnLevel // queue_id for level ranges { @@ -210,12 +212,6 @@ enum ArenaType ARENA_TYPE_5v5 = 5 }; -enum ArenaWorldUnitState -{ - HORDE_WORLD_STATE = 0xE10, - ALLIANCE_WORLD_STATE = 0xE11 -}; - enum BattleGroundType { TYPE_BATTLEGROUND = 3, @@ -420,6 +416,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 { @@ -484,7 +488,7 @@ class BattleGround void SetArenaTeamRatingChangeForTeam(uint32 Team, int32 RatingChange) { m_ArenaTeamRatingChanges[GetTeamIndexByTeamId(Team)] = RatingChange; } int32 GetArenaTeamRatingChangeForTeam(uint32 Team) const { return m_ArenaTeamRatingChanges[GetTeamIndexByTeamId(Team)]; } void CheckArenaWinConditions(); - void UpdateArenaUnitWorldState(); + void UpdateArenaWorldState(); /* Triggers handle */ // must be implemented in BG subclass @@ -623,6 +627,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 b684f4523e1..0fea16bfcbd 100644 --- a/src/game/BattleGroundAB.cpp +++ b/src/game/BattleGroundAB.cpp @@ -420,11 +420,11 @@ void BattleGroundAB::EventPlayerClickedOnFlag(Player *source, GameObject* /*targ return; uint8 node = BG_AB_NODE_STABLES; - GameObject* obj=HashMapHolder<GameObject>::Find(m_BgObjects[node*8+7]); + GameObject* obj=GetBgMap()->GetGameObject(m_BgObjects[node*8+7]); while ( (node < BG_AB_DYNAMIC_NODES_COUNT) && ((!obj) || (!source->IsWithinDistInMap(obj,10)))) { ++node; - obj=HashMapHolder<GameObject>::Find(m_BgObjects[node*8+BG_AB_OBJECT_AURA_CONTESTED]); + obj=GetBgMap()->GetGameObject(m_BgObjects[node*8+BG_AB_OBJECT_AURA_CONTESTED]); } if (node == BG_AB_DYNAMIC_NODES_COUNT) diff --git a/src/game/BattleGroundAB.h b/src/game/BattleGroundAB.h index ef151ad187b..bdc073f6ec8 100644 --- a/src/game/BattleGroundAB.h +++ b/src/game/BattleGroundAB.h @@ -130,8 +130,8 @@ enum BG_AB_Timers enum BG_AB_Score { - BG_AB_WARNING_NEAR_VICTORY_SCORE = 1800, - BG_AB_MAX_TEAM_SCORE = 2000 + BG_AB_WARNING_NEAR_VICTORY_SCORE = 1400, + BG_AB_MAX_TEAM_SCORE = 1600 }; /* do NOT change the order, else wrong behaviour */ diff --git a/src/game/BattleGroundABG.cpp b/src/game/BattleGroundABG.cpp new file mode 100644 index 00000000000..f0ae47482f1 --- /dev/null +++ b/src/game/BattleGroundABG.cpp @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> + * + * 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 + */ + +#include "Player.h" +#include "BattleGround.h" +#include "BattleGroundABG.h" +#include "Language.h" + +BattleGroundABG::BattleGroundABG() +{ + //TODO FIX ME! + m_StartMessageIds[BG_STARTING_EVENT_FIRST] = LANG_BG_WS_START_TWO_MINUTES; + m_StartMessageIds[BG_STARTING_EVENT_SECOND] = LANG_BG_WS_START_ONE_MINUTE; + m_StartMessageIds[BG_STARTING_EVENT_THIRD] = LANG_BG_WS_START_HALF_MINUTE; + m_StartMessageIds[BG_STARTING_EVENT_FOURTH] = LANG_BG_WS_HAS_BEGUN; +} + +BattleGroundABG::~BattleGroundABG() +{ + +} + +void BattleGroundABG::Update(uint32 diff) +{ + BattleGround::Update(diff); +} + +void BattleGroundABG::StartingEventCloseDoors() +{ +} + +void BattleGroundABG::StartingEventOpenDoors() +{ +} + +void BattleGroundABG::AddPlayer(Player *plr) +{ + BattleGround::AddPlayer(plr); + //create score and add it to map, default values are set in constructor + BattleGroundABGScore* sc = new BattleGroundABGScore; + + m_PlayerScores[plr->GetGUID()] = sc; +} + +void BattleGroundABG::RemovePlayer(Player* /*plr*/,uint64 /*guid*/) +{ + +} + +void BattleGroundABG::HandleAreaTrigger(Player * /*Source*/, uint32 /*Trigger*/) +{ + // this is wrong way to implement these things. On official it done by gameobject spell cast. + if (GetStatus() != STATUS_IN_PROGRESS) + return; +} + +void BattleGroundABG::UpdatePlayerScore(Player* Source, uint32 type, uint32 value) +{ + + std::map<uint64, BattleGroundScore*>::iterator itr = m_PlayerScores.find(Source->GetGUID()); + + if(itr == m_PlayerScores.end()) // player not found... + return; + + BattleGround::UpdatePlayerScore(Source,type,value); +}
\ No newline at end of file diff --git a/src/game/BattleGroundABG.h b/src/game/BattleGroundABG.h new file mode 100644 index 00000000000..478e8ffaf46 --- /dev/null +++ b/src/game/BattleGroundABG.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> + * + * 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 + */ + +#ifndef __BATTLEGROUNDABG_H +#define __BATTLEGROUNDABG_H + +class BattleGround; + +class BattleGroundABGScore : public BattleGroundScore +{ + public: + BattleGroundABGScore() {}; + virtual ~BattleGroundABGScore() {}; +}; + +class BattleGroundABG : public BattleGround +{ + friend class BattleGroundMgr; + + public: + BattleGroundABG(); + ~BattleGroundABG(); + void Update(uint32 diff); + + /* inherited from BattlegroundClass */ + virtual void AddPlayer(Player *plr); + virtual void StartingEventCloseDoors(); + virtual void StartingEventOpenDoors(); + + void RemovePlayer(Player *plr,uint64 guid); + void HandleAreaTrigger(Player *Source, uint32 Trigger); + //bool SetupBattleGround(); + + /* Scorekeeping */ + void UpdatePlayerScore(Player *Source, uint32 type, uint32 value); + + private: +}; +#endif
\ No newline at end of file diff --git a/src/game/BattleGroundBE.cpp b/src/game/BattleGroundBE.cpp index c20af53e013..057846285bd 100644 --- a/src/game/BattleGroundBE.cpp +++ b/src/game/BattleGroundBE.cpp @@ -82,7 +82,7 @@ void BattleGroundBE::AddPlayer(Player *plr) m_PlayerScores[plr->GetGUID()] = sc; - UpdateArenaUnitWorldState(); + UpdateArenaWorldState(); } void BattleGroundBE::RemovePlayer(Player* /*plr*/, uint64 /*guid*/) @@ -90,7 +90,7 @@ void BattleGroundBE::RemovePlayer(Player* /*plr*/, uint64 /*guid*/) if (GetStatus() == STATUS_WAIT_LEAVE) return; - UpdateArenaUnitWorldState(); + UpdateArenaWorldState(); CheckArenaWinConditions(); } @@ -107,7 +107,7 @@ void BattleGroundBE::HandleKillPlayer(Player *player, Player *killer) BattleGround::HandleKillPlayer(player,killer); - UpdateArenaUnitWorldState(); + UpdateArenaWorldState(); CheckArenaWinConditions(); } @@ -146,8 +146,7 @@ void BattleGroundBE::HandleAreaTrigger(Player *Source, uint32 Trigger) void BattleGroundBE::FillInitialWorldStates(WorldPacket &data) { data << uint32(0x9f3) << uint32(1); // 9 - - UpdateArenaUnitWorldState(); + UpdateArenaWorldState(); } void BattleGroundBE::Reset() @@ -200,4 +199,3 @@ spell 32725 - Green Team 35774 Gold Team 35775 Green Team */ - diff --git a/src/game/BattleGroundBE.h b/src/game/BattleGroundBE.h index e75e332f44f..7e48a3998c0 100644 --- a/src/game/BattleGroundBE.h +++ b/src/game/BattleGroundBE.h @@ -76,4 +76,3 @@ class BattleGroundBE : public BattleGround void UpdatePlayerScore(Player *Source, uint32 type, uint32 value); }; #endif - diff --git a/src/game/BattleGroundDS.cpp b/src/game/BattleGroundDS.cpp index 0be870be175..9036ef83f93 100644 --- a/src/game/BattleGroundDS.cpp +++ b/src/game/BattleGroundDS.cpp @@ -20,9 +20,13 @@ #include "BattleGroundDS.h" #include "Language.h" #include "Player.h" +#include "Object.h" +#include "ObjectMgr.h" +#include "WorldPacket.h" BattleGroundDS::BattleGroundDS() { + m_BgObjects.resize(BG_DS_OBJECT_MAX); m_StartDelayTimes[BG_STARTING_EVENT_FIRST] = BG_START_DELAY_1M; m_StartDelayTimes[BG_STARTING_EVENT_SECOND] = BG_START_DELAY_30S; @@ -43,14 +47,46 @@ BattleGroundDS::~BattleGroundDS() void BattleGroundDS::Update(uint32 diff) { BattleGround::Update(diff); + if (getWaterFallTimer() < diff) + { + if (isWaterFallActive()) + { + setWaterFallTimer(urand(BG_DS_WATERFALL_TIMER_MIN, BG_DS_WATERFALL_TIMER_MAX)); + for (uint32 i = BG_DS_OBJECT_WATER_1; i <= BG_DS_OBJECT_WATER_2; ++i) + SpawnBGObject(i, getWaterFallTimer()); + setWaterFallActive(false); + } + else + { + setWaterFallTimer(BG_DS_WATERFALL_DURATION); + for (uint32 i = BG_DS_OBJECT_WATER_1; i <= BG_DS_OBJECT_WATER_2; ++i) + SpawnBGObject(i, RESPAWN_IMMEDIATELY); + setWaterFallActive(true); + } + } + else + setWaterFallTimer(getWaterFallTimer() - diff); } void BattleGroundDS::StartingEventCloseDoors() { + for (uint32 i = BG_DS_OBJECT_DOOR_1; i <= BG_DS_OBJECT_DOOR_2; ++i) + SpawnBGObject(i, RESPAWN_IMMEDIATELY); } void BattleGroundDS::StartingEventOpenDoors() { + for (uint32 i = BG_DS_OBJECT_DOOR_1; i <= BG_DS_OBJECT_DOOR_2; ++i) + DoorOpen(i); + + for (uint32 i = BG_DS_OBJECT_BUFF_1; i <= BG_DS_OBJECT_BUFF_2; ++i) + SpawnBGObject(i, 60); + + setWaterFallTimer(urand(BG_DS_WATERFALL_TIMER_MIN, BG_DS_WATERFALL_TIMER_MAX)); + setWaterFallActive(false); + + for (uint32 i = BG_DS_OBJECT_WATER_1; i <= BG_DS_OBJECT_WATER_2; ++i) + SpawnBGObject(i, getWaterFallTimer()); } void BattleGroundDS::AddPlayer(Player *plr) @@ -60,22 +96,87 @@ void BattleGroundDS::AddPlayer(Player *plr) BattleGroundDSScore* sc = new BattleGroundDSScore; m_PlayerScores[plr->GetGUID()] = sc; + + UpdateArenaWorldState(); } void BattleGroundDS::RemovePlayer(Player * /*plr*/, uint64 /*guid*/) { + if (GetStatus() == STATUS_WAIT_LEAVE) + return; + + UpdateArenaWorldState(); + CheckArenaWinConditions(); } void BattleGroundDS::HandleKillPlayer(Player* player, Player* killer) { - BattleGround::HandleKillPlayer(player, killer); + if (GetStatus() != STATUS_IN_PROGRESS) + return; + + if (!killer) + { + sLog.outError("BattleGroundDS: Killer player not found"); + return; + } + + BattleGround::HandleKillPlayer(player,killer); + + UpdateArenaWorldState(); + CheckArenaWinConditions(); } -void BattleGroundDS::HandleAreaTrigger(Player * /*Source*/, uint32 /*Trigger*/) +void BattleGroundDS::HandleAreaTrigger(Player *Source, uint32 Trigger) { + if (GetStatus() != STATUS_IN_PROGRESS) + return; + + switch(Trigger) + { + case 5347: + case 5348: + break; + default: + sLog.outError("WARNING: Unhandled AreaTrigger in Battleground: %u", Trigger); + Source->GetSession()->SendAreaTriggerMessage("Warning: Unhandled AreaTrigger in Battleground: %u", Trigger); + break; + } } +bool BattleGroundDS::HandlePlayerUnderMap(Player *player) +{ + player->TeleportTo(GetMapId(), 1299.046, 784.825, 9.338, 2.422, false); + return true; +} + +void BattleGroundDS::FillInitialWorldStates(WorldPacket &data) +{ + data << uint32(3610) << uint32(1); // 9 show + UpdateArenaWorldState(); +} + +void BattleGroundDS::Reset() +{ + //call parent's class reset + BattleGround::Reset(); +} + + bool BattleGroundDS::SetupBattleGround() { + // gates + if (!AddObject(BG_DS_OBJECT_DOOR_1, BG_DS_OBJECT_TYPE_DOOR_1, 1350.95, 817.2, 20.8096, 3.15, 0, 0, 0.99627, 0.0862864, RESPAWN_IMMEDIATELY) + || !AddObject(BG_DS_OBJECT_DOOR_2, BG_DS_OBJECT_TYPE_DOOR_2, 1232.65, 764.913, 20.0729, 6.3, 0, 0, 0.0310211, -0.999519, RESPAWN_IMMEDIATELY) + // water + || !AddObject(BG_DS_OBJECT_WATER_1, BG_DS_OBJECT_TYPE_WATER_1, 1291.56, 790.837, 7.1, 3.14238, 0, 0, 0.694215, -0.719768, 120) + || !AddObject(BG_DS_OBJECT_WATER_2, BG_DS_OBJECT_TYPE_WATER_2, 1291.56, 790.837, 7.1, 3.14238, 0, 0, 0.694215, -0.719768, 120) + // buffs + || !AddObject(BG_DS_OBJECT_BUFF_1, BG_DS_OBJECT_TYPE_BUFF_1, 1291.7, 813.424, 7.11472, 4.64562, 0, 0, 0.730314, -0.683111, 120) + || !AddObject(BG_DS_OBJECT_BUFF_2, BG_DS_OBJECT_TYPE_BUFF_2, 1291.7, 768.911, 7.11472, 1.55194, 0, 0, 0.700409, 0.713742, 120)) + { + sLog.outErrorDb("BatteGroundDS: Failed to spawn some object!"); + return false; + } + return true; } diff --git a/src/game/BattleGroundDS.h b/src/game/BattleGroundDS.h index 44a6cfbd33a..2ced5c88fd1 100644 --- a/src/game/BattleGroundDS.h +++ b/src/game/BattleGroundDS.h @@ -20,6 +20,34 @@ class BattleGround; +enum BattleGroundDSObjectTypes +{ + BG_DS_OBJECT_DOOR_1 = 0, + BG_DS_OBJECT_DOOR_2 = 1, + BG_DS_OBJECT_WATER_1 = 2, + BG_DS_OBJECT_WATER_2 = 3, + BG_DS_OBJECT_BUFF_1 = 4, + BG_DS_OBJECT_BUFF_2 = 5, + BG_DS_OBJECT_MAX = 6 +}; + +enum BattleGroundDSObjects +{ + BG_DS_OBJECT_TYPE_DOOR_1 = 192642, + BG_DS_OBJECT_TYPE_DOOR_2 = 192643, + BG_DS_OBJECT_TYPE_WATER_1 = 194395, + BG_DS_OBJECT_TYPE_WATER_2 = 191877, + BG_DS_OBJECT_TYPE_BUFF_1 = 184663, + BG_DS_OBJECT_TYPE_BUFF_2 = 184664 +}; + +enum BattleGroundDSData +{ // These values are NOT blizzlike... need the correct data! + BG_DS_WATERFALL_TIMER_MIN = 30000, + BG_DS_WATERFALL_TIMER_MAX = 60000, + BG_DS_WATERFALL_DURATION = 10000, +}; + class BattleGroundDSScore : public BattleGroundScore { public: @@ -45,6 +73,17 @@ class BattleGroundDS : public BattleGround void RemovePlayer(Player *plr, uint64 guid); void HandleAreaTrigger(Player *Source, uint32 Trigger); bool SetupBattleGround(); + virtual void Reset(); + virtual void FillInitialWorldStates(WorldPacket &d); void HandleKillPlayer(Player* player, Player *killer); + bool HandlePlayerUnderMap(Player * plr); + private: + uint32 m_waterTimer; + bool m_waterfallActive; + protected: + bool isWaterFallActive() { return m_waterfallActive; }; + void setWaterFallActive(bool active) { m_waterfallActive = active; }; + void setWaterFallTimer(uint32 timer) { m_waterTimer = timer; }; + uint32 getWaterFallTimer() { return m_waterTimer; }; }; #endif diff --git a/src/game/BattleGroundHandler.cpp b/src/game/BattleGroundHandler.cpp index 8413198272e..3944d4e0bfc 100644 --- a/src/game/BattleGroundHandler.cpp +++ b/src/game/BattleGroundHandler.cpp @@ -285,7 +285,10 @@ void WorldSession::HandleBattlefieldListOpcode( WorldPacket &recv_data ) recv_data >> bgTypeId; // id from DBC uint8 fromWhere; - recv_data >> fromWhere; // 0 - battlemaster, 1 - UI + recv_data >> fromWhere; // 0 - battlemaster (lua: ShowBattlefieldList), 1 - UI (lua: RequestBattlegroundInstanceInfo) + + uint8 unk1; + recv_data >> unk1; // Unknown 3.2.2 BattlemasterListEntry const* bl = sBattlemasterListStore.LookupEntry(bgTypeId); if (!bl) @@ -742,7 +745,7 @@ void WorldSession::HandleBattlemasterJoinArena( WorldPacket & recv_data ) Player *member = itr->getSource(); // calc avg personal rating - avg_pers_rating += member->GetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (arenaslot*6) + 5); + avg_pers_rating += member->GetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (arenaslot * ARENA_TEAM_END) + ARENA_TEAM_PERSONAL_RATING); } if (arenatype) diff --git a/src/game/BattleGroundIC.cpp b/src/game/BattleGroundIC.cpp new file mode 100644 index 00000000000..216b7cbe727 --- /dev/null +++ b/src/game/BattleGroundIC.cpp @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> + * + * 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 + */ + +#include "Player.h" +#include "BattleGround.h" +#include "BattleGroundIC.h" +#include "Language.h" + +BattleGroundIC::BattleGroundIC() +{ + //TODO FIX ME! + m_StartMessageIds[BG_STARTING_EVENT_FIRST] = LANG_BG_WS_START_TWO_MINUTES; + m_StartMessageIds[BG_STARTING_EVENT_SECOND] = LANG_BG_WS_START_ONE_MINUTE; + m_StartMessageIds[BG_STARTING_EVENT_THIRD] = LANG_BG_WS_START_HALF_MINUTE; + m_StartMessageIds[BG_STARTING_EVENT_FOURTH] = LANG_BG_WS_HAS_BEGUN; +} + +BattleGroundIC::~BattleGroundIC() +{ + +} + +void BattleGroundIC::Update(uint32 diff) +{ + BattleGround::Update(diff); +} + +void BattleGroundIC::StartingEventCloseDoors() +{ +} + +void BattleGroundIC::StartingEventOpenDoors() +{ +} + +void BattleGroundIC::AddPlayer(Player *plr) +{ + BattleGround::AddPlayer(plr); + //create score and add it to map, default values are set in constructor + BattleGroundICScore* sc = new BattleGroundICScore; + + m_PlayerScores[plr->GetGUID()] = sc; +} + +void BattleGroundIC::RemovePlayer(Player* /*plr*/,uint64 /*guid*/) +{ + +} + +void BattleGroundIC::HandleAreaTrigger(Player * /*Source*/, uint32 /*Trigger*/) +{ + // this is wrong way to implement these things. On official it done by gameobject spell cast. + if (GetStatus() != STATUS_IN_PROGRESS) + return; +} + +void BattleGroundIC::UpdatePlayerScore(Player* Source, uint32 type, uint32 value) +{ + + std::map<uint64, BattleGroundScore*>::iterator itr = m_PlayerScores.find(Source->GetGUID()); + + if(itr == m_PlayerScores.end()) // player not found... + return; + + BattleGround::UpdatePlayerScore(Source,type,value); +}
\ No newline at end of file diff --git a/src/game/BattleGroundIC.h b/src/game/BattleGroundIC.h new file mode 100644 index 00000000000..5c4b17cc926 --- /dev/null +++ b/src/game/BattleGroundIC.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> + * + * 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 + */ + +#ifndef __BATTLEGROUNDIC_H +#define __BATTLEGROUNDIC_H + +class BattleGround; + +class BattleGroundICScore : public BattleGroundScore +{ + public: + BattleGroundICScore() {}; + virtual ~BattleGroundICScore() {}; +}; + +class BattleGroundIC : public BattleGround +{ + friend class BattleGroundMgr; + + public: + BattleGroundIC(); + ~BattleGroundIC(); + void Update(uint32 diff); + + /* inherited from BattlegroundClass */ + virtual void AddPlayer(Player *plr); + virtual void StartingEventCloseDoors(); + virtual void StartingEventOpenDoors(); + + void RemovePlayer(Player *plr,uint64 guid); + void HandleAreaTrigger(Player *Source, uint32 Trigger); + //bool SetupBattleGround(); + + /* Scorekeeping */ + void UpdatePlayerScore(Player *Source, uint32 type, uint32 value); + + private: +}; +#endif
\ No newline at end of file diff --git a/src/game/BattleGroundMgr.cpp b/src/game/BattleGroundMgr.cpp index 926759c0373..56fbf772aea 100644 --- a/src/game/BattleGroundMgr.cpp +++ b/src/game/BattleGroundMgr.cpp @@ -37,6 +37,8 @@ #include "BattleGroundSA.h" #include "BattleGroundDS.h" #include "BattleGroundRV.h" +#include "BattleGroundIC.h" +#include "BattleGroundABG.h" #include "Chat.h" #include "Map.h" #include "MapInstanced.h" @@ -155,7 +157,7 @@ GroupQueueInfo * BattleGroundQueue::AddGroup(Player *leader, BattleGroundTypeId // create new ginfo // cannot use the method like in addplayer, because that could modify an in-queue group's stats // (e.g. leader leaving queue then joining as individual again) - GroupQueueInfo* ginfo = new GroupQueueInfo; + GroupQueueInfo* ginfo = new GroupQueueInfo; ginfo->BgTypeId = BgTypeId; ginfo->ArenaType = ArenaType; ginfo->ArenaTeamId = arenateamid; @@ -1423,6 +1425,8 @@ void BattleGroundMgr::BuildPvpLogDataPacket(WorldPacket *data, BattleGround *bg) case BATTLEGROUND_SA: // wotlk case BATTLEGROUND_DS: // wotlk case BATTLEGROUND_RV: // wotlk + case BATTLEGROUND_IC: // wotlk + case BATTLEGROUND_ABG: // wotlk *data << (int32)0; // 0 break; default: @@ -1602,6 +1606,12 @@ BattleGround * BattleGroundMgr::CreateNewBattleGround(BattleGroundTypeId bgTypeI case BATTLEGROUND_RV: bg = new BattleGroundRV(*(BattleGroundRV*)bg_template); break; + case BATTLEGROUND_IC: + bg = new BattleGroundIC(*(BattleGroundIC*)bg_template); + break; + case BATTLEGROUND_ABG: + bg = new BattleGroundABG(*(BattleGroundABG*)bg_template); + break; default: //error, but it is handled few lines above return 0; @@ -1641,7 +1651,11 @@ uint32 BattleGroundMgr::CreateBattleGround(BattleGroundTypeId bgTypeId, bool IsA case BATTLEGROUND_SA: bg = new BattleGroundSA; break; case BATTLEGROUND_DS: bg = new BattleGroundDS; break; case BATTLEGROUND_RV: bg = new BattleGroundRV; break; - default:bg = new BattleGround; break; // placeholder for non implemented BG + case BATTLEGROUND_IC: bg = new BattleGroundIC; break; + case BATTLEGROUND_ABG: bg = new BattleGroundABG; break; + default: + bg = new BattleGround; + break; } bg->SetMapId(MapID); @@ -1735,7 +1749,7 @@ void BattleGroundMgr::CreateInitialBattleGrounds() AStartLoc[2] = start->z; AStartLoc[3] = fields[6].GetFloat(); } - else if (bgTypeID == BATTLEGROUND_AA) + else if (bgTypeID == BATTLEGROUND_AA || bgTypeID == BATTLEGROUND_ABG) { AStartLoc[0] = 0; AStartLoc[1] = 0; @@ -1758,7 +1772,7 @@ void BattleGroundMgr::CreateInitialBattleGrounds() HStartLoc[2] = start->z; HStartLoc[3] = fields[8].GetFloat(); } - else if (bgTypeID == BATTLEGROUND_AA) + else if (bgTypeID == BATTLEGROUND_AA || bgTypeID == BATTLEGROUND_ABG) { HStartLoc[0] = 0; HStartLoc[1] = 0; @@ -1931,7 +1945,8 @@ bool BattleGroundMgr::IsArenaType(BattleGroundTypeId bgTypeId) bgTypeId == BATTLEGROUND_NA || bgTypeId == BATTLEGROUND_DS || bgTypeId == BATTLEGROUND_RV || - bgTypeId == BATTLEGROUND_RL ); + bgTypeId == BATTLEGROUND_RL || + bgTypeId == BATTLEGROUND_DS ); } BattleGroundQueueTypeId BattleGroundMgr::BGQueueTypeId(BattleGroundTypeId bgTypeId, uint8 arenaType) @@ -1948,6 +1963,10 @@ BattleGroundQueueTypeId BattleGroundMgr::BGQueueTypeId(BattleGroundTypeId bgType return BATTLEGROUND_QUEUE_EY; case BATTLEGROUND_SA: return BATTLEGROUND_QUEUE_SA; + case BATTLEGROUND_IC: + return BATTLEGROUND_QUEUE_IC; + case BATTLEGROUND_ABG: + return BATTLEGROUND_QUEUE_NONE; case BATTLEGROUND_AA: case BATTLEGROUND_NA: case BATTLEGROUND_RL: @@ -1984,6 +2003,8 @@ BattleGroundTypeId BattleGroundMgr::BGTemplateId(BattleGroundQueueTypeId bgQueue return BATTLEGROUND_EY; case BATTLEGROUND_QUEUE_SA: return BATTLEGROUND_SA; + case BATTLEGROUND_QUEUE_IC: + return BATTLEGROUND_IC; case BATTLEGROUND_QUEUE_2v2: case BATTLEGROUND_QUEUE_3v3: case BATTLEGROUND_QUEUE_5v5: @@ -2134,3 +2155,24 @@ bool BattleGroundMgr::IsBGWeekend(BattleGroundTypeId bgTypeId) return false; } } + +void BattleGroundMgr::DoCompleteAchievement(uint32 achievement, Player * player) +{ + AchievementEntry const* AE = GetAchievementStore()->LookupEntry(achievement); + + if(!player) + { + //Map::PlayerList const &PlayerList = this->GetPlayers(); + //GroupsQueueType::iterator group = SelectedGroups.begin(); + + //if (!PlayerList.isEmpty()) + //for (Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i) + // for (GroupsQueueType::iterator itr = group; itr != SelectedGroups.end(); ++itr) + // if (Player *pPlayer = itr->getSource()) + // pPlayer->CompletedAchievement(AE); + } + else + { + player->CompletedAchievement(AE); + } +} diff --git a/src/game/BattleGroundMgr.h b/src/game/BattleGroundMgr.h index 9100142ebd0..95b45640b69 100644 --- a/src/game/BattleGroundMgr.h +++ b/src/game/BattleGroundMgr.h @@ -250,6 +250,7 @@ class BattleGroundMgr static uint8 BGArenaType(BattleGroundQueueTypeId bgQueueTypeId); static bool IsBGWeekend(BattleGroundTypeId bgTypeId); + void DoCompleteAchievement(uint32 achievement, Player * player = NULL); private: BattleMastersMap mBattleMastersMap; diff --git a/src/game/BattleGroundNA.cpp b/src/game/BattleGroundNA.cpp index b08cdd1196e..da370de7136 100644 --- a/src/game/BattleGroundNA.cpp +++ b/src/game/BattleGroundNA.cpp @@ -79,7 +79,7 @@ void BattleGroundNA::AddPlayer(Player *plr) m_PlayerScores[plr->GetGUID()] = sc; - UpdateArenaUnitWorldState(); + UpdateArenaWorldState(); } void BattleGroundNA::RemovePlayer(Player* /*plr*/, uint64 /*guid*/) @@ -87,7 +87,7 @@ void BattleGroundNA::RemovePlayer(Player* /*plr*/, uint64 /*guid*/) if (GetStatus() == STATUS_WAIT_LEAVE) return; - UpdateArenaUnitWorldState(); + UpdateArenaWorldState(); CheckArenaWinConditions(); } @@ -104,7 +104,7 @@ void BattleGroundNA::HandleKillPlayer(Player *player, Player *killer) BattleGround::HandleKillPlayer(player,killer); - UpdateArenaUnitWorldState(); + UpdateArenaWorldState(); CheckArenaWinConditions(); } @@ -138,9 +138,8 @@ void BattleGroundNA::HandleAreaTrigger(Player *Source, uint32 Trigger) void BattleGroundNA::FillInitialWorldStates(WorldPacket &data) { - data << uint32(0xa11) << uint32(1); - - UpdateArenaUnitWorldState(); + data << uint32(0xa11) << uint32(1); // 9 + UpdateArenaWorldState(); } void BattleGroundNA::Reset() @@ -176,4 +175,3 @@ bool BattleGroundNA::SetupBattleGround() 0040: 00 00 00 00 00 00 d5 08 00 00 00 00 00 00 d3 08 | ................ 0050: 00 00 00 00 00 00 | ...... */ - diff --git a/src/game/BattleGroundNA.h b/src/game/BattleGroundNA.h index 56e2cf373c4..57654bc0c60 100644 --- a/src/game/BattleGroundNA.h +++ b/src/game/BattleGroundNA.h @@ -74,4 +74,3 @@ class BattleGroundNA : public BattleGround bool HandlePlayerUnderMap(Player * plr); }; #endif - diff --git a/src/game/BattleGroundRL.cpp b/src/game/BattleGroundRL.cpp index 8ed8fd1b5b7..4c072713162 100644 --- a/src/game/BattleGroundRL.cpp +++ b/src/game/BattleGroundRL.cpp @@ -79,7 +79,7 @@ void BattleGroundRL::AddPlayer(Player *plr) m_PlayerScores[plr->GetGUID()] = sc; - UpdateArenaUnitWorldState(); + UpdateArenaWorldState(); } void BattleGroundRL::RemovePlayer(Player* /*plr*/, uint64 /*guid*/) @@ -87,7 +87,7 @@ void BattleGroundRL::RemovePlayer(Player* /*plr*/, uint64 /*guid*/) if (GetStatus() == STATUS_WAIT_LEAVE) return; - UpdateArenaUnitWorldState(); + UpdateArenaWorldState(); CheckArenaWinConditions(); } @@ -104,7 +104,7 @@ void BattleGroundRL::HandleKillPlayer(Player *player, Player *killer) BattleGround::HandleKillPlayer(player,killer); - UpdateArenaUnitWorldState(); + UpdateArenaWorldState(); CheckArenaWinConditions(); } @@ -139,9 +139,8 @@ void BattleGroundRL::HandleAreaTrigger(Player *Source, uint32 Trigger) void BattleGroundRL::FillInitialWorldStates(WorldPacket &data) { - data << uint32(0xbba) << uint32(1); - - UpdateArenaUnitWorldState(); + data << uint32(0xbba) << uint32(1); // 9 + UpdateArenaWorldState(); } void BattleGroundRL::Reset() @@ -175,4 +174,3 @@ Packet S->C, id 600, SMSG_INIT_WORLD_STATES (706), len 86 0040: 00 00 00 00 00 00 D3 08 00 00 00 00 00 00 D4 08 | ................ 0050: 00 00 00 00 00 00 | ...... */ - diff --git a/src/game/BattleGroundRL.h b/src/game/BattleGroundRL.h index 772c9dd0879..137ae751bca 100644 --- a/src/game/BattleGroundRL.h +++ b/src/game/BattleGroundRL.h @@ -70,4 +70,3 @@ class BattleGroundRL : public BattleGround bool HandlePlayerUnderMap(Player * plr); }; #endif - diff --git a/src/game/BattleGroundRV.cpp b/src/game/BattleGroundRV.cpp index 16bdd54ade1..39ff09fe521 100644 --- a/src/game/BattleGroundRV.cpp +++ b/src/game/BattleGroundRV.cpp @@ -120,7 +120,8 @@ void BattleGroundRV::AddPlayer(Player *plr) m_PlayerScores[plr->GetGUID()] = sc; - UpdateArenaUnitWorldState(); + UpdateWorldState(BG_RV_WORLD_STATE_A, GetAlivePlayersCountByTeam(ALLIANCE)); + UpdateWorldState(BG_RV_WORLD_STATE_H, GetAlivePlayersCountByTeam(HORDE)); } void BattleGroundRV::RemovePlayer(Player * /*plr*/, uint64 /*guid*/) @@ -128,7 +129,9 @@ void BattleGroundRV::RemovePlayer(Player * /*plr*/, uint64 /*guid*/) if (GetStatus() == STATUS_WAIT_LEAVE) return; - UpdateArenaUnitWorldState(); + UpdateWorldState(BG_RV_WORLD_STATE_A, GetAlivePlayersCountByTeam(ALLIANCE)); + UpdateWorldState(BG_RV_WORLD_STATE_H, GetAlivePlayersCountByTeam(HORDE)); + CheckArenaWinConditions(); } @@ -145,7 +148,9 @@ void BattleGroundRV::HandleKillPlayer(Player *player, Player *killer) BattleGround::HandleKillPlayer(player, killer); - UpdateArenaUnitWorldState(); + UpdateWorldState(BG_RV_WORLD_STATE_A, GetAlivePlayersCountByTeam(ALLIANCE)); + UpdateWorldState(BG_RV_WORLD_STATE_H, GetAlivePlayersCountByTeam(HORDE)); + CheckArenaWinConditions(); } @@ -175,9 +180,9 @@ void BattleGroundRV::HandleAreaTrigger(Player *Source, uint32 Trigger) void BattleGroundRV::FillInitialWorldStates(WorldPacket &data) { + data << uint32(BG_RV_WORLD_STATE_A) << uint32(GetAlivePlayersCountByTeam(ALLIANCE)); + data << uint32(BG_RV_WORLD_STATE_H) << uint32(GetAlivePlayersCountByTeam(HORDE)); data << uint32(BG_RV_WORLD_STATE) << uint32(1); - - UpdateArenaUnitWorldState(); } void BattleGroundRV::Reset() diff --git a/src/game/BattleGroundRV.h b/src/game/BattleGroundRV.h index 4cc368901dd..c4309ae93cf 100644 --- a/src/game/BattleGroundRV.h +++ b/src/game/BattleGroundRV.h @@ -92,7 +92,9 @@ enum BattleGroundRVData BG_RV_FIRE_TO_PILAR_TIMER = 20000, BG_RV_PILAR_TO_FIRE_TIMER = 5000, BG_RV_FIRST_TIMER = 20133, - BG_RV_WORLD_STATE = 0xE1A, + BG_RV_WORLD_STATE_A = 0xe10, + BG_RV_WORLD_STATE_H = 0xe11, + BG_RV_WORLD_STATE = 0xe1a, }; class BattleGroundRVScore : public BattleGroundScore diff --git a/src/game/BattleGroundWS.cpp b/src/game/BattleGroundWS.cpp index 63dd2f48a0b..0071e2c615c 100644 --- a/src/game/BattleGroundWS.cpp +++ b/src/game/BattleGroundWS.cpp @@ -67,9 +67,32 @@ BattleGroundWS::~BattleGroundWS() void BattleGroundWS::Update(uint32 diff) { BattleGround::Update(diff); - + if (GetStatus() == STATUS_IN_PROGRESS) { + if( GetStartTime() >= 25*MINUTE*1000 ) // Òàéìåð òèêàòü íà÷èíàåò ïîñëå 25 ìèíóò + { + if( GetTeamScore(ALLIANCE) == 0 ) + { + if ( GetTeamScore(HORDE) == 0 ) // No one scored - result is tie + EndBattleGround(NULL); + + else // Horde has more points and thus wins + EndBattleGround(HORDE); + } + + else if( GetTeamScore(HORDE) == 0 ) + EndBattleGround(ALLIANCE); // Alliance has >0, Horde has 0, alliance wins + + else if( GetTeamScore(HORDE) == GetTeamScore(ALLIANCE) ) // Team score equal, winner is team that scored the first flag + EndBattleGround(m_FirstFlagCaptureTeam); + + else if( GetTeamScore(HORDE) > GetTeamScore(ALLIANCE) ) // Last but not least, check who has the higher score + EndBattleGround(HORDE); + else + EndBattleGround(ALLIANCE); + } + if (m_FlagState[BG_TEAM_ALLIANCE] == BG_WS_FLAG_STATE_WAIT_RESPAWN) { m_FlagsTimer[BG_TEAM_ALLIANCE] -= diff; @@ -225,7 +248,7 @@ void BattleGroundWS::RespawnFlagAfterDrop(uint32 team) PlaySoundToAll(BG_WS_SOUND_FLAGS_RESPAWNED); - GameObject *obj = HashMapHolder<GameObject>::Find(GetDroppedFlagGUID(team)); + GameObject *obj = GetBgMap()->GetGameObject(GetDroppedFlagGUID(team)); if (obj) obj->Delete(); else @@ -294,6 +317,9 @@ void BattleGroundWS::EventPlayerCapturedFlag(Player *Source) UpdateTeamScore(Source->GetTeam()); // only flag capture should be updated UpdatePlayerScore(Source, SCORE_FLAG_CAPTURES, 1); // +1 flag captures + + if(!m_FirstFlagCaptureTeam) + SetFirstFlagCapture(Source->GetTeam()); if (GetTeamScore(ALLIANCE) == BG_WS_MAX_TEAM_SCORE) winner = ALLIANCE; diff --git a/src/game/BattleGroundWS.h b/src/game/BattleGroundWS.h index 16631afecdc..1a98f0623c5 100644 --- a/src/game/BattleGroundWS.h +++ b/src/game/BattleGroundWS.h @@ -189,6 +189,7 @@ class BattleGroundWS : public BattleGround virtual WorldSafeLocsEntry const* GetClosestGraveYard(Player* player); void UpdateFlagState(uint32 team, uint32 value); + void SetFirstFlagCapture(uint32 team) { m_FirstFlagCaptureTeam = team; } void UpdateTeamScore(uint32 team); void UpdatePlayerScore(Player *Source, uint32 type, uint32 value); void SetDroppedFlagGUID(uint64 guid, uint32 TeamID) { m_DroppedFlagGUID[GetTeamIndexByTeamId(TeamID)] = guid;} @@ -206,7 +207,8 @@ class BattleGroundWS : public BattleGround uint8 m_FlagState[2]; // for checking flag state int32 m_FlagsTimer[2]; int32 m_FlagsDropTimer[2]; - + uint32 m_FirstFlagCaptureTeam; // Winner is based on this if score is equal + uint32 m_ReputationCapture; uint32 m_HonorWinKills; uint32 m_HonorEndKills; diff --git a/src/game/CMakeLists.txt b/src/game/CMakeLists.txt index 0131437b732..a4d656cf7f6 100644 --- a/src/game/CMakeLists.txt +++ b/src/game/CMakeLists.txt @@ -23,10 +23,12 @@ SET(game_STAT_SRCS BattleGround.cpp BattleGroundAA.cpp BattleGroundAB.cpp + BattleGroundABG.cpp BattleGroundAV.cpp BattleGroundBE.cpp BattleGroundDS.cpp BattleGroundEY.cpp + BattleGroundIC.cpp BattleGroundNA.cpp BattleGroundRL.cpp BattleGroundRV.cpp @@ -35,10 +37,12 @@ SET(game_STAT_SRCS BattleGround.h BattleGroundAA.h BattleGroundAB.h + BattleGroundABG.h BattleGroundAV.h BattleGroundBE.h BattleGroundDS.h BattleGroundEY.h + BattleGroundIC.h BattleGroundNA.h BattleGroundRL.h BattleGroundRV.h diff --git a/src/game/CalendarHandler.cpp b/src/game/CalendarHandler.cpp index 8d7bd63a9a9..5860f4acaec 100644 --- a/src/game/CalendarHandler.cpp +++ b/src/game/CalendarHandler.cpp @@ -45,7 +45,7 @@ void WorldSession::HandleCalendarGetCalendar(WorldPacket &recv_data) size_t p_counter = data.wpos(); data << uint32(counter); // instance save count - for (int i = 0; i < TOTAL_DIFFICULTIES; ++i) + for (int i = 0; i < MAX_DIFFICULTY; ++i) { for (Player::BoundInstancesMap::const_iterator itr = _player->m_boundInstances[i].begin(); itr != _player->m_boundInstances[i].end(); ++itr) { diff --git a/src/game/Channel.cpp b/src/game/Channel.cpp index 768b8865eb0..fe6af918a79 100644 --- a/src/game/Channel.cpp +++ b/src/game/Channel.cpp @@ -298,6 +298,7 @@ void Channel::KickOrBan(uint64 good, const char *badname, bool ban) banned.insert(bad->GetGUID()); MakePlayerBanned(&data, bad->GetGUID(), good); _UpdateBanListInDB(); + } else MakePlayerKicked(&data, bad->GetGUID(), good); @@ -351,6 +352,7 @@ void Channel::UnBan(uint64 good, const char *badname) WorldPacket data; MakePlayerUnbanned(&data, bad->GetGUID(), good); SendToAll(&data); + //save banlist _UpdateBanListInDB(); } } @@ -592,6 +594,7 @@ void Channel::Announce(uint64 p) SendToAll(&data); if (m_IsSaved && _UpdateIntInDB("m_announce", m_announce ? 1 : 0)) sLog.outDebug("Channel(%s) announce saved", m_name.c_str()); + } } @@ -624,8 +627,8 @@ void Channel::Moderate(uint64 p) else MakeModerationOff(&data, p); SendToAll(&data); - if (m_IsSaved && _UpdateIntInDB("m_moderate", m_moderate ? 1 : 0)) - sLog.outDebug("Channel(%s) moderate saved", m_name.c_str()); + if (m_IsSaved && _UpdateIntInDB("m_announce", m_announce ? 1 : 0)) + sLog.outDebug("Channel(%s) announce saved", m_name.c_str()); } } @@ -754,15 +757,8 @@ void Channel::SetOwner(uint64 guid, bool exclaim) MakeOwnerChanged(&data, m_ownerGUID); SendToAll(&data); } - /*if(m_IsSaved) - { - std::ostringstream ss; - ss << "UPDATE channels SET m_ownerGUID = '" << guid << "' WHERE m_name = '"<<m_name.c_str()<<"' AND m_team = '"<<m_Team<<"'"; - if(CharacterDatabase.PExecute( ss.str( ).c_str( ) )) - { - sLog.outDebug("Channel(%s) owner saved", m_name.c_str()); - } - }*/ + if (m_IsSaved && _UpdateIntInDB("m_moderate", m_moderate ? 1 : 0)) + sLog.outDebug("Channel(%s) moderate saved", m_name.c_str()); } } diff --git a/src/game/CharacterHandler.cpp b/src/game/CharacterHandler.cpp index ca2561f4771..3ef302c2f79 100644 --- a/src/game/CharacterHandler.cpp +++ b/src/game/CharacterHandler.cpp @@ -84,7 +84,7 @@ bool LoginQueryHolder::Initialize() res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADDECLINEDNAMES, "SELECT genitive, dative, accusative, instrumental, prepositional FROM character_declinedname WHERE guid = '%u'",GUID_LOPART(m_guid)); // in other case still be dummy query res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADGUILD, "SELECT guildid,rank FROM guild_member WHERE guid = '%u'", GUID_LOPART(m_guid)); - res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADARENAINFO, "SELECT arenateamid, played_week, played_season, personal_rating FROM arena_team_member WHERE guid='%u'", GUID_LOPART(m_guid)); + res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADARENAINFO, "SELECT arenateamid, played_week, played_season, wons_season, personal_rating FROM arena_team_member WHERE guid='%u'", GUID_LOPART(m_guid)); res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADACHIEVEMENTS, "SELECT achievement, date FROM character_achievement WHERE guid = '%u'", GUID_LOPART(m_guid)); res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADCRITERIAPROGRESS,"SELECT criteria, counter, date FROM character_achievement_progress WHERE guid = '%u'", GUID_LOPART(m_guid)); res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADEQUIPMENTSETS, "SELECT setguid, setindex, name, iconname, item0, item1, item2, item3, item4, item5, item6, item7, item8, item9, item10, item11, item12, item13, item14, item15, item16, item17, item18 FROM character_equipmentsets WHERE guid = '%u' ORDER BY setindex", GUID_LOPART(m_guid)); @@ -102,6 +102,7 @@ bool LoginQueryHolder::Initialize() // instead pass an account id to this handler class CharacterHandler { + public: void HandleCharEnumCallback(QueryResult * result, uint32 account) { @@ -229,19 +230,19 @@ void WorldSession::HandleCharCreateOpcode( WorldPacket & recv_data ) } // prevent character creating Expansion race without Expansion account - if (raceEntry->addon > Expansion()) + if (raceEntry->expansion > Expansion()) { data << (uint8)CHAR_CREATE_EXPANSION; - sLog.outError("Expansion %u account:[%d] tried to Create character with expansion %u race (%u)",Expansion(),GetAccountId(),raceEntry->addon,race_); + sLog.outError("Expansion %u account:[%d] tried to Create character with expansion %u race (%u)",Expansion(),GetAccountId(),raceEntry->expansion,race_); SendPacket( &data ); return; } // prevent character creating Expansion class without Expansion account - if (classEntry->addon > Expansion()) + if (classEntry->expansion > Expansion()) { data << (uint8)CHAR_CREATE_EXPANSION_CLASS; - sLog.outError("Expansion %u account:[%d] tried to Create character with expansion %u class (%u)",Expansion(),GetAccountId(),classEntry->addon,class_); + sLog.outError("Expansion %u account:[%d] tried to Create character with expansion %u class (%u)",Expansion(),GetAccountId(),classEntry->expansion,class_); SendPacket( &data ); return; } @@ -437,13 +438,8 @@ void WorldSession::HandleCharCreateOpcode( WorldPacket & recv_data ) // extract other data required for player creating uint8 gender, skin, face, hairStyle, hairColor, facialHair, outfitId; - recv_data >> gender; - recv_data >> skin; - recv_data >> face; - recv_data >> hairStyle; - recv_data >> hairColor; - recv_data >> facialHair; - recv_data >> outfitId; + recv_data >> gender >> skin >> face; + recv_data >> hairStyle >> hairColor >> facialHair >> outfitId; if(recv_data.rpos() < recv_data.wpos()) { @@ -604,7 +600,7 @@ void WorldSession::HandlePlayerLogin(LoginQueryHolder * holder) // load player specific part before send times LoadAccountData(holder->GetResult(PLAYER_LOGIN_QUERY_LOADACCOUNTDATA),PER_CHARACTER_CACHE_MASK); - SendAccountDataTimes(); + SendAccountDataTimes(PER_CHARACTER_CACHE_MASK); data.Initialize(SMSG_FEATURE_SYSTEM_STATUS, 2); // added in 2.2.0 data << uint8(2); // unknown value @@ -649,11 +645,6 @@ void WorldSession::HandlePlayerLogin(LoginQueryHolder * holder) DEBUG_LOG( "WORLD: Sent server info" ); } - data.Initialize(SMSG_LEARNED_DANCE_MOVES, 4+4); - data << uint32(0); - data << uint32(0); - SendPacket(&data); - //QueryResult *result = CharacterDatabase.PQuery("SELECT guildid,rank FROM guild_member WHERE guid = '%u'",pCurrChar->GetGUIDLow()); QueryResult *resultGuild = holder->GetResult(PLAYER_LOGIN_QUERY_LOADGUILD); @@ -701,6 +692,11 @@ void WorldSession::HandlePlayerLogin(LoginQueryHolder * holder) } } + data.Initialize(SMSG_LEARNED_DANCE_MOVES, 4+4); + data << uint32(0); + data << uint32(0); + SendPacket(&data); + if(!pCurrChar->isAlive()) pCurrChar->SendCorpseReclaimDelay(true); @@ -1102,8 +1098,8 @@ void WorldSession::HandleAlterAppearance( WorldPacket & recv_data ) { sLog.outDebug("CMSG_ALTER_APPEARANCE"); - uint32 Hair, Color, FacialHair; - recv_data >> Hair >> Color >> FacialHair; + uint32 Hair, Color, FacialHair, SkinColor; + recv_data >> Hair >> Color >> FacialHair >> SkinColor; BarberShopStyleEntry const* bs_hair = sBarberShopStyleStore.LookupEntry(Hair); @@ -1115,7 +1111,12 @@ void WorldSession::HandleAlterAppearance( WorldPacket & recv_data ) if(!bs_facialHair || bs_facialHair->type != 2 || bs_facialHair->race != _player->getRace() || bs_facialHair->gender != _player->getGender()) return; - uint32 Cost = _player->GetBarberShopCost(bs_hair->hair_id, Color, bs_facialHair->hair_id); + BarberShopStyleEntry const* bs_skinColor = sBarberShopStyleStore.LookupEntry(SkinColor); + + if( bs_skinColor && (bs_skinColor->type != 3 || bs_skinColor->race != _player->getRace() || bs_skinColor->gender != _player->getGender())) + return; + + uint32 Cost = _player->GetBarberShopCost(bs_hair->hair_id, Color, bs_facialHair->hair_id, bs_skinColor); // 0 - ok // 1,3 - not enough money @@ -1140,6 +1141,8 @@ void WorldSession::HandleAlterAppearance( WorldPacket & recv_data ) _player->SetByteValue(PLAYER_BYTES, 2, uint8(bs_hair->hair_id)); _player->SetByteValue(PLAYER_BYTES, 3, uint8(Color)); _player->SetByteValue(PLAYER_BYTES_2, 0, uint8(bs_facialHair->hair_id)); + if (bs_skinColor) + _player->SetByteValue(PLAYER_BYTES, 0, uint8(bs_skinColor->hair_id)); _player->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_VISIT_BARBER_SHOP, 1); diff --git a/src/game/Chat.cpp b/src/game/Chat.cpp index 80f75ccffa6..a96086bdba0 100644 --- a/src/game/Chat.cpp +++ b/src/game/Chat.cpp @@ -165,11 +165,12 @@ ChatCommand * ChatHandler::getCommandTable() { "getitemstate", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugGetItemStateCommand, "", NULL }, { "lootrecipient", SEC_GAMEMASTER, false, &ChatHandler::HandleDebugGetLootRecipientCommand, "", NULL }, { "getvalue", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugGetValueCommand, "", NULL }, + { "getitemvalue", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugGetItemValueCommand, "", NULL }, { "Mod32Value", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugMod32ValueCommand, "", NULL }, { "play", SEC_MODERATOR, false, NULL, "", debugPlayCommandTable }, { "send", SEC_ADMINISTRATOR, false, NULL, "", debugSendCommandTable }, { "setaurastate", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugSetAuraStateCommand, "", NULL }, - { "setitemflag", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugSetItemFlagCommand, "", NULL }, + { "setitemvalue", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugSetItemValueCommand, "", NULL }, { "setvalue", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugSetValueCommand, "", NULL }, { "spawnvehicle", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugSpawnVehicle, "", NULL }, { "setvid", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugSetVehicleId, "", NULL }, @@ -1164,6 +1165,8 @@ valid examples: Quest const* linkedQuest; SpellEntry const *linkedSpell; AchievementEntry const* linkedAchievement; + ItemRandomPropertiesEntry const* itemProperty; + ItemRandomSuffixEntry const* itemSuffix; while(!reader.eof()) { @@ -1173,6 +1176,8 @@ valid examples: linkedQuest = NULL; linkedSpell = NULL; linkedAchievement = NULL; + itemProperty = NULL; + itemSuffix = NULL; reader.ignore(255, '|'); } @@ -1289,9 +1294,47 @@ valid examples: return false; } - char c = reader.peek(); + // the itementry is followed by several integers which describe an instance of this item + + // position relative after itemEntry + const uint8 randomPropertyPosition = 6; - // ignore enchants etc. + int32 propertyId = 0; + bool negativeNumber = false; + char c; + for(uint8 i=0; i<randomPropertyPosition; ++i) + { + propertyId = 0; + negativeNumber = false; + while((c = reader.get())!=':') + { + if(c >='0' && c<='9') + { + propertyId*=10; + propertyId += c-'0'; + } else if(c == '-') + negativeNumber = true; + else + return false; + } + } + if (negativeNumber) + propertyId *= -1; + + if (propertyId > 0) + { + itemProperty = sItemRandomPropertiesStore.LookupEntry(propertyId); + if (!itemProperty) + return false; + } + else if(propertyId < 0) + { + itemSuffix = sItemRandomSuffixStore.LookupEntry(-propertyId); + if (!itemSuffix) + return false; + } + + // ignore other integers while((c >='0' && c <='9') || c==':') { reader.ignore(1); @@ -1560,22 +1603,34 @@ valid examples: } else if (linkedItem) { - if (strcmp(linkedItem->Name1, buffer) != 0) + char* const* suffix = itemSuffix?itemSuffix->nameSuffix:(itemProperty?itemProperty->nameSuffix:NULL); + + std::string expectedName = std::string(linkedItem->Name1); + if (suffix) { - ItemLocale const *il = objmgr.GetItemLocale(linkedItem->ItemId); + expectedName += " "; + expectedName += suffix[LOCALE_enUS]; + } - if (!il) - { -#ifdef MANGOS_DEBUG - sLog.outBasic("ChatHandler::isValidChatMessage linked item name doesn't is wrong and there is no localization"); -#endif - return false; - } + if (expectedName != buffer) + { + ItemLocale const *il = objmgr.GetItemLocale(linkedItem->ItemId); bool foundName = false; - for (uint8 i=0; i<il->Name.size(); ++i) + for(uint8 i=LOCALE_koKR; i<MAX_LOCALE; ++i) { - if (il->Name[i] == buffer) + int8 dbIndex = objmgr.GetIndexForLocale(LocaleConstant(i)); + if (dbIndex == -1 || il == NULL || dbIndex >= il->Name.size()) + // using strange database/client combinations can lead to this case + expectedName = linkedItem->Name1; + else + expectedName = il->Name[dbIndex]; + if (suffix) + { + expectedName += " "; + expectedName += suffix[i]; + } + if ( expectedName == buffer) { foundName = true; break; diff --git a/src/game/Chat.h b/src/game/Chat.h index d0d9a6112fc..c799252f4b0 100644 --- a/src/game/Chat.h +++ b/src/game/Chat.h @@ -144,9 +144,10 @@ class TRINITY_DLL_SPEC ChatHandler bool HandleDebugGetItemStateCommand(const char * args); bool HandleDebugGetLootRecipientCommand(const char * args); bool HandleDebugGetValueCommand(const char* args); + bool HandleDebugGetItemValueCommand(const char* args); bool HandleDebugMod32ValueCommand(const char* args); bool HandleDebugSetAuraStateCommand(const char * args); - bool HandleDebugSetItemFlagCommand(const char * args); + bool HandleDebugSetItemValueCommand(const char * args); bool HandleDebugItemExpireCommand(const char * args); bool HandleDebugSetVehicleId(const char * args); bool HandleDebugEnterVehicle(const char * args); diff --git a/src/game/Creature.cpp b/src/game/Creature.cpp index 03068041f23..72a4449d5a5 100644 --- a/src/game/Creature.cpp +++ b/src/game/Creature.cpp @@ -261,19 +261,24 @@ bool Creature::InitEntry(uint32 Entry, uint32 team, const CreatureData *data ) return false; } - // get heroic mode entry + // get difficulty 1 mode entry uint32 actualEntry = Entry; CreatureInfo const *cinfo = normalInfo; - if(normalInfo->HeroicEntry) + // TODO correctly implement spawnmodes for non-bg maps + for (uint32 diff = 0; diff < MAX_DIFFICULTY - 1; ++diff) { - //we already have valid Map pointer for current creature! - if(GetMap()->IsHeroic()) + if (normalInfo->DifficultyEntry[diff]) { - cinfo = objmgr.GetCreatureTemplate(normalInfo->HeroicEntry); - if(!cinfo) + // we already have valid Map pointer for current creature! + if (GetMap()->GetSpawnMode() > diff) { - sLog.outErrorDb("Creature::UpdateEntry creature heroic entry %u does not exist.", actualEntry); - return false; + cinfo = objmgr.GetCreatureTemplate(normalInfo->DifficultyEntry[diff]); + if (!cinfo) + { + // maybe check such things already at startup + sLog.outErrorDb("Creature::UpdateEntry creature difficulty %u entry %u does not exist.", diff + 1, actualEntry); + return false; + } } } } @@ -1565,7 +1570,7 @@ bool Creature::LoadFromDB(uint32 guid, Map *map) m_deathState = DEAD; if(canFly()) { - float tz = GetMap()->GetHeight(data->posX,data->posY,data->posZ,false); + float tz = map->GetHeight(data->posX,data->posY,data->posZ,false); if(data->posZ - tz > 0.1) Relocate(data->posX,data->posY,tz); } @@ -1899,7 +1904,7 @@ void Creature::Respawn(bool force) uint16 poolid = poolhandler.IsPartOfAPool(GetGUIDLow(), GetTypeId()); if (poolid) - poolhandler.UpdatePool(poolid, GetGUIDLow(), GetTypeId()); + poolhandler.UpdatePool(poolid, GetGUIDLow(), TYPEID_UNIT); } SetToNotify(); @@ -2265,7 +2270,7 @@ CreatureDataAddon const* Creature::GetCreatureAddon() const return addon; } - // dependent from heroic mode entry + // dependent from difficulty mode entry return ObjectMgr::GetCreatureTemplateAddon(GetCreatureInfo()->Entry); } @@ -2671,4 +2676,3 @@ time_t Creature::GetLinkedCreatureRespawnTime() const return 0; } - diff --git a/src/game/Creature.h b/src/game/Creature.h index ab9915c0bda..d1c08bb13e2 100644 --- a/src/game/Creature.h +++ b/src/game/Creature.h @@ -167,7 +167,7 @@ enum CreatureFlagsExtra struct CreatureInfo { uint32 Entry; - uint32 HeroicEntry; + uint32 DifficultyEntry[MAX_DIFFICULTY - 1]; uint32 KillCredit[MAX_KILL_CREDIT]; uint32 Modelid1; uint32 Modelid2; @@ -783,7 +783,7 @@ class TRINITY_DLL_SPEC Creature : public Unit bool DisableReputationGain; - CreatureInfo const* m_creatureInfo; // in heroic mode can different from ObjMgr::GetCreatureTemplate(GetEntry()) + CreatureInfo const* m_creatureInfo; // in difficulty mode > 0 can different from ObjMgr::GetCreatureTemplate(GetEntry()) CreatureData const* m_creatureData; uint16 m_LootMode; // bitmask, default DEFAULT_LOOT_MODE, determines what loot will be lootable @@ -814,4 +814,3 @@ class AssistDelayEvent : public BasicEvent }; #endif - diff --git a/src/game/CreatureEventAI.cpp b/src/game/CreatureEventAI.cpp index f50f7e4128b..07de3fa0efc 100644 --- a/src/game/CreatureEventAI.cpp +++ b/src/game/CreatureEventAI.cpp @@ -71,10 +71,9 @@ CreatureEventAI::CreatureEventAI(Creature *c ) : CreatureAI(c) if ((*i).event_flags & EFLAG_DEBUG_ONLY) continue; #endif - if(((*i).event_flags & (EFLAG_HEROIC | EFLAG_NORMAL)) && m_creature->GetMap()->IsDungeon() ) + if(m_creature->GetMap()->IsDungeon()) { - if( (m_creature->GetMap()->IsHeroic() && (*i).event_flags & EFLAG_HEROIC) || - (!m_creature->GetMap()->IsHeroic() && (*i).event_flags & EFLAG_NORMAL)) + if ((1 << (m_creature->GetMap()->GetSpawnMode()+1)) & (*i).event_flags) { //event flagged for instance mode CreatureEventAIList.push_back(CreatureEventAIHolder(*i)); diff --git a/src/game/CreatureEventAI.h b/src/game/CreatureEventAI.h index 55ae1e20bf3..e51b74a9602 100644 --- a/src/game/CreatureEventAI.h +++ b/src/game/CreatureEventAI.h @@ -160,13 +160,15 @@ enum CastFlags enum EventFlags { EFLAG_REPEATABLE = 0x01, //Event repeats - EFLAG_NORMAL = 0x02, //Event only occurs in Normal instance difficulty - EFLAG_HEROIC = 0x04, //Event only occurs in Heroic instance difficulty - EFLAG_RESERVED_3 = 0x08, - EFLAG_RESERVED_4 = 0x10, + EFLAG_DIFFICULTY_0 = 0x02, //Event only occurs in instance difficulty 0 + EFLAG_DIFFICULTY_1 = 0x04, //Event only occurs in instance difficulty 1 + EFLAG_DIFFICULTY_2 = 0x08, //Event only occurs in instance difficulty 2 + EFLAG_DIFFICULTY_3 = 0x10, //Event only occurs in instance difficulty 3 EFLAG_RESERVED_5 = 0x20, EFLAG_RESERVED_6 = 0x40, EFLAG_DEBUG_ONLY = 0x80, //Event only occurs in debug build + + EFLAG_DIFFICULTY_ALL = (EFLAG_DIFFICULTY_0|EFLAG_DIFFICULTY_1|EFLAG_DIFFICULTY_2|EFLAG_DIFFICULTY_3) }; enum SpawnedEventMode diff --git a/src/game/CreatureEventAIMgr.cpp b/src/game/CreatureEventAIMgr.cpp index 462a284a17d..2d4c92ad7bf 100644 --- a/src/game/CreatureEventAIMgr.cpp +++ b/src/game/CreatureEventAIMgr.cpp @@ -640,14 +640,14 @@ void CreatureEventAIMgr::LoadCreatureEventAI_Scripts() sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses incorrect Target type", i, j+1); break; case ACTION_T_SET_INST_DATA: - if (!(temp.event_flags & EFLAG_NORMAL) && !(temp.event_flags & EFLAG_HEROIC)) - sLog.outErrorDb("CreatureEventAI: Event %u Action %u. Cannot set instance data without event flags (normal/heroic).", i, j+1); + if (!(temp.event_flags & EFLAG_DIFFICULTY_ALL)) + sLog.outErrorDb("CreatureEventAI: Event %u Action %u. Cannot set instance data without difficulty event flags.", i, j+1); if (action.set_inst_data.value > 4/*SPECIAL*/) sLog.outErrorDb("CreatureEventAI: Event %u Action %u attempts to set instance data above encounter state 4. Custom case?", i, j+1); break; case ACTION_T_SET_INST_DATA64: - if (!(temp.event_flags & EFLAG_NORMAL) && !(temp.event_flags & EFLAG_HEROIC)) - sLog.outErrorDb("CreatureEventAI: Event %u Action %u. Cannot set instance data without event flags (normal/heroic).", i, j+1); + if (!(temp.event_flags & EFLAG_DIFFICULTY_ALL)) + sLog.outErrorDb("CreatureEventAI: Event %u Action %u. Cannot set instance data without difficulty event flags.", i, j+1); if (action.set_inst_data64.target >= TARGET_T_END) sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses incorrect Target type", i, j+1); break; diff --git a/src/game/DBCEnums.h b/src/game/DBCEnums.h index a0e030bf7cb..97cc6f4798c 100644 --- a/src/game/DBCEnums.h +++ b/src/game/DBCEnums.h @@ -232,6 +232,42 @@ enum AreaFlags AREA_FLAG_OUTDOOR_PVP2 = 0x08000000 // Wintergrasp and it's subzones }; +enum Difficulty +{ + REGULAR_DIFFICULTY = 0, + + DUNGEON_DIFFICULTY_NORMAL = 0, + DUNGEON_DIFFICULTY_HEROIC = 1, + + RAID_DIFFICULTY_10MAN_NORMAL = 0, + RAID_DIFFICULTY_25MAN_NORMAL = 1, + RAID_DIFFICULTY_10MAN_HEROIC = 2, + RAID_DIFFICULTY_25MAN_HEROIC = 3, +}; + +#define MAX_DUNGEON_DIFFICULTY 2 +#define MAX_RAID_DIFFICULTY 4 +#define MAX_DIFFICULTY 4 + +enum SpawnMask +{ + SPAWNMASK_CONTINENT = (1 << REGULAR_DIFFICULTY),// any any maps without spawn modes + + SPAWNMASK_DUNGEON_NORMAL = (1 << DUNGEON_DIFFICULTY_NORMAL), + SPAWNMASK_DUNGEON_HEROIC = (1 << DUNGEON_DIFFICULTY_HEROIC), + SPAWNMASK_DUNGEON_ALL = (SPAWNMASK_DUNGEON_NORMAL | SPAWNMASK_DUNGEON_HEROIC), + + SPAWNMASK_RAID_10MAN_NORMAL = (1 << RAID_DIFFICULTY_10MAN_NORMAL), + SPAWNMASK_RAID_25MAN_NORMAL = (1 << RAID_DIFFICULTY_25MAN_NORMAL), + SPAWNMASK_RAID_NORMAL_ALL = (SPAWNMASK_RAID_10MAN_NORMAL | SPAWNMASK_RAID_25MAN_NORMAL), + + SPAWNMASK_RAID_10MAN_HEROIC = (1 << RAID_DIFFICULTY_10MAN_HEROIC), + SPAWNMASK_RAID_25MAN_HEROIC = (1 << RAID_DIFFICULTY_25MAN_HEROIC), + SPAWNMASK_RAID_HEROIC_ALL = (SPAWNMASK_RAID_10MAN_HEROIC | SPAWNMASK_RAID_25MAN_HEROIC), + + SPAWNMASK_RAID_ALL = (SPAWNMASK_RAID_NORMAL_ALL | SPAWNMASK_RAID_HEROIC_ALL), +}; + enum FactionTemplateFlags { FACTION_TEMPLATE_FLAG_CONTESTED_GUARD = 0x00001000, // faction will attack players that were involved in PvP combats @@ -333,4 +369,3 @@ enum SummonPropFlags }; #endif - diff --git a/src/game/DBCStores.cpp b/src/game/DBCStores.cpp index ba89cb69215..c9832a830eb 100644 --- a/src/game/DBCStores.cpp +++ b/src/game/DBCStores.cpp @@ -100,6 +100,11 @@ DBCStorage <LockEntry> sLockStore(LockEntryfmt); DBCStorage <MailTemplateEntry> sMailTemplateStore(MailTemplateEntryfmt); DBCStorage <MapEntry> sMapStore(MapEntryfmt); + +// DBC used only for initialization sMapDifficultyMap at startup. +DBCStorage <MapDifficultyEntry> sMapDifficultyStore(MapDifficultyEntryfmt); // only for loading +MapDifficultyMap sMapDifficultyMap; + DBCStorage <MovieEntry> sMovieStore(MovieEntryfmt); DBCStorage <QuestSortEntry> sQuestSortStore(QuestSortEntryfmt); @@ -133,7 +138,7 @@ TalentSpellPosMap sTalentSpellPosMap; DBCStorage <TalentTabEntry> sTalentTabStore(TalentTabEntryfmt); // store absolute bit position for first rank for talent inspect -static uint32 sTalentTabPages[12/*MAX_CLASSES*/][3]; +static uint32 sTalentTabPages[MAX_CLASSES][3]; DBCStorage <TaxiNodesEntry> sTaxiNodesStore(TaxiNodesEntryfmt); TaxiMask sTaxiNodesMask; @@ -143,10 +148,10 @@ TaxiMask sOldContinentsNodesMask; TaxiPathSetBySource sTaxiPathSetBySource; DBCStorage <TaxiPathEntry> sTaxiPathStore(TaxiPathEntryfmt); -// DBC used only for initialization sTaxiPathSetBySource at startup. +// DBC used only for initialization sTaxiPathNodeStore at startup. TaxiPathNodesByPath sTaxiPathNodesByPath; - static DBCStorage <TaxiPathNodeEntry> sTaxiPathNodeStore(TaxiPathNodeEntryfmt); + DBCStorage <TotemCategoryEntry> sTotemCategoryStore(TotemCategoryEntryfmt); DBCStorage <VehicleEntry> sVehicleStore(VehicleEntryfmt); DBCStorage <VehicleSeatEntry> sVehicleSeatStore(VehicleSeatEntryfmt); @@ -210,7 +215,7 @@ void LoadDBCStores(const std::string& dataPath) { std::string dbcPath = dataPath+"dbc/"; - const uint32 DBCFilesCount = 79; + const uint32 DBCFilesCount = 80; barGoLink bar( DBCFilesCount ); @@ -243,7 +248,6 @@ void LoadDBCStores(const std::string& dataPath) LoadDBC(availableDbcLocales,bar,bad_dbc_files,sBattlemasterListStore, dbcPath,"BattlemasterList.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sBarberShopStyleStore, dbcPath,"BarberShopStyle.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sCharStartOutfitStore, dbcPath,"CharStartOutfit.dbc"); - LoadDBC(availableDbcLocales,bar,bad_dbc_files,sCharTitlesStore, dbcPath,"CharTitles.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sChatChannelsStore, dbcPath,"ChatChannels.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sChrClassesStore, dbcPath,"ChrClasses.dbc"); @@ -314,6 +318,14 @@ void LoadDBCStores(const std::string& dataPath) LoadDBC(availableDbcLocales,bar,bad_dbc_files,sLockStore, dbcPath,"Lock.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sMailTemplateStore, dbcPath,"MailTemplate.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sMapStore, dbcPath,"Map.dbc"); + + LoadDBC(availableDbcLocales,bar,bad_dbc_files,sMapDifficultyStore, dbcPath,"MapDifficulty.dbc"); + // fill data + for(uint32 i = 1; i < sMapDifficultyStore.GetNumRows(); ++i) + if(MapDifficultyEntry const* entry = sMapDifficultyStore.LookupEntry(i)) + sMapDifficultyMap[MAKE_PAIR32(entry->MapId,entry->Difficulty)] = MapDifficulty(entry->resetTime,entry->maxPlayers); + sMapDifficultyStore.Clear(); + LoadDBC(availableDbcLocales,bar,bad_dbc_files,sMovieStore, dbcPath,"Movie.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sQuestSortStore, dbcPath,"QuestSort.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sRandomPropertiesPointsStore, dbcPath,"RandPropPoints.dbc"); @@ -322,7 +334,7 @@ void LoadDBCStores(const std::string& dataPath) LoadDBC(availableDbcLocales,bar,bad_dbc_files,sSkillLineStore, dbcPath,"SkillLine.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sSkillLineAbilityStore, dbcPath,"SkillLineAbility.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sSoundEntriesStore, dbcPath,"SoundEntries.dbc"); - LoadDBC(availableDbcLocales,bar,bad_dbc_files,sSpellStore, dbcPath,"Spell.dbc", &CustomSpellEntryfmt, &CustomSpellEntryIndex); + LoadDBC(availableDbcLocales,bar,bad_dbc_files,sSpellStore, dbcPath,"Spell.dbc", &CustomSpellEntryfmt, &CustomSpellEntryIndex); for (uint32 i = 1; i < sSpellStore.GetNumRows(); ++i) { SpellEntry const * spell = sSpellStore.LookupEntry(i); @@ -506,18 +518,17 @@ void LoadDBCStores(const std::string& dataPath) } // Check loaded DBC files proper version - if( !sSpellStore.LookupEntry(66530) || // last added spell in 3.1.3 - !sMapStore.LookupEntry(624) || // last map added in 3.1.3 - !sGemPropertiesStore.LookupEntry(1609) || // last gem property added in 3.1.3 - !sItemExtendedCostStore.LookupEntry(2671) || // last item extended cost added in 3.1.3 - !sCharTitlesStore.LookupEntry(166) || // last char title added in 3.1.3 - !sAreaStore.LookupEntry(2905) || // last area (areaflag) added in 3.1.3 - !sItemStore.LookupEntry(46894) ) // last client known item added in 3.1.3 + if( !sSpellStore.LookupEntry(69599) || // last added spell in 3.2.2 + !sMapStore.LookupEntry(650) || // last map added in 3.2.2 + !sGemPropertiesStore.LookupEntry(1629) || // last gem property added in 3.2.2 + !sItemExtendedCostStore.LookupEntry(2723) || // last item extended cost added in 3.2.2 + !sCharTitlesStore.LookupEntry(171) || // last char title added in 3.2.2 + !sAreaStore.LookupEntry(3091) || // last area (areaflag) added in 3.2.2 + !sItemStore.LookupEntry(49667) ) // last client known item added in 3.2.2 { sLog.outError("\nYou have _outdated_ DBC files. Please extract correct versions from current using client."); exit(1); } - sLog.outString(); sLog.outString( ">> Initialized %d data stores", DBCFilesCount ); } @@ -695,6 +706,12 @@ void Map2ZoneCoordinates(float& x,float& y,uint32 zone) std::swap(x,y); // client have map coords swapped } +MapDifficulty const* GetMapDifficultyData(uint32 mapId, Difficulty difficulty) +{ + MapDifficultyMap::const_iterator itr = sMapDifficultyMap.find(MAKE_PAIR32(mapId,difficulty)); + return itr != sMapDifficultyMap.end() ? &itr->second : NULL; +} + uint32 const* GetTalentTabPages(uint8 cls) { return sTalentTabPages[cls]; diff --git a/src/game/DBCStores.h b/src/game/DBCStores.h index 20de8f997d9..dbe94d941db 100644 --- a/src/game/DBCStores.h +++ b/src/game/DBCStores.h @@ -54,6 +54,9 @@ bool IsTotemCategoryCompatiableWith(uint32 itemTotemCategoryId, uint32 requiredT void Zone2MapCoordinates(float &x, float &y, uint32 zone); void Map2ZoneCoordinates(float &x, float &y, uint32 zone); +typedef std::map<uint32/*pair32(map,diff)*/,MapDifficulty> MapDifficultyMap; +MapDifficulty const* GetMapDifficultyData(uint32 mapId, Difficulty difficulty); + uint32 const* /*[3]*/ GetTalentTabPages(uint8 cls); extern DBCStorage <AchievementEntry> sAchievementStore; @@ -110,6 +113,8 @@ extern DBCStorage <ItemSetEntry> sItemSetStore; extern DBCStorage <LockEntry> sLockStore; extern DBCStorage <MailTemplateEntry> sMailTemplateStore; extern DBCStorage <MapEntry> sMapStore; +//extern DBCStorage <MapDifficultyEntry> sMapDifficultyStore; -- use GetMapDifficultyData insteed +extern MapDifficultyMap sMapDifficultyMap; extern DBCStorage <MovieEntry> sMovieStore; extern DBCStorage <QuestSortEntry> sQuestSortStore; extern DBCStorage <RandomPropertiesPointsEntry> sRandomPropertiesPointsStore; diff --git a/src/game/DBCStructure.h b/src/game/DBCStructure.h index a139c4efa51..71fedfe242a 100644 --- a/src/game/DBCStructure.h +++ b/src/game/DBCStructure.h @@ -658,7 +658,7 @@ struct ChrClassesEntry uint32 spellfamily; // 56 // 57, unused uint32 CinematicSequence; // 58 id from CinematicSequences.dbc - uint32 addon; // 59 (0 - original race, 1 - tbc addon, ...) + uint32 expansion; // 59 (0 - original race, 1 - tbc addon, ...) }; struct ChrRacesEntry @@ -669,10 +669,11 @@ struct ChrRacesEntry // 3 unused uint32 model_m; // 4 uint32 model_f; // 5 - // 6-7 unused - uint32 TeamID; // 8 (7-Alliance 1-Horde) - // 9-12 unused - uint32 CinematicSequence; // 13 id from CinematicSequences.dbc + // 6 unused + uint32 TeamID; // 7 (7-Alliance 1-Horde) + // 8-11 unused + uint32 CinematicSequence; // 12 id from CinematicSequences.dbc + //uint32 unk_322; // 13 faction (0 alliance, 1 horde, 2 not available?) char* name[16]; // 14-29 used for DBC language detection/selection // 30 string flags, unused //char* nameFemale[16]; // 31-46, if different from base (male) case @@ -680,7 +681,7 @@ struct ChrRacesEntry //char* nameNeutralGender[16]; // 48-63, if different from base (male) case // 64 string flags, unused // 65-67 unused - uint32 addon; // 68 (0 - original race, 1 - tbc addon, ...) + uint32 expansion; // 68 (0 - original race, 1 - tbc addon, ...) }; /* not used @@ -1043,9 +1044,10 @@ struct ItemExtendedCostEntry uint32 ID; // 0 extended-cost entry id uint32 reqhonorpoints; // 1 required honor points uint32 reqarenapoints; // 2 required arena points - uint32 reqitem[5]; // 3-7 required item id - uint32 reqitemcount[5]; // 8-12 required count of 1st item - uint32 reqpersonalarenarating; // 13 required personal arena rating + //uint32 unk1; // 4 probably indicates new 2v2 bracket restrictions + uint32 reqitem[5]; // 5-8 required item id + uint32 reqitemcount[5]; // 9-13 required count of 1st item + uint32 reqpersonalarenarating; // 14 required personal arena rating}; }; struct ItemLimitCategoryEntry @@ -1062,14 +1064,14 @@ struct ItemRandomPropertiesEntry uint32 ID; // 0 m_ID //char* internalName // 1 m_Name uint32 enchant_id[5]; // 2-6 m_Enchantment - //char* nameSuffix[16] // 7-22 m_name_lang + char* nameSuffix[16]; // 7-22 m_name_lang // 23 name flags }; struct ItemRandomSuffixEntry { uint32 ID; // 0 m_ID - //char* name[16] // 1-16 m_name_lang + char* nameSuffix[16]; // 1-16 m_name_lang // 17, name flags // 18 m_internalName uint32 enchant_id[5]; // 19-21 m_enchantment @@ -1104,7 +1106,7 @@ struct MailTemplateEntry uint32 ID; // 0 //char* subject[16]; // 1-16 // 17 name flags, unused - char* content[16]; // 18-33 + char* content[16]; // 18-33 }; struct MapEntry @@ -1122,21 +1124,13 @@ struct MapEntry // 55 intro text flags uint32 multimap_id; // 56 // 57 - //chat* unknownText1[16]; // 58-73 unknown empty text fields, possible normal Intro text. - // 74 text flags - //chat* heroicIntroText[16]; // 75-90 heroic mode requirement text - // 91 text flags - //chat* unknownText2[16]; // 92-107 unknown empty text fields - // 108 text flags - int32 entrance_map; // 109 map_id of entrance map - float entrance_x; // 110 entrance x coordinate (if exist single entry) - float entrance_y; // 111 entrance y coordinate (if exist single entry) - uint32 resetTimeRaid; // 112 - uint32 resetTimeHeroic; // 113 - // 114 all 0 - // 115 -1, 0 and 720 - uint32 addon; // 116 (0-original maps,1-tbc addon) - // 117 some kind of time? + int32 entrance_map; // 58 map_id of entrance map + float entrance_x; // 59 entrance x coordinate (if exist single entry) + float entrance_y; // 60 entrance y coordinate (if exist single entry) + // 61 -1, 0 and 720 + uint32 addon; // 62 (0-original maps,1-tbc addon) + // 63 some kind of time? + //uint32 maxPlayers; // 64 max players // Helpers uint32 Expansion() const { return addon; } @@ -1148,8 +1142,6 @@ struct MapEntry bool IsBattleGround() const { return map_type == MAP_BATTLEGROUND; } bool IsBattleArena() const { return map_type == MAP_ARENA; } bool IsBattleGroundOrArena() const { return map_type == MAP_BATTLEGROUND || map_type == MAP_ARENA; } - bool SupportsHeroicMode() const { return resetTimeHeroic != 0; } - bool HasResetTime() const { return resetTimeHeroic || resetTimeRaid; } bool IsMountAllowed() const { @@ -1157,7 +1149,7 @@ struct MapEntry MapID==209 || MapID==269 || MapID==309 || // TanarisInstance, CavernsOfTime, Zul'gurub MapID==509 || MapID==534 || MapID==560 || // AhnQiraj, HyjalPast, HillsbradPast MapID==568 || MapID==580 || MapID==615 || // ZulAman, Sunwell Plateau, Obsidian Sanctrum - MapID==616; // Eye Of Eternity + MapID==616 || MapID==595; // Eye Of Eternity, The Culling of Stratholme } bool IsContinent() const @@ -1166,6 +1158,19 @@ struct MapEntry } }; +struct MapDifficultyEntry +{ + //uint32 Id; // 0 + uint32 MapId; // 1 + uint32 Difficulty; // 2 (for arenas: arena slot) + //char* areaTriggerText[16]; // 3-18 text showed when transfer to map failed (missing requirements) + //uint32 textFlags; // 19 + uint32 resetTime; // 20 + uint32 maxPlayers; // 21 + //char* difficultyString; // 22 +}; + + struct MovieEntry { uint32 Id; // 0 index @@ -1191,42 +1196,51 @@ struct RandomPropertiesPointsEntry struct ScalingStatDistributionEntry { - uint32 Id; - int32 StatMod[10]; - uint32 Modifier[10]; - uint32 MaxLevel; + uint32 Id; // 0 + int32 StatMod[10]; // 1-10 + uint32 Modifier[10]; // 11-20 + uint32 MaxLevel; // 21 }; struct ScalingStatValuesEntry { - uint32 Id; - uint32 Level; - uint32 ssdMultiplier[5]; // Multiplier for ScalingStatDistribution - uint32 armorMod[4]; // Armor for level - uint32 dpsMod[6]; // DPS mod for level - uint32 spellBonus; // not sure.. TODO: need more info about - uint32 feralBonus; // Feral AP bonus - + uint32 Id; // 0 + uint32 Level; // 1 + uint32 ssdMultiplier[4]; // 2-5 Multiplier for ScalingStatDistribution + uint32 armorMod[4]; // 6-9 Armor for level + uint32 dpsMod[6]; // 10-15 DPS mod for level + uint32 spellBonus; // 16 spell power for level + uint32 ssdMultiplier2; // 17 there's data from 3.1 dbc ssdMultiplier[3] + //uint32 unk1; // 18 all fields equal to 0 + //uint32 unk2; // 19 unk, probably also Armor for level + uint32 armorMod2[4]; // 20-23 Armor for level + uint32 getssdMultiplier(uint32 mask) const { - if (mask&0x001F) + if (mask & 0x001F) { if(mask & 0x00000001) return ssdMultiplier[0]; if(mask & 0x00000002) return ssdMultiplier[1]; if(mask & 0x00000004) return ssdMultiplier[2]; - if(mask & 0x00000008) return ssdMultiplier[3]; - if(mask & 0x00000010) return ssdMultiplier[4]; + if(mask & 0x00000008) return ssdMultiplier2; + if(mask & 0x00000010) return ssdMultiplier[3]; } return 0; } + uint32 getArmorMod(uint32 mask) const { - if (mask&0x01E0) + if (mask & 0x00F001E0) { if(mask & 0x00000020) return armorMod[0]; if(mask & 0x00000040) return armorMod[1]; if(mask & 0x00000080) return armorMod[2]; if(mask & 0x00000100) return armorMod[3]; + + if(mask & 0x00100000) return armorMod2[0]; // cloth + if(mask & 0x00200000) return armorMod2[1]; // leather + if(mask & 0x00400000) return armorMod2[2]; // mail + if(mask & 0x00800000) return armorMod2[3]; // plate } return 0; } @@ -1239,7 +1253,7 @@ struct ScalingStatValuesEntry if(mask & 0x00000800) return dpsMod[2]; if(mask & 0x00001000) return dpsMod[3]; if(mask & 0x00002000) return dpsMod[4]; - if(mask & 0x00004000) return dpsMod[5]; + if(mask & 0x00004000) return dpsMod[5]; // not used? } return 0; } @@ -1248,9 +1262,9 @@ struct ScalingStatValuesEntry if (mask & 0x00008000) return spellBonus; return 0; } - uint32 getFeralBonus(uint32 mask) const + uint32 getFeralBonus(uint32 mask) const // removed in 3.2.x? { - if (mask & 0x00010000) return feralBonus; + if (mask & 0x00010000) return 0; // not used? return 0; } }; @@ -1342,68 +1356,71 @@ struct SpellEntry uint32 AttributesEx4; // 8 m_attributesExD uint32 AttributesEx5; // 9 m_attributesExE uint32 AttributesEx6; // 10 m_attributesExF - uint32 Stances; // 11 m_shapeshiftMask - uint32 StancesNot; // 12 m_shapeshiftExclude - uint32 Targets; // 13 m_targets - uint32 TargetCreatureType; // 14 m_targetCreatureType - uint32 RequiresSpellFocus; // 15 m_requiresSpellFocus - uint32 FacingCasterFlags; // 16 m_facingCasterFlags - uint32 CasterAuraState; // 17 m_casterAuraState - uint32 TargetAuraState; // 18 m_targetAuraState - uint32 CasterAuraStateNot; // 19 m_excludeCasterAuraState - uint32 TargetAuraStateNot; // 20 m_excludeTargetAuraState - uint32 casterAuraSpell; // 21 m_casterAuraSpell - uint32 targetAuraSpell; // 22 m_targetAuraSpell - uint32 excludeCasterAuraSpell; // 23 m_excludeCasterAuraSpell - uint32 excludeTargetAuraSpell; // 24 m_excludeTargetAuraSpell - uint32 CastingTimeIndex; // 25 m_castingTimeIndex - uint32 RecoveryTime; // 26 m_recoveryTime - uint32 CategoryRecoveryTime; // 27 m_categoryRecoveryTime - uint32 InterruptFlags; // 28 m_interruptFlags - uint32 AuraInterruptFlags; // 29 m_auraInterruptFlags - uint32 ChannelInterruptFlags; // 30 m_channelInterruptFlags - uint32 procFlags; // 31 m_procTypeMask - uint32 procChance; // 32 m_procChance - uint32 procCharges; // 33 m_procCharges - uint32 maxLevel; // 34 m_maxLevel - uint32 baseLevel; // 35 m_baseLevel - uint32 spellLevel; // 36 m_spellLevel - uint32 DurationIndex; // 37 m_durationIndex - uint32 powerType; // 38 m_powerType - uint32 manaCost; // 39 m_manaCost - uint32 manaCostPerlevel; // 40 m_manaCostPerLevel - uint32 manaPerSecond; // 41 m_manaPerSecond - uint32 manaPerSecondPerLevel; // 42 m_manaPerSecondPerLeve - uint32 rangeIndex; // 43 m_rangeIndex - float speed; // 44 m_speed - //uint32 modalNextSpell; // 45 m_modalNextSpell not used - uint32 StackAmount; // 46 m_cumulativeAura - uint32 Totem[2]; // 47-48 m_totem - int32 Reagent[8]; // 49-56 m_reagent - uint32 ReagentCount[8]; // 57-64 m_reagentCount - int32 EquippedItemClass; // 65 m_equippedItemClass (value) - int32 EquippedItemSubClassMask; // 66 m_equippedItemSubclass (mask) - int32 EquippedItemInventoryTypeMask; // 67 m_equippedItemInvTypes (mask) - uint32 Effect[MAX_SPELL_EFFECTS]; // 68-70 m_effect - int32 EffectDieSides[MAX_SPELL_EFFECTS]; // 71-73 m_effectDieSides - int32 EffectBaseDice[MAX_SPELL_EFFECTS]; // 74-76 m_effectBaseDice - float EffectDicePerLevel[MAX_SPELL_EFFECTS]; // 77-79 m_effectDicePerLevel - float EffectRealPointsPerLevel[MAX_SPELL_EFFECTS]; // 80-82 m_effectRealPointsPerLevel - int32 EffectBasePoints[MAX_SPELL_EFFECTS]; // 83-85 m_effectBasePoints (don't must be used in spell/auras explicitly, must be used cached Spell::m_currentBasePoints) - uint32 EffectMechanic[MAX_SPELL_EFFECTS]; // 86-88 m_effectMechanic - uint32 EffectImplicitTargetA[MAX_SPELL_EFFECTS]; // 89-91 m_implicitTargetA - uint32 EffectImplicitTargetB[MAX_SPELL_EFFECTS]; // 92-94 m_implicitTargetB - uint32 EffectRadiusIndex[MAX_SPELL_EFFECTS]; // 95-97 m_effectRadiusIndex - spellradius.dbc - uint32 EffectApplyAuraName[MAX_SPELL_EFFECTS]; // 98-100 m_effectAura - uint32 EffectAmplitude[MAX_SPELL_EFFECTS]; // 101-103 m_effectAuraPeriod - float EffectMultipleValue[MAX_SPELL_EFFECTS]; // 104-106 m_effectAmplitude - uint32 EffectChainTarget[MAX_SPELL_EFFECTS]; // 107-109 m_effectChainTargets - uint32 EffectItemType[MAX_SPELL_EFFECTS]; // 110-112 m_effectItemType - int32 EffectMiscValue[MAX_SPELL_EFFECTS]; // 113-115 m_effectMiscValue - int32 EffectMiscValueB[MAX_SPELL_EFFECTS]; // 116-118 m_effectMiscValueB - uint32 EffectTriggerSpell[MAX_SPELL_EFFECTS]; // 119-121 m_effectTriggerSpell - float EffectPointsPerComboPoint[MAX_SPELL_EFFECTS]; // 122-124 m_effectPointsPerCombo - flag96 EffectSpellClassMask[MAX_SPELL_EFFECTS]; // + // uint32 unk_320_1; // 11 3.2.0 (0x20 - totems, 0x4 - paladin auras, etc...) + uint32 Stances; // 12 m_shapeshiftMask + // uint32 unk_320_2; // 13 3.2.0 + uint32 StancesNot; // 14 m_shapeshiftExclude + // uint32 unk_320_3; // 15 3.2.0 + uint32 Targets; // 16 m_targets + uint32 TargetCreatureType; // 17 m_targetCreatureType + uint32 RequiresSpellFocus; // 18 m_requiresSpellFocus + uint32 FacingCasterFlags; // 19 m_facingCasterFlags + uint32 CasterAuraState; // 20 m_casterAuraState + uint32 TargetAuraState; // 21 m_targetAuraState + uint32 CasterAuraStateNot; // 22 m_excludeCasterAuraState + uint32 TargetAuraStateNot; // 23 m_excludeTargetAuraState + uint32 casterAuraSpell; // 24 m_casterAuraSpell + uint32 targetAuraSpell; // 25 m_targetAuraSpell + uint32 excludeCasterAuraSpell; // 26 m_excludeCasterAuraSpell + uint32 excludeTargetAuraSpell; // 27 m_excludeTargetAuraSpell + uint32 CastingTimeIndex; // 28 m_castingTimeIndex + uint32 RecoveryTime; // 29 m_recoveryTime + uint32 CategoryRecoveryTime; // 30 m_categoryRecoveryTime + uint32 InterruptFlags; // 31 m_interruptFlags + uint32 AuraInterruptFlags; // 32 m_auraInterruptFlags + uint32 ChannelInterruptFlags; // 33 m_channelInterruptFlags + uint32 procFlags; // 34 m_procTypeMask + uint32 procChance; // 35 m_procChance + uint32 procCharges; // 36 m_procCharges + uint32 maxLevel; // 37 m_maxLevel + uint32 baseLevel; // 38 m_baseLevel + uint32 spellLevel; // 39 m_spellLevel + uint32 DurationIndex; // 40 m_durationIndex + uint32 powerType; // 41 m_powerType + uint32 manaCost; // 42 m_manaCost + uint32 manaCostPerlevel; // 43 m_manaCostPerLevel + uint32 manaPerSecond; // 44 m_manaPerSecond + uint32 manaPerSecondPerLevel; // 45 m_manaPerSecondPerLeve + uint32 rangeIndex; // 46 m_rangeIndex + float speed; // 47 m_speed + //uint32 modalNextSpell; // 48 m_modalNextSpell not used + uint32 StackAmount; // 49 m_cumulativeAura + uint32 Totem[2]; // 50-51 m_totem + int32 Reagent[8]; // 50-59 m_reagent + uint32 ReagentCount[8]; // 60-67 m_reagentCount + int32 EquippedItemClass; // 68 m_equippedItemClass (value) + int32 EquippedItemSubClassMask; // 69 m_equippedItemSubclass (mask) + int32 EquippedItemInventoryTypeMask; // 70 m_equippedItemInvTypes (mask) + uint32 Effect[MAX_SPELL_EFFECTS]; // 71-73 m_effect + int32 EffectDieSides[MAX_SPELL_EFFECTS]; // 74-76 m_effectDieSides + int32 EffectBaseDice[MAX_SPELL_EFFECTS]; // 77-79 m_effectBaseDice + float EffectDicePerLevel[MAX_SPELL_EFFECTS]; // 80-82 m_effectDicePerLevel + float EffectRealPointsPerLevel[MAX_SPELL_EFFECTS]; // 83-85 m_effectRealPointsPerLevel + int32 EffectBasePoints[MAX_SPELL_EFFECTS]; // 86-88 m_effectBasePoints (don't must be used in spell/auras explicitly, must be used cached Spell::m_currentBasePoints) + uint32 EffectMechanic[MAX_SPELL_EFFECTS]; // 89-91 m_effectMechanic + uint32 EffectImplicitTargetA[MAX_SPELL_EFFECTS]; // 92-94 m_implicitTargetA + uint32 EffectImplicitTargetB[MAX_SPELL_EFFECTS]; // 95-97 m_implicitTargetB + uint32 EffectRadiusIndex[MAX_SPELL_EFFECTS]; // 98-100 m_effectRadiusIndex - spellradius.dbc + uint32 EffectApplyAuraName[MAX_SPELL_EFFECTS]; // 101-103 m_effectAura + uint32 EffectAmplitude[MAX_SPELL_EFFECTS]; // 104-106 m_effectAuraPeriod + float EffectMultipleValue[MAX_SPELL_EFFECTS]; // 107-109 m_effectAmplitude + uint32 EffectChainTarget[MAX_SPELL_EFFECTS]; // 110-112 m_effectChainTargets + uint32 EffectItemType[MAX_SPELL_EFFECTS]; // 113-115 m_effectItemType + int32 EffectMiscValue[MAX_SPELL_EFFECTS]; // 116-118 m_effectMiscValue + int32 EffectMiscValueB[MAX_SPELL_EFFECTS]; // 119-121 m_effectMiscValueB + uint32 EffectTriggerSpell[MAX_SPELL_EFFECTS]; // 122-124 m_effectTriggerSpell + float EffectPointsPerComboPoint[MAX_SPELL_EFFECTS]; // 125-127 m_effectPointsPerCombo + flag96 EffectSpellClassMask[MAX_SPELL_EFFECTS]; // 127-133 uint32 SpellVisual[2]; // 134-135 m_spellVisualID uint32 SpellIconID; // 136 m_spellIconID uint32 activeIconID; // 137 m_activeIconID @@ -1436,6 +1453,8 @@ struct SpellEntry uint32 runeCostID; // 229 m_runeCostID //uint32 spellMissileID; // 230 m_spellMissileID not used //uint32 PowerDisplayId; // 231 PowerDisplay.dbc, new in 3.1 + //float unk_320_4[3]; // 232-234 3.2.0 + //uint32 spellDescriptionVariableID; // 235 3.2.0 // helpers int32 CalculateSimpleValue(uint8 eff) const { return EffectBasePoints[eff]+int32(EffectBaseDice[eff]); } @@ -1538,7 +1557,7 @@ struct SpellItemEnchantmentEntry uint32 EnchantmentCondition; // 34 m_condition_id uint32 requiredSkill; // 35 m_requiredSkillID uint32 requiredSkillValue; // 36 m_requiredSkillRank - uint32 RequiredLevel; // 37 m_requiredLevel - new in 3.1 + uint32 requiredLevel; // 37 m_requiredLevel }; struct SpellItemEnchantmentConditionEntry @@ -1558,6 +1577,7 @@ struct StableSlotPricesEntry uint32 Price; }; + struct SummonPropertiesEntry { uint32 Id; // 0 @@ -1568,6 +1588,7 @@ struct SummonPropertiesEntry uint32 Flags; // 5 }; + #define MAX_TALENT_RANK 5 #define MAX_PET_TALENT_RANK 3 // use in calculations, expected <= MAX_TALENT_RANK @@ -1747,6 +1768,7 @@ struct WorldMapAreaEntry float x2; // 7 int32 virtual_map_id; // 8 -1 (map_id have correct map) other: virtual map where zone show (map_id - where zone in fact internally) // int32 dungeonMap_id; // 9 pointer to DungeonMap.dbc (owerride x1,x2,y1,y2 coordinates) + // uint32 someMapID; // 10 }; #define MAX_WORLD_MAP_OVERLAY_AREA_IDX 4 @@ -1780,6 +1802,15 @@ struct WorldSafeLocsEntry #endif // Structures not used for casting to loaded DBC data and not required then packing +struct MapDifficulty +{ + MapDifficulty() : resetTime(0), maxPlayers(0) {} + MapDifficulty(uint32 _resetTime, uint32 _maxPlayers) : resetTime(_resetTime), maxPlayers(_maxPlayers) {} + + uint32 resetTime; + uint32 maxPlayers; +}; + struct TalentSpellPos { TalentSpellPos() : talent_id(0), rank(0) {} diff --git a/src/game/DBCfmt.h b/src/game/DBCfmt.h index 2dcb7619a3e..635de26a07d 100644 --- a/src/game/DBCfmt.h +++ b/src/game/DBCfmt.h @@ -36,7 +36,7 @@ const char CharTitlesEntryfmt[]="nxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxi"; const char ChatChannelsEntryfmt[]="iixssssssssssssssssxxxxxxxxxxxxxxxxxx"; // ChatChannelsEntryfmt, index not used (more compact store) const char ChrClassesEntryfmt[]="nxixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxixii"; -const char ChrRacesEntryfmt[]="nxixiixxixxxxissssssssssssssssxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxi"; +const char ChrRacesEntryfmt[]="nxixiixixxxxixssssssssssssssssxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxi"; const char CinematicSequencesEntryfmt[]="nxxxxxxxxx"; const char CreatureDisplayInfofmt[]="nxxxfxxxxxxxxxxx"; const char CreatureFamilyfmt[]="nfifiiiiixssssssssssssssssxx"; @@ -68,26 +68,27 @@ const char Itemfmt[]="niiiiiii"; const char ItemBagFamilyfmt[]="nxxxxxxxxxxxxxxxxx"; //const char ItemDisplayTemplateEntryfmt[]="nxxxxxxxxxxixxxxxxxxxxx"; //const char ItemCondExtCostsEntryfmt[]="xiii"; -const char ItemExtendedCostEntryfmt[]="niiiiiiiiiiiiix"; +const char ItemExtendedCostEntryfmt[]="niixiiiiiiiiiiix"; const char ItemLimitCategoryEntryfmt[]="nxxxxxxxxxxxxxxxxxix"; -const char ItemRandomPropertiesfmt[]="nxiiiiixxxxxxxxxxxxxxxxx"; -const char ItemRandomSuffixfmt[]="nxxxxxxxxxxxxxxxxxxiiiiiiiiii"; +const char ItemRandomPropertiesfmt[]="nxiiiiissssssssssssssssx"; +const char ItemRandomSuffixfmt[]="nssssssssssssssssxxiiiiiiiiii"; const char ItemSetEntryfmt[]="dssssssssssssssssxxxxxxxxxxxxxxxxxxiiiiiiiiiiiiiiiiii"; const char LockEntryfmt[]="niiiiiiiiiiiiiiiiiiiiiiiixxxxxxxx"; const char MailTemplateEntryfmt[]="nxxxxxxxxxxxxxxxxxssssssssssssssssx"; -const char MapEntryfmt[]="nxixssssssssssssssssxixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxiffiixxix"; +const char MapEntryfmt[]="nxixssssssssssssssssxixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxixiffxixx"; +const char MapDifficultyEntryfmt[]="diixxxxxxxxxxxxxxxxxiix"; const char MovieEntryfmt[]="nxx"; const char QuestSortEntryfmt[]="nxxxxxxxxxxxxxxxxx"; const char RandomPropertiesPointsfmt[]="niiiiiiiiiiiiiii"; const char ScalingStatDistributionfmt[]="niiiiiiiiiiiiiiiiiiiii"; -const char ScalingStatValuesfmt[]="iniiiiiiiiiiiiiiiii"; +const char ScalingStatValuesfmt[]="iniiiiiiiiiiiiiiiixxiiii"; const char SkillLinefmt[]="nixssssssssssssssssxxxxxxxxxxxxxxxxxxixxxxxxxxxxxxxxxxxi"; const char SkillLineAbilityfmt[]="niiiixxiiiiixx"; const char SoundEntriesfmt[]="nxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; const char SpellCastTimefmt[]="nixx"; const char SpellDurationfmt[]="niii"; -const char SpellEntryfmt[]="niiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiifxiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiffffffiiiiiiiiiiiiiiiiiiiiifffiiiiiiiiiiiiiiifffiiiiiiiiiiiiixssssssssssssssssxssssssssssssssssxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxiiiiiiiiiiixfffxxxiiiiixx"; -const std::string CustomSpellEntryfmt="pappppppppaaapaaaaaaaaaaapaaapapppppppaaaaapaapaaaaaaaaaaaaaaaaaappppppppppppppppppppppppppppppppppppppppppaaaaaapppppppppaaapppppppppaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaappppppppapppaaaaappaaa"; +const char SpellEntryfmt[]="niiiiiiiiiixixixiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiifxiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiffffffiiiiiiiiiiiiiiiiiiiiifffiiiiiiiiiiiiiiifffiiiiiiiiiiiiixssssssssssssssssxssssssssssssssssxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxiiiiiiiiiiixfffxxxiiiiixxxxxx"; +const std::string CustomSpellEntryfmt="pappppppppaaaaaapaaaaaaaaaaapaaapapppppppaaaaapaapaaaaaaaaaaaaaaaaaappppppppppppppppppppppppppppppppppppppppppaaaaaapppppppppaaapppppppppaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaappppppppapppaaaaappaaaaaaa"; const std::string CustomSpellEntryIndex = "Id"; const char SpellFocusObjectfmt[]="nxxxxxxxxxxxxxxxxx"; const char SpellItemEnchantmentfmt[]="nxiiiiiixxxiiissssssssssssssssxiiiiiii"; @@ -106,7 +107,7 @@ const char TaxiPathNodeEntryfmt[]="diiifffiixx"; const char TotemCategoryEntryfmt[]="nxxxxxxxxxxxxxxxxxii"; const char VehicleEntryfmt[]="niffffiiiiiiiifffffffffffffffssssfifiixx"; const char VehicleSeatEntryfmt[]="niiffffffffffiiiiiifffffffiiifffiiiiiiiffiiiiixxxxxxxxxxxx"; -const char WorldMapAreaEntryfmt[]="xinxffffix"; +const char WorldMapAreaEntryfmt[]="xinxffffixx"; const char WorldMapOverlayEntryfmt[]="nxiiiixxxxxxxxxxx"; const char WorldSafeLocsEntryfmt[]="nifffxxxxxxxxxxxxxxxxx"; diff --git a/src/game/Debugcmds.cpp b/src/game/Debugcmds.cpp index e016d8c98b0..375ad770ded 100644 --- a/src/game/Debugcmds.cpp +++ b/src/game/Debugcmds.cpp @@ -823,7 +823,7 @@ bool ChatHandler::HandleDebugSendSetPhaseShiftCommand(const char* args) return true; } -bool ChatHandler::HandleDebugSetItemFlagCommand(const char* args) +bool ChatHandler::HandleDebugGetItemValueCommand(const char* args) { if (!*args) return false; @@ -835,14 +835,48 @@ bool ChatHandler::HandleDebugSetItemFlagCommand(const char* args) return false; uint32 guid = (uint32)atoi(e); - uint32 flag = (uint32)atoi(f); + uint32 index = (uint32)atoi(f); Item *i = m_session->GetPlayer()->GetItemByGuid(MAKE_NEW_GUID(guid, 0, HIGHGUID_ITEM)); if (!i) return false; - i->SetUInt32Value(ITEM_FIELD_FLAGS, flag); + if (index >= i->GetValuesCount()) + return false; + + uint32 value = i->GetUInt32Value(index); + + PSendSysMessage("Item %u: value at %u is %u", guid, index, value); + + return true; +} + +bool ChatHandler::HandleDebugSetItemValueCommand(const char* args) +{ + if (!*args) + return false; + + char* e = strtok((char*)args, " "); + char* f = strtok(NULL, " "); + char* g = strtok(NULL, " "); + + if (!e || !f || !g) + return false; + + uint32 guid = (uint32)atoi(e); + uint32 index = (uint32)atoi(f); + uint32 value = (uint32)atoi(g); + + Item *i = m_session->GetPlayer()->GetItemByGuid(MAKE_NEW_GUID(guid, 0, HIGHGUID_ITEM)); + + if (!i) + return false; + + if (index >= i->GetValuesCount()) + return false; + + i->SetUInt32Value(index, value); return true; } diff --git a/src/game/DuelHandler.cpp b/src/game/DuelHandler.cpp index c35b9dbdc07..d9854d900c8 100644 --- a/src/game/DuelHandler.cpp +++ b/src/game/DuelHandler.cpp @@ -51,10 +51,8 @@ void WorldSession::HandleDuelAcceptedOpcode(WorldPacket& recvPacket) pl->duel->startTimer = now; plTarget->duel->startTimer = now; - WorldPacket data(SMSG_DUEL_COUNTDOWN, 4); - data << (uint32)3000; // 3 seconds - pl->GetSession()->SendPacket(&data); - plTarget->GetSession()->SendPacket(&data); + pl->SendDuelCountdown(3000); + plTarget->SendDuelCountdown(3000); } void WorldSession::HandleDuelCancelledOpcode(WorldPacket& recvPacket) @@ -84,4 +82,3 @@ void WorldSession::HandleDuelCancelledOpcode(WorldPacket& recvPacket) GetPlayer()->DuelComplete(DUEL_INTERUPTED); } - diff --git a/src/game/DynamicObject.cpp b/src/game/DynamicObject.cpp index db0a4a7f2ef..be56b9f5069 100644 --- a/src/game/DynamicObject.cpp +++ b/src/game/DynamicObject.cpp @@ -33,7 +33,7 @@ DynamicObject::DynamicObject() : WorldObject() m_objectType |= TYPEMASK_DYNAMICOBJECT; m_objectTypeId = TYPEID_DYNAMICOBJECT; - m_updateFlag = (UPDATEFLAG_HIGHGUID | UPDATEFLAG_HAS_POSITION); + m_updateFlag = (UPDATEFLAG_HIGHGUID | UPDATEFLAG_HAS_POSITION | UPDATEFLAG_POSITION); m_valuesCount = DYNAMICOBJECT_END; } @@ -88,9 +88,6 @@ bool DynamicObject::Create(uint32 guidlow, Unit *caster, uint32 spellId, uint32 SetUInt32Value( DYNAMICOBJECT_BYTES, 0x00000001 ); SetUInt32Value( DYNAMICOBJECT_SPELLID, spellId ); SetFloatValue( DYNAMICOBJECT_RADIUS, radius); - SetFloatValue( DYNAMICOBJECT_POS_X, pos.m_positionX ); - SetFloatValue( DYNAMICOBJECT_POS_Y, pos.m_positionY ); - SetFloatValue( DYNAMICOBJECT_POS_Z, pos.m_positionZ ); SetUInt32Value( DYNAMICOBJECT_CASTTIME, getMSTime() ); // new 2.4.0 m_aliveDuration = duration; @@ -184,4 +181,3 @@ bool DynamicObject::isVisibleForInState(Player const* u, bool inVisibleList) con return IsInWorld() && u->IsInWorld() && (IsWithinDistInMap(u->m_seer,World::GetMaxVisibleDistanceForObject()+(inVisibleList ? World::GetVisibleObjectGreyDistance() : 0.0f), false)); } - diff --git a/src/game/DynamicObject.h b/src/game/DynamicObject.h index 13747891964..89b227e64ff 100644 --- a/src/game/DynamicObject.h +++ b/src/game/DynamicObject.h @@ -64,11 +64,9 @@ class DynamicObject : public WorldObject uint32 m_effMask; int32 m_aliveDuration; uint32 m_updateTimer; - time_t m_nextThinkTime; float m_radius; AffectedSet m_affected; private: GridReference<DynamicObject> m_gridRef; }; #endif - diff --git a/src/game/GameEventMgr.cpp b/src/game/GameEventMgr.cpp index 7c879d86e7f..6e66e87cbe1 100644 --- a/src/game/GameEventMgr.cpp +++ b/src/game/GameEventMgr.cpp @@ -1279,7 +1279,9 @@ void GameEventMgr::GameEventSpawn(int16 event_id) for (IdList::iterator itr = mGameEventPoolIds[internal_event_id].begin(); itr != mGameEventPoolIds[internal_event_id].end(); ++itr) { - poolhandler.SpawnPool(*itr); + poolhandler.SpawnPool(*itr, 0, 0); + poolhandler.SpawnPool(*itr, 0, TYPEID_GAMEOBJECT); + poolhandler.SpawnPool(*itr, 0, TYPEID_UNIT); } } diff --git a/src/game/GameObject.h b/src/game/GameObject.h index a915b81fc78..7d55afb7e60 100644 --- a/src/game/GameObject.h +++ b/src/game/GameObject.h @@ -754,4 +754,3 @@ class TRINITY_DLL_SPEC GameObject : public WorldObject GridReference<GameObject> m_gridRef; }; #endif - diff --git a/src/game/GossipDef.cpp b/src/game/GossipDef.cpp index 418f27dc4ea..5b0d0bd1dc8 100644 --- a/src/game/GossipDef.cpp +++ b/src/game/GossipDef.cpp @@ -547,13 +547,13 @@ void PlayerMenu::SendQuestQueryResponse( Quest const *pQuest ) WorldPacket data( SMSG_QUEST_QUERY_RESPONSE, 100 ); // guess size - data << uint32(pQuest->GetQuestId()); + data << uint32(pQuest->GetQuestId()); // quest id data << uint32(pQuest->GetQuestMethod()); // Accepted values: 0, 1 or 2. 0==IsAutoComplete() (skip objectives/details) data << uint32(pQuest->GetQuestLevel()); // may be -1, static data, in other cases must be used dynamic level: Player::GetQuestLevel (0 is not known, but assuming this is no longer valid for quest intended for client) data << uint32(pQuest->GetZoneOrSort()); // zone or sort to display in quest log - data << uint32(pQuest->GetType()); - data << uint32(pQuest->GetSuggestedPlayers()); + data << uint32(pQuest->GetType()); // quest type + data << uint32(pQuest->GetSuggestedPlayers()); // suggested players count data << uint32(pQuest->GetRepObjectiveFaction()); // shown in quest log as part of quest objective data << uint32(pQuest->GetRepObjectiveValue()); // shown in quest log as part of quest objective @@ -566,7 +566,7 @@ void PlayerMenu::SendQuestQueryResponse( Quest const *pQuest ) if (pQuest->HasFlag(QUEST_FLAGS_HIDDEN_REWARDS)) data << uint32(0); // Hide money rewarded else - data << uint32(pQuest->GetRewOrReqMoney()); + data << uint32(pQuest->GetRewOrReqMoney()); // reward money (below max lvl) data << uint32(pQuest->GetRewMoneyMaxLevel()); // used in XP calculation at client data << uint32(pQuest->GetRewSpell()); // reward spell, this spell will display (icon) (casted if RewSpellCast==0) @@ -574,8 +574,8 @@ void PlayerMenu::SendQuestQueryResponse( Quest const *pQuest ) // rewarded honor points data << uint32(Trinity::Honor::hk_honor_at_level(pSession->GetPlayer()->getLevel(), pQuest->GetRewHonorableKills())); - data << uint32(pQuest->GetSrcItemId()); - data << uint32(pQuest->GetFlags() & 0xFFFF); + data << uint32(pQuest->GetSrcItemId()); // source item id + data << uint32(pQuest->GetFlags() & 0xFFFF); // quest flags data << uint32(pQuest->GetCharTitleId()); // CharTitleId, new 2.4.0, player gets this title (id from CharTitles) data << uint32(pQuest->GetPlayersSlain()); // players slain data << uint32(pQuest->GetBonusTalents()); // bonus talents @@ -628,15 +628,12 @@ void PlayerMenu::SendQuestQueryResponse( Quest const *pQuest ) data << uint32(pQuest->ReqSourceId[iI]); } - for (iI = 0; iI < QUEST_OBJECTIVES_COUNT; ++iI) + for (iI = 0; iI < QUEST_ITEM_OBJECTIVES_COUNT; ++iI) { data << uint32(pQuest->ReqItemId[iI]); data << uint32(pQuest->ReqItemCount[iI]); } - data << uint32(0); // TODO: 5 item objective - data << uint32(0); - for (iI = 0; iI < QUEST_OBJECTIVES_COUNT; ++iI) data << ObjectiveText[iI]; @@ -782,7 +779,7 @@ void PlayerMenu::SendQuestGiverRequestItems( Quest const *pQuest, uint64 npcGUID data << uint32( pQuest->GetReqItemsCount() ); ItemPrototype const *pItem; - for (int i = 0; i < QUEST_OBJECTIVES_COUNT; ++i) + for (int i = 0; i < QUEST_ITEM_OBJECTIVES_COUNT; ++i) { if ( !pQuest->ReqItemId[i] ) continue; pItem = objmgr.GetItemPrototype(pQuest->ReqItemId[i]); @@ -807,4 +804,3 @@ void PlayerMenu::SendQuestGiverRequestItems( Quest const *pQuest, uint64 npcGUID pSession->SendPacket( &data ); sLog.outDebug( "WORLD: Sent SMSG_QUESTGIVER_REQUEST_ITEMS NPCGuid=%u, questid=%u", GUID_LOPART(npcGUID), pQuest->GetQuestId() ); } - diff --git a/src/game/GossipDef.h b/src/game/GossipDef.h index 88c15f334a1..5e4c2e8b65a 100644 --- a/src/game/GossipDef.h +++ b/src/game/GossipDef.h @@ -207,4 +207,3 @@ class TRINITY_DLL_SPEC PlayerMenu void SendQuestGiverRequestItems( Quest const *pQuest, uint64 npcGUID, bool Completable, bool CloseOnCancel ); }; #endif - diff --git a/src/game/GridDefines.h b/src/game/GridDefines.h index c51b507fcbd..968118431a7 100644 --- a/src/game/GridDefines.h +++ b/src/game/GridDefines.h @@ -191,4 +191,3 @@ namespace Trinity } } #endif - diff --git a/src/game/GridNotifiers.h b/src/game/GridNotifiers.h index ed6232b101f..9deb5cb2e24 100644 --- a/src/game/GridNotifiers.h +++ b/src/game/GridNotifiers.h @@ -1244,4 +1244,3 @@ namespace Trinity #endif } #endif - diff --git a/src/game/Group.cpp b/src/game/Group.cpp index 9face6d0e7d..a3fe884a645 100644 --- a/src/game/Group.cpp +++ b/src/game/Group.cpp @@ -71,7 +71,7 @@ Group::~Group() // it is undefined whether objectmgr (which stores the groups) or instancesavemgr // will be unloaded first so we must be prepared for both cases // this may unload some instance saves - for (uint8 i = 0; i < TOTAL_DIFFICULTIES; ++i) + for (uint8 i = 0; i < MAX_DIFFICULTY; ++i) for (BoundInstancesMap::iterator itr2 = m_boundInstances[i].begin(); itr2 != m_boundInstances[i].end(); ++itr2) itr2->second.save->RemoveGroup(this); @@ -94,22 +94,27 @@ bool Group::Create(const uint64 &guid, const char * name) m_lootThreshold = ITEM_QUALITY_UNCOMMON; m_looterGuid = guid; - m_difficulty = DIFFICULTY_NORMAL; + m_dungeonDifficulty = DUNGEON_DIFFICULTY_NORMAL; + m_raidDifficulty = RAID_DIFFICULTY_10MAN_NORMAL; if(!isBGGroup()) { Player *leader = objmgr.GetPlayer(guid); - if(leader) m_difficulty = leader->GetDifficulty(); - + if(leader) + { + m_dungeonDifficulty = leader->GetDungeonDifficulty(); + m_raidDifficulty = leader->GetRaidDifficulty(); + } + Player::ConvertInstancesToGroup(leader, this, guid); // store group in database CharacterDatabase.BeginTransaction(); CharacterDatabase.PExecute("DELETE FROM groups WHERE leaderGuid ='%u'", GUID_LOPART(m_leaderGuid)); CharacterDatabase.PExecute("DELETE FROM group_member WHERE leaderGuid ='%u'", GUID_LOPART(m_leaderGuid)); - CharacterDatabase.PExecute("INSERT INTO groups(leaderGuid,mainTank,mainAssistant,lootMethod,looterGuid,lootThreshold,icon1,icon2,icon3,icon4,icon5,icon6,icon7,icon8,isRaid,difficulty) " - "VALUES('%u','%u','%u','%u','%u','%u','" UI64FMTD "','" UI64FMTD "','" UI64FMTD "','" UI64FMTD "','" UI64FMTD "','" UI64FMTD "','" UI64FMTD "','" UI64FMTD "','%u','%u')", + CharacterDatabase.PExecute("INSERT INTO groups (leaderGuid,mainTank,mainAssistant,lootMethod,looterGuid,lootThreshold,icon1,icon2,icon3,icon4,icon5,icon6,icon7,icon8,isRaid,difficulty,raiddifficulty) " + "VALUES ('%u','%u','%u','%u','%u','%u','" UI64FMTD "','" UI64FMTD "','" UI64FMTD "','" UI64FMTD "','" UI64FMTD "','" UI64FMTD "','" UI64FMTD "','" UI64FMTD "','%u','%u','%u')", GUID_LOPART(m_leaderGuid), GUID_LOPART(m_mainTank), GUID_LOPART(m_mainAssistant), uint32(m_lootMethod), - GUID_LOPART(m_looterGuid), uint32(m_lootThreshold), m_targetIcons[0], m_targetIcons[1], m_targetIcons[2], m_targetIcons[3], m_targetIcons[4], m_targetIcons[5], m_targetIcons[6], m_targetIcons[7], isRaidGroup(), m_difficulty); + GUID_LOPART(m_looterGuid), uint32(m_lootThreshold), m_targetIcons[0], m_targetIcons[1], m_targetIcons[2], m_targetIcons[3], m_targetIcons[4], m_targetIcons[5], m_targetIcons[6], m_targetIcons[7], isRaidGroup(), uint32(m_dungeonDifficulty), m_raidDifficulty); } if(!AddMember(guid, name)) @@ -129,8 +134,8 @@ bool Group::LoadGroupFromDB(const uint64 &leaderGuid, QueryResult *result, bool if(!result) { external = false; - // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 - result = CharacterDatabase.PQuery("SELECT mainTank, mainAssistant, lootMethod, looterGuid, lootThreshold, icon1, icon2, icon3, icon4, icon5, icon6, icon7, icon8, isRaid, difficulty FROM groups WHERE leaderGuid ='%u'", GUID_LOPART(leaderGuid)); + // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + result = CharacterDatabase.PQuery("SELECT mainTank, mainAssistant, lootMethod, looterGuid, lootThreshold, icon1, icon2, icon3, icon4, icon5, icon6, icon7, icon8, isRaid, difficulty, raiddifficulty FROM groups WHERE leaderGuid ='%u'", GUID_LOPART(leaderGuid)); if(!result) return false; } @@ -149,7 +154,16 @@ bool Group::LoadGroupFromDB(const uint64 &leaderGuid, QueryResult *result, bool if (m_groupType == GROUPTYPE_RAID) _initRaidSubGroupsCounter(); - m_difficulty = (*result)[14].GetUInt8(); + uint32 diff = (*result)[14].GetUInt8(); + if (diff >= MAX_DUNGEON_DIFFICULTY) + diff = DUNGEON_DIFFICULTY_NORMAL; + m_dungeonDifficulty = Difficulty(diff); + + uint32 r_diff = (*result)[15].GetUInt8(); + if (r_diff >= MAX_RAID_DIFFICULTY) + r_diff = RAID_DIFFICULTY_10MAN_NORMAL; + m_raidDifficulty = Difficulty(r_diff); + m_mainTank = (*result)[0].GetUInt64(); m_mainAssistant = (*result)[1].GetUInt64(); m_lootMethod = (LootMethod)(*result)[2].GetUInt8(); @@ -291,12 +305,21 @@ bool Group::AddMember(const uint64 &guid, const char* name) { // reset the new member's instances, unless he is currently in one of them // including raid/heroic instances that they are not permanently bound to! - player->ResetInstances(INSTANCE_RESET_GROUP_JOIN); + player->ResetInstances(INSTANCE_RESET_GROUP_JOIN,false); + player->ResetInstances(INSTANCE_RESET_GROUP_JOIN,true); - if(player->getLevel() >= LEVELREQUIREMENT_HEROIC && player->GetDifficulty() != GetDifficulty() ) + if (player->getLevel() >= LEVELREQUIREMENT_HEROIC) { - player->SetDifficulty(m_difficulty); - player->SendDungeonDifficulty(true); + if (player->GetDungeonDifficulty() != GetDungeonDifficulty()) + { + player->SetDungeonDifficulty(GetDungeonDifficulty()); + player->SendDungeonDifficulty(true); + } + if (player->GetRaidDifficulty() != GetRaidDifficulty()) + { + player->SetRaidDifficulty(GetRaidDifficulty()); + player->SendRaidDifficulty(true); + } } } player->SetGroupUpdateFlag(GROUP_UPDATE_FULL); @@ -441,7 +464,8 @@ void Group::Disband(bool hideDestroy) CharacterDatabase.PExecute("DELETE FROM groups WHERE leaderGuid='%u'", GUID_LOPART(m_leaderGuid)); CharacterDatabase.PExecute("DELETE FROM group_member WHERE leaderGuid='%u'", GUID_LOPART(m_leaderGuid)); CharacterDatabase.CommitTransaction(); - ResetInstances(INSTANCE_RESET_GROUP_DISBAND, NULL); + ResetInstances(INSTANCE_RESET_GROUP_DISBAND, false, NULL); + ResetInstances(INSTANCE_RESET_GROUP_DISBAND, true, NULL); } m_leaderGuid = 0; @@ -454,12 +478,13 @@ void Group::Disband(bool hideDestroy) void Group::SendLootStartRoll(uint32 CountDown, const Roll &r) { - WorldPacket data(SMSG_LOOT_START_ROLL, (8+4+4+4+4+4)); + WorldPacket data(SMSG_LOOT_START_ROLL, (8+4+4+4+4+4+4)); data << uint64(r.itemGUID); // guid of rolled item data << uint32(r.totalPlayersRolling); // maybe the number of players rolling for it??? data << uint32(r.itemid); // the itemEntryId for the item that shall be rolled for data << uint32(r.itemRandomSuffix); // randomSuffix data << uint32(r.itemRandomPropId); // item random property ID + data << uint32(r.itemCount); // items in stack data << uint32(CountDown); // the countdown time to choose "need" or "greed" for (Roll::PlayerVote::const_iterator itr=r.playerVote.begin(); itr!=r.playerVote.end(); ++itr) @@ -475,7 +500,7 @@ void Group::SendLootStartRoll(uint32 CountDown, const Roll &r) void Group::SendLootRoll(const uint64& SourceGuid, const uint64& TargetGuid, uint8 RollNumber, uint8 RollType, const Roll &r) { - WorldPacket data(SMSG_LOOT_ROLL, (8+4+8+4+4+4+1+1)); + WorldPacket data(SMSG_LOOT_ROLL, (8+4+8+4+4+4+1+1+1)); data << uint64(SourceGuid); // guid of the item rolled data << uint32(0); // unknown, maybe amount of players data << uint64(TargetGuid); @@ -704,23 +729,23 @@ void Group::CountRollVote(const uint64& playerGUID, const uint64& Guid, uint32 N switch (Choise) { - case 0: //Player choose pass + case ROLL_PASS: // Player choose pass { - SendLootRoll(0, playerGUID, 128, 128, *roll); + SendLootRoll(0, playerGUID, 0, ROLL_PASS, *roll); ++roll->totalPass; itr->second = PASS; } break; - case 1: //player choose Need + case ROLL_NEED: // player choose Need { - SendLootRoll(0, playerGUID, 0, 0, *roll); + SendLootRoll(0, playerGUID, 0, ROLL_NEED, *roll); ++roll->totalNeed; itr->second = NEED; } break; - case 2: //player choose Greed + case ROLL_GREED: // player choose Greed { - SendLootRoll(0, playerGUID, 128, 2, *roll); + SendLootRoll(0, playerGUID, 128, ROLL_GREED, *roll); ++roll->totalGreed; itr->second = GREED; } @@ -768,14 +793,14 @@ void Group::CountTheRoll(Rolls::iterator rollI, uint32 NumberOfPlayers) continue; uint8 randomN = urand(1, 99); - SendLootRoll(0, itr->first, randomN, 1, *roll); + SendLootRoll(0, itr->first, randomN, ROLL_NEED, *roll); if (maxresul < randomN) { maxguid = itr->first; maxresul = randomN; } } - SendLootRollWon(0, maxguid, maxresul, 1, *roll); + SendLootRollWon(0, maxguid, maxresul, ROLL_NEED, *roll); player = objmgr.GetPlayer(maxguid); if(player && player->GetSession()) @@ -815,14 +840,14 @@ void Group::CountTheRoll(Rolls::iterator rollI, uint32 NumberOfPlayers) continue; uint8 randomN = urand(1, 99); - SendLootRoll(0, itr->first, randomN, 2, *roll); + SendLootRoll(0, itr->first, randomN, ROLL_GREED, *roll); if (maxresul < randomN) { maxguid = itr->first; maxresul = randomN; } } - SendLootRollWon(0, maxguid, maxresul, 2, *roll); + SendLootRollWon(0, maxguid, maxresul, ROLL_GREED, *roll); player = objmgr.GetPlayer(maxguid); if(player && player->GetSession()) @@ -959,7 +984,8 @@ void Group::SendUpdate() data << (uint8)m_lootMethod; // loot method data << (uint64)m_looterGuid; // looter guid data << (uint8)m_lootThreshold; // loot threshold - data << (uint8)m_difficulty; // Heroic Mod Group + data << (uint8)m_dungeonDifficulty; // Dungeon Difficulty + data << (uint8)m_raidDifficulty; // Raid Difficulty } player->GetSession()->SendPacket( &data ); } @@ -1076,7 +1102,7 @@ bool Group::_addMember(const uint64 &guid, const char* name, bool isAssistant, u else player->SetGroup(this, group); // if the same group invites the player back, cancel the homebind timer - InstanceGroupBind *bind = GetBoundInstance(player->GetMapId(), player->GetDifficulty()); + InstanceGroupBind *bind = GetBoundInstance(player); if(bind && bind->save->GetInstanceId() == player->GetInstanceId()) player->m_InstanceValid = true; } @@ -1162,7 +1188,7 @@ void Group::_setLeader(const uint64 &guid) Player *player = objmgr.GetPlayer(slot->guid); if(player) { - for (uint8 i = 0; i < TOTAL_DIFFICULTIES; ++i) + for (uint8 i = 0; i < MAX_DIFFICULTY; ++i) { for (BoundInstancesMap::iterator itr = m_boundInstances[i].begin(); itr != m_boundInstances[i].end();) { @@ -1211,7 +1237,7 @@ void Group::_removeRolls(const uint64 &guid) roll->playerVote.erase(itr2); - CountRollVote(guid, roll->itemGUID, GetMembersCount()-1, 3); + CountRollVote(guid, roll->itemGUID, GetMembersCount()-1, MAX_ROLL_TYPE); } } @@ -1449,19 +1475,38 @@ void Roll::targetObjectBuildLink() getTarget()->addLootValidatorRef(this); } -void Group::SetDifficulty(uint8 difficulty) +void Group::SetDungeonDifficulty(Difficulty difficulty) { - m_difficulty = difficulty; - if (!isBGGroup()) - CharacterDatabase.PExecute("UPDATE groups SET difficulty = %u WHERE leaderGuid ='%u'", m_difficulty, GUID_LOPART(m_leaderGuid)); - + m_dungeonDifficulty = difficulty; + if(!isBGGroup()) + CharacterDatabase.PExecute("UPDATE groups SET difficulty = %u WHERE leaderGuid ='%u'", m_dungeonDifficulty, GUID_LOPART(m_leaderGuid)); + for (GroupReference *itr = GetFirstMember(); itr != NULL; itr = itr->next()) { Player *player = itr->getSource(); if(!player->GetSession() || player->getLevel() < LEVELREQUIREMENT_HEROIC) continue; - player->SetDifficulty(difficulty); + player->SetDungeonDifficulty(difficulty); player->SendDungeonDifficulty(true); + //send player to recall positio nis a dungeon (to avoid an exploit) + if (sMapStore.LookupEntry(player->GetMap()->IsDungeon())) + player->TeleportTo(player->m_recallMap, player->m_recallX, player->m_recallY, player->m_recallZ, player->m_recallO); + } +} + +void Group::SetRaidDifficulty(Difficulty difficulty) +{ + m_raidDifficulty = difficulty; + if(!isBGGroup()) + CharacterDatabase.PExecute("UPDATE groups SET raiddifficulty = %u WHERE leaderGuid ='%u'", m_raidDifficulty, GUID_LOPART(m_leaderGuid)); + + for(GroupReference *itr = GetFirstMember(); itr != NULL; itr = itr->next()) + { + Player *player = itr->getSource(); + if(!player->GetSession() || player->getLevel() < LEVELREQUIREMENT_HEROIC) + continue; + player->SetRaidDifficulty(difficulty); + player->SendRaidDifficulty(true); } } @@ -1470,7 +1515,7 @@ bool Group::InCombatToInstance(uint32 instanceId) for (GroupReference *itr = GetFirstMember(); itr != NULL; itr = itr->next()) { Player *pPlayer = itr->getSource(); - if(pPlayer && pPlayer->getAttackers().size() && pPlayer->GetInstanceId() == instanceId && (pPlayer->GetMap()->IsRaid() || pPlayer->GetMap()->IsHeroic())) + if(pPlayer && pPlayer->getAttackers().size() && pPlayer->GetInstanceId() == instanceId && (pPlayer->GetMap()->IsRaidOrHeroicDungeon())) for (std::set<Unit*>::const_iterator i = pPlayer->getAttackers().begin(); i!=pPlayer->getAttackers().end(); ++i) if((*i) && (*i)->GetTypeId() == TYPEID_UNIT && ((Creature*)(*i))->GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_INSTANCE_BIND) return true; @@ -1478,7 +1523,7 @@ bool Group::InCombatToInstance(uint32 instanceId) return false; } -void Group::ResetInstances(uint8 method, Player* SendMsgTo) +void Group::ResetInstances(uint8 method, bool isRaid, Player* SendMsgTo) { if(isBGGroup()) return; @@ -1486,13 +1531,13 @@ void Group::ResetInstances(uint8 method, Player* SendMsgTo) // method can be INSTANCE_RESET_ALL, INSTANCE_RESET_CHANGE_DIFFICULTY, INSTANCE_RESET_GROUP_DISBAND // we assume that when the difficulty changes, all instances that can be reset will be - uint8 dif = GetDifficulty(); + Difficulty diff = GetDifficulty(isRaid); - for (BoundInstancesMap::iterator itr = m_boundInstances[dif].begin(); itr != m_boundInstances[dif].end();) + for (BoundInstancesMap::iterator itr = m_boundInstances[diff].begin(); itr != m_boundInstances[diff].end(); ) { InstanceSave *p = itr->second.save; const MapEntry *entry = sMapStore.LookupEntry(itr->first); - if(!entry || (!p->CanReset() && method != INSTANCE_RESET_GROUP_DISBAND)) + if(!entry || entry->IsRaid() != isRaid || !p->CanReset() && method != INSTANCE_RESET_GROUP_DISBAND) { ++itr; continue; @@ -1501,7 +1546,7 @@ void Group::ResetInstances(uint8 method, Player* SendMsgTo) if(method == INSTANCE_RESET_ALL) { // the "reset all instances" method can only reset normal maps - if(dif == DIFFICULTY_HEROIC || entry->map_type == MAP_RAID) + if (entry->map_type == MAP_RAID || diff == DUNGEON_DIFFICULTY_HEROIC) { ++itr; continue; @@ -1531,8 +1576,8 @@ void Group::ResetInstances(uint8 method, Player* SendMsgTo) if(p->CanReset()) p->DeleteFromDB(); else CharacterDatabase.PExecute("DELETE FROM group_instance WHERE instance = '%u'", p->GetInstanceId()); // i don't know for sure if hash_map iterators - m_boundInstances[dif].erase(itr); - itr = m_boundInstances[dif].begin(); + m_boundInstances[diff].erase(itr); + itr = m_boundInstances[diff].begin(); // this unloads the instance save unless online players are bound to it // (eg. permanent binds or GM solo binds) p->RemoveGroup(this); @@ -1542,11 +1587,19 @@ void Group::ResetInstances(uint8 method, Player* SendMsgTo) } } -InstanceGroupBind* Group::GetBoundInstance(uint32 mapid, uint8 difficulty) +InstanceGroupBind* Group::GetBoundInstance(Player* player) { + uint32 mapid = player->GetMapId(); + MapEntry const* mapEntry = sMapStore.LookupEntry(mapid); + if(!mapEntry) + return NULL; + + Difficulty difficulty = player->GetDifficulty(mapEntry->IsRaid()); + // some instances only have one difficulty - const MapEntry* entry = sMapStore.LookupEntry(mapid); - if(!entry || !entry->SupportsHeroicMode()) difficulty = DIFFICULTY_NORMAL; + MapDifficulty const* mapDiff = GetMapDifficultyData(mapid,difficulty); + if(!mapDiff) + difficulty = DUNGEON_DIFFICULTY_NORMAL; BoundInstancesMap::iterator itr = m_boundInstances[difficulty].find(mapid); if(itr != m_boundInstances[difficulty].end()) @@ -1555,6 +1608,24 @@ InstanceGroupBind* Group::GetBoundInstance(uint32 mapid, uint8 difficulty) return NULL; } +InstanceGroupBind* Group::GetBoundInstance(Map* aMap) +{ + // Currently spawn numbering not different from map difficulty + Difficulty difficulty = GetDifficulty(aMap->IsRaid()); + + // some instances only have one difficulty + MapDifficulty const* mapDiff = GetMapDifficultyData(aMap->GetId(),difficulty); + if(!mapDiff) + return NULL; + + BoundInstancesMap::iterator itr = m_boundInstances[difficulty].find(aMap->GetId()); + if(itr != m_boundInstances[difficulty].end()) + return &itr->second; + else + return NULL; +} + + InstanceGroupBind* Group::BindToInstance(InstanceSave *save, bool permanent, bool load) { if(save && !isBGGroup()) @@ -1624,4 +1695,3 @@ void Group::BroadcastGroupUpdate(void) } } } - diff --git a/src/game/Group.h b/src/game/Group.h index e38d39ecd7b..26c2ea878e6 100644 --- a/src/game/Group.h +++ b/src/game/Group.h @@ -25,6 +25,7 @@ #include "GroupRefManager.h" #include "BattleGround.h" #include "LootMgr.h" +#include "DBCEnums.h" #include <map> #include <vector> @@ -100,7 +101,7 @@ class Roll : public LootValidatorRef { public: Roll(uint64 _guid, LootItem const& li) - : itemGUID(_guid), itemid(li.itemid), itemRandomPropId(li.randomPropertyId), itemRandomSuffix(li.randomSuffix), + : itemGUID(_guid), itemid(li.itemid), itemRandomPropId(li.randomPropertyId), itemRandomSuffix(li.randomSuffix), itemCount(li.count), totalPlayersRolling(0), totalNeed(0), totalGreed(0), totalPass(0), itemSlot(0) {} ~Roll() { } void setLoot(Loot *pLoot) { link(pLoot, this); } @@ -111,6 +112,7 @@ class Roll : public LootValidatorRef uint32 itemid; int32 itemRandomPropId; uint32 itemRandomSuffix; + uint8 itemCount; typedef std::map<uint64, RollVote> PlayerVote; PlayerVote playerVote; //vote position correspond with player position (in group) uint8 totalPlayersRolling; @@ -281,11 +283,15 @@ class TRINITY_DLL_SPEC Group } void SetTargetIcon(uint8 id, uint64 guid); - void SetDifficulty(uint8 difficulty); - uint8 GetDifficulty() { return m_difficulty; } + + Difficulty GetDifficulty(bool isRaid) const { return isRaid ? m_raidDifficulty : m_dungeonDifficulty; } + Difficulty GetDungeonDifficulty() const { return m_dungeonDifficulty; } + Difficulty GetRaidDifficulty() const { return m_raidDifficulty; } + void SetDungeonDifficulty(Difficulty difficulty); + void SetRaidDifficulty(Difficulty difficulty); uint16 InInstance(); bool InCombatToInstance(uint32 instanceId); - void ResetInstances(uint8 method, Player* SendMsgTo); + void ResetInstances(uint8 method, bool isRaid, Player* SendMsgTo); // -no description- //void SendInit(WorldSession *session); @@ -329,8 +335,9 @@ class TRINITY_DLL_SPEC Group InstanceGroupBind* BindToInstance(InstanceSave *save, bool permanent, bool load = false); void UnbindInstance(uint32 mapid, uint8 difficulty, bool unload = false); - InstanceGroupBind* GetBoundInstance(uint32 mapid, uint8 difficulty); - BoundInstancesMap& GetBoundInstances(uint8 difficulty) { return m_boundInstances[difficulty]; } + InstanceGroupBind* GetBoundInstance(Player* player); + InstanceGroupBind* GetBoundInstance(Map* aMap); + BoundInstancesMap& GetBoundInstances(Difficulty difficulty) { return m_boundInstances[difficulty]; } // FG: evil hacks void BroadcastGroupUpdate(void); @@ -402,15 +409,15 @@ class TRINITY_DLL_SPEC Group uint64 m_mainTank; uint64 m_mainAssistant; GroupType m_groupType; - uint8 m_difficulty; + Difficulty m_dungeonDifficulty; + Difficulty m_raidDifficulty; BattleGround* m_bgGroup; uint64 m_targetIcons[TARGETICONCOUNT]; LootMethod m_lootMethod; ItemQualities m_lootThreshold; uint64 m_looterGuid; Rolls RollId; - BoundInstancesMap m_boundInstances[TOTAL_DIFFICULTIES]; + BoundInstancesMap m_boundInstances[MAX_DIFFICULTY]; uint8* m_subGroupsCounts; }; #endif - diff --git a/src/game/GroupHandler.cpp b/src/game/GroupHandler.cpp index fab192bbedc..f8bdc008e51 100644 --- a/src/game/GroupHandler.cpp +++ b/src/game/GroupHandler.cpp @@ -96,7 +96,7 @@ void WorldSession::HandleGroupInviteOpcode( WorldPacket & recv_data ) return; } // just ignore us - if(player->GetInstanceId() != 0 && player->GetDifficulty() != GetPlayer()->GetDifficulty()) + if(player->GetInstanceId() != 0 && player->GetDungeonDifficulty() != GetPlayer()->GetDungeonDifficulty()) { SendPartyResult(PARTY_OP_INVITE, membername, PARTY_RESULT_TARGET_IGNORE_YOU); return; @@ -386,10 +386,10 @@ void WorldSession::HandleLootRoll( WorldPacket &recv_data ) uint64 Guid; uint32 NumberOfPlayers; - uint8 Choise; + uint8 rollType; recv_data >> Guid; //guid of the item rolled recv_data >> NumberOfPlayers; - recv_data >> Choise; //0: pass, 1: need, 2: greed + recv_data >> rollType; //0: pass, 1: need, 2: greed //sLog.outDebug("WORLD RECIEVE CMSG_LOOT_ROLL, From:%u, Numberofplayers:%u, Choise:%u", (uint32)Guid, NumberOfPlayers, Choise); @@ -398,14 +398,14 @@ void WorldSession::HandleLootRoll( WorldPacket &recv_data ) return; // everything's fine, do it - group->CountRollVote(GetPlayer()->GetGUID(), Guid, NumberOfPlayers, Choise); + group->CountRollVote(GetPlayer()->GetGUID(), Guid, NumberOfPlayers, rollType); - switch (Choise) + switch (rollType) { - case 1: + case ROLL_NEED: GetPlayer()->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_ROLL_NEED, 1); break; - case 2: + case ROLL_GREED: GetPlayer()->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_ROLL_GREED, 1); break; } @@ -919,4 +919,3 @@ void WorldSession::HandleOptOutOfLootOpcode( WorldPacket & recv_data ) if(unkn!=0) sLog.outError("CMSG_GROUP_PASS_ON_LOOT: activation not implemented!"); } - diff --git a/src/game/Guild.cpp b/src/game/Guild.cpp index 5e1e1409039..76c93a07956 100644 --- a/src/game/Guild.cpp +++ b/src/game/Guild.cpp @@ -953,15 +953,13 @@ void Guild::LogGuildEvent(uint8 EventType, uint32 PlayerGuid1, uint32 PlayerGuid // Bank content related void Guild::DisplayGuildBankContent(WorldSession *session, uint8 TabId) { - WorldPacket data(SMSG_GUILD_BANK_LIST, 1300); - - GuildBankTab const* tab = GetBankTab(TabId); - if (!tab) - return; + GuildBankTab const* tab = m_TabListMap[TabId]; if (!IsMemberHaveRights(session->GetPlayer()->GetGUIDLow(),TabId,GUILD_BANK_RIGHT_VIEW_TAB)) return; + WorldPacket data(SMSG_GUILD_BANK_LIST,1200); + data << uint64(GetGuildBankMoney()); data << uint8(TabId); data << uint32(GetMemberSlotWithdrawRem(session->GetPlayer()->GetGUIDLow(), TabId)); // remaining slots for today @@ -979,9 +977,7 @@ void Guild::DisplayGuildBankContent(WorldSession *session, uint8 TabId) void Guild::DisplayGuildBankContentUpdate(uint8 TabId, int32 slot1, int32 slot2) { - GuildBankTab const* tab = GetBankTab(TabId); - if (!tab) - return; + GuildBankTab const* tab = m_TabListMap[TabId]; WorldPacket data(SMSG_GUILD_BANK_LIST,1200); @@ -1029,9 +1025,7 @@ void Guild::DisplayGuildBankContentUpdate(uint8 TabId, int32 slot1, int32 slot2) void Guild::DisplayGuildBankContentUpdate(uint8 TabId, GuildItemPosCountVec const& slots) { - GuildBankTab const* tab = GetBankTab(TabId); - if (!tab) - return; + GuildBankTab const* tab = m_TabListMap[TabId]; WorldPacket data(SMSG_GUILD_BANK_LIST,1200); @@ -1101,6 +1095,20 @@ void Guild::DisplayGuildBankTabsInfo(WorldSession *session) sLog.outDebug("WORLD: Sent (SMSG_GUILD_BANK_LIST)"); } +void Guild::DisplayGuildBankMoneyUpdate() +{ + WorldPacket data(SMSG_GUILD_BANK_LIST, 8+1+4+1+1); + + data << uint64(GetGuildBankMoney()); + data << uint8(0); // TabId, default 0 + data << uint32(0); // slot withdrow, default 0 + data << uint8(0); // Tell client this is a tab content packet + data << uint8(0); // not send items + BroadcastPacket(&data); + + sLog.outDebug("WORLD: Sent (SMSG_GUILD_BANK_LIST)"); +} + void Guild::CreateNewBankTab() { if (m_PurchasedTabs >= GUILD_BANK_MAX_TABS) @@ -1121,14 +1129,6 @@ void Guild::CreateNewBankTab() void Guild::SetGuildBankTabInfo(uint8 TabId, std::string Name, std::string Icon) { - if (TabId >= GUILD_BANK_MAX_TABS) - return; - if (TabId >= m_TabListMap.size()) - return; - - if (!m_TabListMap[TabId]) - return; - if (m_TabListMap[TabId]->Name == Name && m_TabListMap[TabId]->Icon == Icon) return; @@ -1572,7 +1572,7 @@ void Guild::UnloadGuildBankEventLog() void Guild::DisplayGuildBankLogs(WorldSession *session, uint8 TabId) { - if (TabId > GUILD_BANK_MAX_TABS) + if (TabId >= GUILD_BANK_MAX_TABS) // tabs starts in 0 return; if (TabId == GUILD_BANK_MAX_TABS) @@ -1739,7 +1739,7 @@ Item* Guild::StoreItem(uint8 tabId, GuildItemPosCountVec const& dest, Item* pIte return lastItem; } -// Return stored item (if stored to stack, it can diff. from pItem). And pItem can be deleted in this case. +// Return stored item (if stored to stack, it can diff. from pItem). And pItem ca be deleted in this case. Item* Guild::_StoreItem( uint8 tab, uint8 slot, Item *pItem, uint32 count, bool clone ) { if (!pItem) @@ -1765,15 +1765,15 @@ Item* Guild::_StoreItem( uint8 tab, uint8 slot, Item *pItem, uint32 count, bool pItem->SetUInt64Value(ITEM_FIELD_OWNER, 0); AddGBankItemToDB(GetId(), tab, slot, pItem->GetGUIDLow(), pItem->GetEntry()); pItem->FSetState(ITEM_NEW); - pItem->SaveToDB(); // not in inventory and can be save standalone + pItem->SaveToDB(); // not in onventory and can be save standalone return pItem; } else { - pItem2->SetCount(pItem2->GetCount() + count); + pItem2->SetCount( pItem2->GetCount() + count ); pItem2->FSetState(ITEM_CHANGED); - pItem2->SaveToDB(); // not in inventory and can be save standalone + pItem2->SaveToDB(); // not in onventory and can be save standalone if (!clone) { @@ -1968,12 +1968,7 @@ void Guild::SetGuildBankTabText(uint8 TabId, std::string text) void Guild::SendGuildBankTabText(WorldSession *session, uint8 TabId) { - if (TabId >= GUILD_BANK_MAX_TABS) // tabs starts in 0 - return; - - GuildBankTab const *tab = GetBankTab(TabId); - if (!tab) - return; + GuildBankTab const* tab = m_TabListMap[TabId]; WorldPacket data(MSG_QUERY_GUILD_BANK_TEXT, 1+tab->Text.size()+1); data << uint8(TabId); @@ -1999,7 +1994,7 @@ void Guild::SwapItems(Player * pl, uint8 BankTab, uint8 BankTabSlot, uint8 BankT { sLog.outCrash("Guild::SwapItems: Player %s(GUIDLow: %u) tried to move item %u from tab %u slot %u to tab %u slot %u, but item %u has a stack of zero!", pl->GetName(), pl->GetGUIDLow(), pItemSrc->GetEntry(), BankTab, BankTabSlot, BankTabDst, BankTabSlotDst, pItemSrc->GetEntry()); - //return; // Commented out for now, uncomment when it's verified that this causes a crash! + //return; // Commented out for now, uncomment when it's verified that this causes a crash!! } if (SplitedAmount >= pItemSrc->GetCount()) diff --git a/src/game/Guild.h b/src/game/Guild.h index f3626942bfc..9e7c2ed9941 100644 --- a/src/game/Guild.h +++ b/src/game/Guild.h @@ -389,6 +389,7 @@ class Guild // ** Guild bank ** // Content & item deposit/withdraw void DisplayGuildBankContent(WorldSession *session, uint8 TabId); + void DisplayGuildBankMoneyUpdate(); void SwapItems( Player * pl, uint8 BankTab, uint8 BankTabSlot, uint8 BankTabDst, uint8 BankTabSlotDst, uint32 SplitedAmount); void MoveFromBankToChar( Player * pl, uint8 BankTab, uint8 BankTabSlot, uint8 PlayerBag, uint8 PlayerSlot, uint32 SplitedAmount); @@ -400,7 +401,6 @@ class Guild void SetGuildBankTabText(uint8 TabId, std::string text); void SendGuildBankTabText(WorldSession *session, uint8 TabId); void SetGuildBankTabInfo(uint8 TabId, std::string name, std::string icon); - const GuildBankTab *GetBankTab(uint8 index) { if(index >= m_TabListMap.size()) return NULL; return m_TabListMap[index]; } const uint8 GetPurchasedTabs() const { return m_PurchasedTabs; } uint32 GetBankRights(uint32 rankId, uint8 TabId) const; bool IsMemberHaveRights(uint32 LowGuid, uint8 TabId,uint32 rights) const; @@ -408,6 +408,7 @@ class Guild // Load/unload void LoadGuildBankFromDB(); void UnloadGuildBank(); + bool IsGuildBankLoaded() const { return m_GuildBankLoaded; } void IncOnlineMemberCount() { ++m_OnlineMembers; } // Money deposit/withdraw void SendMoneyInfo(WorldSession *session, uint32 LowGuid); @@ -489,4 +490,3 @@ class Guild Item* _StoreItem( uint8 tab, uint8 slot, Item *pItem, uint32 count, bool clone ); }; #endif - diff --git a/src/game/GuildHandler.cpp b/src/game/GuildHandler.cpp index 80f5d124e94..e69a55d4024 100644 --- a/src/game/GuildHandler.cpp +++ b/src/game/GuildHandler.cpp @@ -31,36 +31,32 @@ void WorldSession::HandleGuildQueryOpcode(WorldPacket& recvPacket) { - uint32 guildId; - Guild *guild; - - //sLog.outDebug("WORLD: Received CMSG_GUILD_QUERY"); + sLog.outDebug("WORLD: Received CMSG_GUILD_QUERY"); + uint32 guildId; recvPacket >> guildId; - guild = objmgr.GetGuildById(guildId); - if(!guild) + if(Guild *guild = objmgr.GetGuildById(guildId)) { - SendGuildCommandResult(GUILD_CREATE_S, "", GUILD_PLAYER_NOT_IN_GUILD); + guild->Query(this); return; } - guild->Query(this); + SendGuildCommandResult(GUILD_CREATE_S, "", GUILD_PLAYER_NOT_IN_GUILD); } void WorldSession::HandleGuildCreateOpcode(WorldPacket& recvPacket) { - std::string gname; - - //sLog.outDebug("WORLD: Received CMSG_GUILD_CREATE"); + sLog.outDebug("WORLD: Received CMSG_GUILD_CREATE"); + std::string gname; recvPacket >> gname; - if(GetPlayer()->GetGuildId()) + if(GetPlayer()->GetGuildId()) // already in guild return; Guild *guild = new Guild; - if(!guild->Create(GetPlayer(),gname)) + if(!guild->Create(GetPlayer(), gname)) { delete guild; return; @@ -71,12 +67,11 @@ void WorldSession::HandleGuildCreateOpcode(WorldPacket& recvPacket) void WorldSession::HandleGuildInviteOpcode(WorldPacket& recvPacket) { - std::string Invitedname, plname; + sLog.outDebug("WORLD: Received CMSG_GUILD_INVITE"); - //sLog.outDebug("WORLD: Received CMSG_GUILD_INVITE"); + std::string Invitedname, plname; Player * player = NULL; - recvPacket >> Invitedname; if(normalizePlayerName(Invitedname)) @@ -137,15 +132,14 @@ void WorldSession::HandleGuildInviteOpcode(WorldPacket& recvPacket) data << guild->GetName(); player->GetSession()->SendPacket(&data); - //sLog.outDebug("WORLD: Sent (SMSG_GUILD_INVITE)"); + sLog.outDebug("WORLD: Sent (SMSG_GUILD_INVITE)"); } void WorldSession::HandleGuildRemoveOpcode(WorldPacket& recvPacket) { - std::string plName; - - //sLog.outDebug("WORLD: Received CMSG_GUILD_REMOVE"); + sLog.outDebug("WORLD: Received CMSG_GUILD_REMOVE"); + std::string plName; recvPacket >> plName; if(!normalizePlayerName(plName)) @@ -202,7 +196,7 @@ void WorldSession::HandleGuildAcceptOpcode(WorldPacket& /*recvPacket*/) Guild *guild; Player *player = GetPlayer(); - //sLog.outDebug("WORLD: Received CMSG_GUILD_ACCEPT"); + sLog.outDebug("WORLD: Received CMSG_GUILD_ACCEPT"); guild = objmgr.GetGuildById(player->GetGuildIdInvited()); if(!guild || player->GetGuildId()) @@ -223,12 +217,12 @@ void WorldSession::HandleGuildAcceptOpcode(WorldPacket& /*recvPacket*/) data << player->GetName(); guild->BroadcastPacket(&data); - //sLog.outDebug("WORLD: Sent (SMSG_GUILD_EVENT)"); + sLog.outDebug("WORLD: Sent (SMSG_GUILD_EVENT)"); } void WorldSession::HandleGuildDeclineOpcode(WorldPacket& /*recvPacket*/) { - //sLog.outDebug("WORLD: Received CMSG_GUILD_DECLINE"); + sLog.outDebug("WORLD: Received CMSG_GUILD_DECLINE"); GetPlayer()->SetGuildIdInvited(0); GetPlayer()->SetInGuild(0); @@ -237,7 +231,7 @@ void WorldSession::HandleGuildDeclineOpcode(WorldPacket& /*recvPacket*/) void WorldSession::HandleGuildInfoOpcode(WorldPacket& /*recvPacket*/) { Guild *guild; - //sLog.outDebug("WORLD: Received CMSG_GUILD_INFO"); + sLog.outDebug("WORLD: Received CMSG_GUILD_INFO"); guild = objmgr.GetGuildById(GetPlayer()->GetGuildId()); if(!guild) @@ -259,21 +253,17 @@ void WorldSession::HandleGuildInfoOpcode(WorldPacket& /*recvPacket*/) void WorldSession::HandleGuildRosterOpcode(WorldPacket& /*recvPacket*/) { - //sLog.outDebug("WORLD: Received CMSG_GUILD_ROSTER"); - - Guild* guild = objmgr.GetGuildById(GetPlayer()->GetGuildId()); - if(!guild) - return; + sLog.outDebug("WORLD: Received CMSG_GUILD_ROSTER"); - guild->Roster(this); + if(Guild* guild = objmgr.GetGuildById(_player->GetGuildId())) + guild->Roster(this); } void WorldSession::HandleGuildPromoteOpcode(WorldPacket& recvPacket) { - std::string plName; - - //sLog.outDebug("WORLD: Received CMSG_GUILD_PROMOTE"); + sLog.outDebug("WORLD: Received CMSG_GUILD_PROMOTE"); + std::string plName; recvPacket >> plName; if(!normalizePlayerName(plName)) @@ -285,6 +275,7 @@ void WorldSession::HandleGuildPromoteOpcode(WorldPacket& recvPacket) SendGuildCommandResult(GUILD_CREATE_S, "", GUILD_PLAYER_NOT_IN_GUILD); return; } + if(!guild->HasRankRight(GetPlayer()->GetRank(), GR_RIGHT_PROMOTE)) { SendGuildCommandResult(GUILD_INVITE_S, "", GUILD_PERMISSIONS); @@ -332,10 +323,9 @@ void WorldSession::HandleGuildPromoteOpcode(WorldPacket& recvPacket) void WorldSession::HandleGuildDemoteOpcode(WorldPacket& recvPacket) { - std::string plName; - - //sLog.outDebug("WORLD: Received CMSG_GUILD_DEMOTE"); + sLog.outDebug("WORLD: Received CMSG_GUILD_DEMOTE"); + std::string plName; recvPacket >> plName; if(!normalizePlayerName(plName)) @@ -401,17 +391,15 @@ void WorldSession::HandleGuildDemoteOpcode(WorldPacket& recvPacket) void WorldSession::HandleGuildLeaveOpcode(WorldPacket& /*recvPacket*/) { - std::string plName; - Guild *guild; + sLog.outDebug("WORLD: Received CMSG_GUILD_LEAVE"); - //sLog.outDebug("WORLD: Received CMSG_GUILD_LEAVE"); - - guild = objmgr.GetGuildById(_player->GetGuildId()); + Guild *guild = objmgr.GetGuildById(_player->GetGuildId()); if(!guild) { SendGuildCommandResult(GUILD_CREATE_S, "", GUILD_PLAYER_NOT_IN_GUILD); return; } + if(_player->GetGUID() == guild->GetLeader() && guild->GetMemberSize() > 1) { SendGuildCommandResult(GUILD_QUIT_S, "", GUILD_LEADER_LEAVE); @@ -424,8 +412,6 @@ void WorldSession::HandleGuildLeaveOpcode(WorldPacket& /*recvPacket*/) return; } - plName = _player->GetName(); - guild->DelMember(_player->GetGUID()); // Put record into guildlog guild->LogGuildEvent(GUILD_EVENT_LOG_LEAVE_GUILD, _player->GetGUIDLow(), 0, 0); @@ -433,27 +419,25 @@ void WorldSession::HandleGuildLeaveOpcode(WorldPacket& /*recvPacket*/) WorldPacket data(SMSG_GUILD_EVENT, (2+10)); // guess size data << (uint8)GE_LEFT; data << (uint8)1; // strings count - data << plName; + data << _player->GetName(); guild->BroadcastPacket(&data); - //sLog.outDebug("WORLD: Sent (SMSG_GUILD_EVENT)"); + sLog.outDebug("WORLD: Sent (SMSG_GUILD_EVENT)"); SendGuildCommandResult(GUILD_QUIT_S, guild->GetName(), GUILD_PLAYER_NO_MORE_IN_GUILD); } void WorldSession::HandleGuildDisbandOpcode(WorldPacket& /*recvPacket*/) { - std::string name; - Guild *guild; - - //sLog.outDebug("WORLD: Received CMSG_GUILD_DISBAND"); + sLog.outDebug("WORLD: Received CMSG_GUILD_DISBAND"); - guild = objmgr.GetGuildById(GetPlayer()->GetGuildId()); + Guild *guild = objmgr.GetGuildById(GetPlayer()->GetGuildId()); if(!guild) { SendGuildCommandResult(GUILD_CREATE_S, "", GUILD_PLAYER_NOT_IN_GUILD); return; } + if(GetPlayer()->GetGUID() != guild->GetLeader()) { SendGuildCommandResult(GUILD_INVITE_S, "", GUILD_PERMISSIONS); @@ -462,23 +446,22 @@ void WorldSession::HandleGuildDisbandOpcode(WorldPacket& /*recvPacket*/) guild->Disband(); - //sLog.outDebug("WORLD: Guild Sucefully Disbanded"); + sLog.outDebug("WORLD: Guild Successfully Disbanded"); } void WorldSession::HandleGuildLeaderOpcode(WorldPacket& recvPacket) { - std::string name; - Player *oldLeader = GetPlayer(); - Guild *guild; - - //sLog.outDebug("WORLD: Received CMSG_GUILD_LEADER"); + sLog.outDebug("WORLD: Received CMSG_GUILD_LEADER"); + std::string name; recvPacket >> name; + Player *oldLeader = GetPlayer(); + if(!normalizePlayerName(name)) return; - guild = objmgr.GetGuildById(oldLeader->GetGuildId()); + Guild *guild = objmgr.GetGuildById(oldLeader->GetGuildId()); if (!guild) { @@ -516,28 +499,28 @@ void WorldSession::HandleGuildLeaderOpcode(WorldPacket& recvPacket) void WorldSession::HandleGuildMOTDOpcode(WorldPacket& recvPacket) { - Guild *guild; + sLog.outDebug("WORLD: Received CMSG_GUILD_MOTD"); + std::string MOTD; - //sLog.outDebug("WORLD: Received CMSG_GUILD_MOTD"); + if(!recvPacket.empty()) + recvPacket >> MOTD; + else + MOTD = ""; - guild = objmgr.GetGuildById(GetPlayer()->GetGuildId()); + Guild *guild = objmgr.GetGuildById(GetPlayer()->GetGuildId()); if(!guild) { SendGuildCommandResult(GUILD_CREATE_S, "", GUILD_PLAYER_NOT_IN_GUILD); return; } + if(!guild->HasRankRight(GetPlayer()->GetRank(), GR_RIGHT_SETMOTD)) { SendGuildCommandResult(GUILD_INVITE_S, "", GUILD_PERMISSIONS); return; } - if(!recvPacket.empty()) - recvPacket >> MOTD; - else - MOTD = ""; - guild->SetMOTD(MOTD); WorldPacket data(SMSG_GUILD_EVENT, (2+MOTD.size()+1)); @@ -546,15 +529,14 @@ void WorldSession::HandleGuildMOTDOpcode(WorldPacket& recvPacket) data << MOTD; guild->BroadcastPacket(&data); - //sLog.outDebug("WORLD: Sent (SMSG_GUILD_EVENT)"); + sLog.outDebug("WORLD: Sent (SMSG_GUILD_EVENT)"); } void WorldSession::HandleGuildSetPublicNoteOpcode(WorldPacket& recvPacket) { - std::string name,PNOTE; - - //sLog.outDebug("WORLD: Received CMSG_GUILD_SET_PUBLIC_NOTE"); + sLog.outDebug("WORLD: Received CMSG_GUILD_SET_PUBLIC_NOTE"); + std::string name,PNOTE; recvPacket >> name; if(!normalizePlayerName(name)) @@ -590,10 +572,9 @@ void WorldSession::HandleGuildSetPublicNoteOpcode(WorldPacket& recvPacket) void WorldSession::HandleGuildSetOfficerNoteOpcode(WorldPacket& recvPacket) { - std::string plName, OFFNOTE; - - //sLog.outDebug("WORLD: Received CMSG_GUILD_SET_OFFICER_NOTE"); + sLog.outDebug("WORLD: Received CMSG_GUILD_SET_OFFICER_NOTE"); + std::string plName, OFFNOTE; recvPacket >> plName; if(!normalizePlayerName(plName)) @@ -605,6 +586,7 @@ void WorldSession::HandleGuildSetOfficerNoteOpcode(WorldPacket& recvPacket) SendGuildCommandResult(GUILD_CREATE_S, "", GUILD_PLAYER_NOT_IN_GUILD); return; } + if (!guild->HasRankRight(GetPlayer()->GetRank(), GR_RIGHT_EOFFNOTE)) { SendGuildCommandResult(GUILD_INVITE_S, "", GUILD_PERMISSIONS); @@ -628,23 +610,19 @@ void WorldSession::HandleGuildSetOfficerNoteOpcode(WorldPacket& recvPacket) void WorldSession::HandleGuildRankOpcode(WorldPacket& recvPacket) { - //recvPacket.hexlike(); - - Guild *guild; std::string rankname; uint32 rankId; uint32 rights, MoneyPerDay; - //sLog.outDebug("WORLD: Received CMSG_GUILD_RANK"); + sLog.outDebug("WORLD: Received CMSG_GUILD_RANK"); - guild = objmgr.GetGuildById(GetPlayer()->GetGuildId()); + Guild *guild = objmgr.GetGuildById(GetPlayer()->GetGuildId()); if(!guild) { recvPacket.rpos(recvPacket.wpos()); // set to end to avoid warnings spam SendGuildCommandResult(GUILD_CREATE_S, "", GUILD_PLAYER_NOT_IN_GUILD); return; } - else if(GetPlayer()->GetGUID() != guild->GetLeader()) { recvPacket.rpos(recvPacket.wpos()); // set to end to avoid warnings spam @@ -683,12 +661,12 @@ void WorldSession::HandleGuildRankOpcode(WorldPacket& recvPacket) void WorldSession::HandleGuildAddRankOpcode(WorldPacket& recvPacket) { - Guild *guild; - std::string rankname; + sLog.outDebug("WORLD: Received CMSG_GUILD_ADD_RANK"); - //sLog.outDebug("WORLD: Received CMSG_GUILD_ADD_RANK"); + std::string rankname; + recvPacket >> rankname; - guild = objmgr.GetGuildById(GetPlayer()->GetGuildId()); + Guild *guild = objmgr.GetGuildById(GetPlayer()->GetGuildId()); if(!guild) { SendGuildCommandResult(GUILD_CREATE_S, "", GUILD_PLAYER_NOT_IN_GUILD); @@ -704,8 +682,6 @@ void WorldSession::HandleGuildAddRankOpcode(WorldPacket& recvPacket) if(guild->GetRanksSize() >= GUILD_RANKS_MAX_COUNT) // client not let create more 10 than ranks return; - recvPacket >> rankname; - guild->CreateRank(rankname, GR_RIGHT_GCHATLISTEN | GR_RIGHT_GCHATSPEAK); guild->Query(this); @@ -714,18 +690,14 @@ void WorldSession::HandleGuildAddRankOpcode(WorldPacket& recvPacket) void WorldSession::HandleGuildDelRankOpcode(WorldPacket& /*recvPacket*/) { - Guild *guild; - std::string rankname; + sLog.outDebug("WORLD: Received CMSG_GUILD_DEL_RANK"); - //sLog.outDebug("WORLD: Received CMSG_GUILD_DEL_RANK"); - - guild = objmgr.GetGuildById(GetPlayer()->GetGuildId()); + Guild *guild = objmgr.GetGuildById(GetPlayer()->GetGuildId()); if(!guild) { SendGuildCommandResult(GUILD_CREATE_S, "", GUILD_PLAYER_NOT_IN_GUILD); return; } - else if(GetPlayer()->GetGUID() != guild->GetLeader()) { SendGuildCommandResult(GUILD_INVITE_S, "", GUILD_PERMISSIONS); @@ -746,12 +718,12 @@ void WorldSession::SendGuildCommandResult(uint32 typecmd, const std::string& str data << cmdresult; SendPacket(&data); - //sLog.outDebug("WORLD: Sent (SMSG_GUILD_COMMAND_RESULT)"); + sLog.outDebug("WORLD: Sent (SMSG_GUILD_COMMAND_RESULT)"); } void WorldSession::HandleGuildChangeInfoTextOpcode(WorldPacket& recvPacket) { - //sLog.outDebug("WORLD: Received CMSG_GUILD_INFO_TEXT"); + sLog.outDebug("WORLD: Received CMSG_GUILD_INFO_TEXT"); std::string GINFO; @@ -775,17 +747,14 @@ void WorldSession::HandleGuildChangeInfoTextOpcode(WorldPacket& recvPacket) void WorldSession::HandleSaveGuildEmblemOpcode(WorldPacket& recvPacket) { - //sLog.outDebug("WORLD: Received MSG_SAVE_GUILD_EMBLEM"); + sLog.outDebug("WORLD: Received MSG_SAVE_GUILD_EMBLEM"); uint64 vendorGuid; - uint32 EmblemStyle; - uint32 EmblemColor; - uint32 BorderStyle; - uint32 BorderColor; - uint32 BackgroundColor; + uint32 EmblemStyle, EmblemColor, BorderStyle, BorderColor, BackgroundColor; recvPacket >> vendorGuid; + recvPacket >> EmblemStyle >> EmblemColor >> BorderStyle >> BorderColor >> BackgroundColor; Creature *pCreature = GetPlayer()->GetNPCIfCanInteractWith(vendorGuid,UNIT_NPC_FLAG_TABARDDESIGNER); if (!pCreature) @@ -800,12 +769,6 @@ void WorldSession::HandleSaveGuildEmblemOpcode(WorldPacket& recvPacket) if(GetPlayer()->hasUnitState(UNIT_STAT_DIED)) GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); - recvPacket >> EmblemStyle; - recvPacket >> EmblemColor; - recvPacket >> BorderStyle; - recvPacket >> BorderColor; - recvPacket >> BackgroundColor; - Guild *guild = objmgr.GetGuildById(GetPlayer()->GetGuildId()); if(!guild) { @@ -841,17 +804,9 @@ void WorldSession::HandleGuildEventLogQueryOpcode(WorldPacket& /* recvPacket */) { // empty sLog.outDebug("WORLD: Received (MSG_GUILD_EVENT_LOG_QUERY)"); - //recvPacket.hexlike(); - - uint32 GuildId = GetPlayer()->GetGuildId(); - if (GuildId == 0) - return; - - Guild *pGuild = objmgr.GetGuildById(GuildId); - if(!pGuild) - return; - - pGuild->DisplayGuildEventLog(this); + if(uint32 GuildId = GetPlayer()->GetGuildId()) + if(Guild *pGuild = objmgr.GetGuildById(GuildId)) + pGuild->DisplayGuildEventLog(this); } /****** GUILD BANK *******/ @@ -859,53 +814,44 @@ void WorldSession::HandleGuildEventLogQueryOpcode(WorldPacket& /* recvPacket */) void WorldSession::HandleGuildBankMoneyWithdrawn( WorldPacket & /* recv_data */ ) { sLog.outDebug("WORLD: Received (MSG_GUILD_BANK_MONEY_WITHDRAWN)"); - //recv_data.hexlike(); - - uint32 GuildId = GetPlayer()->GetGuildId(); - if (GuildId == 0) - return; - - Guild *pGuild = objmgr.GetGuildById(GuildId); - if(!pGuild) - return; - - pGuild->SendMoneyInfo(this, GetPlayer()->GetGUIDLow()); + if(uint32 GuildId = GetPlayer()->GetGuildId()) + if(Guild *pGuild = objmgr.GetGuildById(GuildId)) + pGuild->SendMoneyInfo(this, GetPlayer()->GetGUIDLow()); } void WorldSession::HandleGuildPermissions( WorldPacket& /* recv_data */ ) { sLog.outDebug("WORLD: Received (MSG_GUILD_PERMISSIONS)"); - uint32 GuildId = GetPlayer()->GetGuildId(); - if (GuildId == 0) - return; - - Guild *pGuild = objmgr.GetGuildById(GuildId); - if(!pGuild) - return; - - uint32 rankId = GetPlayer()->GetRank(); - - WorldPacket data(MSG_GUILD_PERMISSIONS, 4*15+1); - data << uint32(rankId); // guild rank id - data << uint32(pGuild->GetRankRights(rankId)); // rank rights - // money per day left - data << uint32(pGuild->GetMemberMoneyWithdrawRem(GetPlayer()->GetGUIDLow())); - data << uint8(pGuild->GetPurchasedTabs()); // tabs count - // why sending all info when not all tabs are purchased??? - for (int i = 0; i < GUILD_BANK_MAX_TABS; ++i) + if(uint32 GuildId = GetPlayer()->GetGuildId()) { - data << uint32(pGuild->GetBankRights(rankId, uint8(i))); - data << uint32(pGuild->GetMemberSlotWithdrawRem(GetPlayer()->GetGUIDLow(), uint8(i))); + if(Guild *pGuild = objmgr.GetGuildById(GuildId)) + { + uint32 rankId = GetPlayer()->GetRank(); + + WorldPacket data(MSG_GUILD_PERMISSIONS, 4*15+1); + data << uint32(rankId); // guild rank id + data << uint32(pGuild->GetRankRights(rankId)); // rank rights + // money per day left + data << uint32(pGuild->GetMemberMoneyWithdrawRem(GetPlayer()->GetGUIDLow())); + data << uint8(pGuild->GetPurchasedTabs()); // tabs count + // why sending all info when not all tabs are purchased??? + for (int i = 0; i < GUILD_BANK_MAX_TABS; ++i) + { + data << uint32(pGuild->GetBankRights(rankId, uint8(i))); + data << uint32(pGuild->GetMemberSlotWithdrawRem(GetPlayer()->GetGUIDLow(), uint8(i))); + } + SendPacket(&data); + sLog.outDebug("WORLD: Sent (MSG_GUILD_PERMISSIONS)"); + } } - SendPacket(&data); - sLog.outDebug("WORLD: Sent (MSG_GUILD_PERMISSIONS)"); } /* Called when clicking on Guild bank gameobject */ void WorldSession::HandleGuildBankerActivate( WorldPacket & recv_data ) { sLog.outDebug("WORLD: Received (CMSG_GUILD_BANKER_ACTIVATE)"); + uint64 GoGuid; uint8 unk; recv_data >> GoGuid >> unk; @@ -917,7 +863,7 @@ void WorldSession::HandleGuildBankerActivate( WorldPacket & recv_data ) { if(Guild *pGuild = objmgr.GetGuildById(GuildId)) { - pGuild->DisplayGuildBankTabsInfo(this); + pGuild->DisplayGuildBankTabsInfo(this); // this also will load guild bank if not yet return; } } @@ -929,31 +875,35 @@ void WorldSession::HandleGuildBankerActivate( WorldPacket & recv_data ) void WorldSession::HandleGuildBankQueryTab( WorldPacket & recv_data ) { sLog.outDebug("WORLD: Received (CMSG_GUILD_BANK_QUERY_TAB)"); + uint64 GoGuid; - uint8 TabId,unk1; + uint8 TabId, unk1; recv_data >> GoGuid >> TabId >> unk1; if (!GetPlayer()->GetGameObjectIfCanInteractWith(GoGuid, GAMEOBJECT_TYPE_GUILD_BANK)) return; uint32 GuildId = GetPlayer()->GetGuildId(); - if (GuildId == 0) + if (!GuildId) return; Guild *pGuild = objmgr.GetGuildById(GuildId); - if(!pGuild) + if (!pGuild) + return; + + if (!pGuild->IsGuildBankLoaded() || TabId >= pGuild->GetPurchasedTabs()) return; // Let's update the amount of gold the player can withdraw before displaying the content - // This is usefull if money withdraw right has changed + // This is useful if money withdraw right has changed pGuild->SendMoneyInfo(this, GetPlayer()->GetGUIDLow()); - pGuild->DisplayGuildBankContent(this, TabId); } void WorldSession::HandleGuildBankDepositMoney( WorldPacket & recv_data ) { sLog.outDebug("WORLD: Received (CMSG_GUILD_BANK_DEPOSIT_MONEY)"); + uint64 GoGuid; uint32 money; recv_data >> GoGuid >> money; @@ -964,15 +914,18 @@ void WorldSession::HandleGuildBankDepositMoney( WorldPacket & recv_data ) if (!GetPlayer()->GetGameObjectIfCanInteractWith(GoGuid, GAMEOBJECT_TYPE_GUILD_BANK)) return; + if (GetPlayer()->GetMoney() < money) + return; + uint32 GuildId = GetPlayer()->GetGuildId(); - if (GuildId == 0) + if (!GuildId) return; Guild *pGuild = objmgr.GetGuildById(GuildId); - if(!pGuild) + if (!pGuild) return; - if (GetPlayer()->GetMoney() < money) + if (!pGuild->IsGuildBankLoaded() || !pGuild->GetPurchasedTabs()) return; CharacterDatabase.BeginTransaction(); @@ -995,11 +948,13 @@ void WorldSession::HandleGuildBankDepositMoney( WorldPacket & recv_data ) pGuild->DisplayGuildBankTabsInfo(this); pGuild->DisplayGuildBankContent(this, 0); + pGuild->DisplayGuildBankMoneyUpdate(); } void WorldSession::HandleGuildBankWithdrawMoney( WorldPacket & recv_data ) { sLog.outDebug("WORLD: Received (CMSG_GUILD_BANK_WITHDRAW_MONEY)"); + uint64 GoGuid; uint32 money; recv_data >> GoGuid >> money; @@ -1018,6 +973,9 @@ void WorldSession::HandleGuildBankWithdrawMoney( WorldPacket & recv_data ) if(!pGuild) return; + if (!pGuild->IsGuildBankLoaded() || !pGuild->GetPurchasedTabs()) + return; + if (pGuild->GetGuildBankMoney()<money) // not enough money in bank return; @@ -1043,12 +1001,12 @@ void WorldSession::HandleGuildBankWithdrawMoney( WorldPacket & recv_data ) pGuild->SendMoneyInfo(this, GetPlayer()->GetGUIDLow()); pGuild->DisplayGuildBankTabsInfo(this); pGuild->DisplayGuildBankContent(this,0); + pGuild->DisplayGuildBankMoneyUpdate(); } void WorldSession::HandleGuildBankSwapItems( WorldPacket & recv_data ) { sLog.outDebug("WORLD: Received (CMSG_GUILD_BANK_SWAP_ITEMS)"); - //recv_data.hexlike(); uint64 GoGuid; uint8 BankToBank; @@ -1063,6 +1021,21 @@ void WorldSession::HandleGuildBankSwapItems( WorldPacket & recv_data ) uint32 SplitedAmount = 0; recv_data >> GoGuid >> BankToBank; + + uint32 GuildId = GetPlayer()->GetGuildId(); + if (!GuildId) + { + recv_data.rpos(recv_data.wpos()); // prevent additional spam at rejected packet + return; + } + + Guild *pGuild = objmgr.GetGuildById(GuildId); + if (!pGuild || !pGuild->IsGuildBankLoaded()) + { + recv_data.rpos(recv_data.wpos()); // prevent additional spam at rejected packet + return; + } + if (BankToBank) { recv_data >> BankTabDst; @@ -1074,7 +1047,10 @@ void WorldSession::HandleGuildBankSwapItems( WorldPacket & recv_data ) recv_data >> unk2; // always 0 recv_data >> SplitedAmount; - if (BankTabSlotDst >= GUILD_BANK_MAX_SLOTS || (BankTabDst == BankTab && BankTabSlotDst == BankTabSlot) || BankTab >= GUILD_BANK_MAX_TABS) + if (BankTabSlotDst >= GUILD_BANK_MAX_SLOTS || + (BankTabDst == BankTab && BankTabSlotDst == BankTabSlot) || + BankTab >= pGuild->GetPurchasedTabs() || + BankTabDst >= pGuild->GetPurchasedTabs()) { recv_data.rpos(recv_data.wpos()); // prevent additional spam at rejected packet return; @@ -1100,7 +1076,8 @@ void WorldSession::HandleGuildBankSwapItems( WorldPacket & recv_data ) recv_data >> SplitedAmount; } - if ((BankTabSlot >= GUILD_BANK_MAX_SLOTS && BankTabSlot != 0xFF) || BankTab >= GUILD_BANK_MAX_TABS) + if (BankTabSlot >= GUILD_BANK_MAX_SLOTS && BankTabSlot != 0xFF || + BankTab >= pGuild->GetPurchasedTabs()) { recv_data.rpos(recv_data.wpos()); // prevent additional spam at rejected packet return; @@ -1110,30 +1087,20 @@ void WorldSession::HandleGuildBankSwapItems( WorldPacket & recv_data ) if (!GetPlayer()->GetGameObjectIfCanInteractWith(GoGuid, GAMEOBJECT_TYPE_GUILD_BANK)) return; - uint32 GuildId = GetPlayer()->GetGuildId(); - if (GuildId == 0) - return; - - Guild *pGuild = objmgr.GetGuildById(GuildId); - if(!pGuild) - return; - if (BankTab >= pGuild->GetPurchasedTabs()) return; - Player *pl = GetPlayer(); - // Bank <-> Bank if (BankToBank) { - pGuild->SwapItems(pl, BankTab, BankTabSlot, BankTabDst, BankTabSlotDst, SplitedAmount); + pGuild->SwapItems(_player, BankTab, BankTabSlot, BankTabDst, BankTabSlotDst, SplitedAmount); return; } // Player <-> Bank // allow work with inventory only - if(!Player::IsInventoryPos(PlayerBag,PlayerSlot) && !(PlayerBag == NULL_BAG && PlayerSlot == NULL_SLOT)) + if(!Player::IsInventoryPos(PlayerBag, PlayerSlot) && !(PlayerBag == NULL_BAG && PlayerSlot == NULL_SLOT) ) { _player->SendEquipError( EQUIP_ERR_NONE, NULL, NULL ); return; @@ -1141,15 +1108,15 @@ void WorldSession::HandleGuildBankSwapItems( WorldPacket & recv_data ) // BankToChar swap or char to bank remaining if (ToChar) // Bank -> Char cases - pGuild->MoveFromBankToChar(pl, BankTab, BankTabSlot, PlayerBag, PlayerSlot, SplitedAmount); + pGuild->MoveFromBankToChar(_player, BankTab, BankTabSlot, PlayerBag, PlayerSlot, SplitedAmount); else // Char -> Bank cases - pGuild->MoveFromCharToBank(pl, PlayerBag, PlayerSlot, BankTab, BankTabSlot, SplitedAmount); + pGuild->MoveFromCharToBank(_player, PlayerBag, PlayerSlot, BankTab, BankTabSlot, SplitedAmount); } void WorldSession::HandleGuildBankBuyTab( WorldPacket & recv_data ) { sLog.outDebug("WORLD: Received (CMSG_GUILD_BANK_BUY_TAB)"); - //recv_data.hexlike(); + uint64 GoGuid; uint8 TabId; @@ -1160,25 +1127,20 @@ void WorldSession::HandleGuildBankBuyTab( WorldPacket & recv_data ) return; uint32 GuildId = GetPlayer()->GetGuildId(); - if (GuildId==0) + if (!GuildId) return; Guild *pGuild = objmgr.GetGuildById(GuildId); if(!pGuild) return; - uint32 TabCost = GetGuildBankTabPrice(TabId) * GOLD; - if (!TabCost) - return; - - if (pGuild->GetPurchasedTabs() >= GUILD_BANK_MAX_TABS) + // m_PurchasedTabs = 0 when buying Tab 0, that is why this check can be made + if (!pGuild->IsGuildBankLoaded() || TabId != pGuild->GetPurchasedTabs()) return; - if (TabId != pGuild->GetPurchasedTabs()) // m_PurchasedTabs = 0 when buying Tab 0, that is why this check can be made - { - sLog.outError("Error: trying to buy a tab non contigous to owned ones"); + uint32 TabCost = GetGuildBankTabPrice(TabId) * GOLD; + if (!TabCost) return; - } if (GetPlayer()->GetMoney() < TabCost) // Should not happen, this is checked by client return; @@ -1195,7 +1157,7 @@ void WorldSession::HandleGuildBankBuyTab( WorldPacket & recv_data ) void WorldSession::HandleGuildBankUpdateTab( WorldPacket & recv_data ) { sLog.outDebug("WORLD: Received (CMSG_GUILD_BANK_UPDATE_TAB)"); - //recv_data.hexlike(); + uint64 GoGuid; uint8 TabId; std::string Name; @@ -1216,11 +1178,14 @@ void WorldSession::HandleGuildBankUpdateTab( WorldPacket & recv_data ) return; uint32 GuildId = GetPlayer()->GetGuildId(); - if (GuildId==0) + if (!GuildId) return; Guild *pGuild = objmgr.GetGuildById(GuildId); - if(!pGuild) + if (!pGuild) + return; + + if (!pGuild->IsGuildBankLoaded() || TabId >= pGuild->GetPurchasedTabs()) return; pGuild->SetGuildBankTabInfo(TabId, Name, IconIndex); @@ -1232,16 +1197,23 @@ void WorldSession::HandleGuildBankLogQuery( WorldPacket & recv_data ) { sLog.outDebug("WORLD: Received (MSG_GUILD_BANK_LOG_QUERY)"); + uint8 TabId; + recv_data >> TabId; + uint32 GuildId = GetPlayer()->GetGuildId(); - if (GuildId == 0) + if (!GuildId) return; Guild *pGuild = objmgr.GetGuildById(GuildId); - if(!pGuild) + if (!pGuild) return; - uint8 TabId; - recv_data >> TabId; + if (!pGuild->IsGuildBankLoaded()) + return; + + // GUILD_BANK_MAX_TABS send by client for money log + if (TabId >= pGuild->GetPurchasedTabs() && TabId != GUILD_BANK_MAX_TABS) + return; pGuild->DisplayGuildBankLogs(this, TabId); } @@ -1250,16 +1222,19 @@ void WorldSession::HandleQueryGuildBankTabText(WorldPacket &recv_data) { sLog.outDebug("WORLD: Received MSG_QUERY_GUILD_BANK_TEXT"); + uint8 TabId; + recv_data >> TabId; + uint32 GuildId = GetPlayer()->GetGuildId(); - if (GuildId == 0) + if (!GuildId) return; Guild *pGuild = objmgr.GetGuildById(GuildId); - if(!pGuild) + if (!pGuild) return; - uint8 TabId; - recv_data >> TabId; + if (!pGuild->IsGuildBankLoaded() || TabId >= pGuild->GetPurchasedTabs()) + return; pGuild->SendGuildBankTabText(this, TabId); } @@ -1267,18 +1242,22 @@ void WorldSession::HandleQueryGuildBankTabText(WorldPacket &recv_data) void WorldSession::HandleSetGuildBankTabText(WorldPacket &recv_data) { sLog.outDebug("WORLD: Received CMSG_SET_GUILD_BANK_TEXT"); + + uint8 TabId; + std::string Text; + recv_data >> TabId; + recv_data >> Text; + uint32 GuildId = GetPlayer()->GetGuildId(); - if (GuildId == 0) + if (!GuildId) return; Guild *pGuild = objmgr.GetGuildById(GuildId); - if(!pGuild) + if (!pGuild) return; - uint8 TabId; - std::string Text; - recv_data >> TabId; - recv_data >> Text; + if (!pGuild->IsGuildBankLoaded() || TabId >= pGuild->GetPurchasedTabs()) + return; pGuild->SetGuildBankTabText(TabId, Text); } @@ -1289,4 +1268,3 @@ void WorldSession::SendSaveGuildEmblem( uint32 msg ) data << uint32(msg); // not part of guild SendPacket( &data ); } - diff --git a/src/game/InstanceSaveMgr.cpp b/src/game/InstanceSaveMgr.cpp index 8c1aab1b60b..128674d978a 100644 --- a/src/game/InstanceSaveMgr.cpp +++ b/src/game/InstanceSaveMgr.cpp @@ -77,15 +77,27 @@ InstanceSaveManager::~InstanceSaveManager() - adding instance into manager - called from InstanceMap::Add, _LoadBoundInstances, LoadGroups */ -InstanceSave* InstanceSaveManager::AddInstanceSave(uint32 mapId, uint32 instanceId, uint8 difficulty, time_t resetTime, bool canReset, bool load) +InstanceSave* InstanceSaveManager::AddInstanceSave(uint32 mapId, uint32 instanceId, Difficulty difficulty, time_t resetTime, bool canReset, bool load) { - InstanceSave *save = GetInstanceSave(instanceId); - if(save) return save; + if(InstanceSave *old_save = GetInstanceSave(instanceId)) + return old_save; const MapEntry* entry = sMapStore.LookupEntry(mapId); - if(!entry || instanceId == 0) + if (!entry) { - sLog.outError("InstanceSaveManager::AddInstanceSave: mapid = %d, instanceid = %d!", mapId, instanceId); + sLog.outError("InstanceSaveManager::AddInstanceSave: wrong mapid = %d!", mapId, instanceId); + return NULL; + } + + if (instanceId == 0) + { + sLog.outError("InstanceSaveManager::AddInstanceSave: mapid = %d, wrong instanceid = %d!", mapId, instanceId); + return NULL; + } + + if (difficulty >= (entry->IsRaid() ? MAX_RAID_DIFFICULTY : MAX_DUNGEON_DIFFICULTY)) + { + sLog.outError("InstanceSaveManager::AddInstanceSave: mapid = %d, instanceid = %d, wrong dificalty %u!", mapId, instanceId, difficulty); return NULL; } @@ -93,19 +105,19 @@ InstanceSave* InstanceSaveManager::AddInstanceSave(uint32 mapId, uint32 instance { // initialize reset time // for normal instances if no creatures are killed the instance will reset in two hours - if(entry->map_type == MAP_RAID || difficulty == DIFFICULTY_HEROIC) - resetTime = GetResetTimeFor(mapId); + if(entry->map_type == MAP_RAID || difficulty > DUNGEON_DIFFICULTY_NORMAL) + resetTime = GetResetTimeFor(mapId,difficulty); else { resetTime = time(NULL) + 2 * HOUR; // normally this will be removed soon after in InstanceMap::Add, prevent error - ScheduleReset(true, resetTime, InstResetEvent(0, mapId, instanceId)); + ScheduleReset(true, resetTime, InstResetEvent(0, mapId, difficulty, instanceId)); } } sLog.outDebug("InstanceSaveManager::AddInstanceSave: mapid = %d, instanceid = %d", mapId, instanceId); - save = new InstanceSave(mapId, instanceId, difficulty, resetTime, canReset); + InstanceSave *save = new InstanceSave(mapId, instanceId, difficulty, resetTime, canReset); if(!load) save->SaveToDB(); m_instanceSaveById[instanceId] = save; @@ -141,7 +153,7 @@ void InstanceSaveManager::RemoveInstanceSave(uint32 InstanceId) } } -InstanceSave::InstanceSave(uint16 MapId, uint32 InstanceId, uint8 difficulty, time_t resetTime, bool canReset) +InstanceSave::InstanceSave(uint16 MapId, uint32 InstanceId, Difficulty difficulty, time_t resetTime, bool canReset) : m_resetTime(resetTime), m_instanceid(InstanceId), m_mapid(MapId), m_difficulty(difficulty), m_canReset(canReset) { @@ -180,7 +192,7 @@ time_t InstanceSave::GetResetTimeForDB() { // only save the reset time for normal instances const MapEntry *entry = sMapStore.LookupEntry(GetMapId()); - if(!entry || entry->map_type == MAP_RAID || GetDifficulty() == DIFFICULTY_HEROIC) + if(!entry || entry->map_type == MAP_RAID || GetDifficulty() == DUNGEON_DIFFICULTY_HEROIC) return 0; else return GetResetTime(); @@ -402,18 +414,26 @@ void InstanceSaveManager::LoadResetTimes() // get the current reset times for normal instances (these may need to be updated) // these are only kept in memory for InstanceSaves that are loaded later // resettime = 0 in the DB for raid/heroic instances so those are skipped - typedef std::map<uint32, std::pair<uint32, time_t> > ResetTimeMapType; - ResetTimeMapType InstResetTime; - QueryResult *result = CharacterDatabase.Query("SELECT id, map, resettime FROM instance WHERE resettime > 0"); + typedef std::pair<uint32 /*PAIR32(map,difficulty)*/, time_t> ResetTimeMapDiffType; + typedef std::map<uint32, ResetTimeMapDiffType> InstResetTimeMapDiffType; + InstResetTimeMapDiffType instResetTime; + + // index instance ids by map/difficulty pairs for fast reset warning send + typedef std::multimap<uint32 /*PAIR32(map,difficulty)*/, uint32 /*instanceid*/ > ResetTimeMapDiffInstances; + ResetTimeMapDiffInstances mapDiffResetInstances; + + QueryResult *result = CharacterDatabase.Query("SELECT id, map, difficulty, resettime FROM instance WHERE resettime > 0"); if( result ) { do { - if(time_t resettime = time_t((*result)[2].GetUInt64())) + if(time_t resettime = time_t((*result)[3].GetUInt64())) { uint32 id = (*result)[0].GetUInt32(); uint32 mapid = (*result)[1].GetUInt32(); - InstResetTime[id] = std::pair<uint32, uint64>(mapid, resettime); + uint32 difficulty = (*result)[2].GetUInt32(); + instResetTime[id] = ResetTimeMapDiffType(MAKE_PAIR32(mapid,difficulty), resettime); + mapDiffResetInstances.insert(ResetTimeMapDiffInstances::value_type(MAKE_PAIR32(mapid,difficulty),id)); } } while (result->NextRow()); @@ -428,8 +448,8 @@ void InstanceSaveManager::LoadResetTimes() Field *fields = result->Fetch(); uint32 instance = fields[1].GetUInt32(); time_t resettime = time_t(fields[0].GetUInt64() + 2 * HOUR); - ResetTimeMapType::iterator itr = InstResetTime.find(instance); - if(itr != InstResetTime.end() && itr->second.second != resettime) + InstResetTimeMapDiffType::iterator itr = instResetTime.find(instance); + if(itr != instResetTime.end() && itr->second.second != resettime) { CharacterDatabase.DirectPExecute("UPDATE instance SET resettime = '"UI64FMTD"' WHERE id = '%u'", uint64(resettime), instance); itr->second.second = resettime; @@ -440,62 +460,65 @@ void InstanceSaveManager::LoadResetTimes() } // schedule the reset times - for (ResetTimeMapType::iterator itr = InstResetTime.begin(); itr != InstResetTime.end(); ++itr) + for(InstResetTimeMapDiffType::iterator itr = instResetTime.begin(); itr != instResetTime.end(); ++itr) if(itr->second.second > now) - ScheduleReset(true, itr->second.second, InstResetEvent(0, itr->second.first, itr->first)); + ScheduleReset(true, itr->second.second, InstResetEvent(0, PAIR32_LOPART(itr->second.first),Difficulty(PAIR32_HIPART(itr->second.first)),itr->first)); } // load the global respawn times for raid/heroic instances uint32 diff = sWorld.getConfig(CONFIG_INSTANCE_RESET_TIME_HOUR) * HOUR; - m_resetTimeByMapId.resize(sMapStore.GetNumRows()+1); - result = CharacterDatabase.Query("SELECT mapid, resettime FROM instance_reset"); + result = CharacterDatabase.Query("SELECT mapid, difficulty, resettime FROM instance_reset"); if(result) { do { Field *fields = result->Fetch(); uint32 mapid = fields[0].GetUInt32(); - if(!objmgr.GetInstanceTemplate(mapid)) + Difficulty difficulty = Difficulty(fields[1].GetUInt32()); + uint64 oldresettime = fields[2].GetUInt64(); + + MapDifficulty const* mapDiff = GetMapDifficultyData(mapid,difficulty); + if(!mapDiff) { - sLog.outError("InstanceSaveManager::LoadResetTimes: invalid mapid %u in instance_reset!", mapid); - CharacterDatabase.DirectPExecute("DELETE FROM instance_reset WHERE mapid = '%u'", mapid); + sLog.outError("InstanceSaveManager::LoadResetTimes: invalid mapid(%u)/difficulty(%u) pair in instance_reset!", mapid, difficulty); + CharacterDatabase.DirectPExecute("DELETE FROM instance_reset WHERE mapid = '%u' AND difficulty = '%u'", mapid,difficulty); continue; } // update the reset time if the hour in the configs changes - uint64 oldresettime = fields[1].GetUInt64(); uint64 newresettime = (oldresettime / DAY) * DAY + diff; if(oldresettime != newresettime) - CharacterDatabase.DirectPExecute("UPDATE instance_reset SET resettime = '"UI64FMTD"' WHERE mapid = '%u'", newresettime, mapid); + CharacterDatabase.DirectPExecute("UPDATE instance_reset SET resettime = '"UI64FMTD"' WHERE mapid = '%u' AND difficulty = '%u'", newresettime, mapid, difficulty); - m_resetTimeByMapId[mapid] = newresettime; + SetResetTimeFor(mapid,difficulty,newresettime); } while(result->NextRow()); delete result; } // clean expired instances, references to them will be deleted in CleanupInstances // must be done before calculating new reset times - _DelHelper(CharacterDatabase, "id, map, difficulty", "instance", "LEFT JOIN instance_reset ON mapid = map WHERE (instance.resettime < '"UI64FMTD"' AND instance.resettime > '0') OR (NOT instance_reset.resettime IS NULL AND instance_reset.resettime < '"UI64FMTD"')", (uint64)now, (uint64)now); + _DelHelper(CharacterDatabase, "id, map, instance.difficulty", "instance", "LEFT JOIN instance_reset ON mapid = map AND instance.difficulty = instance_reset.difficulty WHERE (instance.resettime < '"UI64FMTD"' AND instance.resettime > '0') OR (NOT instance_reset.resettime IS NULL AND instance_reset.resettime < '"UI64FMTD"')", (uint64)now, (uint64)now); // calculate new global reset times for expired instances and those that have never been reset yet // add the global reset times to the priority queue - for (uint32 i = 0; i < sInstanceTemplate.MaxEntry; i++) + for(MapDifficultyMap::const_iterator itr = sMapDifficultyMap.begin(); itr != sMapDifficultyMap.end(); ++itr) { - InstanceTemplate const* temp = objmgr.GetInstanceTemplate(i); - if(!temp) continue; - // only raid/heroic maps have a global reset time - const MapEntry* entry = sMapStore.LookupEntry(temp->map); - if(!entry || !entry->HasResetTime()) + uint32 map_diff_pair = itr->first; + uint32 mapid = PAIR32_LOPART(map_diff_pair); + Difficulty difficulty = Difficulty(PAIR32_HIPART(map_diff_pair)); + MapDifficulty const* mapDiff = &itr->second; + if (!mapDiff->resetTime) continue; - uint32 period = temp->reset_delay * DAY; - assert(period != 0); - time_t t = m_resetTimeByMapId[temp->map]; + // the reset_delay must be at least one day + uint32 period = (mapDiff->resetTime / DAY * sWorld.getRate(RATE_INSTANCE_RESET_TIME)) * DAY; + + time_t t = GetResetTimeFor(mapid,difficulty); if(!t) { // initialize the reset time t = today + period + diff; - CharacterDatabase.DirectPExecute("INSERT INTO instance_reset VALUES ('%u','"UI64FMTD"')", i, (uint64)t); + CharacterDatabase.DirectPExecute("INSERT INTO instance_reset VALUES ('%u','%u','"UI64FMTD"')", mapid, difficulty, (uint64)t); } if(t < now) @@ -504,17 +527,23 @@ void InstanceSaveManager::LoadResetTimes() // calculate the next reset time t = (t / DAY) * DAY; t += ((today - t) / period + 1) * period + diff; - CharacterDatabase.DirectPExecute("UPDATE instance_reset SET resettime = '"UI64FMTD"' WHERE mapid = '%u'", (uint64)t, i); + CharacterDatabase.DirectPExecute("UPDATE instance_reset SET resettime = '"UI64FMTD"' WHERE mapid = '%u' AND difficulty= '%u'", (uint64)t, mapid, difficulty); } - m_resetTimeByMapId[temp->map] = t; + SetResetTimeFor(mapid,difficulty,t); // schedule the global reset/warning uint8 type = 1; static int tim[4] = {3600, 900, 300, 60}; for (; type < 4; type++) - if(t - tim[type-1] > now) break; - ScheduleReset(true, t - tim[type-1], InstResetEvent(type, i)); + if(t - tim[type-1] > now) + break; + + for(ResetTimeMapDiffInstances::const_iterator in_itr = mapDiffResetInstances.lower_bound(map_diff_pair); + in_itr != mapDiffResetInstances.upper_bound(map_diff_pair); ++in_itr) + { + ScheduleReset(true, t - tim[type-1], InstResetEvent(type, mapid, difficulty, in_itr->second)); + } } } @@ -555,8 +584,8 @@ void InstanceSaveManager::Update() else { // global reset/warning for a certain map - time_t resetTime = GetResetTimeFor(event.mapid); - _ResetOrWarnAll(event.mapid, event.type != 4, resetTime - now); + time_t resetTime = GetResetTimeFor(event.mapid,event.difficulty); + _ResetOrWarnAll(event.mapid, event.difficulty, event.type != 4, resetTime - now); if(event.type != 4) { // schedule the next warning/reset @@ -607,29 +636,28 @@ void InstanceSaveManager::_ResetInstance(uint32 mapid, uint32 instanceId) else objmgr.DeleteRespawnTimeForInstance(instanceId); // even if map is not loaded } -void InstanceSaveManager::_ResetOrWarnAll(uint32 mapid, bool warn, uint32 timeLeft) +void InstanceSaveManager::_ResetOrWarnAll(uint32 mapid, Difficulty difficulty, bool warn, uint32 timeLeft) { // global reset for all instances of the given map - // note: this isn't fast but it's meant to be executed very rarely - Map const *map = MapManager::Instance().CreateBaseMap(mapid); - if(!map->Instanceable()) + MapEntry const *mapEntry = sMapStore.LookupEntry(mapid); + if (!mapEntry->Instanceable()) return; + uint64 now = (uint64)time(NULL); if(!warn) { - // this is called one minute before the reset time - InstanceTemplate const* temp = objmgr.GetInstanceTemplate(mapid); - if(!temp || !temp->reset_delay) + MapDifficulty const* mapDiff = GetMapDifficultyData(mapid,difficulty); + if (!mapDiff || !mapDiff->resetTime) { - sLog.outError("InstanceSaveManager::ResetOrWarnAll: no instance template or reset delay for map %d", mapid); + sLog.outError("InstanceSaveManager::ResetOrWarnAll: not valid difficulty or no reset delay for map %d", mapid); return; } // remove all binds to instances of the given map for (InstanceSaveHashMap::iterator itr = m_instanceSaveById.begin(); itr != m_instanceSaveById.end();) { - if(itr->second->GetMapId() == mapid) + if (itr->second->GetMapId() == mapid && itr->second->GetDifficulty() == difficulty) _ResetSave(itr); else ++itr; @@ -644,16 +672,14 @@ void InstanceSaveManager::_ResetOrWarnAll(uint32 mapid, bool warn, uint32 timeLe // calculate the next reset time uint32 diff = sWorld.getConfig(CONFIG_INSTANCE_RESET_TIME_HOUR) * HOUR; - uint32 period = temp->reset_delay * DAY; + uint32 period = mapDiff->resetTime * DAY; uint64 next_reset = ((now + timeLeft + MINUTE) / DAY * DAY) + period + diff; // update it in the DB - CharacterDatabase.PExecute("UPDATE instance_reset SET resettime = '"UI64FMTD"' WHERE mapid = '%d'", next_reset, mapid); - - // schedule next reset. - m_resetTimeByMapId[mapid] = (time_t) next_reset; - ScheduleReset(true, (time_t) (next_reset-3600), InstResetEvent(1, mapid)); + CharacterDatabase.PExecute("UPDATE instance_reset SET resettime = '"UI64FMTD"' WHERE mapid = '%d' AND difficulty = '%d'", next_reset, mapid, difficulty); } + // note: this isn't fast but it's meant to be executed very rarely + Map const *map = MapManager::Instance().CreateBaseMap(mapid); // _not_ include difficulty MapInstanced::InstancedMaps &instMaps = ((MapInstanced*)map)->GetInstancedMaps(); MapInstanced::InstancedMaps::iterator mitr; for (mitr = instMaps.begin(); mitr != instMaps.end(); ++mitr) @@ -682,4 +708,3 @@ uint32 InstanceSaveManager::GetNumBoundGroupsTotal() ret += itr->second->GetGroupCount(); return ret; } - diff --git a/src/game/InstanceSaveMgr.h b/src/game/InstanceSaveMgr.h index 29972210f3d..6d031af752d 100644 --- a/src/game/InstanceSaveMgr.h +++ b/src/game/InstanceSaveMgr.h @@ -29,6 +29,8 @@ #include <map> #include "Utilities/UnorderedMap.h" #include "Database/DatabaseEnv.h" +#include "DBCEnums.h" +#include "ObjectDefines.h" struct InstanceTemplate; struct MapEntry; @@ -50,7 +52,7 @@ class InstanceSave - any new instance is being generated - the first time a player bound to InstanceId logs in - when a group bound to the instance is loaded */ - InstanceSave(uint16 MapId, uint32 InstanceId, uint8 difficulty, time_t resetTime, bool canReset); + InstanceSave(uint16 MapId, uint32 InstanceId, Difficulty difficulty, time_t resetTime, bool canReset); /* Unloaded when m_playerList and m_groupList become empty or when the instance is reset */ @@ -95,7 +97,7 @@ class InstanceSave /* currently it is possible to omit this information from this structure but that would depend on a lot of things that can easily change in future */ - uint8 GetDifficulty() { return m_difficulty; } + Difficulty GetDifficulty() { return m_difficulty; } typedef std::list<Player*> PlayerListType; typedef std::list<Group*> GroupListType; @@ -108,8 +110,8 @@ class InstanceSave GroupListType m_groupList; time_t m_resetTime; uint32 m_instanceid; - uint16 m_mapid; - uint8 m_difficulty; + uint32 m_mapid; + Difficulty m_difficulty; bool m_canReset; }; @@ -120,33 +122,44 @@ class MANGOS_DLL_DECL InstanceSaveManager : public MaNGOS::Singleton<InstanceSav InstanceSaveManager(); ~InstanceSaveManager(); - typedef std::map<uint32 /*InstanceId*/, InstanceSave*> InstanceSaveMap; typedef UNORDERED_MAP<uint32 /*InstanceId*/, InstanceSave*> InstanceSaveHashMap; - typedef std::map<uint32 /*mapId*/, InstanceSaveMap> InstanceSaveMapMap; + typedef UNORDERED_MAP<uint32 /*mapId*/, InstanceSaveHashMap> InstanceSaveMapMap; /* resetTime is a global propery of each (raid/heroic) map all instances of that map reset at the same time */ struct InstResetEvent { uint8 type; + Difficulty difficulty:8; uint16 mapid; uint16 instanceId; - InstResetEvent(uint8 t = 0, uint16 m = 0, uint16 i = 0) : type(t), mapid(m), instanceId(i) {} + + InstResetEvent() : type(0), difficulty(DUNGEON_DIFFICULTY_NORMAL), mapid(0), instanceId(0) {} + InstResetEvent(uint8 t, uint32 _mapid, Difficulty d, uint16 _instanceid) + : type(t), difficulty(d), mapid(_mapid), instanceId(_instanceid) {} bool operator == (const InstResetEvent& e) { return e.instanceId == instanceId; } }; typedef std::multimap<time_t /*resetTime*/, InstResetEvent> ResetTimeQueue; - typedef std::vector<time_t /*resetTime*/> ResetTimeVector; + typedef UNORDERED_MAP<uint32 /*PAIR32(map,difficulty)*/,time_t /*resetTime*/> ResetTimeByMapDifficultyMap; void CleanupInstances(); void PackInstances(); void LoadResetTimes(); - time_t GetResetTimeFor(uint32 mapid) { return m_resetTimeByMapId[mapid]; } + time_t GetResetTimeFor(uint32 mapid, Difficulty d) const + { + ResetTimeByMapDifficultyMap::const_iterator itr = m_resetTimeByMapDifficulty.find(MAKE_PAIR32(mapid,d)); + return itr != m_resetTimeByMapDifficulty.end() ? itr->second : 0; + } + void SetResetTimeFor(uint32 mapid, Difficulty d, time_t t) + { + m_resetTimeByMapDifficulty[MAKE_PAIR32(mapid,d)] = t; + } void ScheduleReset(bool add, time_t time, InstResetEvent event); void Update(); - InstanceSave* AddInstanceSave(uint32 mapId, uint32 instanceId, uint8 difficulty, time_t resetTime, bool canReset, bool load = false); + InstanceSave* AddInstanceSave(uint32 mapId, uint32 instanceId, Difficulty difficulty, time_t resetTime, bool canReset, bool load = false); void RemoveInstanceSave(uint32 InstanceId); static void DeleteInstanceFromDB(uint32 instanceid); @@ -158,7 +171,7 @@ class MANGOS_DLL_DECL InstanceSaveManager : public MaNGOS::Singleton<InstanceSav uint32 GetNumBoundGroupsTotal(); private: - void _ResetOrWarnAll(uint32 mapid, bool warn, uint32 timeleft); + void _ResetOrWarnAll(uint32 mapid, Difficulty difficulty, bool warn, uint32 timeleft); void _ResetInstance(uint32 mapid, uint32 instanceId); void _ResetSave(InstanceSaveHashMap::iterator &itr); void _DelHelper(DatabaseType &db, const char *fields, const char *table, const char *queryTail,...); @@ -166,11 +179,10 @@ class MANGOS_DLL_DECL InstanceSaveManager : public MaNGOS::Singleton<InstanceSav bool lock_instLists; // fast lookup by instance id InstanceSaveHashMap m_instanceSaveById; - // fast lookup for reset times - ResetTimeVector m_resetTimeByMapId; + // fast lookup for reset times (always use existed functions for access/set) + ResetTimeByMapDifficultyMap m_resetTimeByMapDifficulty; ResetTimeQueue m_resetTimeQueue; }; #define sInstanceSaveManager Trinity::Singleton<InstanceSaveManager>::Instance() #endif - diff --git a/src/game/Item.cpp b/src/game/Item.cpp index f26106cb452..05c1adec795 100644 --- a/src/game/Item.cpp +++ b/src/game/Item.cpp @@ -751,15 +751,15 @@ uint32 Item::GetEnchantRequiredLevel() const for (uint32 enchant_slot = PERM_ENCHANTMENT_SLOT; enchant_slot < MAX_ENCHANTMENT_SLOT; ++enchant_slot) if (uint32 enchant_id = GetEnchantmentId(EnchantmentSlot(enchant_slot))) if (SpellItemEnchantmentEntry const* enchantEntry = sSpellItemEnchantmentStore.LookupEntry(enchant_id)) - if (enchantEntry->RequiredLevel > level) - level = enchantEntry->RequiredLevel; + if (enchantEntry->requiredLevel > level) + level = enchantEntry->requiredLevel; return level; } bool Item::IsBoundByEnchant() const { // Check all enchants for soulbound - for (uint32 enchant_slot = PERM_ENCHANTMENT_SLOT; enchant_slot < MAX_ENCHANTMENT_SLOT; ++enchant_slot) + for (uint32 enchant_slot = PERM_ENCHANTMENT_SLOT; enchant_slot < MAX_ENCHANTMENT_SLOT; ++enchant_slot) if (uint32 enchant_id = GetEnchantmentId(EnchantmentSlot(enchant_slot))) if (SpellItemEnchantmentEntry const* enchantEntry = sSpellItemEnchantmentStore.LookupEntry(enchant_id)) if (enchantEntry->slot & ENCHANTMENT_CAN_SOULBOUND) diff --git a/src/game/Item.h b/src/game/Item.h index a26b9148f21..710e0a56d57 100644 --- a/src/game/Item.h +++ b/src/game/Item.h @@ -319,6 +319,21 @@ class TRINITY_DLL_SPEC Item : public Object bool IsWeaponVellum() const { return GetProto()->IsWeaponVellum(); } bool IsArmorVellum() const { return GetProto()->IsArmorVellum(); } bool IsConjuredConsumable() const { return GetProto()->IsConjuredConsumable(); } + + // Item Refund system + uint32 GetPaidHonorPoints() { return m_paidHonorPoints; } + uint32 GetPaidArenaPoints() { return m_paidArenaPoints; } + uint32 GetPaidExtendedCostId(uint32 pos) { return m_paidExtendedCostId[pos]; } + uint32 GetPaidExtendedCostCount(uint32 pos) { return m_paidExtendedCostCount[pos]; } + uint32 GetRefundExpiryTime() { return GetUInt32Value(ITEM_FIELD_CREATE_PLAYED_TIME); } + void SetRefundExpiryTime(uint32 timeval) { SetUInt32Value(ITEM_FIELD_CREATE_PLAYED_TIME, timeval); } + void SetPaidHonorPoints(uint32 value) { m_paidHonorPoints = value; } + void SetPaidArenaPoints(uint32 value) { m_paidArenaPoints = value; } + void SetPaidExtendedCost(uint32 pos, uint32 entry, uint32 count) + { + m_paidExtendedCostId[pos] = entry; + m_paidExtendedCostCount[pos] = count; + } private: uint8 m_slot; @@ -326,6 +341,11 @@ class TRINITY_DLL_SPEC Item : public Object ItemUpdateState uState; int16 uQueuePos; bool mb_in_trade; // true if item is currently in trade-window + + // refund system + uint32 m_paidHonorPoints; + uint32 m_paidArenaPoints; + uint32 m_paidExtendedCostId[5]; + uint32 m_paidExtendedCostCount[5]; }; #endif - diff --git a/src/game/ItemHandler.cpp b/src/game/ItemHandler.cpp index ad9b1a7de4b..b4b22fe90cc 100644 --- a/src/game/ItemHandler.cpp +++ b/src/game/ItemHandler.cpp @@ -67,7 +67,7 @@ void WorldSession::HandleSwapInvItemOpcode( WorldPacket & recv_data ) //sLog.outDebug("WORLD: CMSG_SWAP_INV_ITEM"); uint8 srcslot, dstslot; - recv_data >> srcslot >> dstslot; + recv_data >> dstslot >> srcslot; //sLog.outDebug("STORAGE: receive srcslot = %u, dstslot = %u", srcslot, dstslot); // prevent attempt swap same item to current position generated by client at special checting sequence @@ -319,6 +319,7 @@ void WorldSession::HandleItemQuerySingleOpcode( WorldPacket & recv_data ) data << pProto->DisplayInfoID; data << pProto->Quality; data << pProto->Flags; + data << pProto->Faction; // 3.2 faction? data << pProto->BuyPrice; data << pProto->SellPrice; data << pProto->InventoryType; @@ -947,10 +948,10 @@ void WorldSession::HandleSetAmmoOpcode(WorldPacket & recv_data) void WorldSession::SendEnchantmentLog(uint64 Target, uint64 Caster,uint32 ItemID,uint32 SpellID) { WorldPacket data(SMSG_ENCHANTMENTLOG, (8+8+4+4+1)); // last check 2.0.10 - data << Target; - data << Caster; - data << ItemID; - data << SpellID; + data << uint64(Target); + data << uint64(Caster); + data << uint32(ItemID); + data << uint32(SpellID); data << uint8(0); SendPacket(&data); } @@ -1336,3 +1337,112 @@ void WorldSession::HandleCancelTempEnchantmentOpcode(WorldPacket& recv_data) item->ClearEnchantment(TEMP_ENCHANTMENT_SLOT); } +void WorldSession::HandleItemRefundInfoRequest(WorldPacket& recv_data) +{ + sLog.outDebug("WORLD: CMSG_ITEM_REFUND_INFO_REQUEST"); + + uint64 guid; + + recv_data >> guid; // item guid + + Item *item = _player->GetItemByGuid(guid); + + if(!item) + { + sLog.outDebug("Item refund: item not found!"); + return; + } + + if(!item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_REFUNDABLE)) + { + sLog.outDebug("Item refund: item not refundable!"); + return; + } + + // item refund system not implemented yet + WorldPacket data(SMSG_ITEM_REFUND_TIMER, 8+4+4+4+4*4+4*4+4+4); // guess size + data << uint64(guid); // item guid + data << uint32(1); // unknown + data << uint32(item->GetPaidHonorPoints()); // honor point cost + data << uint32(item->GetPaidArenaPoints()); // arena point cost + for(uint32 i = 0; i < 5; ++i) // extended cost data + { + data << uint32(item->GetPaidExtendedCostId(i)); + data << uint32(item->GetPaidExtendedCostCount(i)); + } + data << uint32(0); + data << uint32(0); + SendPacket(&data); +} + +void WorldSession::HandleItemRefund(WorldPacket &recv_data) +{ + sLog.outDebug("WORLD: CMSG_ITEM_REFUND"); + uint64 guid; + recv_data >> guid; // item guid + + Item *item = _player->GetItemByGuid(guid); + if(!item) + { + sLog.outDebug("Item refund: item not found!"); + return; + } + + if(!item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAGS_REFUNDABLE)) + { + sLog.outDebug("Item refund: item not refundable!"); + return; + } + + if(item->GetRefundExpiryTime() <= time(NULL)) // item refund has expired + { + WorldPacket data(SMSG_ITEM_REFUND); + data << uint64(guid); // guid + data << uint32(1); // error, abort refund + return; + } + + WorldPacket data(SMSG_ITEM_REFUND); + data << uint64(guid); // guid? + data << uint32(0); // must be 0 or client side error in refund + data << uint32(0); // unk - message sent to client? + data << uint32(item->GetPaidHonorPoints()); // honor points refund + data << uint32(item->GetPaidArenaPoints()); // arena points refund + for(uint32 i = 0; i < 5; ++i) // extended cost? + { + data << uint32(item->GetPaidExtendedCostId(i)); + data << uint32(item->GetPaidExtendedCostCount(i)); + } + SendPacket(&data); + + // Grant back extendedcost items + uint32 count = 0; + uint32 itemid = 0; + for(uint32 i = 0; i < 5; ++i) + { + count = item->GetPaidExtendedCostCount(i); + itemid = item->GetPaidExtendedCostId(i); + if (count && itemid) + { + ItemPosCountVec dest; + uint8 msg = _player->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, itemid, count); + if (msg == EQUIP_ERR_OK) + { + Item* it = _player->StoreNewItem(dest, itemid, true); + _player->SendNewItem(it, count, true, false, true); + } + + // What to do if there's no space? + } + } + // Grant back Honor points + if (uint32 honorRefund = item->GetPaidHonorPoints() > 0) + _player->ModifyHonorPoints(honorRefund); + + // Grant back Arena points + if (uint32 arenaRefund = item->GetPaidArenaPoints() > 0) + _player->ModifyArenaPoints(arenaRefund); + + // Destroy item + _player->DestroyItemCount(item->GetEntry(), 1, true, true); +} diff --git a/src/game/ItemPrototype.h b/src/game/ItemPrototype.h index a6daf47cb48..4a2ab112538 100644 --- a/src/game/ItemPrototype.h +++ b/src/game/ItemPrototype.h @@ -65,10 +65,13 @@ enum ItemModType ITEM_MOD_SPELL_DAMAGE_DONE = 42, // deprecated ITEM_MOD_MANA_REGENERATION = 43, ITEM_MOD_ARMOR_PENETRATION_RATING = 44, - ITEM_MOD_SPELL_POWER = 45 + ITEM_MOD_SPELL_POWER = 45, + ITEM_MOD_HEALTH_REGEN = 46, + ITEM_MOD_SPELL_PENETRATION = 47, + ITEM_MOD_BLOCK_VALUE = 48 }; -#define MAX_ITEM_MOD 46 +#define MAX_ITEM_MOD 49 enum ItemSpelltriggerType { @@ -108,9 +111,13 @@ enum ITEM_FLAGS ITEM_FLAGS_OPENABLE = 0x00000004, ITEM_FLAGS_WRAPPED = 0x00000008, ITEM_FLAGS_BROKEN = 0x00000010, // appears red icon (like when item durability==0) + ITEM_FLAGS_TOTEM = 0x00000020, // ? + ITEM_FLAGS_USABLE = 0x00000040, // ? ITEM_FLAGS_WRAPPER = 0x00000200, // used or not used wrapper ITEM_FLAGS_PARTY_LOOT = 0x00000800, // determines if item is party loot or not + ITEM_FLAGS_REFUNDABLE = 0x00001000, // item cost can be refunded within 2 hours after purchase ITEM_FLAGS_CHARTER = 0x00002000, // arena/guild charter + ITEM_FLAGS_REFUNDABLE_2 = 0x00008000, ITEM_FLAGS_PROSPECTABLE = 0x00040000, ITEM_FLAGS_UNIQUE_EQUIPPED = 0x00080000, ITEM_FLAGS_USEABLE_IN_ARENA = 0x00200000, @@ -118,7 +125,9 @@ enum ITEM_FLAGS ITEM_FLAGS_SPECIALUSE = 0x00800000, // last used flag in 2.3.0 ITEM_FLAGS_BOA = 0x08000000, // bind on account (set in template for items that can binded in like way) ITEM_FLAGS_TRIGGERED_CAST = 0x10000000, // used by enchanting scrolls made with vellum - ITEM_FLAGS_MILLABLE = 0x20000000 + ITEM_FLAGS_ENCHANT_SCROLL = 0x10000000, // for enchant scrolls + ITEM_FLAGS_MILLABLE = 0x20000000, + ITEM_FLAGS_BOP_TRADEABLE = 0x80000000 }; enum BAG_FAMILY_MASK @@ -515,6 +524,7 @@ struct ItemPrototype uint32 DisplayInfoID; // id from ItemDisplayInfo.dbc uint32 Quality; uint32 Flags; + uint32 Faction; uint32 BuyCount; uint32 BuyPrice; uint32 SellPrice; @@ -649,4 +659,3 @@ struct ItemLocale #pragma pack(pop) #endif #endif - diff --git a/src/game/Level1.cpp b/src/game/Level1.cpp index 4ae90ebdcc3..bb99299e060 100644 --- a/src/game/Level1.cpp +++ b/src/game/Level1.cpp @@ -827,7 +827,7 @@ bool ChatHandler::HandleNamegoCommand(const char* args) Map* cMap = target->GetMap(); if (cMap->Instanceable() && cMap->GetInstanceId() != pMap->GetInstanceId()) { - target->UnbindInstance(pMap->GetInstanceId(), target->GetDifficulty(), true); + target->UnbindInstance(pMap->GetInstanceId(), target->GetDungeonDifficulty(), true); // cannot summon from instance to instance //PSendSysMessage(LANG_CANNOT_SUMMON_TO_INST,nameLink.c_str()); //SetSentErrorMessage(true); @@ -968,24 +968,26 @@ bool ChatHandler::HandleGonameCommand(const char* args) // if the player or the player's group is bound to another instance // the player will not be bound to another one - InstancePlayerBind *pBind = _player->GetBoundInstance(target->GetMapId(), target->GetDifficulty()); + InstancePlayerBind *pBind = _player->GetBoundInstance(target->GetMapId(), target->GetDifficulty(cMap->IsRaid())); if (!pBind) { Group *group = _player->GetGroup(); // if no bind exists, create a solo bind - InstanceGroupBind *gBind = group ? group->GetBoundInstance(target->GetMapId(), target->GetDifficulty()) : NULL; - // if no bind exists, create a solo bind + InstanceGroupBind *gBind = group ? group->GetBoundInstance(target) : NULL; // if no bind exists, create a solo bind if (!gBind) if (InstanceSave *save = sInstanceSaveManager.GetInstanceSave(target->GetInstanceId())) _player->BindToInstance(save, !save->CanReset()); } - _player->SetDifficulty(target->GetDifficulty()); + if(cMap->IsRaid()) + _player->SetRaidDifficulty(target->GetRaidDifficulty()); + else + _player->SetDungeonDifficulty(target->GetDungeonDifficulty()); } PSendSysMessage(LANG_APPEARING_AT, chrNameLink.c_str()); - if (needReportToTarget(target)) - ChatHandler(target).PSendSysMessage(LANG_APPEARING_TO, GetNameLink().c_str()); + //if (needReportToTarget(target)) + // ChatHandler(target).PSendSysMessage(LANG_APPEARING_TO, GetNameLink().c_str()); // stop flight if need if (_player->isInFlight()) diff --git a/src/game/Level2.cpp b/src/game/Level2.cpp index 3c2a7bf8f1d..f22a3dedfbb 100644 --- a/src/game/Level2.cpp +++ b/src/game/Level2.cpp @@ -4361,6 +4361,7 @@ bool ChatHandler::HandleWintergraspTimerCommand(const char* args) time *= MINUTE * IN_MILISECONDS; pvpWG->setTimer((uint32)time); + PSendSysMessage(LANG_BG_WG_CHANGE_TIMER, secsToTimeString(pvpWG->GetTimer(), true).c_str()); return true; } diff --git a/src/game/Level3.cpp b/src/game/Level3.cpp index a095be0a531..e4adb4c6550 100644 --- a/src/game/Level3.cpp +++ b/src/game/Level3.cpp @@ -54,6 +54,7 @@ #include "InstanceData.h" #include "AuctionHouseBot.h" #include "CreatureEventAIMgr.h" +#include "DBCEnums.h" bool ChatHandler::HandleAHBotOptionsCommand(const char *args) { @@ -3108,9 +3109,7 @@ bool ChatHandler::HandleGameObjectStateCommand(const char *args) gobj->SendObjectDeSpawnAnim(gobj->GetGUID()); else if(type == -2) { - WorldPacket data(SMSG_GAMEOBJECT_SPAWN_ANIM_OBSOLETE, 8); - data << gobj->GetGUID(); - gobj->SendMessageToSet(&data,true); + return false; } return true; } @@ -3933,7 +3932,7 @@ bool ChatHandler::HandleLookupMapCommand(const char *args) if(!*args) return false; - std::string namepart = args; + /*std::string namepart = args; std::wstring wnamepart; // converting string that we try to find to lower case @@ -4000,6 +3999,7 @@ bool ChatHandler::HandleLookupMapCommand(const char *args) ss << GetTrinityString(LANG_HEROIC); uint32 ResetTimeRaid = MapInfo->resetTimeRaid; + std::string ResetTimeRaidStr; if(ResetTimeRaid) ResetTimeRaidStr = secsToTimeString(ResetTimeRaid, true, false); @@ -4029,7 +4029,7 @@ bool ChatHandler::HandleLookupMapCommand(const char *args) if(!found) SendSysMessage(LANG_COMMAND_NOMAPFOUND); - + */ return true; } @@ -5410,6 +5410,14 @@ bool ChatHandler::HandleServerShutDownCommand(const char *args) char* time_str = strtok ((char*) args, " "); char* exitcode_str = strtok (NULL, ""); + char* tailStr = *args!='"' ? strtok(NULL, "") : (char*)args; + if(!tailStr) + return false; + + char* reason = extractQuotedArg(tailStr); + if(!reason) + return false; + int32 time = atoi (time_str); ///- Prevent interpret wrong arg value as 0 secs shutdown time @@ -5675,7 +5683,7 @@ bool ChatHandler::HandleQuestComplete(const char *args) } // Add quest items for quests that require items - for (uint8 x = 0; x < QUEST_OBJECTIVES_COUNT; ++x) + for (uint8 x = 0; x < QUEST_ITEM_OBJECTIVES_COUNT; ++x) { uint32 id = pQuest->ReqItemId[x]; uint32 count = pQuest->ReqItemCount[x]; @@ -6800,14 +6808,14 @@ bool ChatHandler::HandleInstanceListBindsCommand(const char* /*args*/) Player* player = getSelectedPlayer(); if (!player) player = m_session->GetPlayer(); uint32 counter = 0; - for (uint8 i = 0; i < TOTAL_DIFFICULTIES; ++i) + for (uint8 i = 0; i < MAX_DIFFICULTY; ++i) { - Player::BoundInstancesMap &binds = player->GetBoundInstances(i); + Player::BoundInstancesMap &binds = player->GetBoundInstances(Difficulty(i)); for (Player::BoundInstancesMap::const_iterator itr = binds.begin(); itr != binds.end(); ++itr) { InstanceSave *save = itr->second.save; std::string timeleft = GetTimeString(save->GetResetTime() - time(NULL)); - PSendSysMessage("map: %d inst: %d perm: %s diff: %s canReset: %s TTR: %s", itr->first, save->GetInstanceId(), itr->second.perm ? "yes" : "no", save->GetDifficulty() == DIFFICULTY_NORMAL ? "normal" : "heroic", save->CanReset() ? "yes" : "no", timeleft.c_str()); + PSendSysMessage("map: %d inst: %d perm: %s diff: %d canReset: %s TTR: %s", itr->first, save->GetInstanceId(), itr->second.perm ? "yes" : "no", save->GetDifficulty(), save->CanReset() ? "yes" : "no", timeleft.c_str()); counter++; } } @@ -6816,15 +6824,14 @@ bool ChatHandler::HandleInstanceListBindsCommand(const char* /*args*/) Group *group = player->GetGroup(); if(group) { - for (uint8 i = 0; i < TOTAL_DIFFICULTIES; ++i) + for (uint8 i = 0; i < MAX_DIFFICULTY; ++i) { - Group::BoundInstancesMap &binds = group->GetBoundInstances(i); + Group::BoundInstancesMap &binds = group->GetBoundInstances(Difficulty(i)); for (Group::BoundInstancesMap::const_iterator itr = binds.begin(); itr != binds.end(); ++itr) { InstanceSave *save = itr->second.save; std::string timeleft = GetTimeString(save->GetResetTime() - time(NULL)); - PSendSysMessage("map: %d inst: %d perm: %s diff: %s canReset: %s TTR: %s", itr->first, save->GetInstanceId(), itr->second.perm ? "yes" : "no", save->GetDifficulty() == DIFFICULTY_NORMAL ? "normal" : "heroic", save->CanReset() ? "yes" : "no", timeleft.c_str()); - counter++; + PSendSysMessage("map: %d inst: %d perm: %s diff: %d canReset: %s TTR: %s", itr->first, save->GetInstanceId(), itr->second.perm ? "yes" : "no", save->GetDifficulty(), save->CanReset() ? "yes" : "no", timeleft.c_str()); counter++; } } } @@ -6844,17 +6851,17 @@ bool ChatHandler::HandleInstanceUnbindCommand(const char *args) Player* player = getSelectedPlayer(); if (!player) player = m_session->GetPlayer(); uint32 counter = 0; - for (uint8 i = 0; i < TOTAL_DIFFICULTIES; ++i) + for (uint8 i = 0; i < MAX_DIFFICULTY; ++i) { - Player::BoundInstancesMap &binds = player->GetBoundInstances(i); + Player::BoundInstancesMap &binds = player->GetBoundInstances(Difficulty(i)); for (Player::BoundInstancesMap::iterator itr = binds.begin(); itr != binds.end();) { if(itr->first != player->GetMapId()) { InstanceSave *save = itr->second.save; std::string timeleft = GetTimeString(save->GetResetTime() - time(NULL)); - PSendSysMessage("unbinding map: %d inst: %d perm: %s diff: %s canReset: %s TTR: %s", itr->first, save->GetInstanceId(), itr->second.perm ? "yes" : "no", save->GetDifficulty() == DIFFICULTY_NORMAL ? "normal" : "heroic", save->CanReset() ? "yes" : "no", timeleft.c_str()); - player->UnbindInstance(itr, i); + PSendSysMessage("unbinding map: %d inst: %d perm: %s diff: %d canReset: %s TTR: %s", itr->first, save->GetInstanceId(), itr->second.perm ? "yes" : "no", save->GetDifficulty(), save->CanReset() ? "yes" : "no", timeleft.c_str()); + player->UnbindInstance(itr, Difficulty(i)); counter++; } else @@ -7537,4 +7544,3 @@ bool ChatHandler::HandleUnbindSightCommand(const char *args) m_session->GetPlayer()->StopCastingBindSight(); return true; } - diff --git a/src/game/LootHandler.cpp b/src/game/LootHandler.cpp index de464cf050e..74b9730691f 100644 --- a/src/game/LootHandler.cpp +++ b/src/game/LootHandler.cpp @@ -222,7 +222,7 @@ void WorldSession::HandleLootMoneyOpcode( WorldPacket & /*recv_data*/ ) Player* playerGroup = itr->getSource(); if(!playerGroup) continue; - if (player->IsWithinDist(playerGroup,sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE),false)) + if (player->IsWithinDistInMap(playerGroup,sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE),false)) playersNear.push_back(playerGroup); } diff --git a/src/game/LootMgr.cpp b/src/game/LootMgr.cpp index 2cfd92f11fc..809df7e9e51 100644 --- a/src/game/LootMgr.cpp +++ b/src/game/LootMgr.cpp @@ -1449,4 +1449,3 @@ void LoadLootTemplates_Reference() // output error for any still listed ids (not referenced from any loot table) LootTemplates_Reference.ReportUnusedIds(ids_set); } - diff --git a/src/game/LootMgr.h b/src/game/LootMgr.h index bcd9b564904..84532ece197 100644 --- a/src/game/LootMgr.h +++ b/src/game/LootMgr.h @@ -33,7 +33,8 @@ enum RollType { ROLL_PASS = 0, ROLL_NEED = 1, - ROLL_GREED = 2 + ROLL_GREED = 2, + MAX_ROLL_TYPE = 3 }; #define MAX_NR_LOOT_ITEMS 16 @@ -365,4 +366,3 @@ inline void LoadLootTables() } #endif - diff --git a/src/game/Map.cpp b/src/game/Map.cpp index a34ce673d9a..5a72c6ed8f0 100644 --- a/src/game/Map.cpp +++ b/src/game/Map.cpp @@ -38,6 +38,7 @@ #include "MapRefManager.h" #include "Vehicle.h" #include "WaypointManager.h" +#include "DBCEnums.h" #include "MapInstanced.h" #include "InstanceSaveMgr.h" @@ -217,12 +218,12 @@ Map::Map(uint32 id, time_t expiry, uint32 InstanceId, uint8 SpawnMode, Map* _par { m_notifyTimer.SetInterval(IN_MILISECONDS/2); - for (uint8 idx = 0; idx < MAX_NUMBER_OF_GRIDS; ++idx) + for (unsigned int idx=0; idx < MAX_NUMBER_OF_GRIDS; ++idx) { - for (uint8 j = 0; j < MAX_NUMBER_OF_GRIDS; ++j) + for (unsigned int j=0; j < MAX_NUMBER_OF_GRIDS; ++j) { //z code - GridMaps[idx][j] = NULL; + GridMaps[idx][j] =NULL; setNGrid(NULL, idx, j); } } @@ -2384,6 +2385,7 @@ void Map::RemoveAllObjectsInRemoveList() i_objectsToRemove.erase(itr); } + //sLog.outDebug("Object remover 2 check."); } @@ -2584,11 +2586,11 @@ bool InstanceMap::Add(Player *player) if(!mapSave) { sLog.outDetail("InstanceMap::Add: creating instance save for map %d spawnmode %d with instance id %d", GetId(), GetSpawnMode(), GetInstanceId()); - mapSave = sInstanceSaveManager.AddInstanceSave(GetId(), GetInstanceId(), GetSpawnMode(), 0, true); + mapSave = sInstanceSaveManager.AddInstanceSave(GetId(), GetInstanceId(), Difficulty(GetSpawnMode()), 0, true); } // check for existing instance binds - InstancePlayerBind *playerBind = player->GetBoundInstance(GetId(), GetSpawnMode()); + InstancePlayerBind *playerBind = player->GetBoundInstance(GetId(), Difficulty(GetSpawnMode())); if(playerBind && playerBind->perm) { // cannot enter other instances if bound permanently @@ -2604,7 +2606,7 @@ bool InstanceMap::Add(Player *player) if(pGroup) { // solo saves should be reset when entering a group - InstanceGroupBind *groupBind = pGroup->GetBoundInstance(GetId(), GetSpawnMode()); + InstanceGroupBind *groupBind = pGroup->GetBoundInstance(this); if(playerBind) { sLog.outError("InstanceMap::Add: player %s(%d) is being put in instance %d,%d,%d,%d,%d,%d but he is in group %d and is bound to instance %d,%d,%d,%d,%d,%d!", player->GetName(), player->GetGUIDLow(), mapSave->GetMapId(), mapSave->GetInstanceId(), mapSave->GetDifficulty(), mapSave->GetPlayerCount(), mapSave->GetGroupCount(), mapSave->CanReset(), GUID_LOPART(pGroup->GetLeaderGUID()), playerBind->save->GetMapId(), playerBind->save->GetInstanceId(), playerBind->save->GetDifficulty(), playerBind->save->GetPlayerCount(), playerBind->save->GetGroupCount(), playerBind->save->CanReset()); @@ -2811,7 +2813,7 @@ void InstanceMap::UnloadAll() void InstanceMap::SendResetWarnings(uint32 timeLeft) const { for (MapRefManager::const_iterator itr = m_mapRefManager.begin(); itr != m_mapRefManager.end(); ++itr) - itr->getSource()->SendInstanceResetWarning(GetId(), itr->getSource()->GetDifficulty(), timeLeft); + itr->getSource()->SendInstanceResetWarning(GetId(), itr->getSource()->GetDifficulty(IsRaid()), timeLeft); } void InstanceMap::SetResetSchedule(bool on) @@ -2819,26 +2821,45 @@ void InstanceMap::SetResetSchedule(bool on) // only for normal instances // the reset time is only scheduled when there are no payers inside // it is assumed that the reset time will rarely (if ever) change while the reset is scheduled - if (IsDungeon() && !HavePlayers() && !IsRaid() && !IsHeroic()) + if(IsDungeon() && !HavePlayers() && !IsRaidOrHeroicDungeon()) { InstanceSave *save = sInstanceSaveManager.GetInstanceSave(GetInstanceId()); if (!save) sLog.outError("InstanceMap::SetResetSchedule: cannot turn schedule %s, no save available for instance %d of %d", on ? "on" : "off", GetInstanceId(), GetId()); - else sInstanceSaveManager.ScheduleReset(on, save->GetResetTime(), InstanceSaveManager::InstResetEvent(0, GetId(), GetInstanceId())); + else sInstanceSaveManager.ScheduleReset(on, save->GetResetTime(), InstanceSaveManager::InstResetEvent(0, GetId(), Difficulty(GetSpawnMode()), GetInstanceId())); } } +MapDifficulty const* InstanceMap::GetMapDifficulty() const +{ + return GetMapDifficultyData(GetId(),GetDifficulty()); +} + uint32 InstanceMap::GetMaxPlayers() const { - InstanceTemplate const* iTemplate = objmgr.GetInstanceTemplate(GetId()); - if (!iTemplate) + if(MapDifficulty const* mapDiff = GetMapDifficulty()) + { + if(mapDiff->maxPlayers || IsRegularDifficulty()) // Normal case (expect that regular difficulty always have correct maxplayers) + return mapDiff->maxPlayers; + else // DBC have 0 maxplayers for heroic instances with expansion < 2 + { // The heroic entry exists, so we don't have to check anything, simply return normal max players + MapDifficulty const* normalDiff = GetMapDifficultyData(GetId(), REGULAR_DIFFICULTY); + return normalDiff ? normalDiff->maxPlayers : 0; + } + } + else // I'd rather assert(false); return 0; - return IsHeroic() ? iTemplate->maxPlayersHeroic : iTemplate->maxPlayers; +} + +uint32 InstanceMap::GetMaxResetDelay() const +{ + MapDifficulty const* mapDiff = GetMapDifficulty(); + return mapDiff ? mapDiff->resetTime : 0; } /* ******* Battleground Instance Maps ******* */ -BattleGroundMap::BattleGroundMap(uint32 id, time_t expiry, uint32 InstanceId, Map* _parent) - : Map(id, expiry, InstanceId, DIFFICULTY_NORMAL, _parent) +BattleGroundMap::BattleGroundMap(uint32 id, time_t expiry, uint32 InstanceId, Map* _parent, uint8 spawnMode) + : Map(id, expiry, InstanceId, spawnMode, _parent) { //lets initialize visibility distance for BG/Arenas BattleGroundMap::InitVisibilityDistance(); @@ -3789,4 +3810,3 @@ void Map::UpdateIteratorBack(Player *player) if(m_mapRefIter == player->GetMapRef()) m_mapRefIter = m_mapRefIter->nocheck_prev(); } - diff --git a/src/game/Map.h b/src/game/Map.h index fa4e7a03468..981a48bbbb6 100644 --- a/src/game/Map.h +++ b/src/game/Map.h @@ -51,6 +51,7 @@ class CreatureGroup; struct ScriptInfo; struct ScriptAction; struct Position; +class BattleGround; typedef ACE_RW_Thread_Mutex GridRWLock; @@ -229,9 +230,6 @@ struct InstanceTemplate { uint32 map; uint32 parent; - uint32 maxPlayers; - uint32 maxPlayersHeroic; - uint32 reset_delay; // FIX ME: now exist normal/heroic raids with possible different time of reset. uint32 access_id; float startLocX; float startLocY; @@ -383,7 +381,8 @@ class MANGOS_DLL_SPEC Map : public GridRefManager<NGridType>, public MaNGOS::Obj // NOTE: this duplicate of Instanceable(), but Instanceable() can be changed when BG also will be instanceable bool IsDungeon() const { return i_mapEntry && i_mapEntry->IsDungeon(); } bool IsRaid() const { return i_mapEntry && i_mapEntry->IsRaid(); } - bool IsHeroic() const { return i_spawnMode == DIFFICULTY_HEROIC; } + bool IsRaidOrHeroicDungeon() const { return IsRaid() || i_spawnMode > DUNGEON_DIFFICULTY_NORMAL; } + bool IsHeroic() const { return IsRaid() ? i_spawnMode >= RAID_DIFFICULTY_10MAN_HEROIC : i_spawnMode >= DUNGEON_DIFFICULTY_HEROIC; } bool IsBattleGround() const { return i_mapEntry && i_mapEntry->IsBattleGround(); } bool IsBattleArena() const { return i_mapEntry && i_mapEntry->IsBattleArena(); } bool IsBattleGroundOrArena() const { return i_mapEntry && i_mapEntry->IsBattleGroundOrArena(); } @@ -610,7 +609,13 @@ class TRINITY_DLL_SPEC InstanceMap : public Map bool CanEnter(Player* player); void SendResetWarnings(uint32 timeLeft) const; void SetResetSchedule(bool on); + + // have meaning only for instanced map (that have set real difficulty) + Difficulty GetDifficulty() const { return Difficulty(GetSpawnMode()); } + bool IsRegularDifficulty() const { return GetDifficulty() == REGULAR_DIFFICULTY; } uint32 GetMaxPlayers() const; + uint32 GetMaxResetDelay() const; + MapDifficulty const* GetMapDifficulty() const; virtual void InitVisibilityDistance(); private: @@ -623,7 +628,7 @@ class TRINITY_DLL_SPEC InstanceMap : public Map class TRINITY_DLL_SPEC BattleGroundMap : public Map { public: - BattleGroundMap(uint32 id, time_t, uint32 InstanceId, Map* _parent); + BattleGroundMap(uint32 id, time_t, uint32 InstanceId, Map* _parent, uint8 spawnMode); ~BattleGroundMap(); bool Add(Player *); @@ -634,6 +639,10 @@ class TRINITY_DLL_SPEC BattleGroundMap : public Map void RemoveAllPlayers(); virtual void InitVisibilityDistance(); + BattleGround* GetBG() { return m_bg; } + void SetBG(BattleGround* bg) { m_bg = bg; } + private: + BattleGround* m_bg; }; /*inline @@ -710,4 +719,3 @@ Map::VisitGrid(const float &x, const float &y, float radius, NOTIFIER ¬ifier) cell_lock->Visit(cell_lock, grid_object_notifier, *this, radius, x_off, y_off); } #endif - diff --git a/src/game/MapInstanced.cpp b/src/game/MapInstanced.cpp index c77e40cb8f9..2fd9564a263 100644 --- a/src/game/MapInstanced.cpp +++ b/src/game/MapInstanced.cpp @@ -26,7 +26,7 @@ #include "InstanceSaveMgr.h" #include "World.h" -MapInstanced::MapInstanced(uint32 id, time_t expiry) : Map(id, expiry, 0, 0) +MapInstanced::MapInstanced(uint32 id, time_t expiry) : Map(id, expiry, 0, DUNGEON_DIFFICULTY_NORMAL) { // initialize instanced maps list m_InstancedMaps.clear(); @@ -40,7 +40,9 @@ void MapInstanced::InitVisibilityDistance() return; //initialize visibility distances for all instance copies for (InstancedMaps::iterator i = m_InstancedMaps.begin(); i != m_InstancedMaps.end(); ++i) + { (*i).second->InitVisibilityDistance(); + } } void MapInstanced::Update(const uint32& t) @@ -118,46 +120,63 @@ void MapInstanced::UnloadAll() - create the instance if it's not created already - the player is not actually added to the instance (only in InstanceMap::Add) */ -Map* MapInstanced::CreateInstance(const uint32 mapId, Player * player, uint32 instanceId) +Map* MapInstanced::CreateInstance(const uint32 mapId, Player * player) { - if(instanceId) - if(Map *map = _FindMap(instanceId)) - return map; + if(GetId() != mapId || !player) + return NULL; + + Map* map = NULL; + uint32 NewInstanceId = 0; // instanceId of the resulting map if(IsBattleGroundOrArena()) { - instanceId = player->GetBattleGroundId(); - if(instanceId) - if(Map *map = _FindMap(instanceId)) - return map; - return CreateBattleGround(instanceId); + // instantiate or find existing bg map for player + // the instance id is set in battlegroundid + NewInstanceId = player->GetBattleGroundId(); + if(!NewInstanceId) return NULL; + map = _FindMap(NewInstanceId); + if(!map) + map = CreateBattleGround(NewInstanceId, player->GetBattleGround()); } - else if(InstanceSave *pSave = player->GetInstanceSave(GetId())) + else { - if(!instanceId) + InstancePlayerBind *pBind = player->GetBoundInstance(GetId(), player->GetDifficulty(IsRaid())); + InstanceSave *pSave = pBind ? pBind->save : NULL; + + // the player's permanent player bind is taken into consideration first + // then the player's group bind and finally the solo bind. + if(!pBind || !pBind->perm) { - instanceId = pSave->GetInstanceId(); // go from outside to instance - if(Map *map = _FindMap(instanceId)) - return map; + InstanceGroupBind *groupBind = NULL; + Group *group = player->GetGroup(); + // use the player's difficulty setting (it may not be the same as the group's) + if(group && (groupBind = group->GetBoundInstance(this))) + pSave = groupBind->save; } - else if(instanceId != pSave->GetInstanceId()) // cannot go from one instance to another - return NULL; - // else log in at a saved instance - - return CreateInstance(instanceId, pSave, pSave->GetDifficulty()); - } - else if(!player->GetSession()->PlayerLoading()) - { - if(!instanceId) - instanceId = MapManager::Instance().GenerateInstanceId(); + if(pSave) + { + // solo/perm/group + NewInstanceId = pSave->GetInstanceId(); + map = _FindMap(NewInstanceId); + // it is possible that the save exists but the map doesn't + if(!map) + map = CreateInstance(NewInstanceId, pSave, pSave->GetDifficulty()); + } + else + { + // if no instanceId via group members or instance saves is found + // the instance will be created for the first time + NewInstanceId = MapManager::Instance().GenerateInstanceId(); - return CreateInstance(instanceId, NULL, player->GetDifficulty()); + Difficulty diff = player->GetGroup() ? player->GetGroup()->GetDifficulty(IsRaid()) : player->GetDifficulty(IsRaid()); + map = CreateInstance(NewInstanceId, NULL, diff); + } } - return NULL; + return map; } -InstanceMap* MapInstanced::CreateInstance(uint32 InstanceId, InstanceSave *save, uint8 difficulty) +InstanceMap* MapInstanced::CreateInstance(uint32 InstanceId, InstanceSave *save, Difficulty difficulty) { // load/create a map Guard guard(*this); @@ -177,7 +196,9 @@ InstanceMap* MapInstanced::CreateInstance(uint32 InstanceId, InstanceSave *save, } // some instances only have one difficulty - if (entry && !entry->SupportsHeroicMode()) difficulty = DIFFICULTY_NORMAL; + MapDifficulty const* mapDiff = GetMapDifficultyData(GetId(),difficulty); + if (!mapDiff) + difficulty = DUNGEON_DIFFICULTY_NORMAL; sLog.outDebug("MapInstanced::CreateInstance: %s map instance %d for %d created with difficulty %s", save?"":"new ", InstanceId, GetId(), difficulty?"heroic":"normal"); @@ -191,15 +212,21 @@ InstanceMap* MapInstanced::CreateInstance(uint32 InstanceId, InstanceSave *save, return map; } -BattleGroundMap* MapInstanced::CreateBattleGround(uint32 InstanceId) +BattleGroundMap* MapInstanced::CreateBattleGround(uint32 InstanceId, BattleGround* bg) { // load/create a map Guard guard(*this); sLog.outDebug("MapInstanced::CreateBattleGround: map bg %d for %d created.", InstanceId, GetId()); - BattleGroundMap *map = new BattleGroundMap(GetId(), GetGridExpiry(), InstanceId, this); + // 0-59 normal spawn 60-69 difficulty_1, 70-79 difficulty_2, 80 dufficulty_3 + uint8 spawnMode = (bg->GetQueueId() > QUEUE_ID_MAX_LEVEL_59) ? (bg->GetQueueId() - QUEUE_ID_MAX_LEVEL_59) : 0; + while (!GetMapDifficultyData(GetId(), Difficulty(spawnMode))) + spawnMode--; + BattleGroundMap *map = new BattleGroundMap(GetId(), GetGridExpiry(), InstanceId, this, spawnMode); ASSERT(map->IsBattleGroundOrArena()); + map->SetBG(bg); + bg->SetBgMap(map); m_InstancedMaps[InstanceId] = map; return map; @@ -235,4 +262,3 @@ bool MapInstanced::CanEnter(Player *player) //assert(false); return true; } - diff --git a/src/game/MapInstanced.h b/src/game/MapInstanced.h index 22622d362ce..90aa5f5508e 100644 --- a/src/game/MapInstanced.h +++ b/src/game/MapInstanced.h @@ -23,6 +23,7 @@ #include "Map.h" #include "InstanceSaveMgr.h" +#include "DBCEnums.h" class TRINITY_DLL_DECL MapInstanced : public Map { @@ -41,7 +42,7 @@ class TRINITY_DLL_DECL MapInstanced : public Map void UnloadAll(); bool CanEnter(Player* player); - Map* CreateInstance(const uint32 mapId, Player * player, uint32 instanceId); + Map* CreateInstance(const uint32 mapId, Player * player); Map* FindMap(uint32 InstanceId) const { return _FindMap(InstanceId); } bool DestroyInstance(InstancedMaps::iterator &itr); @@ -63,8 +64,8 @@ class TRINITY_DLL_DECL MapInstanced : public Map private: - InstanceMap* CreateInstance(uint32 InstanceId, InstanceSave *save, uint8 difficulty); - BattleGroundMap* CreateBattleGround(uint32 InstanceId); + InstanceMap* CreateInstance(uint32 InstanceId, InstanceSave *save, Difficulty difficulty); + BattleGroundMap* CreateBattleGround(uint32 InstanceId, BattleGround* bg); InstancedMaps m_InstancedMaps; @@ -77,4 +78,3 @@ class TRINITY_DLL_DECL MapInstanced : public Map uint16 GridMapReference[MAX_NUMBER_OF_GRIDS][MAX_NUMBER_OF_GRIDS]; }; #endif - diff --git a/src/game/MapManager.cpp b/src/game/MapManager.cpp index 5121b9dc574..d1457b5adee 100644 --- a/src/game/MapManager.cpp +++ b/src/game/MapManager.cpp @@ -82,7 +82,7 @@ MapManager::Initialize() void MapManager::InitializeVisibilityDistanceInfo() { - for (MapMapType::iterator iter = i_maps.begin(); iter != i_maps.end(); ++iter) + for (MapMapType::iterator iter=i_maps.begin(); iter != i_maps.end(); ++iter) (*iter).second->InitVisibilityDistance(); } @@ -90,9 +90,9 @@ void MapManager::InitializeVisibilityDistanceInfo() void MapManager::checkAndCorrectGridStatesArray() { bool ok = true; - for (uint8 i = 0; i < MAX_GRID_STATE; ++i) + for (int i=0; i<MAX_GRID_STATE; i++) { - if (i_GridStates[i] != si_GridStates[i]) + if(i_GridStates[i] != si_GridStates[i]) { sLog.outError("MapManager::checkGridStates(), GridState: si_GridStates is currupt !!!"); ok = false; @@ -107,10 +107,8 @@ void MapManager::checkAndCorrectGridStatesArray() } #endif } - if (!ok) + if(!ok) ++i_GridStateErrorCount; - if (i_GridStateErrorCount > 2) - assert(false); // force a crash. Too many errors } Map* @@ -127,13 +125,9 @@ MapManager::_createBaseMap(uint32 id) { m = new MapInstanced(id, i_gridCleanUpDelay); } - else if (entry) - { - m = new Map(id, i_gridCleanUpDelay, 0, 0); - } else { - assert(false); + m = new Map(id, i_gridCleanUpDelay, 0, REGULAR_DIFFICULTY); } i_maps[id] = m; } @@ -148,7 +142,7 @@ Map* MapManager::CreateMap(uint32 id, const WorldObject* obj, uint32 instanceId) //if(!obj->IsInWorld()) sLog.outError("GetMap: called for map %d with object (typeid %d, guid %d, mapid %d, instanceid %d) who is not in world!", id, obj->GetTypeId(), obj->GetGUIDLow(), obj->GetMapId(), obj->GetInstanceId()); Map *m = _createBaseMap(id); - if (m && (obj->GetTypeId() == TYPEID_PLAYER) && m->Instanceable()) m = ((MapInstanced*)m)->CreateInstance(id, (Player*)obj, instanceId); + if (m && (obj->GetTypeId() == TYPEID_PLAYER) && m->Instanceable()) m = ((MapInstanced*)m)->CreateInstance(id, (Player*)obj); return m; } @@ -192,14 +186,22 @@ bool MapManager::CanPlayerEnter(uint32 mapid, Player* player) sLog.outDebug("MAP: Player '%s' must be in a raid group to enter instance of '%s'", player->GetName(), mapName); return false; } + // Åñëè ÈÊ èëè È×, òî ïðîâåðÿòü óðîâåíü øìîòà îäåòîãî íà ïåðñå. + //if(mapid==649) } } //The player has a heroic mode and tries to enter into instance which has no a heroic mode - if (!entry->SupportsHeroicMode() && player->GetDifficulty() == DIFFICULTY_HEROIC) + MapDifficulty const* mapDiff = GetMapDifficultyData(entry->MapID,player->GetDifficulty(entry->map_type == MAP_RAID)); + if (!mapDiff) { + bool isNormalTargetMap = entry->map_type == MAP_RAID + ? (player->GetRaidDifficulty() == RAID_DIFFICULTY_10MAN_NORMAL) + : (player->GetDungeonDifficulty() == DUNGEON_DIFFICULTY_NORMAL); + //Send aborted message - player->SendTransferAborted(mapid, TRANSFER_ABORT_DIFFICULTY, DIFFICULTY_HEROIC); + // FIX ME: what about absent normal/heroic mode with specific players limit... + player->SendTransferAborted(mapid, TRANSFER_ABORT_DIFFICULTY, isNormalTargetMap ? DUNGEON_DIFFICULTY_NORMAL : DUNGEON_DIFFICULTY_HEROIC); return false; } @@ -240,13 +242,13 @@ bool MapManager::CanPlayerEnter(uint32 mapid, Player* player) //Get instance where player's group is bound & its map if (player->GetGroup()) { - InstanceGroupBind* boundedInstance = player->GetGroup()->GetBoundInstance(mapid, player->GetDifficulty()); + InstanceGroupBind* boundedInstance = player->GetGroup()->GetBoundInstance(player); if (boundedInstance && boundedInstance->save) { if (Map *boundedMap = MapManager::Instance().FindMap(mapid,boundedInstance->save->GetInstanceId())) { //Player permanently bounded to different instance than groups one - InstancePlayerBind* playerBoundedInstance = player->GetBoundInstance(mapid, player->GetDifficulty()); + InstancePlayerBind* playerBoundedInstance = player->GetBoundInstance(mapid, player->GetDungeonDifficulty()); if (playerBoundedInstance && playerBoundedInstance->perm && playerBoundedInstance->save && boundedInstance->save->GetInstanceId() != playerBoundedInstance->save->GetInstanceId()) { @@ -263,7 +265,8 @@ bool MapManager::CanPlayerEnter(uint32 mapid, Player* player) } //Instance is full - int8 maxPlayers = (player->GetDifficulty() == DIFFICULTY_HEROIC) ? instance->maxPlayersHeroic : instance->maxPlayers; + MapDifficulty const* mapDiff = ((InstanceMap*)player)->GetMapDifficulty(); + int8 maxPlayers = mapDiff ? mapDiff->maxPlayers : 0; if (maxPlayers != -1) //-1: unlimited access { if (boundedMap->GetPlayersCountExceptGMs() >= maxPlayers) @@ -336,17 +339,6 @@ MapManager::Update(uint32 diff) void MapManager::DoDelayedMovesAndRemoves() { - /* - std::vector<Map*> update_queue(i_maps.size()); - for (MapMapType::iterator iter = i_maps.begin(), uint32 i = 0; iter != i_maps.end(); ++iter, ++i) - update_queue[i] = iter->second; - - omp_set_num_threads(sWorld.getConfig(CONFIG_NUMTHREADS)); - -#pragma omp parallel for schedule(dynamic) private(i) shared(update_queue) - for (uint32 i = 0; i < i_maps.size(); ++i) - update_queue[i]->DoDelayedMovesAndRemoves(); - */ } bool MapManager::ExistMapAndVMap(uint32 mapid, float x,float y) @@ -427,4 +419,3 @@ uint32 MapManager::GetNumPlayersInInstances() } return ret; } - diff --git a/src/game/MapManager.h b/src/game/MapManager.h index 05fd3db9951..f4bc5feafa2 100644 --- a/src/game/MapManager.h +++ b/src/game/MapManager.h @@ -156,4 +156,3 @@ class MANGOS_DLL_DECL MapManager : public MaNGOS::Singleton<MapManager, MaNGOS:: MapUpdater m_updater; }; #endif - diff --git a/src/game/MiscHandler.cpp b/src/game/MiscHandler.cpp index c51ca063e48..85e1a497a25 100644 --- a/src/game/MiscHandler.cpp +++ b/src/game/MiscHandler.cpp @@ -47,6 +47,7 @@ #include "AccountMgr.h" #include "Vehicle.h" #include "CreatureAI.h" +#include "DBCEnums.h" void WorldSession::HandleRepopRequestOpcode( WorldPacket & recv_data ) { @@ -468,7 +469,7 @@ void WorldSession::HandleSetTargetOpcode( WorldPacket & recv_data ) uint64 guid ; recv_data >> guid; - _player->SetUInt32Value(UNIT_FIELD_TARGET,guid); + _player->SetUInt32Value(UNIT_FIELD_TARGET, guid); // update reputation list if need Unit* unit = ObjectAccessor::GetUnit(*_player, guid ); @@ -692,10 +693,8 @@ void WorldSession::HandleSetContactNotesOpcode( WorldPacket & recv_data ) void WorldSession::HandleBugOpcode( WorldPacket & recv_data ) { - uint32 suggestion, contentlen; - std::string content; - uint32 typelen; - std::string type; + uint32 suggestion, contentlen, typelen; + std::string content, type; recv_data >> suggestion >> contentlen >> content; @@ -737,7 +736,7 @@ void WorldSession::HandleReclaimCorpseOpcode(WorldPacket &recv_data) if(corpse->GetGhostTime() + GetPlayer()->GetCorpseReclaimDelay(corpse->GetType()==CORPSE_RESURRECTABLE_PVP) > time(NULL)) return; - if (!corpse->IsWithinDist(GetPlayer(), CORPSE_RECLAIM_RADIUS, true)) + if (!corpse->IsWithinDistInMap(GetPlayer(), CORPSE_RECLAIM_RADIUS, true)) return; uint64 guid; @@ -988,8 +987,8 @@ void WorldSession::HandleRequestAccountData(WorldPacket& recv_data) dest.resize(destSize); - WorldPacket data (SMSG_UPDATE_ACCOUNT_DATA, 8+4+4+4+destSize); - data << uint64(_player->GetGUID()); // player guid + WorldPacket data(SMSG_UPDATE_ACCOUNT_DATA, 8+4+4+4+destSize); + data << uint64(_player ? _player->GetGUID() : 0); // player guid data << uint32(type); // type (0-7) data << uint32(adata->Time); // unix time data << uint32(size); // decompressed length @@ -1053,7 +1052,12 @@ void WorldSession::HandleMoveTimeSkippedOpcode( WorldPacket & recv_data ) /* WorldSession::Update( getMSTime() );*/ DEBUG_LOG( "WORLD: Time Lag/Synchronization Resent/Update" ); - recv_data.read_skip<uint64>(); + uint64 guid; + if(!recv_data.readPackGUID(guid)) + { + recv_data.rpos(recv_data.wpos()); + return; + } recv_data.read_skip<uint32>(); /* uint64 guid; @@ -1441,10 +1445,16 @@ void WorldSession::HandleResetInstancesOpcode( WorldPacket & /*recv_data*/ ) if(pGroup) { if(pGroup->IsLeader(_player->GetGUID())) - pGroup->ResetInstances(INSTANCE_RESET_ALL, _player); + { + pGroup->ResetInstances(INSTANCE_RESET_ALL, false, _player); + pGroup->ResetInstances(INSTANCE_RESET_ALL, true,_player); + } } else - _player->ResetInstances(INSTANCE_RESET_ALL); + { + _player->ResetInstances(INSTANCE_RESET_ALL, false); + _player->ResetInstances(INSTANCE_RESET_ALL, true); + } } void WorldSession::HandleSetDungeonDifficultyOpcode( WorldPacket & recv_data ) @@ -1454,15 +1464,15 @@ void WorldSession::HandleSetDungeonDifficultyOpcode( WorldPacket & recv_data ) uint32 mode; recv_data >> mode; - if(mode == _player->GetDifficulty()) - return; - - if(mode > DIFFICULTY_HEROIC) + if(mode >= MAX_DUNGEON_DIFFICULTY) { sLog.outError("WorldSession::HandleSetDungeonDifficultyOpcode: player %d sent an invalid instance mode %d!", _player->GetGUIDLow(), mode); return; } + if(Difficulty(mode) == _player->GetDungeonDifficulty()) + return; + // cannot reset while in an instance Map *map = _player->GetMap(); if(map && map->IsDungeon()) @@ -1480,21 +1490,64 @@ void WorldSession::HandleSetDungeonDifficultyOpcode( WorldPacket & recv_data ) { // the difficulty is set even if the instances can't be reset //_player->SendDungeonDifficulty(true); - pGroup->ResetInstances(INSTANCE_RESET_CHANGE_DIFFICULTY, _player); - pGroup->SetDifficulty(mode); + pGroup->ResetInstances(INSTANCE_RESET_CHANGE_DIFFICULTY, false, _player); + pGroup->SetDungeonDifficulty(Difficulty(mode)); } } else { - _player->ResetInstances(INSTANCE_RESET_CHANGE_DIFFICULTY); - _player->SetDifficulty(mode); + _player->ResetInstances(INSTANCE_RESET_CHANGE_DIFFICULTY, false); + _player->SetDungeonDifficulty(Difficulty(mode)); + } +} + +void WorldSession::HandleSetRaidDifficultyOpcode( WorldPacket & recv_data ) +{ + sLog.outDebug("MSG_SET_RAID_DIFFICULTY"); + + uint32 mode; + recv_data >> mode; + + if(mode >= MAX_RAID_DIFFICULTY) + { + sLog.outError("WorldSession::HandleSetRaidDifficultyOpcode: player %d sent an invalid instance mode %d!", _player->GetGUIDLow(), mode); + return; + } + + // cannot reset while in an instance + Map *map = _player->GetMap(); + if(map && map->IsDungeon()) + { + sLog.outError("WorldSession::HandleSetRaidDifficultyOpcode: player %d tried to reset the instance while inside!", _player->GetGUIDLow()); + return; } + + if(Difficulty(mode) == _player->GetRaidDifficulty()) + return; + + if(_player->getLevel() < LEVELREQUIREMENT_HEROIC) + return; + + if(Group *pGroup = _player->GetGroup()) + { + if(pGroup->IsLeader(_player->GetGUID())) + { + // the difficulty is set even if the instances can't be reset + //_player->SendDungeonDifficulty(true); + pGroup->ResetInstances(INSTANCE_RESET_CHANGE_DIFFICULTY, true, _player); + pGroup->SetRaidDifficulty(Difficulty(mode)); + } + } + else + { + _player->ResetInstances(INSTANCE_RESET_CHANGE_DIFFICULTY, true); + _player->SetRaidDifficulty(Difficulty(mode)); + } } void WorldSession::HandleCancelMountAuraOpcode( WorldPacket & /*recv_data*/ ) { sLog.outDebug("WORLD: CMSG_CANCEL_MOUNT_AURA"); - //recv_data.hexlike(); //If player is not mounted, so go out :) if (!_player->IsMounted()) // not blizz like; no any messages on blizz @@ -1519,7 +1572,10 @@ void WorldSession::HandleMoveSetCanFlyAckOpcode( WorldPacket & recv_data ) sLog.outDebug("WORLD: CMSG_MOVE_SET_CAN_FLY_ACK"); //recv_data.hexlike(); - recv_data.read_skip<uint64>(); // guid + uint64 guid; // guid - unused + if(!recv_data.readPackGUID(guid)) + return; + recv_data.read_skip<uint32>(); // unk MovementInfo movementInfo; @@ -1558,3 +1614,13 @@ void WorldSession::HandleQueryInspectAchievements( WorldPacket & recv_data ) player->GetAchievementMgr().SendRespondInspectAchievements(_player); } + +void WorldSession::HandleWorldStateUITimerUpdate(WorldPacket& recv_data) +{ + // empty opcode + sLog.outDebug("WORLD: CMSG_WORLD_STATE_UI_TIMER_UPDATE"); + + WorldPacket data(SMSG_WORLD_STATE_UI_TIMER_UPDATE, 4); + data << uint32(time(NULL)); + SendPacket(&data); +} diff --git a/src/game/MotionMaster.cpp b/src/game/MotionMaster.cpp index 705cb20053a..c49765ded54 100644 --- a/src/game/MotionMaster.cpp +++ b/src/game/MotionMaster.cpp @@ -589,4 +589,3 @@ bool MotionMaster::GetDestination(float &x, float &y, float &z) return top()->GetDestination(x,y,z); } - diff --git a/src/game/MovementHandler.cpp b/src/game/MovementHandler.cpp index a718d1601a2..7968fe06fb7 100644 --- a/src/game/MovementHandler.cpp +++ b/src/game/MovementHandler.cpp @@ -149,10 +149,14 @@ void WorldSession::HandleMoveWorldportAckOpcode() } } - if((mEntry->IsRaid() || (mEntry->IsNonRaidDungeon() && mEntry->SupportsHeroicMode() && GetPlayer()->IsHeroic())) && mInstance) + if (mInstance && mEntry->IsDungeon()) { - uint32 timeleft = sInstanceSaveManager.GetResetTimeFor(GetPlayer()->GetMapId()) - time(NULL); - GetPlayer()->SendInstanceResetWarning(GetPlayer()->GetMapId(), GetPlayer()->GetDifficulty(), timeleft); + Difficulty diff = GetPlayer()->GetDifficulty(mEntry->IsRaid()); + if (uint32 timeReset = sInstanceSaveManager.GetResetTimeFor(GetPlayer()->GetMapId(),diff)) + { + uint32 timeleft = timeReset - time(NULL); + GetPlayer()->SendInstanceResetWarning(GetPlayer()->GetMapId(), diff, timeleft); + } } // mount allow check @@ -179,9 +183,11 @@ void WorldSession::HandleMoveTeleportAck(WorldPacket& recv_data) { sLog.outDebug("MSG_MOVE_TELEPORT_ACK"); uint64 guid; - uint32 flags, time; - recv_data >> guid; + if(!recv_data.readPackGUID(guid)) + return; + + uint32 flags, time; recv_data >> flags >> time; DEBUG_LOG("Guid " UI64FMTD, guid); DEBUG_LOG("Flags %u, time %u", flags, time/IN_MILISECONDS); @@ -226,6 +232,7 @@ void WorldSession::HandleMovementOpcodes( WorldPacket & recv_data ) { uint16 opcode = recv_data.GetOpcode(); //sLog.outDebug("WORLD: Recvd %s (%u, 0x%X) opcode", LookupOpcodeName(opcode), opcode, opcode); + recv_data.hexlike(); Unit *mover = _player->m_mover; @@ -241,17 +248,23 @@ void WorldSession::HandleMovementOpcodes( WorldPacket & recv_data ) } /* extract packet */ + uint64 guid; + + if(!recv_data.readPackGUID(guid)) + return; + MovementInfo movementInfo; + movementInfo.guid = guid; ReadMovementInfo(recv_data, &movementInfo); /*----------------*/ - if (recv_data.size() != recv_data.rpos()) + /* if(recv_data.size() != recv_data.rpos()) { sLog.outError("MovementHandler: player %s (guid %d, account %u) sent a packet (opcode %u) that is " SIZEFMTD " bytes larger than it should be. Kicked as cheater.", _player->GetName(), _player->GetGUIDLow(), _player->GetSession()->GetAccountId(), recv_data.GetOpcode(), recv_data.size() - recv_data.rpos()); - KickPlayer(); + KickPlayer();*/ recv_data.rpos(recv_data.wpos()); // prevent warnings spam - return; - } + /* return; + }*/ if (!Trinity::IsValidMapCoord(movementInfo.x, movementInfo.y, movementInfo.z, movementInfo.o)) { @@ -320,10 +333,10 @@ void WorldSession::HandleMovementOpcodes( WorldPacket & recv_data ) /*----------------------*/ /* process position-change */ - recv_data.put<uint32>(6, getMSTime()); // fix time, offset flags(4) + unk(2) - WorldPacket data(recv_data.GetOpcode(), (mover->GetPackGUID().size()+recv_data.size())); - data.append(mover->GetPackGUID()); // use mover guid - data.append(recv_data.contents(), recv_data.size()); + WorldPacket data(opcode, recv_data.size()); + movementInfo.time = getMSTime(); + movementInfo.guid = mover->GetGUID(); + WriteMovementInfo(&data, &movementInfo); GetPlayer()->SendMessageToSet(&data, false); mover->m_movementInfo = movementInfo; @@ -338,7 +351,7 @@ void WorldSession::HandleMovementOpcodes( WorldPacket & recv_data ) if (plMover) // nothing is charmed, or player charmed { plMover->SetPosition(movementInfo.x, movementInfo.y, movementInfo.z, movementInfo.o); - plMover->UpdateFallInformationIfNeed(movementInfo, recv_data.GetOpcode()); + plMover->UpdateFallInformationIfNeed(movementInfo, opcode); if (movementInfo.z < -500.0f) { @@ -389,14 +402,16 @@ void WorldSession::HandleMovementOpcodes( WorldPacket & recv_data ) void WorldSession::HandleForceSpeedChangeAck(WorldPacket &recv_data) { - //sLog.outDebug("WORLD: Recvd %s (%u, 0x%X) opcode", LookupOpcodeName(recv_data.GetOpcode()), recv_data.GetOpcode(), recv_data.GetOpcode()); - + uint32 opcode = recv_data.GetOpcode(); + sLog.outDebug("WORLD: Recvd %s (%u, 0x%X) opcode", LookupOpcodeName(opcode), opcode, opcode); + /* extract packet */ uint64 guid; uint32 unk1; float newspeed; - recv_data >> guid; + if(!recv_data.readPackGUID(guid)) + return; // now can skip not our packet if(_player->GetGUID() != guid) @@ -410,6 +425,7 @@ void WorldSession::HandleForceSpeedChangeAck(WorldPacket &recv_data) recv_data >> unk1; // counter or moveEvent MovementInfo movementInfo; + movementInfo.guid = guid; ReadMovementInfo(recv_data, &movementInfo); recv_data >> newspeed; @@ -422,7 +438,6 @@ void WorldSession::HandleForceSpeedChangeAck(WorldPacket &recv_data) static char const* move_type_name[MAX_MOVE_TYPE] = { "Walk", "Run", "RunBack", "Swim", "SwimBack", "TurnRate", "Flight", "FlightBack", "PitchRate" }; - uint16 opcode = recv_data.GetOpcode(); switch(opcode) { case CMSG_FORCE_WALK_SPEED_CHANGE_ACK: move_type = MOVE_WALK; force_move_type = MOVE_WALK; break; @@ -498,7 +513,8 @@ void WorldSession::HandleMoveNotActiveMover(WorldPacket &recv_data) sLog.outDebug("WORLD: Recvd CMSG_MOVE_NOT_ACTIVE_MOVER"); uint64 old_mover_guid; - recv_data >> old_mover_guid; + if(!recv_data.readPackGUID(old_mover_guid)) + return; /*if(_player->m_mover->GetGUID() == old_mover_guid) { @@ -507,7 +523,12 @@ void WorldSession::HandleMoveNotActiveMover(WorldPacket &recv_data) return; }*/ - ReadMovementInfo(recv_data, &_player->m_mover->m_movementInfo); + MovementInfo mi; + mi.guid = old_mover_guid; + ReadMovementInfo(recv_data, &mi); + + //ReadMovementInfo(recv_data, &_player->m_mover->m_movementInfo); + _player->m_movementInfo = mi; } void WorldSession::HandleDismissControlledVehicle(WorldPacket &recv_data) @@ -523,7 +544,19 @@ void WorldSession::HandleDismissControlledVehicle(WorldPacket &recv_data) return; } - ReadMovementInfo(recv_data, &_player->m_mover->m_movementInfo); + uint64 guid; + + if(!recv_data.readPackGUID(guid)) + return; + + MovementInfo mi; + mi.guid = guid; + ReadMovementInfo(recv_data, &mi); + + _player->m_movementInfo = mi; + + /* + ReadMovementInfo(recv_data, &_player->m_mover->m_movementInfo);*/ _player->ExitVehicle(); } @@ -584,7 +617,10 @@ void WorldSession::HandleMoveKnockBackAck( WorldPacket & recv_data ) { sLog.outDebug("CMSG_MOVE_KNOCK_BACK_ACK"); - recv_data.read_skip<uint64>(); // guid + uint64 guid; // guid - unused + if(!recv_data.readPackGUID(guid)) + return; + recv_data.read_skip<uint32>(); // unk MovementInfo movementInfo; @@ -595,7 +631,10 @@ void WorldSession::HandleMoveHoverAck( WorldPacket& recv_data ) { sLog.outDebug("CMSG_MOVE_HOVER_ACK"); - recv_data.read_skip<uint64>(); // guid + uint64 guid; // guid - unused + if(!recv_data.readPackGUID(guid)) + return; + recv_data.read_skip<uint32>(); // unk MovementInfo movementInfo; @@ -608,7 +647,10 @@ void WorldSession::HandleMoveWaterWalkAck(WorldPacket& recv_data) { sLog.outDebug("CMSG_MOVE_WATER_WALK_ACK"); - recv_data.read_skip<uint64>(); // guid + uint64 guid; // guid - unused + if(!recv_data.readPackGUID(guid)) + return; + recv_data.read_skip<uint32>(); // unk MovementInfo movementInfo; @@ -629,4 +671,3 @@ void WorldSession::HandleSummonResponseOpcode(WorldPacket& recv_data) _player->SummonIfPossible(agree); } - diff --git a/src/game/Object.cpp b/src/game/Object.cpp index 6aa4b3949c5..f3cff243e93 100644 --- a/src/game/Object.cpp +++ b/src/game/Object.cpp @@ -1398,6 +1398,16 @@ bool WorldObject::IsInBetween(const WorldObject *obj1, const WorldObject *obj2, return abs(sin(angle)) * GetExactDist2d(obj1->GetPositionX(), obj1->GetPositionY()) < size; } +bool WorldObject::isInFront(WorldObject const* target, float distance, float arc) const +{ + return IsWithinDist(target, distance) && HasInArc( arc, target ); +} + +bool WorldObject::isInBack(WorldObject const* target, float distance, float arc) const +{ + return IsWithinDist(target, distance) && !HasInArc( 2 * M_PI - arc, target ); +} + void WorldObject::GetRandomPoint(const Position &pos, float distance, float &rand_x, float &rand_y, float &rand_z) const { if(!distance) @@ -1932,38 +1942,52 @@ Creature* WorldObject::SummonTrigger(float x, float y, float z, float ang, uint3 return summon; } -Creature* WorldObject::FindNearestCreature(uint32 uiEntry, float fMaxSearchRange, bool bAlive) +Creature* WorldObject::FindNearestCreature(uint32 entry, float range, bool alive) { - Creature *pCreature = NULL; - Trinity::NearestCreatureEntryWithLiveStateInObjectRangeCheck checker(*this, uiEntry, bAlive, fMaxSearchRange); - Trinity::CreatureLastSearcher<Trinity::NearestCreatureEntryWithLiveStateInObjectRangeCheck> searcher(this, pCreature, checker); - VisitNearbyObject(fMaxSearchRange, searcher); - return pCreature; + Creature *creature = NULL; + Trinity::NearestCreatureEntryWithLiveStateInObjectRangeCheck checker(*this, entry, alive, range); + Trinity::CreatureLastSearcher<Trinity::NearestCreatureEntryWithLiveStateInObjectRangeCheck> searcher(this, creature, checker); + VisitNearbyObject(range, searcher); + return creature; } -GameObject* WorldObject::FindNearestGameObject(uint32 uiEntry, float fMaxSearchRange) +GameObject* WorldObject::FindNearestGameObject(uint32 entry, float range) { - GameObject *pGO = NULL; - Trinity::NearestGameObjectEntryInObjectRangeCheck checker(*this, uiEntry, fMaxSearchRange); - Trinity::GameObjectLastSearcher<Trinity::NearestGameObjectEntryInObjectRangeCheck> searcher(this, pGO, checker); - VisitNearbyGridObject(fMaxSearchRange, searcher); - return pGO; + GameObject *go = NULL; + Trinity::NearestGameObjectEntryInObjectRangeCheck checker(*this, entry, range); + Trinity::GameObjectLastSearcher<Trinity::NearestGameObjectEntryInObjectRangeCheck> searcher(this, go, checker); + VisitNearbyGridObject(range, searcher); + return go; +} + +void WorldObject::GetGameObjectListWithEntryInGrid(std::list<GameObject*>& lList, uint32 uiEntry, float fMaxSearchRange) +{ + CellPair pair(Trinity::ComputeCellPair(this->GetPositionX(), this->GetPositionY())); + Cell cell(pair); + cell.data.Part.reserved = ALL_DISTRICT; + cell.SetNoCreate(); + + Trinity::AllGameObjectsWithEntryInRange check(this, uiEntry, fMaxSearchRange); + Trinity::GameObjectListSearcher<Trinity::AllGameObjectsWithEntryInRange> searcher(this, lList, check); + TypeContainerVisitor<Trinity::GameObjectListSearcher<Trinity::AllGameObjectsWithEntryInRange>, GridTypeMapContainer> visitor(searcher); + + CellLock<GridReadGuard> cell_lock(cell, pair); + cell_lock->Visit(cell_lock, visitor, *(this->GetMap())); } void WorldObject::GetCreatureListWithEntryInGrid(std::list<Creature*>& lList, uint32 uiEntry, float fMaxSearchRange) { + CellPair pair(Trinity::ComputeCellPair(this->GetPositionX(), this->GetPositionY())); + Cell cell(pair); + cell.data.Part.reserved = ALL_DISTRICT; + cell.SetNoCreate(); + Trinity::AllCreaturesOfEntryInRange check(this, uiEntry, fMaxSearchRange); Trinity::CreatureListSearcher<Trinity::AllCreaturesOfEntryInRange> searcher(this, lList, check); TypeContainerVisitor<Trinity::CreatureListSearcher<Trinity::AllCreaturesOfEntryInRange>, GridTypeMapContainer> visitor(searcher); - VisitNearbyObject(fMaxSearchRange, searcher); -} -void WorldObject::GetGameObjectListWithEntryInGrid(std::list<GameObject*>& lList, uint32 uiEntry, float fMaxSearchRange) -{ - Trinity::AllGameObjectsWithEntryInRange check(this, uiEntry, fMaxSearchRange); - Trinity::GameObjectListSearcher<Trinity::AllGameObjectsWithEntryInRange> searcher(this, lList, check); - TypeContainerVisitor<Trinity::GameObjectListSearcher<Trinity::AllGameObjectsWithEntryInRange>, GridTypeMapContainer> visitor(searcher); - VisitNearbyGridObject(fMaxSearchRange, searcher); + CellLock<GridReadGuard> cell_lock(cell, pair); + cell_lock->Visit(cell_lock, visitor, *(this->GetMap())); } /* diff --git a/src/game/Object.h b/src/game/Object.h index b068033bdf3..83189f30b23 100644 --- a/src/game/Object.h +++ b/src/game/Object.h @@ -237,8 +237,7 @@ class TRINITY_DLL_SPEC Object bool HasFlag( uint16 index, uint32 flag ) const { - if(index >= m_valuesCount && !PrintIndexError(index , false)) - return false; + if( index >= m_valuesCount && !PrintIndexError( index , false ) ) return false; return (m_uint32Values[ index ] & flag) != 0; } @@ -549,6 +548,8 @@ class TRINITY_DLL_SPEC WorldObject : public Object, public WorldLocation bool IsInRange(WorldObject const* obj, float minRange, float maxRange, bool is3D = true) const; bool IsInRange2d(float x, float y, float minRange, float maxRange) const; bool IsInRange3d(float x, float y, float z, float minRange, float maxRange) const; + bool isInFront(WorldObject const* target,float distance, float arc = M_PI) const; + bool isInBack(WorldObject const* target, float distance, float arc = M_PI) const; bool IsInBetween(const WorldObject *obj1, const WorldObject *obj2, float size = 0) const; @@ -611,11 +612,11 @@ class TRINITY_DLL_SPEC WorldObject : public Object, public WorldLocation GameObject* SummonGameObject(uint32 entry, float x, float y, float z, float ang, float rotation0, float rotation1, float rotation2, float rotation3, uint32 respawnTime); Creature* SummonTrigger(float x, float y, float z, float ang, uint32 dur, CreatureAI* (*GetAI)(Creature*) = NULL); - Creature* FindNearestCreature(uint32 uiEntry, float fMaxSearchRange, bool bAlive = true); - GameObject* FindNearestGameObject(uint32 uiEntry, float fMaxSearchRange); + Creature* FindNearestCreature(uint32 entry, float range, bool alive = true); + GameObject* FindNearestGameObject(uint32 entry, float range); - void GetCreatureListWithEntryInGrid(std::list<Creature*>& lList, uint32 uiEntry, float fMaxSearchRange); void GetGameObjectListWithEntryInGrid(std::list<GameObject*>& lList, uint32 uiEntry, float fMaxSearchRange); + void GetCreatureListWithEntryInGrid(std::list<Creature*>& lList, uint32 uiEntry, float fMaxSearchRange); void DestroyForNearbyPlayers(); @@ -655,4 +656,3 @@ class TRINITY_DLL_SPEC WorldObject : public Object, public WorldLocation uint32 m_phaseMask; // in area phase state }; #endif - diff --git a/src/game/ObjectAccessor.cpp b/src/game/ObjectAccessor.cpp index 2dfd9c9ae7b..e52423eabd8 100644 --- a/src/game/ObjectAccessor.cpp +++ b/src/game/ObjectAccessor.cpp @@ -49,7 +49,10 @@ ObjectAccessor::ObjectAccessor() {} ObjectAccessor::~ObjectAccessor() { for (Player2CorpsesMapType::const_iterator itr = i_player2corpse.begin(); itr != i_player2corpse.end(); ++itr) + { + itr->second->RemoveFromWorld(); delete itr->second; + } } Creature* @@ -351,6 +354,10 @@ ObjectAccessor::ConvertCorpseForPlayer(uint64 player_guid, bool insignia) // remove corpse from DB corpse->DeleteFromDB(); + // we don't want bones to save some cpu.. :) + delete corpse; + return NULL; + Corpse *bones = NULL; // create the bones only if the map and the grid is loaded at the corpse's location // ignore bones creating option in case insignia @@ -521,4 +528,3 @@ template Creature* ObjectAccessor::GetObjectInWorld<Creature>(uint32 mapid, floa template Corpse* ObjectAccessor::GetObjectInWorld<Corpse>(uint32 mapid, float x, float y, uint64 guid, Corpse* /*fake*/); template GameObject* ObjectAccessor::GetObjectInWorld<GameObject>(uint32 mapid, float x, float y, uint64 guid, GameObject* /*fake*/); template DynamicObject* ObjectAccessor::GetObjectInWorld<DynamicObject>(uint32 mapid, float x, float y, uint64 guid, DynamicObject* /*fake*/); - diff --git a/src/game/ObjectAccessor.h b/src/game/ObjectAccessor.h index 79afa78fb6a..780c108e5e4 100644 --- a/src/game/ObjectAccessor.h +++ b/src/game/ObjectAccessor.h @@ -267,4 +267,3 @@ class MANGOS_DLL_DECL ObjectAccessor : public MaNGOS::Singleton<ObjectAccessor, LockType i_petGuard; }; #endif - diff --git a/src/game/ObjectMgr.cpp b/src/game/ObjectMgr.cpp index 1d9f2d64878..d1b7d58c54f 100644 --- a/src/game/ObjectMgr.cpp +++ b/src/game/ObjectMgr.cpp @@ -204,10 +204,6 @@ ObjectMgr::~ObjectMgr() for (GuildMap::iterator itr = mGuildMap.begin(); itr != mGuildMap.end(); ++itr) delete itr->second; - mGuildMap.clear(); - - for (CachePlayerInfoMap::iterator itr = m_mPlayerInfoMap.begin(); itr != m_mPlayerInfoMap.end(); ++itr) - delete itr->second; for (ArenaTeamMap::iterator itr = mArenaTeamMap.begin(); itr != mArenaTeamMap.end(); ++itr) delete itr->second; @@ -219,61 +215,6 @@ ObjectMgr::~ObjectMgr() itr->second.Clear(); } -void ObjectMgr::LoadPlayerInfoInCache() -{ - QueryResult *result = CharacterDatabase.PQuery("SELECT guid, name, data, class FROM characters"); - if(!result) - { - sLog.outError( "Loading Player Cache failed."); - return; - } - - PCachePlayerInfo pPPlayerInfo = NULL; - Field *fields = NULL; - Tokens tdata; - barGoLink bar( result->GetRowCount() ); - do - { - bar.step(); - fields = result->Fetch(); - pPPlayerInfo = new CachePlayerInfo(); - - pPPlayerInfo->sPlayerName = fields[1].GetString(); - - tdata.clear(); - tdata = StrSplit(fields[2].GetCppString(), " "); - - pPPlayerInfo->unLevel = Player::GetUInt32ValueFromArray(tdata,UNIT_FIELD_LEVEL); - pPPlayerInfo->unfield = Player::GetUInt32ValueFromArray(tdata,UNIT_FIELD_BYTES_0); - - pPPlayerInfo->unArenaInfoId0 = Player::GetUInt32ValueFromArray(tdata,PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 0 * 6); - pPPlayerInfo->unArenaInfoId1 = Player::GetUInt32ValueFromArray(tdata,PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 1 * 6); - pPPlayerInfo->unArenaInfoId2 = Player::GetUInt32ValueFromArray(tdata,PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 2 * 6); - - pPPlayerInfo->unArenaInfoSlot0 = Player::GetUInt32ValueFromArray(tdata,PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 0 * 6 + 5); - pPPlayerInfo->unArenaInfoSlot1 = Player::GetUInt32ValueFromArray(tdata,PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 1 * 6 + 5); - pPPlayerInfo->unArenaInfoSlot2 = Player::GetUInt32ValueFromArray(tdata,PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 2 * 6 + 5); - - pPPlayerInfo->unClass = (uint32)fields[3].GetUInt32(); - m_mPlayerInfoMap[fields[0].GetUInt32()] = pPPlayerInfo; - } - while (result->NextRow()); - delete result; - - sLog.outString(); - sLog.outString( ">> Loaded info about %d players", m_mPlayerInfoMap.size()); -} - -PCachePlayerInfo ObjectMgr::GetPlayerInfoFromCache(uint32 unPlayerGuid) const -{ - //Now m_mPlayerInfoMap is using only for search, but when dinamic inserting/removing - //will be implemented we should lock it to prevent simultaneous access. - //Inserting - when new created player is saving - //Removing - when player has been deleted - CachePlayerInfoMap::const_iterator ipos = m_mPlayerInfoMap.find(unPlayerGuid); - return ipos == m_mPlayerInfoMap.end() ? NULL : ipos->second; -} - Group * ObjectMgr::GetGroupByLeader(const uint64 &guid) const { for (GroupSet::const_iterator itr = mGroupSet.begin(); itr != mGroupSet.end(); ++itr) @@ -570,8 +511,8 @@ void ObjectMgr::LoadCreatureTemplates() sLog.outString( ">> Loaded %u creature definitions", sCreatureStorage.RecordCount ); sLog.outString(); - std::set<uint32> heroicEntries; // already loaded heroic value in creatures - std::set<uint32> hasHeroicEntries; // already loaded creatures with heroic entry values + std::set<uint32> difficultyEntries[MAX_DIFFICULTY - 1]; // already loaded difficulty 1 value in creatures + std::set<uint32> hasDifficultyEntries[MAX_DIFFICULTY - 1]; // already loaded creatures with difficulty 1 values // check data correctness for (uint32 i = 1; i < sCreatureStorage.MaxEntry; ++i) @@ -580,84 +521,105 @@ void ObjectMgr::LoadCreatureTemplates() if (!cInfo) continue; - if (cInfo->HeroicEntry) + bool ok = true; // bool to allow continue outside this loop + for (uint32 diff = 0; diff < MAX_DIFFICULTY - 1 && ok; ++diff) { - CreatureInfo const* heroicInfo = GetCreatureTemplate(cInfo->HeroicEntry); - if (!heroicInfo) - { - sLog.outErrorDb("Creature (Entry: %u) have `heroic_entry`=%u but creature entry %u not exist.", i, cInfo->HeroicEntry, cInfo->HeroicEntry); + if (!cInfo->DifficultyEntry[diff]) continue; - } + ok = false; // will be set to true at the end of this loop again - if (heroicEntries.find(i)!=heroicEntries.end()) + CreatureInfo const* difficultyInfo = GetCreatureTemplate(cInfo->DifficultyEntry[diff]); + if (!difficultyInfo) { - sLog.outErrorDb("Creature (Entry: %u) listed as heroic but have value in `heroic_entry`.",i); + sLog.outErrorDb("Creature (Entry: %u) have `difficulty_entry_%u`=%u but creature entry %u not exist.", + i, diff + 1, cInfo->DifficultyEntry[diff], cInfo->DifficultyEntry[diff]); continue; } - if (heroicEntries.find(cInfo->HeroicEntry)!=heroicEntries.end()) + if (difficultyEntries[diff].find(i) != difficultyEntries[diff].end()) { - sLog.outErrorDb("Creature (Entry: %u) already listed as heroic for another entry.",cInfo->HeroicEntry); + sLog.outErrorDb("Creature (Entry: %u) listed as difficulty %u but have value in `difficulty_entry_1`.", i, diff + 1); continue; } - if (hasHeroicEntries.find(cInfo->HeroicEntry)!=hasHeroicEntries.end()) + bool ok2 = true; + for (uint32 diff2 = 0; diff2 < MAX_DIFFICULTY - 1 && ok2; ++diff2) { - sLog.outErrorDb("Creature (Entry: %u) have `heroic_entry`=%u but creature entry %u have heroic entry also.",i,cInfo->HeroicEntry,cInfo->HeroicEntry); - continue; + ok2 = false; + if (difficultyEntries[diff2].find(cInfo->DifficultyEntry[diff]) != difficultyEntries[diff2].end()) + { + sLog.outErrorDb("Creature (Entry: %u) already listed as difficulty %u for another entry.", cInfo->DifficultyEntry[diff], diff2 + 1); + continue; + } + + if (hasDifficultyEntries[diff2].find(cInfo->DifficultyEntry[diff]) != hasDifficultyEntries[diff2].end()) + { + sLog.outErrorDb("Creature (Entry: %u) have `difficulty_entry_%u`=%u but creature entry %u have difficulty %u entry also.", + i, diff + 1, cInfo->DifficultyEntry[diff], cInfo->DifficultyEntry[diff], diff2 + 1); + continue; + } + ok2 = true; } + if (!ok2) + continue; - if (cInfo->unit_class != heroicInfo->unit_class) + if (cInfo->unit_class != difficultyInfo->unit_class) { - sLog.outErrorDb("Creature (Entry: %u, class %u) has different `unit_class` in heroic mode (Entry: %u, class %u).",i, cInfo->unit_class, cInfo->HeroicEntry, heroicInfo->unit_class); + sLog.outErrorDb("Creature (Entry: %u, class %u) has different `unit_class` in difficulty %u mode (Entry: %u, class %u).", + i, cInfo->unit_class, diff + 1, cInfo->DifficultyEntry[diff], difficultyInfo->unit_class); continue; } - if (cInfo->npcflag != heroicInfo->npcflag) + if (cInfo->npcflag != difficultyInfo->npcflag) { - sLog.outErrorDb("Creature (Entry: %u) listed in `creature_template_substitution` has different `npcflag` in heroic mode.",i); + sLog.outErrorDb("Creature (Entry: %u) has different `npcflag` in difficulty %u mode (Entry: %u).", i, diff + 1, cInfo->DifficultyEntry[diff]); continue; } - if (cInfo->trainer_class != heroicInfo->trainer_class) + if (cInfo->trainer_class != difficultyInfo->trainer_class) { - sLog.outErrorDb("Creature (Entry: %u) has different `trainer_class` in heroic mode (Entry: %u).",i,cInfo->HeroicEntry); + sLog.outErrorDb("Creature (Entry: %u) has different `trainer_class` in difficulty %u mode (Entry: %u).", i, diff + 1, cInfo->DifficultyEntry[diff]); continue; } - if (cInfo->trainer_race != heroicInfo->trainer_race) + if (cInfo->trainer_race != difficultyInfo->trainer_race) { - sLog.outErrorDb("Creature (Entry: %u) has different `trainer_race` in heroic mode (Entry: %u).",i,cInfo->HeroicEntry); + sLog.outErrorDb("Creature (Entry: %u) has different `trainer_race` in difficulty %u mode (Entry: %u).", i, diff + 1, cInfo->DifficultyEntry[diff]); continue; } - if (cInfo->trainer_type != heroicInfo->trainer_type) + if (cInfo->trainer_type != difficultyInfo->trainer_type) { - sLog.outErrorDb("Creature (Entry: %u) listed in `creature_template_substitution` has different `trainer_type` in heroic mode.",i); + sLog.outErrorDb("Creature (Entry: %u) has different `trainer_type` in difficulty %u mode (Entry: %u).", i, diff + 1, cInfo->DifficultyEntry[diff]); continue; } - if (cInfo->trainer_spell != heroicInfo->trainer_spell) + if (cInfo->trainer_spell != difficultyInfo->trainer_spell) { - sLog.outErrorDb("Creature (Entry: %u) listed in `creature_template_substitution` has different `trainer_spell` in heroic mode.",i); + sLog.outErrorDb("Creature (Entry: %u) has different `trainer_spell` in difficulty %u mode (Entry: %u).", i, diff + 1, cInfo->DifficultyEntry[diff]); continue; } - if (heroicInfo->AIName && *heroicInfo->AIName) + if (difficultyInfo->AIName && *difficultyInfo->AIName) { - sLog.outErrorDb("Heroic mode creature (Entry: %u) has `AIName`, but in any case will used normal mode creature (Entry: %u) AIName.",cInfo->HeroicEntry,i); + sLog.outErrorDb("Difficulty %u mode creature (Entry: %u) has `AIName`, but in any case will used difficulty 0 mode creature (Entry: %u) AIName.", + diff, cInfo->DifficultyEntry[diff], i); continue; } - if (heroicInfo->ScriptID) + if (difficultyInfo->ScriptID) { - sLog.outErrorDb("Heroic mode creature (Entry: %u) has `ScriptName`, but in any case will used normal mode creature (Entry: %u) ScriptName.",cInfo->HeroicEntry,i); + sLog.outErrorDb("Difficulty %u mode creature (Entry: %u) has `ScriptName`, but in any case will used difficulty 0 mode creature (Entry: %u) ScriptName.", + diff, cInfo->DifficultyEntry[diff], i); continue; } - hasHeroicEntries.insert(i); - heroicEntries.insert(cInfo->HeroicEntry); + hasDifficultyEntries[diff].insert(i); + difficultyEntries[diff].insert(cInfo->DifficultyEntry[diff]); + ok = true; } + if (!ok) + continue; FactionTemplateEntry const* factionTemplate = sFactionTemplateStore.LookupEntry(cInfo->faction_A); if (!factionTemplate) @@ -1232,11 +1194,20 @@ void ObjectMgr::LoadCreatures() } // build single time for check creature data - std::set<uint32> heroicCreatures; + std::set<uint32> difficultyCreatures[MAX_DIFFICULTY - 1]; for (uint32 i = 0; i < sCreatureStorage.MaxEntry; ++i) - if(CreatureInfo const* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(i)) - if(cInfo->HeroicEntry) - heroicCreatures.insert(cInfo->HeroicEntry); + if (CreatureInfo const* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(i)) + for (uint32 diff = 0; diff < MAX_DIFFICULTY - 1; ++diff) + if (cInfo->DifficultyEntry[diff]) + difficultyCreatures[diff].insert(cInfo->DifficultyEntry[diff]); + + // build single time for check spawnmask + std::map<uint32,uint32> spawnMasks; + for(uint32 i = 0; i < sMapStore.GetNumRows(); ++i) + if(sMapStore.LookupEntry(i)) + for(int k = 0; k < MAX_DIFFICULTY; ++k) + if (GetMapDifficultyData(i,Difficulty(k))) + spawnMasks[i] |= (1 << k); //TODO: remove this //gameeventmgr.mGameEventCreatureGuids.resize(52*2-1); @@ -1280,12 +1251,29 @@ void ObjectMgr::LoadCreatures() int16 gameEvent = fields[18].GetInt16(); int16 PoolId = fields[19].GetInt16(); - if(heroicCreatures.find(data.id)!=heroicCreatures.end()) + MapEntry const* mapEntry = sMapStore.LookupEntry(data.mapid); + if(!mapEntry) { - sLog.outErrorDb("Table `creature` have creature (GUID: %u) that listed as heroic template (entry: %u) in `creature_template_substitution`, skipped.",guid,data.id ); + sLog.outErrorDb("Table `creature` have creature (GUID: %u) that spawned at not existed map (Id: %u), skipped.",guid, data.mapid ); continue; } + if (data.spawnMask & ~spawnMasks[data.mapid]) + sLog.outErrorDb("Table `creature` have creature (GUID: %u) that have wrong spawn mask %u including not supported difficulty modes for map (Id: %u).",guid, data.spawnMask, data.mapid ); + + bool ok = true; + for (uint32 diff = 0; diff < MAX_DIFFICULTY - 1 && ok; ++diff) + { + if (difficultyCreatures[diff].find(data.id) != difficultyCreatures[diff].end()) + { + sLog.outErrorDb("Table `creature` have creature (GUID: %u) that listed as difficulty %u template (entry: %u) in `creature_template`, skipped.", + guid, diff + 1, data.id ); + ok = false; + } + } + if (!ok) + continue; + // I do not know why but in db most display id are not zero /*if(data.displayid == 11686 || data.displayid == 24719) { @@ -1313,8 +1301,7 @@ void ObjectMgr::LoadCreatures() if(cInfo->flags_extra & CREATURE_FLAG_EXTRA_INSTANCE_BIND) { - MapEntry const* map = sMapStore.LookupEntry(data.mapid); - if(!map || !map->IsDungeon()) + if(!mapEntry || !mapEntry->IsDungeon()) sLog.outErrorDb("Table `creature` have creature (GUID: %u Entry: %u) with `creature_template`.`flags_extra` including CREATURE_FLAG_EXTRA_INSTANCE_BIND but creature are not in instance.",guid,data.id); } @@ -1569,6 +1556,14 @@ void ObjectMgr::LoadGameobjects() return; } + // build single time for check spawnmask + std::map<uint32,uint32> spawnMasks; + for(uint32 i = 0; i < sMapStore.GetNumRows(); ++i) + if(sMapStore.LookupEntry(i)) + for(int k = 0; k < MAX_DIFFICULTY; ++k) + if (GetMapDifficultyData(i,Difficulty(k))) + spawnMasks[i] |= (1 << k); + barGoLink bar(result->GetRowCount()); do @@ -1580,12 +1575,18 @@ void ObjectMgr::LoadGameobjects() uint32 entry = fields[ 1].GetUInt32(); GameObjectInfo const* gInfo = GetGameObjectInfo(entry); - if (!gInfo) + if(!gInfo) { sLog.outErrorDb("Table `gameobject` has gameobject (GUID: %u) with non existing gameobject entry %u, skipped.", guid, entry); continue; } + if(!gInfo->displayId) + { + sLog.outErrorDb("Gameobject (GUID: %u Entry %u GoType: %u) doesn't have displayId (%u), not loaded.", guid, entry, gInfo->type, gInfo->displayId); + continue; + } + if (gInfo->displayId && !sGameObjectDisplayInfoStore.LookupEntry(gInfo->displayId)) { sLog.outErrorDb("Gameobject (GUID: %u Entry %u GoType: %u) have invalid displayId (%u), not loaded.",guid, entry, gInfo->type, gInfo->displayId); @@ -1606,6 +1607,13 @@ void ObjectMgr::LoadGameobjects() data.rotation3 = fields[10].GetFloat(); data.spawntimesecs = fields[11].GetInt32(); + MapEntry const* mapEntry = sMapStore.LookupEntry(data.mapid); + if(!mapEntry) + { + sLog.outErrorDb("Table `gameobject` have gameobject (GUID: %u Entry: %u) that spawned at not existed map (Id: %u), skip", guid, data.id, data.mapid); + continue; + } + if (data.spawntimesecs==0 && gInfo->IsDespawnAtAction()) { sLog.outErrorDb("Table `gameobject` have gameobject (GUID: %u Entry: %u) with `spawntimesecs` (0) value, but gameobejct marked as despawnable at action.",guid,data.id); @@ -1623,6 +1631,10 @@ void ObjectMgr::LoadGameobjects() data.go_state = GOState(go_state); data.spawnMask = fields[14].GetUInt8(); + + if (data.spawnMask & ~spawnMasks[data.mapid]) + sLog.outErrorDb("Table `gameobject` have gameobject (GUID: %u Entry: %u) that have wrong spawn mask %u including not supported difficulty modes for map (Id: %u), skip", guid, data.id, data.spawnMask, data.mapid); + data.phaseMask = fields[15].GetUInt16(); int16 gameEvent = fields[16].GetInt16(); int16 PoolId = fields[17].GetInt16(); @@ -1804,13 +1816,6 @@ bool ObjectMgr::GetPlayerNameByGUID(const uint64 &guid, std::string &name) const return true; } - PCachePlayerInfo pInfo = GetPlayerInfoFromCache(GUID_LOPART(guid)); - if(pInfo) - { - name = pInfo->sPlayerName.c_str(); - return true; - } - QueryResult *result = CharacterDatabase.PQuery("SELECT name FROM characters WHERE guid = '%u'", GUID_LOPART(guid)); if(result) @@ -1825,6 +1830,12 @@ bool ObjectMgr::GetPlayerNameByGUID(const uint64 &guid, std::string &name) const uint32 ObjectMgr::GetPlayerTeamByGUID(const uint64 &guid) const { + // prevent DB access for online player + if(Player* player = GetPlayer(guid)) + { + return Player::TeamForRace(player->getRace()); + } + QueryResult *result = CharacterDatabase.PQuery("SELECT race FROM characters WHERE guid = '%u'", GUID_LOPART(guid)); if(result) @@ -1839,6 +1850,12 @@ uint32 ObjectMgr::GetPlayerTeamByGUID(const uint64 &guid) const uint32 ObjectMgr::GetPlayerAccountIdByGUID(const uint64 &guid) const { + // prevent DB access for online player + if(Player* player = GetPlayer(guid)) + { + return player->GetSession()->GetAccountId(); + } + QueryResult *result = CharacterDatabase.PQuery("SELECT account FROM characters WHERE guid = '%u'", GUID_LOPART(guid)); if(result) { @@ -3319,9 +3336,9 @@ void ObjectMgr::LoadGroups() Group *group = NULL; uint64 leaderGuid = 0; uint32 count = 0; - // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 - QueryResult *result = CharacterDatabase.Query("SELECT mainTank, mainAssistant, lootMethod, looterGuid, lootThreshold, icon1, icon2, icon3, icon4, icon5, icon6, icon7, icon8, isRaid, difficulty, leaderGuid FROM groups"); - + // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 + QueryResult *result = CharacterDatabase.Query("SELECT mainTank, mainAssistant, lootMethod, looterGuid, lootThreshold, icon1, icon2, icon3, icon4, icon5, icon6, icon7, icon8, isRaid, difficulty, raiddifficulty, leaderGuid FROM groups"); + if( !result ) { barGoLink bar( 1 ); @@ -3340,7 +3357,7 @@ void ObjectMgr::LoadGroups() bar.step(); Field *fields = result->Fetch(); ++count; - leaderGuid = MAKE_NEW_GUID(fields[15].GetUInt32(),0,HIGHGUID_PLAYER); + leaderGuid = MAKE_NEW_GUID(fields[16].GetUInt32(),0,HIGHGUID_PLAYER); group = new Group; if(!group->LoadGroupFromDB(leaderGuid, result, false)) @@ -3454,7 +3471,14 @@ void ObjectMgr::LoadGroups() continue; } - InstanceSave *save = sInstanceSaveManager.AddInstanceSave(mapEntry->MapID, fields[2].GetUInt32(), fields[4].GetUInt8(), (time_t)fields[5].GetUInt64(), (fields[6].GetUInt32() == 0), true); + uint32 diff = fields[4].GetUInt8(); + if(diff >= (mapEntry->IsRaid() ? MAX_RAID_DIFFICULTY : MAX_DUNGEON_DIFFICULTY)) + { + sLog.outErrorDb("Wrong dungeon difficulty use in group_instance table: %d", diff + 1); + diff = 0; // default for both difficaly types + } + + InstanceSave *save = sInstanceSaveManager.AddInstanceSave(mapEntry->MapID, fields[2].GetUInt32(), Difficulty(diff), (time_t)fields[5].GetUInt64(), (fields[6].GetUInt32() == 0), true); group->BindToInstance(save, fields[3].GetBool(), true); }while( result->NextRow() ); delete result; @@ -3484,31 +3508,31 @@ void ObjectMgr::LoadQuests() "QuestFlags, SpecialFlags, CharTitleId, PlayersSlain, BonusTalents, PrevQuestId, NextQuestId, ExclusiveGroup, NextQuestInChain, SrcItemId, SrcItemCount, SrcSpell," // 29 30 31 32 33 34 35 36 37 38 "Title, Details, Objectives, OfferRewardText, RequestItemsText, EndText, ObjectiveText1, ObjectiveText2, ObjectiveText3, ObjectiveText4," - // 39 40 41 42 43 44 45 46 - "ReqItemId1, ReqItemId2, ReqItemId3, ReqItemId4, ReqItemCount1, ReqItemCount2, ReqItemCount3, ReqItemCount4," - // 47 48 49 50 51 52 53 54 + // 39 40 41 42 43 44 45 46 47 48 49 50 + "ReqItemId1, ReqItemId2, ReqItemId3, ReqItemId4, ReqItemId5, ReqItemId6, ReqItemCount1, ReqItemCount2, ReqItemCount3, ReqItemCount4, ReqItemCount5, ReqItemCount6," + // 51 52 53 54 55 56 57 58 "ReqSourceId1, ReqSourceId2, ReqSourceId3, ReqSourceId4, ReqSourceCount1, ReqSourceCount2, ReqSourceCount3, ReqSourceCount4," - // 55 56 57 58 59 60 61 62 + // 59 60 61 62 63 64 65 66 "ReqCreatureOrGOId1, ReqCreatureOrGOId2, ReqCreatureOrGOId3, ReqCreatureOrGOId4, ReqCreatureOrGOCount1, ReqCreatureOrGOCount2, ReqCreatureOrGOCount3, ReqCreatureOrGOCount4," - // 63 64 65 66 + // 67 68 69 70 "ReqSpellCast1, ReqSpellCast2, ReqSpellCast3, ReqSpellCast4," - // 67 68 69 70 71 72 + // 71 72 73 74 75 76 "RewChoiceItemId1, RewChoiceItemId2, RewChoiceItemId3, RewChoiceItemId4, RewChoiceItemId5, RewChoiceItemId6," - // 73 74 75 76 77 78 + // 77 78 79 80 81 82 "RewChoiceItemCount1, RewChoiceItemCount2, RewChoiceItemCount3, RewChoiceItemCount4, RewChoiceItemCount5, RewChoiceItemCount6," - // 79 80 81 82 83 84 85 86 + // 83 84 85 86 87 88 89 90 "RewItemId1, RewItemId2, RewItemId3, RewItemId4, RewItemCount1, RewItemCount2, RewItemCount3, RewItemCount4," - // 87 88 89 90 91 92 93 94 95 96 + // 91 92 93 94 95 96 97 98 99 100 "RewRepFaction1, RewRepFaction2, RewRepFaction3, RewRepFaction4, RewRepFaction5, RewRepValue1, RewRepValue2, RewRepValue3, RewRepValue4, RewRepValue5," - // 97 98 99 100 101 102 103 104 105 106 107 + // 101 102 103 104 105 106 107 108 109 110 111 "RewHonorableKills, RewOrReqMoney, RewMoneyMaxLevel, RewSpell, RewSpellCast, RewMailTemplateId, RewMailDelaySecs, PointMapId, PointX, PointY, PointOpt," - // 108 109 110 111 112 113 114 115 + // 112 113 114 115 116 117 118 119 "DetailsEmote1, DetailsEmote2, DetailsEmote3, DetailsEmote4, DetailsEmoteDelay1, DetailsEmoteDelay2, DetailsEmoteDelay3, DetailsEmoteDelay4," - // 116 117 118 119 120 121 + // 120 121 122 123 124 125 "IncompleteEmote, CompleteEmote, OfferRewardEmote1, OfferRewardEmote2, OfferRewardEmote3, OfferRewardEmote4," - // 122 123 124 125 + // 126 127 128 129 "OfferRewardEmoteDelay1, OfferRewardEmoteDelay2, OfferRewardEmoteDelay3, OfferRewardEmoteDelay4," - // 126 127 + // 130 131 "StartScript, CompleteScript" " FROM quest_template"); if(result == NULL) @@ -3537,8 +3561,7 @@ void ObjectMgr::LoadQuests() delete result; - - std::map<uint32,uint32> usedMailTemplates; + std::map<uint32,uint32> usedMailTemplates; // Post processing for (QuestMap::iterator iter = mQuestTemplates.begin(); iter != mQuestTemplates.end(); ++iter) @@ -3765,7 +3788,7 @@ void ObjectMgr::LoadQuests() } } - for (uint8 j = 0; j < QUEST_OBJECTIVES_COUNT; ++j ) + for (uint8 j = 0; j < QUEST_ITEM_OBJECTIVES_COUNT; ++j ) { uint32 id = qinfo->ReqItemId[j]; if(id) @@ -4057,7 +4080,7 @@ void ObjectMgr::LoadQuests() if (qinfo->NextQuestInChain) { QuestMap::iterator qNextItr = mQuestTemplates.find(qinfo->NextQuestInChain); - if (qNextItr == mQuestTemplates.end()) + if(qNextItr == mQuestTemplates.end()) { sLog.outErrorDb("Quest %u has `NextQuestInChain` = %u but quest %u does not exist, quest chain will not work.", qinfo->GetQuestId(),qinfo->NextQuestInChain ,qinfo->NextQuestInChain ); @@ -4068,7 +4091,7 @@ void ObjectMgr::LoadQuests() } // fill additional data stores - if (qinfo->PrevQuestId) + if(qinfo->PrevQuestId) { if (mQuestTemplates.find(abs(qinfo->GetPrevQuestId())) == mQuestTemplates.end()) { @@ -4080,7 +4103,7 @@ void ObjectMgr::LoadQuests() } } - if (qinfo->NextQuestId) + if(qinfo->NextQuestId) { QuestMap::iterator qNextItr = mQuestTemplates.find(abs(qinfo->GetNextQuestId())); if (qNextItr == mQuestTemplates.end()) @@ -4094,9 +4117,9 @@ void ObjectMgr::LoadQuests() } } - if (qinfo->ExclusiveGroup) + if(qinfo->ExclusiveGroup) mExclusiveQuestGroups.insert(std::pair<int32, uint32>(qinfo->ExclusiveGroup, qinfo->GetQuestId())); - if (qinfo->LimitTime) + if(qinfo->LimitTime) qinfo->SetFlag(QUEST_TRINITY_FLAGS_TIMED); } @@ -4666,36 +4689,36 @@ void ObjectMgr::LoadWaypointScripts() void ObjectMgr::LoadItemTexts() { QueryResult *result = CharacterDatabase.Query("SELECT id, text FROM item_text"); - + uint32 count = 0; - + if( !result ) { barGoLink bar( 1 ); bar.step(); - + sLog.outString(); sLog.outString( ">> Loaded %u item pages", count ); return; } - + barGoLink bar( result->GetRowCount() ); - + Field* fields; do { bar.step(); - + fields = result->Fetch(); - + mItemTexts[ fields[0].GetUInt32() ] = fields[1].GetCppString(); - + ++count; - + } while ( result->NextRow() ); - + delete result; - + sLog.outString(); sLog.outString( ">> Loaded %u item texts", count ); } @@ -4813,37 +4836,17 @@ void ObjectMgr::LoadInstanceTemplate() for (uint32 i = 0; i < sInstanceTemplate.MaxEntry; i++) { InstanceTemplate* temp = (InstanceTemplate*)GetInstanceTemplate(i); - if(!temp) continue; - const MapEntry* entry = sMapStore.LookupEntry(temp->map); - if(!entry) - { - sLog.outErrorDb("ObjectMgr::LoadInstanceTemplate: bad mapid %d for template!", temp->map); - continue; - } - else if(!entry->HasResetTime()) + if(!temp) continue; - //FIXME: now exist heroic instance, normal/heroic raid instances - // entry->resetTimeHeroic store reset time for both heroic mode instance (raid and non-raid) - // entry->resetTimeRaid store reset time for normal raid only - // for current state entry->resetTimeRaid == entry->resetTimeHeroic in case raid instances with heroic mode. - // but at some point wee need implement reset time dependent from raid instance mode - if(temp->reset_delay == 0) + if(!MapManager::IsValidMAP(temp->map)) + sLog.outErrorDb("ObjectMgr::LoadInstanceTemplate: bad mapid %d for template!", temp->map); + + if(!MapManager::IsValidMapCoord(temp->parent,temp->startLocX,temp->startLocY,temp->startLocZ,temp->startLocO)) { - // use defaults from the DBC - if(entry->resetTimeHeroic) // for both raid and non raids, read above - { - temp->reset_delay = entry->resetTimeHeroic / DAY; - } - else if (entry->resetTimeRaid && entry->map_type == MAP_RAID) - // for normal raid only - { - temp->reset_delay = entry->resetTimeRaid / DAY; - } + sLog.outErrorDb("ObjectMgr::LoadInstanceTemplate: bad parent entrance coordinates for map id %d template!", temp->map); + temp->parent = 0; // will have wrong continent 0 parent, at least existed } - - // the reset_delay must be at least one day - temp->reset_delay = std::max((uint32)1, (uint32)(temp->reset_delay * sWorld.getRate(RATE_INSTANCE_RESET_TIME))); } sLog.outString( ">> Loaded %u Instance Template definitions", sInstanceTemplate.RecordCount ); @@ -5250,6 +5253,7 @@ void ObjectMgr::LoadAreaTriggerScripts() sLog.outString( ">> Loaded %u areatrigger scripts", count ); } +// use searched_node for search some known node uint32 ObjectMgr::GetNearestTaxiNode( float x, float y, float z, uint32 mapid, uint32 team ) { bool found = false; @@ -5259,7 +5263,8 @@ uint32 ObjectMgr::GetNearestTaxiNode( float x, float y, float z, uint32 mapid, u for (uint32 i = 1; i < sTaxiNodesStore.GetNumRows(); ++i) { TaxiNodesEntry const* node = sTaxiNodesStore.LookupEntry(i); - if(!node || node->map_id != mapid || !node->MountCreatureID[team == ALLIANCE ? 1 : 0] && node->MountCreatureID[0] != 32981) // dk flight + + if(!node || node->map_id != mapid || !node->MountCreatureID[team == ALLIANCE ? 1 : 0] && node->MountCreatureID[0] != 32981) // dk flight continue; uint8 field = (uint8)((i - 1) / 32); @@ -5269,7 +5274,7 @@ uint32 ObjectMgr::GetNearestTaxiNode( float x, float y, float z, uint32 mapid, u if((sTaxiNodesMask[field] & submask)==0) continue; - float dist2 = (node->x - x)*(node->x - x)+(node->y - y)*(node->y - y)+(node->z - z)*(node->z - z); + float dist2 = (node->x - x)*(node->x - x)+(node->y - y)*(node->y - y)+(node->z - z)*(node->z - z); if(found) { if(dist2 < dist) @@ -5479,7 +5484,7 @@ WorldSafeLocsEntry const *ObjectMgr::GetClosestGraveYard(float x, float y, float if(graveLow==graveUp && !map->IsBattleArena()) { - sLog.outErrorDb("Table `game_graveyard_zone` incomplete: Zone %u Team %u does not have a linked graveyard.",zoneId,team); + //sLog.outErrorDb("Table `game_graveyard_zone` incomplete: Zone %u Team %u does not have a linked graveyard.",zoneId,team); return NULL; } diff --git a/src/game/ObjectMgr.h b/src/game/ObjectMgr.h index 1c5367387fc..440763c21cc 100644 --- a/src/game/ObjectMgr.h +++ b/src/game/ObjectMgr.h @@ -257,23 +257,6 @@ enum ConditionType #define MAX_CONDITION 14 // maximum value in ConditionType enum -//Player's info -typedef struct _tagCachePlayerInfo -{ - std::string sPlayerName; - uint32 unfield; - uint32 unLevel; - uint8 unClass; -//Arena - uint32 unArenaInfoId0; - uint32 unArenaInfoId1; - uint32 unArenaInfoId2; - uint32 unArenaInfoSlot0; - uint32 unArenaInfoSlot1; - uint32 unArenaInfoSlot2; -}CachePlayerInfo, *PCachePlayerInfo; -typedef UNORDERED_MAP<uint32, PCachePlayerInfo> CachePlayerInfoMap; - struct PlayerCondition { ConditionType condition; // additional condition type @@ -641,10 +624,6 @@ class ObjectMgr uint32 GenerateMailID(); uint32 GeneratePetNumber(); - void LoadPlayerInfoInCache(); - PCachePlayerInfo GetPlayerInfoFromCache(uint32 unPlayerGuid) const; - CachePlayerInfoMap m_mPlayerInfoMap; - uint32 CreateItemText(std::string text); void AddItemText(uint32 itemTextId, std::string text) { mItemTexts[itemTextId] = text; } std::string GetItemText( uint32 id ) diff --git a/src/game/Opcodes.cpp b/src/game/Opcodes.cpp index ba1deaeff7c..6dc88c9d37a 100644 --- a/src/game/Opcodes.cpp +++ b/src/game/Opcodes.cpp @@ -347,7 +347,7 @@ OpcodeHandler opcodeTable[NUM_MSG_TYPES] = /*0x13C*/ { "SMSG_AI_REACTION", STATUS_NEVER, &WorldSession::Handle_ServerSide }, /*0x13D*/ { "CMSG_SET_SELECTION", STATUS_LOGGEDIN, &WorldSession::HandleSetSelectionOpcode }, /*0x13E*/ { "CMSG_EQUIPMENT_SET_DELETE", STATUS_LOGGEDIN, &WorldSession::HandleEquipmentSetDelete }, - /*0x13F*/ { "CMSG_INSTANCE_LOCK_RESPONSE", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x13F*/ { "CMSG_INSTANCE_LOCK_WARNING_RESPONSE", STATUS_NEVER, &WorldSession::Handle_NULL }, /*0x140*/ { "CMSG_UNUSED2", STATUS_NEVER, &WorldSession::Handle_NULL }, /*0x141*/ { "CMSG_ATTACKSWING", STATUS_LOGGEDIN, &WorldSession::HandleAttackSwingOpcode }, /*0x142*/ { "CMSG_ATTACKSTOP", STATUS_LOGGEDIN, &WorldSession::HandleAttackStopOpcode }, @@ -355,7 +355,7 @@ OpcodeHandler opcodeTable[NUM_MSG_TYPES] = /*0x144*/ { "SMSG_ATTACKSTOP", STATUS_NEVER, &WorldSession::Handle_ServerSide }, /*0x145*/ { "SMSG_ATTACKSWING_NOTINRANGE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, /*0x146*/ { "SMSG_ATTACKSWING_BADFACING", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x147*/ { "SMSG_ATTACKSWING_NOTSTANDING", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x147*/ { "SMSG_INSTANCE_LOCK_WARNING_QUERY", STATUS_NEVER, &WorldSession::Handle_ServerSide }, /*0x148*/ { "SMSG_ATTACKSWING_DEADTARGET", STATUS_NEVER, &WorldSession::Handle_ServerSide }, /*0x149*/ { "SMSG_ATTACKSWING_CANT_ATTACK", STATUS_NEVER, &WorldSession::Handle_ServerSide }, /*0x14A*/ { "SMSG_ATTACKERSTATEUPDATE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, @@ -547,11 +547,11 @@ OpcodeHandler opcodeTable[NUM_MSG_TYPES] = /*0x204*/ { "CMSG_DECHARGE", STATUS_NEVER, &WorldSession::Handle_NULL }, /*0x205*/ { "CMSG_GMTICKET_CREATE", STATUS_LOGGEDIN, &WorldSession::HandleGMTicketCreateOpcode }, /*0x206*/ { "SMSG_GMTICKET_CREATE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x207*/ { "CMSG_GMTICKET_UPDATETEXT", STATUS_LOGGEDIN, &WorldSession::HandleGMTicketUpdateOpcode }, + /*0x207*/ { "CMSG_GMTICKET_UPDATETEXT", STATUS_LOGGEDIN, &WorldSession::HandleGMTicketUpdateOpcode }, /*0x208*/ { "SMSG_GMTICKET_UPDATETEXT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, /*0x209*/ { "SMSG_ACCOUNT_DATA_TIMES", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x20A*/ { "CMSG_REQUEST_ACCOUNT_DATA", STATUS_LOGGEDIN, &WorldSession::HandleRequestAccountData }, - /*0x20B*/ { "CMSG_UPDATE_ACCOUNT_DATA", STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT, &WorldSession::HandleUpdateAccountData}, + /*0x20A*/ { "CMSG_REQUEST_ACCOUNT_DATA", STATUS_AUTHED, &WorldSession::HandleRequestAccountData }, + /*0x20B*/ { "CMSG_UPDATE_ACCOUNT_DATA", STATUS_AUTHED, &WorldSession::HandleUpdateAccountData }, /*0x20C*/ { "SMSG_UPDATE_ACCOUNT_DATA", STATUS_NEVER, &WorldSession::Handle_ServerSide }, /*0x20D*/ { "SMSG_CLEAR_FAR_SIGHT_IMMEDIATE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, /*0x20E*/ { "SMSG_POWERGAINLOG_OBSOLETE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, @@ -686,8 +686,8 @@ OpcodeHandler opcodeTable[NUM_MSG_TYPES] = /*0x28F*/ { "CMSG_GROUP_ASSISTANT_LEADER", STATUS_LOGGEDIN, &WorldSession::HandleGroupAssistantLeaderOpcode}, /*0x290*/ { "CMSG_BUYBACK_ITEM", STATUS_LOGGEDIN, &WorldSession::HandleBuybackItem }, /*0x291*/ { "SMSG_SERVER_MESSAGE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x292*/ { "CMSG_MEETINGSTONE_JOIN", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x293*/ { "CMSG_MEETINGSTONE_LEAVE", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x292*/ { "CMSG_SET_SAVED_INSTANCE_EXTEND", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x293*/ { "CMSG_MEETINGSTONE_LEAVE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, /*0x294*/ { "CMSG_MEETINGSTONE_CHEAT", STATUS_NEVER, &WorldSession::Handle_NULL }, /*0x295*/ { "SMSG_MEETINGSTONE_SETQUEUE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, /*0x296*/ { "CMSG_MEETINGSTONE_INFO", STATUS_LOGGEDIN, &WorldSession::HandleMeetingStoneInfo }, @@ -1069,7 +1069,7 @@ OpcodeHandler opcodeTable[NUM_MSG_TYPES] = /*0x40E*/ { "CMSG_REFER_A_FRIEND", STATUS_NEVER, &WorldSession::Handle_NULL }, /*0x40F*/ { "CMSG_DECLINE_CHANNEL_INVITE", STATUS_LOGGEDIN, &WorldSession::HandleChannelDeclineInvite }, /*0x410*/ { "CMSG_DECLINE_CHANNEL_INVITE", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x411*/ { "CMSG_GROUPACTION_THROTTLED", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x411*/ { "SMSG_GROUPACTION_THROTTLED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, /*0x412*/ { "SMSG_OVERRIDE_LIGHT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, /*0x413*/ { "SMSG_TOTEM_CREATED", STATUS_NEVER, &WorldSession::Handle_ServerSide }, /*0x414*/ { "CMSG_TOTEM_DESTROYED", STATUS_LOGGEDIN, &WorldSession::HandleTotemDestroyed }, @@ -1230,12 +1230,12 @@ OpcodeHandler opcodeTable[NUM_MSG_TYPES] = /*0x4AF*/ { "UMSG_UNKNOWN_1199", STATUS_NEVER, &WorldSession::Handle_NULL }, /*0x4B0*/ { "UMSG_UNKNOWN_1200", STATUS_NEVER, &WorldSession::Handle_NULL }, /*0x4B1*/ { "UMSG_UNKNOWN_1201", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x4B2*/ { "SMSG_UNKNOWN_1202", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x4B3*/ { "UMSG_UNKNOWN_1203", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x4B4*/ { "UMSG_UNKNOWN_1204", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x4B2*/ { "SMSG_ITEM_REFUND_TIMER", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x4B3*/ { "CMSG_ITEM_REFUND_INFO_REQUEST", STATUS_LOGGEDIN, &WorldSession::HandleItemRefundInfoRequest }, + /*0x4B4*/ { "CMSG_ITEM_REFUND", STATUS_LOGGEDIN, &WorldSession::HandleItemRefund }, /*0x4B5*/ { "SMSG_UNKNOWN_1205", STATUS_NEVER, &WorldSession::Handle_ServerSide }, - /*0x4B6*/ { "CMSG_UNKNOWN_1206", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x4B7*/ { "SMSG_UNKNOWN_1207", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x4B6*/ { "CMSG_CORPSE_MAP_POSITION_QUERY", STATUS_LOGGEDIN, &WorldSession::HandleCorpseMapPositionQuery }, + /*0x4B7*/ { "CMSG_CORPSE_MAP_POSITION_QUERY_RESPONSE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, /*0x4B8*/ { "CMSG_LFG_SET_ROLES", STATUS_LOGGEDIN, &WorldSession::HandleLfgSetRoles }, /*0x4B9*/ { "UMSG_UNKNOWN_1209", STATUS_NEVER, &WorldSession::Handle_NULL }, /*0x4BA*/ { "CMSG_UNKNOWN_1210", STATUS_NEVER, &WorldSession::Handle_NULL }, @@ -1255,7 +1255,50 @@ OpcodeHandler opcodeTable[NUM_MSG_TYPES] = /*0x4C8*/ { "SMSG_UNKNOWN_1224", STATUS_NEVER, &WorldSession::Handle_ServerSide }, /*0x4C9*/ { "UMSG_UNKNOWN_1225", STATUS_NEVER, &WorldSession::Handle_NULL }, /*0x4CA*/ { "UMSG_UNKNOWN_1226", STATUS_NEVER, &WorldSession::Handle_NULL }, - /*0x4CB*/ { "CMSG_EQUIPMENT_SET_USE", STATUS_LOGGEDIN, &WorldSession::HandleEquipmentSetUse }, - /*0x4CC*/ { "SMSG_EQUIPMENT_SET_USE_RESULT", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x4CB*/ { "UMSG_UNKNOWN_1227", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x4CC*/ { "UMSG_UNKNOWN_1228", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x4CD*/ { "SMSG_UNKNOWN_1229", 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 }, + /*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 }, + /*0x4D8*/ { "SMSG_UNKNOWN_1240", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x4D9*/ { "CMSG_UNKNOWN_1241", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x4DA*/ { "SMSG_UNKNOWN_1242", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x4DB*/ { "UMSG_UNKNOWN_1243", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x4DC*/ { "UMSG_UNKNOWN_1244", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x4DD*/ { "UMSG_UNKNOWN_1245", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x4DE*/ { "SMSG_UNKNOWN_1246", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x4DF*/ { "CMSG_UNKNOWN_1247", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x4E0*/ { "SMSG_UNKNOWN_1248", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x4E1*/ { "SMSG_UNKNOWN_1249", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x4E2*/ { "CMSG_UNKNOWN_1250", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x4E3*/ { "CMSG_UNKNOWN_1251", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x4E4*/ { "SMSG_UNKNOWN_1252", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x4E5*/ { "SMSG_UNKNOWN_1253", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x4E6*/ { "SMSG_UNKNOWN_1254", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x4E7*/ { "CMSG_UNKNOWN_1255", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x4E8*/ { "SMSG_UNKNOWN_1256", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x4E9*/ { "UMSG_UNKNOWN_1257", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x4EA*/ { "UMSG_UNKNOWN_1258", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x4EB*/ { "MSG_SET_RAID_DIFFICULTY", STATUS_LOGGEDIN, &WorldSession::HandleSetRaidDifficultyOpcode }, + /*0x4EC*/ { "UMSG_UNKNOWN_1260", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x4ED*/ { "SMSG_TOGGLE_XP_GAIN", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x4EE*/ { "SMSG_UNKNOWN_1262", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x4EF*/ { "SMSG_UNKNOWN_1263", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x4F0*/ { "CMSG_UNKNOWN_1264", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x4F1*/ { "SMSG_UNKNOWN_1265", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x4F2*/ { "UMSG_UNKNOWN_1266", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x4F3*/ { "UMSG_UNKNOWN_1267", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x4F4*/ { "UMSG_UNKNOWN_1268", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x4F5*/ { "UMSG_UNKNOWN_1269", STATUS_NEVER, &WorldSession::Handle_NULL }, + /*0x4F6*/ { "CMSG_WORLD_STATE_UI_TIMER_UPDATE", STATUS_LOGGEDIN, &WorldSession::HandleWorldStateUITimerUpdate }, + /*0x4F7*/ { "SMSG_WORLD_STATE_UI_TIMER_UPDATE", STATUS_NEVER, &WorldSession::Handle_ServerSide }, + /*0x4F8*/ { "CMSG_UNKNOWN_1272", STATUS_NEVER, &WorldSession::Handle_NULL }, }; - diff --git a/src/game/Opcodes.h b/src/game/Opcodes.h index c3371f866b6..007e17f1687 100644 --- a/src/game/Opcodes.h +++ b/src/game/Opcodes.h @@ -355,7 +355,7 @@ enum Opcodes SMSG_AI_REACTION = 0x13C, CMSG_SET_SELECTION = 0x13D, CMSG_EQUIPMENT_SET_DELETE = 0x13E, - CMSG_INSTANCE_LOCK_RESPONSE = 0x13F, + CMSG_INSTANCE_LOCK_WARNING_RESPONSE = 0x13F, CMSG_UNUSED2 = 0x140, CMSG_ATTACKSWING = 0x141, CMSG_ATTACKSTOP = 0x142, @@ -363,7 +363,7 @@ enum Opcodes SMSG_ATTACKSTOP = 0x144, SMSG_ATTACKSWING_NOTINRANGE = 0x145, SMSG_ATTACKSWING_BADFACING = 0x146, - SMSG_INSTANCE_LOCK_QUERY = 0x147, + SMSG_INSTANCE_LOCK_WARNING_QUERY = 0x147, SMSG_ATTACKSWING_DEADTARGET = 0x148, SMSG_ATTACKSWING_CANT_ATTACK = 0x149, SMSG_ATTACKERSTATEUPDATE = 0x14A, @@ -519,8 +519,8 @@ enum Opcodes CMSG_SETSHEATHED = 0x1E0, SMSG_COOLDOWN_CHEAT = 0x1E1, SMSG_SPELL_DELAYED = 0x1E2, - CMSG_PLAYER_MACRO_OBSOLETE = 0x1E3, - SMSG_PLAYER_MACRO_OBSOLETE = 0x1E4, + CMSG_QUEST_POI_QUERY = 0x1E3, + SMSG_QUEST_POI_QUERY_RESPONSE = 0x1E4, CMSG_GHOST = 0x1E5, CMSG_GM_INVIS = 0x1E6, SMSG_INVALID_PROMOTION_CODE = 0x1E7, @@ -694,7 +694,7 @@ enum Opcodes CMSG_GROUP_ASSISTANT_LEADER = 0x28F, CMSG_BUYBACK_ITEM = 0x290, SMSG_SERVER_MESSAGE = 0x291, - CMSG_MEETINGSTONE_JOIN = 0x292, // lua: SetSavedInstanceExtend + CMSG_SET_SAVED_INSTANCE_EXTEND = 0x292, // lua: SetSavedInstanceExtend SMSG_MEETINGSTONE_LEAVE = 0x293, CMSG_MEETINGSTONE_CHEAT = 0x294, SMSG_MEETINGSTONE_SETQUEUE = 0x295, @@ -1077,7 +1077,7 @@ enum Opcodes CMSG_REFER_A_FRIEND = 0x40E, MSG_GM_CHANGE_ARENA_RATING = 0x40F, CMSG_DECLINE_CHANNEL_INVITE = 0x410, - CMSG_GROUPACTION_THROTTLED = 0x411, + SMSG_GROUPACTION_THROTTLED = 0x411, // SMSG? SMSG_OVERRIDE_LIGHT = 0x412, SMSG_TOTEM_CREATED = 0x413, CMSG_TOTEM_DESTROYED = 0x414, @@ -1226,7 +1226,7 @@ enum Opcodes SMSG_SERVER_BUCK_DATA_START = 0x4A3, // not found CMSG_QUERY_VEHICLE_STATUS = 0x4A4, // not found UMSG_UNKNOWN_1189 = 0x4A5, // not found, old SMSG_PET_GUIDS - SMSG_UNKNOWN_1190 = 0x4A6, // smsg unk, old SMSG_CLIENTCACHE_VERSION + SMSG_UNKNOWN_1190 = 0x4A6, // smsg unk, "You can't do that yet" SMSG_UNKNOWN_1191 = 0x4A7, // smsg guid+uint32 (vehicle) CMSG_UNKNOWN_1192 = 0x4A8, // cmsg uint64 CMSG_EJECT_PASSENGER = 0x4A9, // cmsg uint64 @@ -1238,12 +1238,12 @@ enum Opcodes UMSG_UNKNOWN_1199 = 0x4AF, // not found UMSG_UNKNOWN_1200 = 0x4B0, // not found UMSG_UNKNOWN_1201 = 0x4B1, // not found - SMSG_UNKNOWN_1202 = 0x4B2, // refund something - CMSG_UNKNOWN_1203 = 0x4B3, // refund request? - CMSG_UNKNOWN_1204 = 0x4B4, // lua: ContainerRefundItemPurchase - SMSG_UNKNOWN_1205 = 0x4B5, // refund something - CMSG_UNKNOWN_1206 = 0x4B6, // CMSG, uint32 - SMSG_UNKNOWN_1207 = 0x4B7, // SMSG, string+float + SMSG_ITEM_REFUND_TIMER = 0x4B2, // refund something + CMSG_ITEM_REFUND_INFO_REQUEST = 0x4B3, // refund request? + CMSG_ITEM_REFUND = 0x4B4, // lua: ContainerRefundItemPurchase + SMSG_ITEM_REFUND = 0x4B5, // refund something + CMSG_CORPSE_MAP_POSITION_QUERY = 0x4B6, // CMSG, uint32 + CMSG_CORPSE_MAP_POSITION_QUERY_RESPONSE = 0x4B7, // SMSG, 3*float+float CMSG_LFG_SET_ROLES = 0x4B8, // CMSG, empty, lua: SetLFGRoles UMSG_UNKNOWN_1209 = 0x4B9, // not found CMSG_UNKNOWN_1210 = 0x4BA, // CMSG, uint64, lua: CalendarContextEventSignUp @@ -1255,17 +1255,61 @@ enum Opcodes SMSG_TALENTS_INFO = 0x4C0, // SMSG, talents related CMSG_LEARN_PREVIEW_TALENTS = 0x4C1, // CMSG, lua: LearnPreviewTalents (for player?) CMSG_LEARN_PREVIEW_TALENTS_PET = 0x4C2, // CMSG, lua: LearnPreviewTalents (for pet?) - UMSG_UNKNOWN_1219 = 0x4C3, // not found - UMSG_UNKNOWN_1220 = 0x4C4, // not found - UMSG_UNKNOWN_1221 = 0x4C5, // not found - UMSG_UNKNOWN_1222 = 0x4C6, // not found - SMSG_UNKNOWN_1223 = 0x4C7, // uint64, arena pet? - SMSG_UNKNOWN_1224 = 0x4C8, // uint32 "Can't change arena team..." - UMSG_UNKNOWN_1225 = 0x4C9, // not found - UMSG_UNKNOWN_1226 = 0x4CA, // not found - CMSG_EQUIPMENT_SET_USE = 0x4CB, // CMSG, lua: UseEquipmentSet - SMSG_EQUIPMENT_SET_USE_RESULT = 0x4CC, // SMSG, UseEquipmentSetResult? - NUM_MSG_TYPES = 0x4CD + UMSG_UNKNOWN_1219 = 0x4C3, // not found 3.2 + UMSG_UNKNOWN_1220 = 0x4C4, // not found 3.2 + UMSG_UNKNOWN_1221 = 0x4C5, // not found 3.2 + UMSG_UNKNOWN_1222 = 0x4C6, // not found 3.2 + SMSG_UNKNOWN_1223 = 0x4C7, // uint64, arena pet? 3.2 + SMSG_UNKNOWN_1224 = 0x4C8, // uint32 "Can't modify arena team while queued or in a match." 3.2 + UMSG_UNKNOWN_1225 = 0x4C9, // not found 3.2 + UMSG_UNKNOWN_1226 = 0x4CA, // not found 3.2 + UMSG_UNKNOWN_1227 = 0x4CB, // not found 3.2 + UMSG_UNKNOWN_1228 = 0x4CC, // not found 3.2 + SMSG_UNKNOWN_1229 = 0x4CD, // SMSG, any opcode? + SMSG_UNKNOWN_1230 = 0x4CE, // SMSG, movement related + CMSG_UNKNOWN_1231_ACK = 0x4CF, // movement related + SMSG_UNKNOWN_1232 = 0x4D0, // SMSG, movement related + CMSG_UNKNOWN_1233_ACK = 0x4D1, // movement related + SMSG_UNKNOWN_1234 = 0x4D2, // SMSG, movement related + SMSG_UNKNOWN_1235 = 0x4D3, // SMSG, movement related + SMSG_UNKNOWN_1236 = 0x4D4, // SMSG, movement related + CMSG_EQUIPMENT_SET_USE = 0x4D5, // CMSG, lua: UseEquipmentSet + SMSG_EQUIPMENT_SET_USE_RESULT = 0x4D6, // SMSG, UseEquipmentSetResult? + UMSG_UNKNOWN_1239 = 0x4D7, // not found 3.2 + SMSG_UNKNOWN_1240 = 0x4D8, // SMSG, uint64, string + CMSG_CHAR_FACTION_CHANGE = 0x4D9, // lua: CreateCharacter (PFC client response) + SMSG_CHAR_FACTION_CHANGE = 0x4DA, // response to 1241 (PFC server response) + UMSG_UNKNOWN_1243 = 0x4DB, // not found 3.2 + UMSG_UNKNOWN_1244 = 0x4DC, // not found 3.2 + UMSG_UNKNOWN_1245 = 0x4DD, // not found 3.2 + SMSG_UNKNOWN_1246 = 0x4DE, // uint32, BattlefieldMgrEntryInvite + CMSG_UNKNOWN_1247 = 0x4DF, // lua: BattlefieldMgrEntryInviteResponse + SMSG_UNKNOWN_1248 = 0x4E0, // uint32, uint8, uint8 + SMSG_UNKNOWN_1249 = 0x4E1, // uint32 BattlefieldMgrQueueInvite + CMSG_UNKNOWN_1250 = 0x4E2, // lua: BattlefieldMgrQueueInviteResponse + CMSG_UNKNOWN_1251 = 0x4E3, // lua: BattlefieldMgrQueueRequest + SMSG_UNKNOWN_1252 = 0x4E4, // uint32, uint8 queue full/can't join + SMSG_UNKNOWN_1253 = 0x4E5, // uint32 wintergrasp is full, you'll be ejected soon + SMSG_UNKNOWN_1254 = 0x4E6, // uint32, uint32, uint8 + CMSG_UNKNOWN_1255 = 0x4E7, // lua: BattlefieldMgrExitRequest + SMSG_UNKNOWN_1256 = 0x4E8, // uint32, uint32 + UMSG_UNKNOWN_1257 = 0x4E9, // not found 3.2 + UMSG_UNKNOWN_1258 = 0x4EA, // not found 3.2 + MSG_SET_RAID_DIFFICULTY = 0x4EB, // lua: SetRaidDifficulty + UMSG_UNKNOWN_1260 = 0x4EC, // not found 3.2 + SMSG_TOGGLE_XP_GAIN = 0x4ED, // enable/disable XP gain console message + SMSG_UNKNOWN_1262 = 0x4EE, + SMSG_UNKNOWN_1263 = 0x4EF, + CMSG_UNKNOWN_1264 = 0x4F0, // lua: GMResponseResolve + SMSG_UNKNOWN_1265 = 0x4F1, + UMSG_UNKNOWN_1266 = 0x4F2, // not found 3.2 + UMSG_UNKNOWN_1267 = 0x4F3, // not found 3.2 + UMSG_UNKNOWN_1268 = 0x4F4, // not found 3.2 + UMSG_UNKNOWN_1269 = 0x4F5, // not found 3.2 + CMSG_WORLD_STATE_UI_TIMER_UPDATE = 0x4F6, + SMSG_WORLD_STATE_UI_TIMER_UPDATE = 0x4F7, + CMSG_UNKNOWN_1272 = 0x4F8, // called from lua: CreateCharacter, paid race change + NUM_MSG_TYPES = 0x4F9 }; /// Player state @@ -1298,4 +1342,3 @@ inline const char* LookupOpcodeName(uint16 id) } #endif /// @} - diff --git a/src/game/OutdoorPvPWG.cpp b/src/game/OutdoorPvPWG.cpp index 28cf16645e6..94389f1c812 100644 --- a/src/game/OutdoorPvPWG.cpp +++ b/src/game/OutdoorPvPWG.cpp @@ -801,14 +801,14 @@ void OutdoorPvPWG::SendInitWorldStatesTo(Player *player) const data << uint32(571); data << uint32(ZONE_WINTERGRASP); data << uint32(0); - data << uint16(4+5+4+m_buildingStates.size()); + data << uint16(4+2+4+m_buildingStates.size()); data << uint32(3803) << uint32(getDefenderTeam() == TEAM_ALLIANCE ? 1 : 0); data << uint32(3802) << uint32(getDefenderTeam() != TEAM_ALLIANCE ? 1 : 0); data << uint32(3801) << uint32(isWarTime() ? 0 : 1); data << uint32(3710) << uint32(isWarTime() ? 1 : 0); - for (uint32 i = 0; i < 5; ++i) + for (uint32 i = 0; i < 2; ++i) data << ClockWorldState[i] << m_clock[i]; data << uint32(3490) << uint32(m_vehicles[TEAM_HORDE].size()); @@ -1219,19 +1219,17 @@ void OutdoorPvPWG::UpdateClockDigit(uint32 &timer, uint32 digit, uint32 mod) if (m_clock[digit] != value) { m_clock[digit] = value; - SendUpdateWorldState(ClockWorldState[digit], value); + SendUpdateWorldState(ClockWorldState[digit], (timer + time(NULL))); } } void OutdoorPvPWG::UpdateClock() { uint32 timer = m_timer / 1000; - UpdateClockDigit(timer, 0, 10); - UpdateClockDigit(timer, 1, 6); - UpdateClockDigit(timer, 2, 10); - UpdateClockDigit(timer, 3, 6); if (!isWarTime()) - UpdateClockDigit(timer, 4, 10); + UpdateClockDigit(timer, 1, 10); + else + UpdateClockDigit(timer, 0, 10); } bool OutdoorPvPWG::Update(uint32 diff) diff --git a/src/game/OutdoorPvPWG.h b/src/game/OutdoorPvPWG.h index 63381b15f7b..c9700fe5123 100644 --- a/src/game/OutdoorPvPWG.h +++ b/src/game/OutdoorPvPWG.h @@ -29,7 +29,7 @@ const uint32 WintergraspFaction[3] = {1732, 1735, 35}; const uint32 WG_MARK_OF_HONOR = 43589; const uint32 VehNumWorldState[2] = {3680,3490}; const uint32 MaxVehNumWorldState[2] = {3681,3491}; -const uint32 ClockWorldState[5] = {3785,3784,3782,3976,3975}; +const uint32 ClockWorldState[2] = {3781,4354}; enum OutdoorPvPWGSpell { @@ -268,7 +268,7 @@ class OutdoorPvPWG : public OutdoorPvP bool m_wartime; bool m_changeDefender; uint32 m_timer; - uint32 m_clock[5]; + uint32 m_clock[2]; uint32 m_workshopCount[2]; uint32 m_towerDestroyedCount[2]; uint32 m_towerDamagedCount[2]; diff --git a/src/game/Pet.cpp b/src/game/Pet.cpp index 95f1300a1bb..373f611094b 100644 --- a/src/game/Pet.cpp +++ b/src/game/Pet.cpp @@ -435,8 +435,7 @@ void Pet::SavePetToDB(PetSaveMode mode) << curmana << ", " << GetPower(POWER_HAPPINESS) << ", '"; - // save only spell slots from action bar - for (uint32 i = ACTION_BAR_INDEX_PET_SPELL_START; i < ACTION_BAR_INDEX_PET_SPELL_END; ++i) + for(uint32 i = ACTION_BAR_INDEX_START; i < ACTION_BAR_INDEX_END; ++i) { ss << uint32(m_charmInfo->GetActionBarEntry(i)->GetType()) << " " << uint32(m_charmInfo->GetActionBarEntry(i)->GetAction()) << " "; diff --git a/src/game/PetHandler.cpp b/src/game/PetHandler.cpp index 41cafc3c7a4..1b2503eed0b 100644 --- a/src/game/PetHandler.cpp +++ b/src/game/PetHandler.cpp @@ -400,22 +400,64 @@ void WorldSession::HandlePetSetAction( WorldPacket & recv_data ) } count = (recv_data.size() == 24) ? 2 : 1; - for (uint8 i = 0; i < count; ++i) - { - uint32 position; - uint32 data; - - recv_data >> position; - recv_data >> data; - - uint32 spell_id = UNIT_ACTION_BUTTON_ACTION(data); - uint8 act_state = UNIT_ACTION_BUTTON_TYPE(data); - - sLog.outDetail( "Player %s has changed pet spell action. Position: %u, Spell: %u, State: 0x%X", _player->GetName(), position, spell_id, uint32(act_state)); + uint32 position[2]; + uint32 data[2]; + bool move_command = false; + + for(uint8 i = 0; i < count; ++i) + { + recv_data >> position[i]; + recv_data >> data[i]; + + uint8 act_state = UNIT_ACTION_BUTTON_TYPE(data[i]); + //ignore invalid position - if(position >= MAX_UNIT_ACTION_BAR_INDEX) + if(position[i] >= MAX_UNIT_ACTION_BAR_INDEX) return; + + // in the normal case, command and reaction buttons can only be moved, not removed + // at moving count ==2, at removing count == 1 + // ignore attempt to remove command|reaction buttons (not possible at normal case) + if (act_state == ACT_COMMAND || act_state == ACT_REACTION) + { + if (count == 1) + return; + + move_command = true; + } + } + + // check swap (at command->spell swap client remove spell first in another packet, so check only command move correctness) + if (move_command) + { + uint8 act_state_0 = UNIT_ACTION_BUTTON_TYPE(data[0]); + if(act_state_0 == ACT_COMMAND || act_state_0 == ACT_REACTION) + { + uint32 spell_id_0 = UNIT_ACTION_BUTTON_ACTION(data[0]); + UnitActionBarEntry const* actionEntry_1 = charmInfo->GetActionBarEntry(position[1]); + if (!actionEntry_1 || spell_id_0 != actionEntry_1->GetAction() || + act_state_0 != actionEntry_1->GetType()) + return; + } + + uint8 act_state_1 = UNIT_ACTION_BUTTON_TYPE(data[1]); + if(act_state_1 == ACT_COMMAND || act_state_1 == ACT_REACTION) + { + uint32 spell_id_1 = UNIT_ACTION_BUTTON_ACTION(data[1]); + UnitActionBarEntry const* actionEntry_0 = charmInfo->GetActionBarEntry(position[0]); + if (!actionEntry_0 || spell_id_1 != actionEntry_0->GetAction() || + act_state_1 != actionEntry_0->GetType()) + return; + } + } + + for(uint8 i = 0; i < count; ++i) + { + uint32 spell_id = UNIT_ACTION_BUTTON_ACTION(data[i]); + uint8 act_state = UNIT_ACTION_BUTTON_TYPE(data[i]); + + sLog.outDetail( "Player %s has changed pet spell action. Position: %u, Spell: %u, State: 0x%X", _player->GetName(), position[i], spell_id, uint32(act_state)); //if it's act for spell (en/disable/cast) and there is a spell given (0 = remove spell) which pet doesn't know, don't add if(!((act_state == ACT_ENABLED || act_state == ACT_DISABLED || act_state == ACT_PASSIVE) && spell_id && !pet->HasSpell(spell_id))) @@ -438,7 +480,7 @@ void WorldSession::HandlePetSetAction( WorldPacket & recv_data ) } - charmInfo->SetActionBar(position,spell_id,ActiveStates(act_state)); + charmInfo->SetActionBar(position[i],spell_id,ActiveStates(act_state)); } } } diff --git a/src/game/PetitionsHandler.cpp b/src/game/PetitionsHandler.cpp index 718f063beca..aac54ad99e5 100644 --- a/src/game/PetitionsHandler.cpp +++ b/src/game/PetitionsHandler.cpp @@ -50,30 +50,35 @@ void WorldSession::HandlePetitionBuyOpcode(WorldPacket & recv_data) { sLog.outDebug("Received opcode CMSG_PETITION_BUY"); - //recv_data.hexlike(); + recv_data.hexlike(); uint64 guidNPC; - uint64 unk1, unk3, unk4, unk5, unk6, unk7; - uint32 unk2; + uint32 clientIndex; // 1 for guild and arenaslot+1 for arenas in client std::string name; - uint16 unk8; - uint8 unk9; - uint32 unk10; // selected index - uint32 unk11; + recv_data >> guidNPC; // NPC GUID - recv_data >> unk1; // 0 - recv_data >> unk2; // 0 + recv_data.read_skip<uint32>(); // 0 + recv_data.read_skip<uint64>(); // 0 recv_data >> name; // name + recv_data.read_skip<std::string>(); // some string + recv_data.read_skip<uint32>(); // 0 + recv_data.read_skip<uint32>(); // 0 + recv_data.read_skip<uint32>(); // 0 + recv_data.read_skip<uint32>(); // 0 + recv_data.read_skip<uint32>(); // 0 + recv_data.read_skip<uint32>(); // 0 + recv_data.read_skip<uint32>(); // 0 + recv_data.read_skip<uint16>(); // 0 + recv_data.read_skip<uint32>(); // 0 + recv_data.read_skip<uint32>(); // 0 + recv_data.read_skip<uint32>(); // 0 + + for (int i = 0; i < 10; ++i) + recv_data.read_skip<std::string>(); + + recv_data >> clientIndex; // index + recv_data.read_skip<uint32>(); // 0 - recv_data >> unk3; // 0 - recv_data >> unk4; // 0 - recv_data >> unk5; // 0 - recv_data >> unk6; // 0 - recv_data >> unk7; // 0 - recv_data >> unk8; // 0 - recv_data >> unk9; // 0 - recv_data >> unk10; // index - recv_data >> unk11; // 0 sLog.outDebug("Petitioner with GUID %u tried sell petition: name %s", GUID_LOPART(guidNPC), name.c_str()); // prevent cheating @@ -111,7 +116,7 @@ void WorldSession::HandlePetitionBuyOpcode(WorldPacket & recv_data) return; } - switch(unk10) + switch(clientIndex) // arenaSlot+1 as received from client (1 from 3 case) { case 1: charterid = ARENA_TEAM_CHARTER_2v2; @@ -129,11 +134,11 @@ void WorldSession::HandlePetitionBuyOpcode(WorldPacket & recv_data) type = 5; // 5v5 break; default: - sLog.outDebug("unknown selection at buy petition: %u", unk10); + sLog.outDebug("unknown selection at buy arena petition: %u", clientIndex); return; } - if(_player->GetArenaTeamId(unk10-1)) + if(_player->GetArenaTeamId(clientIndex - 1)) // arenaSlot+1 as received from client { SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, name, "", ERR_ALREADY_IN_ARENA_TEAM); return; @@ -208,7 +213,6 @@ void WorldSession::HandlePetitionBuyOpcode(WorldPacket & recv_data) if (result) { - do { Field *fields = result->Fetch(); @@ -328,11 +332,11 @@ void WorldSession::SendPetitionQueryOpcode(uint64 petitionguid) return; } - WorldPacket data(SMSG_PETITION_QUERY_RESPONSE, (4+8+name.size()+1+1+4*13)); - data << GUID_LOPART(petitionguid); // guild/team guid (in Trinity always same as GUID_LOPART(petition guid) - data << ownerguid; // charter owner guid + WorldPacket data(SMSG_PETITION_QUERY_RESPONSE, (4+8+name.size()+1+1+4*12+2+10)); + data << uint32(GUID_LOPART(petitionguid)); // guild/team guid (in Trinity always same as GUID_LOPART(petition guid) + data << uint64(ownerguid); // charter owner guid data << name; // name (guild/arena team) - data << uint8(0); // 1 + data << uint8(0); // some string if(type == 9) { data << uint32(9); @@ -341,9 +345,9 @@ void WorldSession::SendPetitionQueryOpcode(uint64 petitionguid) } else { - data << type-1; - data << type-1; - data << type; // bypass client - side limitation, a different value is needed here for each petition + data << uint32(type-1); + data << uint32(type-1); + data << uint32(type); // bypass client - side limitation, a different value is needed here for each petition } data << uint32(0); // 5 data << uint32(0); // 6 @@ -353,11 +357,17 @@ void WorldSession::SendPetitionQueryOpcode(uint64 petitionguid) data << uint32(0); // 10 data << uint32(0); // 11 data << uint32(0); // 13 count of next strings? + + for(int i = 0; i < 10; ++i) + data << uint8(0); // some string + data << uint32(0); // 14 + if(type == 9) data << uint32(0); // 15 0 - guild, 1 - arena team else data << uint32(1); + SendPacket(&data); } @@ -949,4 +959,3 @@ void WorldSession::SendPetitionShowList(uint64 guid) SendPacket(&data); sLog.outDebug("Sent SMSG_PETITION_SHOWLIST"); } - diff --git a/src/game/Player.cpp b/src/game/Player.cpp index 5d33d75f92b..c1e4a9aa5ef 100644 --- a/src/game/Player.cpp +++ b/src/game/Player.cpp @@ -119,6 +119,14 @@ enum CharacterFlags CHARACTER_FLAG_UNK32 = 0x80000000 }; +enum CharacterCustomizeFlags +{ + CHAR_CUSTOMIZE_FLAG_NONE = 0x00000000, + CHAR_CUSTOMIZE_FLAG_CUSTOMIZE = 0x00000001, // name, gender, etc... + CHAR_CUSTOMIZE_FLAG_FACTION = 0x00010000, // name, gender, faction, etc... + CHAR_CUSTOMIZE_FLAG_RACE = 0x00100000 // name, gender, race, etc... +}; + // corpse reclaim times #define DEATH_EXPIRE_STEP (5*MINUTE) #define MAX_DEATH_COUNT 3 @@ -422,7 +430,8 @@ Player::Player (WorldSession *session): Unit(), m_achievementMgr(this), m_reputa m_HomebindTimer = 0; m_InstanceValid = true; - m_dungeonDifficulty = DIFFICULTY_NORMAL; + m_dungeonDifficulty = DUNGEON_DIFFICULTY_NORMAL; + m_raidDifficulty = RAID_DIFFICULTY_10MAN_NORMAL; m_lastPotionId = 0; @@ -449,6 +458,7 @@ Player::Player (WorldSession *session): Unit(), m_achievementMgr(this), m_reputa m_baseSpellPower = 0; m_baseFeralAP = 0; m_baseManaRegen = 0; + m_baseHealthRegen = 0; // Honor System m_lastHonorUpdateTime = time(NULL); @@ -541,7 +551,7 @@ void Player::CleanupsBeforeDelete() m_transport->RemovePassenger(this); // clean up player-instance binds, may unload some instance saves - for (uint8 i = 0; i < TOTAL_DIFFICULTIES; ++i) + for (uint8 i = 0; i < MAX_DIFFICULTY; ++i) for (BoundInstancesMap::iterator itr = m_boundInstances[i].begin(); itr != m_boundInstances[i].end(); ++itr) itr->second.save->RemovePlayer(this); } @@ -1142,7 +1152,7 @@ void Player::Update( uint32 p_time ) //sLog.outCrash("Player has m_pad %u during update!", m_pad); //if(m_spellModTakingSpell) sLog.outCrash("Player has m_spellModTakingSpell %u during update!", m_spellModTakingSpell->m_spellInfo->Id); - return; + return; m_spellModTakingSpell = NULL; } @@ -1515,8 +1525,8 @@ bool Player::BuildEnumData( QueryResult * result, WorldPacket * p_data ) char_flags |= CHARACTER_FLAG_DECLINED; *p_data << uint32(char_flags); // character flags - // character customize (flags?) - *p_data << uint32(atLoginFlags & AT_LOGIN_CUSTOMIZE ? 1 : 0); + // character customize flags + *p_data << uint32(atLoginFlags & AT_LOGIN_CUSTOMIZE ? CHAR_CUSTOMIZE_FLAG_CUSTOMIZE : CHAR_CUSTOMIZE_FLAG_NONE); *p_data << uint8(1); // unknown // Pets info @@ -1707,6 +1717,7 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati m_movementInfo.t_z = 0.0f; m_movementInfo.t_o = 0.0f; m_movementInfo.t_time = 0; + m_movementInfo.t_seat = -1; } } @@ -2170,6 +2181,7 @@ void Player::RegenerateHealth() // always regeneration bonus (including combat) addvalue += GetTotalAuraModifier(SPELL_AURA_MOD_HEALTH_REGEN_IN_COMBAT); + addvalue += m_baseHealthRegen / 2.5f; if (addvalue < 0) addvalue = 0; @@ -2448,6 +2460,9 @@ void Player::GiveXP(uint32 xp, Unit* victim) if(!isAlive()) return; + if(HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_NO_XP_GAIN)) + return; + uint8 level = getLevel(); // Favored experience increase START @@ -2617,6 +2632,9 @@ void Player::InitStatsForLevel(bool reapplyMods) SetUInt32Value(PLAYER_FIELD_MAX_LEVEL, sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL) ); SetUInt32Value(PLAYER_NEXT_LEVEL_XP, objmgr.GetXPForLevel(getLevel())); + // reset before any aura state sources (health set/aura apply) + SetUInt32Value(UNIT_FIELD_AURASTATE, 0); + UpdateSkillsForLevel (); // set default cast time multiplier @@ -2916,7 +2934,7 @@ bool Player::AddTalent(uint32 spell_id, uint8 spec, bool learning) return false; } - if (!SpellMgr::IsSpellValid(spellInfo,this,false)) + if(!SpellMgr::IsSpellValid(spellInfo,this,false)) { // do character spell book cleanup (all characters) if(!IsInWorld() && !learning) // spell load case @@ -2968,7 +2986,7 @@ bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool dependen if (!spellInfo) { // do character spell book cleanup (all characters) - if (!IsInWorld() && !learning) // spell load case + if(!IsInWorld() && !learning) // spell load case { sLog.outError("Player::addSpell: Non-existed in SpellStore spell #%u request, deleting for all characters in `character_spell`.",spell_id); CharacterDatabase.PExecute("DELETE FROM character_spell WHERE spell = '%u'",spell_id); @@ -2979,7 +2997,7 @@ bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool dependen return false; } - if (!SpellMgr::IsSpellValid(spellInfo,this,false)) + if(!SpellMgr::IsSpellValid(spellInfo,this,false)) { // do character spell book cleanup (all characters) if(!IsInWorld() && !learning) // spell load case @@ -3008,11 +3026,11 @@ bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool dependen { uint32 next_active_spell_id = 0; // fix activate state for non-stackable low rank (and find next spell for !active case) - if (!SpellMgr::canStackSpellRanks(spellInfo) && spellmgr.GetSpellRank(spellInfo->Id) != 0) + if(!SpellMgr::canStackSpellRanks(spellInfo) && spellmgr.GetSpellRank(spellInfo->Id) != 0) { - if (uint32 next = spellmgr.GetNextSpellInChain(spell_id)) + if(uint32 next = spellmgr.GetNextSpellInChain(spell_id)) { - if (HasSpell(next)) + if(HasSpell(next)) { // high rank already known so this must !active active = false; @@ -3022,10 +3040,10 @@ bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool dependen } // not do anything if already known in expected state - if (itr->second->state != PLAYERSPELL_REMOVED && itr->second->active == active && + if(itr->second->state != PLAYERSPELL_REMOVED && itr->second->active == active && itr->second->dependent == dependent && itr->second->disabled == disabled) { - if (!IsInWorld() && !learning) // explicitly load from DB and then exist in it already and set correctly + if(!IsInWorld() && !learning) // explicitly load from DB and then exist in it already and set correctly itr->second->state = PLAYERSPELL_UNCHANGED; return false; @@ -3041,21 +3059,21 @@ bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool dependen } // update active state for known spell - if (itr->second->active != active && itr->second->state != PLAYERSPELL_REMOVED && !itr->second->disabled) + if(itr->second->active != active && itr->second->state != PLAYERSPELL_REMOVED && !itr->second->disabled) { itr->second->active = active; - if (!IsInWorld() && !learning && !dependent_set) // explicitly load from DB and then exist in it already and set correctly + if(!IsInWorld() && !learning && !dependent_set) // explicitly load from DB and then exist in it already and set correctly itr->second->state = PLAYERSPELL_UNCHANGED; - else if (itr->second->state != PLAYERSPELL_NEW) + else if(itr->second->state != PLAYERSPELL_NEW) itr->second->state = PLAYERSPELL_CHANGED; - if (active) + if(active) { if (IsPassiveSpell(spell_id) && IsNeedCastPassiveSpellAtLearn(spellInfo)) - CastSpell(this, spell_id, true); + CastSpell (this,spell_id,true); } - else if (IsInWorld()) + else if(IsInWorld()) { if(next_active_spell_id) { @@ -3063,7 +3081,7 @@ bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool dependen WorldPacket data(SMSG_SUPERCEDED_SPELL, 4 + 4); data << uint32(spell_id); data << uint32(next_active_spell_id); - GetSession()->SendPacket(&data); + GetSession()->SendPacket( &data ); } else { @@ -3076,18 +3094,18 @@ bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool dependen return active; // learn (show in spell book if active now) } - if (itr->second->disabled != disabled && itr->second->state != PLAYERSPELL_REMOVED) + if(itr->second->disabled != disabled && itr->second->state != PLAYERSPELL_REMOVED) { - if (itr->second->state != PLAYERSPELL_NEW) + if(itr->second->state != PLAYERSPELL_NEW) itr->second->state = PLAYERSPELL_CHANGED; itr->second->disabled = disabled; - if (disabled) + if(disabled) return false; disabled_case = true; } - else switch (itr->second->state) + else switch(itr->second->state) { case PLAYERSPELL_UNCHANGED: // known saved spell return false; @@ -3101,7 +3119,7 @@ bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool dependen default: // known not saved yet spell (new or modified) { // can be in case spell loading but learned at some previous spell loading - if (!IsInWorld() && !learning && !dependent_set) + if(!IsInWorld() && !learning && !dependent_set) itr->second->state = PLAYERSPELL_UNCHANGED; return false; @@ -3109,19 +3127,18 @@ bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool dependen } } - // skip new spell adding if spell already known (disabled spells case) - if (!disabled_case) + if(!disabled_case) // skip new spell adding if spell already known (disabled spells case) { // talent: unlearn all other talent ranks (high and low) - if (TalentSpellPos const *talentPos = GetTalentSpellPos(spell_id)) + if(TalentSpellPos const *talentPos = GetTalentSpellPos(spell_id)) { - if (TalentEntry const *talentInfo = sTalentStore.LookupEntry( talentPos->talent_id )) + if(TalentEntry const *talentInfo = sTalentStore.LookupEntry( talentPos->talent_id )) { for (uint8 rank = 0; rank < MAX_TALENT_RANK; ++rank) { // skip learning spell and no rank spell case uint32 rankSpellId = talentInfo->RankID[rank]; - if (!rankSpellId || rankSpellId == spell_id) + if(!rankSpellId || rankSpellId == spell_id) continue; removeSpell(rankSpellId,false,false); @@ -3129,9 +3146,9 @@ bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool dependen } } // non talent spell: learn low ranks (recursive call) - else if (uint32 prev_spell = spellmgr.GetPrevSpellInChain(spell_id)) + else if(uint32 prev_spell = spellmgr.GetPrevSpellInChain(spell_id)) { - if (!IsInWorld() || disabled) // at spells loading, no output, but allow save + if(!IsInWorld() || disabled) // at spells loading, no output, but allow save addSpell(prev_spell,active,true,true,disabled); else // at normal learning learnSpell(prev_spell,true); @@ -3144,23 +3161,21 @@ bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool dependen newspell->disabled = disabled; // replace spells in action bars and spellbook to bigger rank if only one spell rank must be accessible - if (newspell->active && !newspell->disabled && !SpellMgr::canStackSpellRanks(spellInfo) && spellmgr.GetSpellRank(spellInfo->Id) != 0) + if(newspell->active && !newspell->disabled && !SpellMgr::canStackSpellRanks(spellInfo) && spellmgr.GetSpellRank(spellInfo->Id) != 0) { for (PlayerSpellMap::iterator itr2 = m_spells.begin(); itr2 != m_spells.end(); ++itr2 ) { - if (itr2->second->state == PLAYERSPELL_REMOVED) - continue; + if(itr2->second->state == PLAYERSPELL_REMOVED) continue; SpellEntry const *i_spellInfo = sSpellStore.LookupEntry(itr2->first); - if (!i_spellInfo) - continue; + if(!i_spellInfo) continue; - if (spellmgr.IsRankSpellDueToSpell(spellInfo,itr2->first)) + if( spellmgr.IsRankSpellDueToSpell(spellInfo,itr2->first) ) { - if (itr2->second->active) + if(itr2->second->active) { - if (spellmgr.IsHighRankOfSpell(spell_id,itr2->first)) + if(spellmgr.IsHighRankOfSpell(spell_id,itr2->first)) { - if (IsInWorld()) // not send spell (re-/over-)learn packets at loading + if(IsInWorld()) // not send spell (re-/over-)learn packets at loading { WorldPacket data(SMSG_SUPERCEDED_SPELL, 4 + 4); data << uint32(itr2->first); @@ -3174,19 +3189,19 @@ bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool dependen itr2->second->state = PLAYERSPELL_CHANGED; superceded_old = true; // new spell replace old in action bars and spell book. } - else if (spellmgr.IsHighRankOfSpell(itr2->first, spell_id)) + else if(spellmgr.IsHighRankOfSpell(itr2->first,spell_id)) { - if (IsInWorld()) // not send spell (re-/over-)learn packets at loading + if(IsInWorld()) // not send spell (re-/over-)learn packets at loading { WorldPacket data(SMSG_SUPERCEDED_SPELL, 4 + 4); data << uint32(spell_id); data << uint32(itr2->first); - GetSession()->SendPacket(&data); + GetSession()->SendPacket( &data ); } // mark new spell as disable (not learned yet for client and will not learned) newspell->active = false; - if (newspell->state != PLAYERSPELL_NEW) + if(newspell->state != PLAYERSPELL_NEW) newspell->state = PLAYERSPELL_CHANGED; } } @@ -3228,7 +3243,7 @@ bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool dependen // update free primary prof.points (if any, can be none in case GM .learn prof. learning) if (uint32 freeProfs = GetFreePrimaryProfessionPoints()) { - if (spellmgr.IsPrimaryProfessionFirstRankSpell(spell_id)) + if(spellmgr.IsPrimaryProfessionFirstRankSpell(spell_id)) SetFreePrimaryProfessions(freeProfs-1); } @@ -3252,7 +3267,7 @@ bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool dependen if (skill_max_value < new_skill_max_value) skill_max_value = new_skill_max_value; - SetSkill(spellLearnSkill->skill, skill_value, skill_max_value); + SetSkill(spellLearnSkill->skill,skill_value,skill_max_value); } else { @@ -3270,16 +3285,16 @@ bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool dependen // lockpicking/runeforging special case, not have ABILITY_LEARNED_ON_GET_RACE_OR_CLASS_SKILL ((pSkill->id==SKILL_LOCKPICKING || pSkill->id==SKILL_RUNEFORGING) && _spell_idx->second->max_value==0)) { - switch (GetSkillRangeType(pSkill,_spell_idx->second->racemask!=0)) + switch(GetSkillRangeType(pSkill,_spell_idx->second->racemask!=0)) { case SKILL_RANGE_LANGUAGE: - SetSkill(pSkill->id, 300, 300); + SetSkill(pSkill->id, 300, 300 ); break; case SKILL_RANGE_LEVEL: - SetSkill(pSkill->id, 1, GetMaxSkillValueForLevel()); + SetSkill(pSkill->id, 1, GetMaxSkillValueForLevel() ); break; case SKILL_RANGE_MONO: - SetSkill(pSkill->id, 1, 1); + SetSkill(pSkill->id, 1, 1 ); break; default: break; @@ -3296,9 +3311,9 @@ bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool dependen if (!itr2->second.autoLearned) { if (!IsInWorld() || !itr2->second.active) // at spells loading, no output, but allow save - addSpell(itr2->second.spell, itr2->second.active, true, true, false); + addSpell(itr2->second.spell,itr2->second.active,true,true,false); else // at normal learning - learnSpell(itr2->second.spell, true); + learnSpell(itr2->second.spell,true); } } @@ -3398,13 +3413,13 @@ void Player::removeSpell(uint32 spell_id, bool disabled, bool learn_low_rank) if (SpellChainNode const* node = spellmgr.GetSpellChainNode(spell_id)) { if (HasSpell(node->next) && !GetTalentSpellPos(node->next)) - removeSpell(node->next,disabled); + removeSpell(node->next,disabled); } //unlearn spells dependent from recently removed spells SpellsRequiringSpellMap const &reqMap = spellmgr.GetSpellsRequiringSpell(); SpellsRequiringSpellMap::const_iterator itr2 = reqMap.find(spell_id); for (uint32 i = reqMap.count(spell_id); i > 0; --i, ++itr2) - removeSpell(itr2->second, disabled, false); + removeSpell(itr2->second,disabled,false); // re-search, it can be corrupted in prev loop itr = m_spells.find(spell_id); @@ -3510,7 +3525,7 @@ void Player::removeSpell(uint32 spell_id, bool disabled, bool learn_low_rank) ((pSkill->id == SKILL_LOCKPICKING || pSkill->id == SKILL_RUNEFORGING) && _spell_idx->second->max_value == 0)) { // not reset skills for professions and racial abilities - if ((pSkill->categoryId == SKILL_CATEGORY_SECONDARY || pSkill->categoryId == SKILL_CATEGORY_PROFESSION) && + if ((pSkill->categoryId==SKILL_CATEGORY_SECONDARY || pSkill->categoryId==SKILL_CATEGORY_PROFESSION) && (IsProfessionSkill(pSkill->id) || _spell_idx->second->racemask!=0)) continue; @@ -3722,7 +3737,7 @@ void Player::_SaveSpellCooldowns() } // if something changed execute if (!first_round) - CharacterDatabase.Execute(ss.str().c_str()); + CharacterDatabase.Execute( ss.str().c_str() ); } uint32 Player::resetTalentsCost() const @@ -3858,19 +3873,19 @@ Mail* Player::GetMail(uint32 id) void Player::_SetCreateBits(UpdateMask *updateMask, Player *target) const { - if (target == this) + if(target == this) Object::_SetCreateBits(updateMask, target); else { for (uint16 index = 0; index < m_valuesCount; index++) - if (GetUInt32Value(index) != 0 && updateVisualBits.GetBit(index)) + if(GetUInt32Value(index) != 0 && updateVisualBits.GetBit(index)) updateMask->SetBit(index); } } void Player::_SetUpdateBits(UpdateMask *updateMask, Player *target) const { - if (target == this) + if(target == this) Object::_SetUpdateBits(updateMask, target); else { @@ -4248,6 +4263,7 @@ void Player::DeleteFromDB(uint64 playerguid, uint32 accountId, bool updateRealmC CharacterDatabase.PExecute("DELETE FROM group_instance WHERE leaderGuid = '%u'",guid); CharacterDatabase.PExecute("DELETE FROM groups WHERE leaderGuid = '%u'",guid); CharacterDatabase.PExecute("DELETE FROM group_member WHERE leaderGuid = '%u' OR memberGuid = '%u'",guid,guid); + CharacterDatabase.PExecute("DELETE FROM groups WHERE leaderGuid = '%u'",guid); CharacterDatabase.PExecute("DELETE FROM character_inventory WHERE guid = '%u'",guid); CharacterDatabase.PExecute("DELETE FROM character_queststatus WHERE guid = '%u'",guid); CharacterDatabase.PExecute("DELETE FROM character_reputation WHERE guid = '%u'",guid); @@ -4272,8 +4288,12 @@ void Player::DeleteFromDB(uint64 playerguid, uint32 accountId, bool updateRealmC CharacterDatabase.PExecute("DELETE FROM character_battleground_data WHERE guid = '%u'",guid); CharacterDatabase.PExecute("DELETE FROM character_glyphs WHERE guid = '%u'",guid); CharacterDatabase.PExecute("DELETE FROM character_queststatus_daily WHERE guid = '%u'",guid); + CharacterDatabase.PExecute("DELETE FROM character_battleground_data WHERE guid = '%u'",guid); + CharacterDatabase.PExecute("DELETE FROM character_glyphs WHERE guid = '%u'",guid); + CharacterDatabase.PExecute("DELETE FROM character_queststatus_daily WHERE guid = '%u'",guid); CharacterDatabase.PExecute("DELETE FROM character_talent WHERE guid = '%u'",guid); CharacterDatabase.PExecute("DELETE FROM character_skills WHERE guid = '%u'",guid); + CharacterDatabase.CommitTransaction(); //loginDatabase.PExecute("UPDATE realmcharacters SET numchars = numchars - 1 WHERE acctid = %d AND realmid = %d", accountId, realmID); @@ -4540,17 +4560,17 @@ void Player::CreateCorpse() corpse->SetUInt32Value( CORPSE_FIELD_GUILD, GetGuildId() ); uint32 iDisplayID; - uint16 iIventoryType; + uint32 iIventoryType; uint32 _cfi; for (uint8 i = 0; i < EQUIPMENT_SLOT_END; i++) { if(m_items[i]) { iDisplayID = m_items[i]->GetProto()->DisplayInfoID; - iIventoryType = (uint16)m_items[i]->GetProto()->InventoryType; + iIventoryType = m_items[i]->GetProto()->InventoryType; - _cfi = (uint16(iDisplayID)) | (iIventoryType)<< 24; - corpse->SetUInt32Value(CORPSE_FIELD_ITEM + i,_cfi); + _cfi = iDisplayID | (iIventoryType << 24); + corpse->SetUInt32Value(CORPSE_FIELD_ITEM + i, _cfi); } } @@ -5111,6 +5131,15 @@ uint32 Player::GetMeleeCritDamageReduction(uint32 damage) const return uint32 (melee * damage /100.0f); } +uint32 Player::GetMeleeDamageReduction(uint32 damage) const +{ + float rate = GetRatingBonusValue(CR_CRIT_TAKEN_MELEE); + // Resilience not limited (limit it by 100%) + if (rate > 100.0f) + rate = 100.0f; + return uint32 (rate * damage / 100.0f); +} + uint32 Player::GetRangedCritDamageReduction(uint32 damage) const { float ranged = GetRatingBonusValue(CR_CRIT_TAKEN_RANGED)*2.2f; @@ -5118,6 +5147,15 @@ uint32 Player::GetRangedCritDamageReduction(uint32 damage) const return uint32 (ranged * damage /100.0f); } +uint32 Player::GetRangedDamageReduction(uint32 damage) const +{ + float rate = GetRatingBonusValue(CR_CRIT_TAKEN_RANGED); + // Resilience not limited (limit it by 100%) + if (rate > 100.0f) + rate = 100.0f; + return uint32 (rate * damage / 100.0f); +} + uint32 Player::GetSpellCritDamageReduction(uint32 damage) const { float spell = GetRatingBonusValue(CR_CRIT_TAKEN_SPELL)*2.2f; @@ -5127,13 +5165,13 @@ uint32 Player::GetSpellCritDamageReduction(uint32 damage) const return uint32 (spell * damage / 100.0f); } -uint32 Player::GetDotDamageReduction(uint32 damage) const +uint32 Player::GetSpellDamageReduction(uint32 damage) const { - float spellDot = GetRatingBonusValue(CR_CRIT_TAKEN_SPELL); - // Dot resilience not limited (limit it by 100%) - if (spellDot > 100.0f) - spellDot = 100.0f; - return uint32 (spellDot * damage / 100.0f); + float rate = GetRatingBonusValue(CR_CRIT_TAKEN_SPELL); + // Resilience not limited (limit it by 100%) + if (rate > 100.0f) + rate = 100.0f; + return uint32 (rate * damage / 100.0f); } float Player::GetExpertiseDodgeOrParryReduction(WeaponAttackType attType) const @@ -5456,7 +5494,7 @@ bool Player::UpdateSkillPro(uint16 SkillId, int32 Chance, uint32 step) uint16 SkillValue = SKILL_VALUE(data); uint16 MaxValue = SKILL_MAX(data); - if (!MaxValue || !SkillValue || SkillValue >= MaxValue ) + if ( !MaxValue || !SkillValue || SkillValue >= MaxValue ) return false; int32 Roll = irand(1,1000); @@ -5874,7 +5912,7 @@ ActionButton* Player::addActionButton(uint8 button, uint32 action, uint8 type) { if(button >= MAX_ACTION_BUTTONS) { - sLog.outError( "Action %u not added into button %u for player %s: button must be < 132", action, button, GetName() ); + sLog.outError( "Action %u not added into button %u for player %s: button must be < 144", action, button, GetName() ); return NULL; } @@ -6001,7 +6039,6 @@ void Player::SendMessageToSet(WorldPacket *data, bool self) // we use World::GetMaxVisibleDistance() because i cannot see why not use a distance // update: replaced by GetMap()->GetVisibilityDistance() - Trinity::MessageDistDeliverer notifier(this, data, GetMap()->GetVisibilityDistance()); VisitNearbyWorldObject(GetMap()->GetVisibilityDistance(), notifier); } @@ -6025,7 +6062,7 @@ void Player::SendMessageToSetInRange(WorldPacket *data, float dist, bool self, b } void Player::SendDirectMessage(WorldPacket *data) -{ +{ if (m_session) m_session->SendPacket(data); } @@ -6212,7 +6249,7 @@ void Player::RewardReputation(Unit *pVictim, float rate) Map const *pMap = GetMap(); if(pMap && pMap->IsDungeon()) { - bool Heroic = pMap->IsHeroic(); + bool Heroic = ((InstanceMap*)pMap)->GetDifficulty() == DUNGEON_DIFFICULTY_HEROIC; InstanceTemplate const *pInstance = objmgr.GetInstanceTemplate(pMap->GetId()); if(pInstance) @@ -6348,6 +6385,7 @@ bool Player::RewardHonor(Unit *uVictim, uint32 groupsize, float honor, bool pvpt uint64 victim_guid = 0; uint32 victim_rank = 0; + uint32 rank_diff = 0; time_t now = time(NULL); // need call before fields update to have chance move yesterday data to appropriate fields before today data change. @@ -6500,7 +6538,7 @@ bool Player::RewardHonor(Unit *uVictim, uint32 groupsize, float honor, bool pvpt return true; } -void Player::ModifyHonorPoints( int32 value ) +void Player::ModifyHonorPoints(int32 value) { if(value < 0) { @@ -6513,7 +6551,7 @@ void Player::ModifyHonorPoints( int32 value ) SetUInt32Value(PLAYER_FIELD_HONOR_CURRENCY, GetHonorPoints() < sWorld.getConfig(CONFIG_MAX_HONOR_POINTS) - value ? GetHonorPoints() + value : sWorld.getConfig(CONFIG_MAX_HONOR_POINTS)); } -void Player::ModifyArenaPoints( int32 value ) +void Player::ModifyArenaPoints(int32 value) { if(value < 0) { @@ -6809,7 +6847,7 @@ void Player::DuelComplete(DuelCompleteType type) duel->opponent->AttackStop(); } break; - case DUEL_WON: + case DUEL_WON: GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOSE_DUEL, 1); if (duel->opponent) { @@ -7092,6 +7130,9 @@ void Player::_ApplyItemBonuses(ItemPrototype const *proto, uint8 slot, bool appl case ITEM_MOD_SPELL_POWER: ApplySpellPowerBonus(int32(val), apply); break; + case ITEM_MOD_HEALTH_REGEN: + ApplyHealthRegenBonus(int32(val), apply); + break; // depricated item mods case ITEM_MOD_SPELL_HEALING_DONE: case ITEM_MOD_SPELL_DAMAGE_DONE: @@ -7855,13 +7896,13 @@ void Player::SendLoot(uint64 guid, LootType loot_type) if (go->getLootState() == GO_READY) { - uint32 lootid = go->GetGOInfo()->GetLootId(); + uint32 lootid = go->GetGOInfo()->GetLootId(); //TODO: fix this big hack if((go->GetEntry() == BG_AV_OBJECTID_MINE_N || go->GetEntry() == BG_AV_OBJECTID_MINE_S)) if( BattleGround *bg = GetBattleGround()) if(bg->GetTypeID() == BATTLEGROUND_AV) - if(!(((BattleGroundAV*)bg)->PlayerCanDoMineQuest(go->GetEntry(), GetTeam()))) + if(!(((BattleGroundAV*)bg)->PlayerCanDoMineQuest(go->GetEntry(),GetTeam()))) { SendLootRelease(guid); return; @@ -7875,7 +7916,7 @@ void Player::SendLoot(uint64 guid, LootType loot_type) } if (loot_type == LOOT_FISHING) - go->getFishLoot(loot, this); + go->getFishLoot(loot,this); go->SetLootState(GO_ACTIVATED); } @@ -7900,17 +7941,17 @@ void Player::SendLoot(uint64 guid, LootType loot_type) switch (loot_type) { case LOOT_DISENCHANTING: - loot->FillLoot(item->GetProto()->DisenchantID, LootTemplates_Disenchant, this, true); + loot->FillLoot(item->GetProto()->DisenchantID, LootTemplates_Disenchant, this,true); break; case LOOT_PROSPECTING: - loot->FillLoot(item->GetEntry(), LootTemplates_Prospecting, this, true); + loot->FillLoot(item->GetEntry(), LootTemplates_Prospecting, this,true); break; case LOOT_MILLING: - loot->FillLoot(item->GetEntry(), LootTemplates_Milling, this, true); + loot->FillLoot(item->GetEntry(), LootTemplates_Milling, this,true); break; default: - loot->FillLoot(item->GetEntry(), LootTemplates_Item, this, true); - loot->generateMoneyLoot(item->GetProto()->MinMoneyLoot, item->GetProto()->MaxMoneyLoot); + loot->FillLoot(item->GetEntry(), LootTemplates_Item, this,true); + loot->generateMoneyLoot(item->GetProto()->MinMoneyLoot,item->GetProto()->MaxMoneyLoot); break; } } @@ -8177,10 +8218,16 @@ void Player::SendInitWorldStates(uint32 zoneid, uint32 areaid) case 3968: NumberOfFields = 11; break; + case 4378: + NumberOfFields = 11; + break; case 3703: NumberOfFields = 11; break; - default: + case 4384: + NumberOfFields = 30; + break; + default: NumberOfFields = 12; break; } @@ -8200,6 +8247,13 @@ void Player::SendInitWorldStates(uint32 zoneid, uint32 areaid) data << uint32(0xC77) << uint32(sWorld.getConfig(CONFIG_ARENA_SEASON_IN_PROGRESS)); // 8 Arena season id data << uint32(0xF3D) << uint32(sWorld.getConfig(CONFIG_ARENA_SEASON_ID)); + + // May be send timer to start Wintergrasp + //if(sWorld.GetWintergrapsState()==4354) + // data << uint32(0x1102) << sWorld.GetWintergrapsTimer(); + //else + // data << uint32(0xEC5) << sWorld.GetWintergrapsTimer(); + // --- if(mapid == 530) // Outland { data << uint32(0x9bf) << uint32(0x0); // 7 @@ -8287,7 +8341,7 @@ void Player::SendInitWorldStates(uint32 zoneid, uint32 areaid) data << uint32(0x532) << uint32(0x1); // 8 frostwolfhut hc data << uint32(0x531) << uint32(0x0); // 9 frostwolfhut ac data << uint32(0x52e) << uint32(0x0); // 10 stormpike firstaid a_a - data << uint32(0x571) << uint32(0x0); // 11 east frostwolf tower horde assaulted - unused + data << uint32(0x571) << uint32(0x0); // 11 east frostwolf tower horde assaulted -unused data << uint32(0x570) << uint32(0x0); // 12 west frostwolf tower horde assaulted - unused data << uint32(0x567) << uint32(0x1); // 13 frostwolfe c data << uint32(0x566) << uint32(0x1); // 14 frostwolfw c @@ -8298,7 +8352,7 @@ void Player::SendInitWorldStates(uint32 zoneid, uint32 areaid) data << uint32(0x518) << uint32(0x0); // 19 stoneheart grave a_a data << uint32(0x517) << uint32(0x0); // 20 stoneheart grave h_a data << uint32(0x574) << uint32(0x0); // 21 1396 unk - data << uint32(0x573) << uint32(0x0); // 22 iceblood tower horde assaulted - unused + data << uint32(0x573) << uint32(0x0); // 22 iceblood tower horde assaulted -unused data << uint32(0x572) << uint32(0x0); // 23 towerpoint horde assaulted - unused data << uint32(0x56f) << uint32(0x0); // 24 1391 unk data << uint32(0x56e) << uint32(0x0); // 25 iceblood a @@ -8625,7 +8679,52 @@ void Player::SendInitWorldStates(uint32 zoneid, uint32 areaid) data << uint32(0xbba) << uint32(0x0); // 9 show } break; + case 4378: // Dalaran Sewers + if (bg && bg->GetTypeID() == BATTLEGROUND_DS) + bg->FillInitialWorldStates(data); + else + { + data << uint32(3601) << uint32(0x0); // 7 gold + data << uint32(3600) << uint32(0x0); // 8 green + data << uint32(3610) << uint32(0x0); // 9 show + } + break; case 3703: // Shattrath City + case 4384: // SA + /*if (bg && bg->GetTypeID() == BATTLEGROUND_SA) + bg->FillInitialWorldStates(data); + else + {*/ + // 1-3 A defend, 4-6 H defend, 7-9 unk defend, 1 - ok, 2 - half destroyed, 3 - destroyed + data << uint32(0xf09) << uint32(0x4); // 7 3849 Gate of Temple + data << uint32(0xe36) << uint32(0x4); // 8 3638 Gate of Yellow Moon + data << uint32(0xe27) << uint32(0x4); // 9 3623 Gate of Green Emerald + data << uint32(0xe24) << uint32(0x4); // 10 3620 Gate of Blue Sapphire + data << uint32(0xe21) << uint32(0x4); // 11 3617 Gate of Red Sun + data << uint32(0xe1e) << uint32(0x4); // 12 3614 Gate of Purple Ametyst + + data << uint32(0xdf3) << uint32(0x0); // 13 3571 bonus timer (1 - on, 0 - off) + data << uint32(0xded) << uint32(0x0); // 14 3565 Horde Attacker + data << uint32(0xdec) << uint32(0x1); // 15 3564 Alliance Attacker + // End Round (timer), better explain this by example, eg. ends in 19:59 -> A:BC + data << uint32(0xde9) << uint32(0x9); // 16 3561 C + data << uint32(0xde8) << uint32(0x5); // 17 3560 B + data << uint32(0xde7) << uint32(0x19); // 18 3559 A + data << uint32(0xe35) << uint32(0x1); // 19 3637 East g - Horde control + data << uint32(0xe34) << uint32(0x1); // 20 3636 West g - Horde control + data << uint32(0xe33) << uint32(0x1); // 21 3635 South g - Horde control + data << uint32(0xe32) << uint32(0x0); // 22 3634 East g - Alliance control + data << uint32(0xe31) << uint32(0x0); // 23 3633 West g - Alliance control + data << uint32(0xe30) << uint32(0x0); // 24 3632 South g - Alliance control + data << uint32(0xe2f) << uint32(0x1); // 25 3631 Chamber of Ancients - Horde control + data << uint32(0xe2e) << uint32(0x0); // 26 3630 Chamber of Ancients - Alliance control + data << uint32(0xe2d) << uint32(0x0); // 27 3629 Beach1 - Horde control + data << uint32(0xe2c) << uint32(0x0); // 28 3628 Beach2 - Horde control + data << uint32(0xe2b) << uint32(0x1); // 29 3627 Beach1 - Alliance control + data << uint32(0xe2a) << uint32(0x1); // 30 3626 Beach2 - Alliance control + // and many unks... + //} + break; break; case 4406: // Ring of Valor if (bg && bg->GetTypeID() == BATTLEGROUND_RV) @@ -8691,7 +8790,7 @@ void Player::SendPetSkillWipeConfirm() /*** STORAGE SYSTEM ***/ /*********************************************************/ -void Player::SetVirtualItemSlot(uint8 i, Item *item) +void Player::SetVirtualItemSlot( uint8 i, Item* item) { assert(i < 3); if (i < 2 && item) @@ -8711,7 +8810,7 @@ void Player::SetVirtualItemSlot(uint8 i, Item *item) } } -void Player::SetSheath(SheathState sheathed) +void Player::SetSheath( SheathState sheathed ) { switch (sheathed) { @@ -8740,7 +8839,7 @@ void Player::SetSheath(SheathState sheathed) Unit::SetSheath(sheathed); // this must visualize Sheath changing for other players... } -uint8 Player::FindEquipSlot(ItemPrototype const* proto, uint32 slot, bool swap) const +uint8 Player::FindEquipSlot( ItemPrototype const* proto, uint32 slot, bool swap ) const { uint8 pClass = getClass(); @@ -8958,10 +9057,10 @@ uint8 Player::CanUnequipItems( uint32 item, uint32 count ) const return res; } -uint32 Player::GetItemCount(uint32 item, bool inBankAlso, Item *skipItem) const +uint32 Player::GetItemCount(uint32 item, bool inBankAlso, Item* skipItem) const { uint32 count = 0; - for (uint8 i = EQUIPMENT_SLOT_START; i < INVENTORY_SLOT_ITEM_END; ++i) + for (uint8 i = EQUIPMENT_SLOT_START; i < INVENTORY_SLOT_ITEM_END; i++) if (Item *pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i)) if (pItem != skipItem && pItem->GetEntry() == item) count += pItem->GetCount(); @@ -9031,21 +9130,21 @@ Item* Player::GetItemByGuid( uint64 guid ) const return NULL; } -Item* Player::GetItemByPos(uint16 pos) const +Item* Player::GetItemByPos( uint16 pos ) const { uint8 bag = pos >> 8; uint8 slot = pos & 255; - return GetItemByPos(bag, slot); + return GetItemByPos( bag, slot ); } Item* Player::GetItemByPos( uint8 bag, uint8 slot ) const { - if (bag == INVENTORY_SLOT_BAG_0 && (slot < BANK_SLOT_BAG_END || (slot >= KEYRING_SLOT_START && slot < CURRENCYTOKEN_SLOT_END))) + if (bag == INVENTORY_SLOT_BAG_0 && ( slot < BANK_SLOT_BAG_END || (slot >= KEYRING_SLOT_START && slot < CURRENCYTOKEN_SLOT_END) )) return m_items[slot]; else if ((bag >= INVENTORY_SLOT_BAG_START && bag < INVENTORY_SLOT_BAG_END) || (bag >= BANK_SLOT_BAG_START && bag < BANK_SLOT_BAG_END)) { - if (Bag *pBag = (Bag*)GetItemByPos(INVENTORY_SLOT_BAG_0, bag)) + if (Bag *pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, bag)) return pBag->GetItemByPos(slot); } return NULL; @@ -9090,9 +9189,9 @@ Item* Player::GetShield(bool useable) const return item; } -uint8 Player::GetAttackBySlot(uint8 slot) +uint8 Player::GetAttackBySlot( uint8 slot ) { - switch (slot) + switch(slot) { case EQUIPMENT_SLOT_MAINHAND: return BASE_ATTACK; case EQUIPMENT_SLOT_OFFHAND: return OFF_ATTACK; @@ -9101,35 +9200,35 @@ uint8 Player::GetAttackBySlot(uint8 slot) } } -bool Player::IsInventoryPos(uint8 bag, uint8 slot) +bool Player::IsInventoryPos( uint8 bag, uint8 slot ) { - if (bag == INVENTORY_SLOT_BAG_0 && slot == NULL_SLOT) + if( bag == INVENTORY_SLOT_BAG_0 && slot == NULL_SLOT ) return true; - if (bag == INVENTORY_SLOT_BAG_0 && slot >= INVENTORY_SLOT_ITEM_START && slot < INVENTORY_SLOT_ITEM_END) + if( bag == INVENTORY_SLOT_BAG_0 && ( slot >= INVENTORY_SLOT_ITEM_START && slot < INVENTORY_SLOT_ITEM_END ) ) return true; - if (bag >= INVENTORY_SLOT_BAG_START && bag < INVENTORY_SLOT_BAG_END) + if( bag >= INVENTORY_SLOT_BAG_START && bag < INVENTORY_SLOT_BAG_END ) return true; - if (bag == INVENTORY_SLOT_BAG_0 && slot >= KEYRING_SLOT_START && slot < CURRENCYTOKEN_SLOT_END) + if( bag == INVENTORY_SLOT_BAG_0 && ( slot >= KEYRING_SLOT_START && slot < CURRENCYTOKEN_SLOT_END ) ) return true; return false; } -bool Player::IsEquipmentPos(uint8 bag, uint8 slot) +bool Player::IsEquipmentPos( uint8 bag, uint8 slot ) { - if (bag == INVENTORY_SLOT_BAG_0 && slot < EQUIPMENT_SLOT_END) + if( bag == INVENTORY_SLOT_BAG_0 && ( slot < EQUIPMENT_SLOT_END ) ) return true; - if (bag == INVENTORY_SLOT_BAG_0 && slot >= INVENTORY_SLOT_BAG_START && slot < INVENTORY_SLOT_BAG_END) + if( bag == INVENTORY_SLOT_BAG_0 && ( slot >= INVENTORY_SLOT_BAG_START && slot < INVENTORY_SLOT_BAG_END ) ) return true; return false; } -bool Player::IsBankPos(uint8 bag, uint8 slot) +bool Player::IsBankPos( uint8 bag, uint8 slot ) { - if (bag == INVENTORY_SLOT_BAG_0 && slot >= BANK_SLOT_ITEM_START && slot < BANK_SLOT_ITEM_END) + if( bag == INVENTORY_SLOT_BAG_0 && ( slot >= BANK_SLOT_ITEM_START && slot < BANK_SLOT_ITEM_END ) ) return true; - if (bag == INVENTORY_SLOT_BAG_0 && slot >= BANK_SLOT_BAG_START && slot < BANK_SLOT_BAG_END) + if( bag == INVENTORY_SLOT_BAG_0 && ( slot >= BANK_SLOT_BAG_START && slot < BANK_SLOT_BAG_END ) ) return true; - if (bag >= BANK_SLOT_BAG_START && bag < BANK_SLOT_BAG_END) + if( bag >= BANK_SLOT_BAG_START && bag < BANK_SLOT_BAG_END ) return true; return false; } @@ -9138,14 +9237,14 @@ bool Player::IsBagPos( uint16 pos ) { uint8 bag = pos >> 8; uint8 slot = pos & 255; - if (bag == INVENTORY_SLOT_BAG_0 && slot >= INVENTORY_SLOT_BAG_START && slot < INVENTORY_SLOT_BAG_END) + if( bag == INVENTORY_SLOT_BAG_0 && ( slot >= INVENTORY_SLOT_BAG_START && slot < INVENTORY_SLOT_BAG_END ) ) return true; - if (bag == INVENTORY_SLOT_BAG_0 && slot >= BANK_SLOT_BAG_START && slot < BANK_SLOT_BAG_END) + if( bag == INVENTORY_SLOT_BAG_0 && ( slot >= BANK_SLOT_BAG_START && slot < BANK_SLOT_BAG_END ) ) return true; return false; } -bool Player::IsValidPos(uint8 bag, uint8 slot) +bool Player::IsValidPos( uint8 bag, uint8 slot ) { // post selected if(bag == NULL_BAG) @@ -9188,7 +9287,7 @@ bool Player::IsValidPos(uint8 bag, uint8 slot) if (bag >= INVENTORY_SLOT_BAG_START && bag < INVENTORY_SLOT_BAG_END) { Bag* pBag = (Bag*)GetItemByPos (INVENTORY_SLOT_BAG_0, bag); - if (!pBag) + if(!pBag) return false; // any post selected @@ -9202,7 +9301,7 @@ bool Player::IsValidPos(uint8 bag, uint8 slot) if( bag >= BANK_SLOT_BAG_START && bag < BANK_SLOT_BAG_END ) { Bag* pBag = (Bag*)GetItemByPos (INVENTORY_SLOT_BAG_0, bag); - if (!pBag) + if(!pBag) return false; // any post selected @@ -9219,66 +9318,66 @@ bool Player::IsValidPos(uint8 bag, uint8 slot) bool Player::HasItemCount( uint32 item, uint32 count, bool inBankAlso ) const { uint32 tempcount = 0; - for (uint8 i = EQUIPMENT_SLOT_START; i < INVENTORY_SLOT_ITEM_END; ++i) + for (uint8 i = EQUIPMENT_SLOT_START; i < INVENTORY_SLOT_ITEM_END; i++) { Item *pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i ); - if (pItem && pItem->GetEntry() == item) + if( pItem && pItem->GetEntry() == item ) { tempcount += pItem->GetCount(); - if (tempcount >= count) + if( tempcount >= count ) return true; } } for (uint8 i = KEYRING_SLOT_START; i < CURRENCYTOKEN_SLOT_END; ++i) { Item *pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i ); - if (pItem && pItem->GetEntry() == item) + if( pItem && pItem->GetEntry() == item ) { tempcount += pItem->GetCount(); - if (tempcount >= count) + if( tempcount >= count ) return true; } } - for (uint8 i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; ++i) + for (uint8 i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++) { - if (Bag* pBag = (Bag*)GetItemByPos(INVENTORY_SLOT_BAG_0, i)) + if(Bag* pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, i )) { - for (uint32 j = 0; j < pBag->GetBagSize(); ++j) + for (uint32 j = 0; j < pBag->GetBagSize(); j++) { Item* pItem = GetItemByPos( i, j ); - if (pItem && pItem->GetEntry() == item) + if( pItem && pItem->GetEntry() == item ) { tempcount += pItem->GetCount(); - if (tempcount >= count) + if( tempcount >= count ) return true; } } } } - if (inBankAlso) + if(inBankAlso) { - for (uint8 i = BANK_SLOT_ITEM_START; i < BANK_SLOT_ITEM_END; ++i) + for (uint8 i = BANK_SLOT_ITEM_START; i < BANK_SLOT_ITEM_END; i++) { - Item *pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i); - if (pItem && pItem->GetEntry() == item) + Item *pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i ); + if( pItem && pItem->GetEntry() == item ) { tempcount += pItem->GetCount(); - if (tempcount >= count) + if( tempcount >= count ) return true; } } - for (uint8 i = BANK_SLOT_BAG_START; i < BANK_SLOT_BAG_END; ++i) + for (uint8 i = BANK_SLOT_BAG_START; i < BANK_SLOT_BAG_END; i++) { - if(Bag* pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, i)) + if(Bag* pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, i )) { - for (uint32 j = 0; j < pBag->GetBagSize(); ++j) + for (uint32 j = 0; j < pBag->GetBagSize(); j++) { - Item *pItem = GetItemByPos(i, j); - if (pItem && pItem->GetEntry() == item) + Item* pItem = GetItemByPos( i, j ); + if( pItem && pItem->GetEntry() == item ) { tempcount += pItem->GetCount(); - if (tempcount >= count) + if( tempcount >= count ) return true; } } @@ -9289,19 +9388,19 @@ bool Player::HasItemCount( uint32 item, uint32 count, bool inBankAlso ) const return false; } -bool Player::HasItemOrGemWithIdEquipped(uint32 item, uint32 count, uint8 except_slot) const +bool Player::HasItemOrGemWithIdEquipped( uint32 item, uint32 count, uint8 except_slot ) const { uint32 tempcount = 0; for (uint8 i = EQUIPMENT_SLOT_START; i < EQUIPMENT_SLOT_END; ++i) { - if (i == except_slot) + if(i == except_slot) continue; - Item *pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i); - if (pItem && pItem->GetEntry() == item) + Item *pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i ); + if( pItem && pItem->GetEntry() == item) { tempcount += pItem->GetCount(); - if (tempcount >= count) + if( tempcount >= count ) return true; } } @@ -9311,14 +9410,14 @@ bool Player::HasItemOrGemWithIdEquipped(uint32 item, uint32 count, uint8 except_ { for (uint8 i = EQUIPMENT_SLOT_START; i < EQUIPMENT_SLOT_END; ++i) { - if (i == except_slot) + if(i == except_slot) continue; - Item *pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i); - if (pItem && pItem->GetProto()->Socket[0].Color) + Item *pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i ); + if( pItem && pItem->GetProto()->Socket[0].Color) { tempcount += pItem->GetGemCountWithID(item); - if (tempcount >= count) + if( tempcount >= count ) return true; } } @@ -12298,6 +12397,15 @@ void Player::ApplyEnchantment(Item *item, EnchantmentSlot slot, bool apply, bool if (!ignore_condition && pEnchant->EnchantmentCondition && !((Player*)this)->EnchantmentFitsRequirements(pEnchant->EnchantmentCondition, -1)) return; + if ((pEnchant->requiredLevel) > ((Player*)this)->getLevel()) + return; + + if ((pEnchant->requiredSkill) > 0) + { + if ((pEnchant->requiredSkillValue) > (((Player*)this)->GetSkillValue(pEnchant->requiredSkill))) + return; + } + if (!item->IsBroken()) { for (int s = 0; s < 3; ++s) @@ -12560,6 +12668,10 @@ void Player::ApplyEnchantment(Item *item, EnchantmentSlot slot, bool apply, bool ((Player*)this)->ApplySpellPowerBonus(enchant_amount, apply); sLog.outDebug("+ %u SPELL_POWER", enchant_amount); break; + case ITEM_MOD_HEALTH_REGEN: + ((Player*)this)->ApplyHealthRegenBonus(enchant_amount, apply); + sLog.outDebug("+ %u HEALTH_REGENERATION", enchant_amount); + break; case ITEM_MOD_SPELL_HEALING_DONE: // deprecated case ITEM_MOD_SPELL_DAMAGE_DONE: // deprecated default: @@ -12936,7 +13048,7 @@ bool Player::CanCompleteQuest( uint32 quest_id ) if ( qInfo->HasFlag( QUEST_TRINITY_FLAGS_DELIVER ) ) { - for (uint8 i = 0; i < QUEST_OBJECTIVES_COUNT; i++) + for (uint8 i = 0; i < QUEST_ITEM_OBJECTIVES_COUNT; i++) { if( qInfo->ReqItemCount[i]!= 0 && q_status.m_itemcount[i] < qInfo->ReqItemCount[i] ) return false; @@ -12986,7 +13098,7 @@ bool Player::CanCompleteRepeatableQuest( Quest const *pQuest ) return false; if (pQuest->HasFlag( QUEST_TRINITY_FLAGS_DELIVER) ) - for (uint8 i = 0; i < QUEST_OBJECTIVES_COUNT; i++) + for (uint8 i = 0; i < QUEST_ITEM_OBJECTIVES_COUNT; i++) if( pQuest->ReqItemId[i] && pQuest->ReqItemCount[i] && !HasItemCount(pQuest->ReqItemId[i],pQuest->ReqItemCount[i]) ) return false; @@ -13013,7 +13125,7 @@ bool Player::CanRewardQuest( Quest const *pQuest, bool msg ) // prevent receive reward with quest items in bank if ( pQuest->HasFlag( QUEST_TRINITY_FLAGS_DELIVER ) ) { - for (uint8 i = 0; i < QUEST_OBJECTIVES_COUNT; i++) + for (uint8 i = 0; i < QUEST_ITEM_OBJECTIVES_COUNT; i++) { if( pQuest->ReqItemCount[i]!= 0 && GetItemCount(pQuest->ReqItemId[i]) < pQuest->ReqItemCount[i] ) @@ -13088,7 +13200,7 @@ void Player::AddQuest( Quest const *pQuest, Object *questGiver ) if ( pQuest->HasFlag( QUEST_TRINITY_FLAGS_DELIVER ) ) { - for (uint8 i = 0; i < QUEST_OBJECTIVES_COUNT; ++i) + for (uint8 i = 0; i < QUEST_ITEM_OBJECTIVES_COUNT; ++i) questStatusData.m_itemcount[i] = 0; } @@ -13186,13 +13298,10 @@ void Player::RewardQuest( Quest const *pQuest, uint32 reward, Object* questGiver uint32 quest_id = pQuest->GetQuestId(); - for (uint8 i = 0; i < QUEST_OBJECTIVES_COUNT; ++i) + for (uint8 i = 0; i < QUEST_ITEM_OBJECTIVES_COUNT; ++i) if (pQuest->ReqItemId[i]) DestroyItemCount( pQuest->ReqItemId[i], pQuest->ReqItemCount[i], true); -// This is wrong. If SrcItem is supposed to be destroyed on quest complete then the item will be either in ReqItemId or ReqSrcItemId -// TakeQuestSourceItem(quest_id, true); // take quest src item from player on completing quest - for (uint8 i = 0; i < QUEST_SOURCE_ITEM_IDS_COUNT; ++i) { if (pQuest->ReqSourceId[i]) @@ -13864,7 +13973,7 @@ void Player::AdjustQuestReqItemCount(Quest const* pQuest, QuestStatusData& quest { if (pQuest->HasFlag( QUEST_TRINITY_FLAGS_DELIVER)) { - for (uint8 i = 0; i < QUEST_OBJECTIVES_COUNT; ++i) + for (uint8 i = 0; i < QUEST_ITEM_OBJECTIVES_COUNT; ++i) { uint32 reqitemcount = pQuest->ReqItemCount[i]; if (reqitemcount != 0) @@ -13944,7 +14053,7 @@ void Player::ItemAddedQuestCheck( uint32 entry, uint32 count) if( !qInfo || !qInfo->HasFlag(QUEST_TRINITY_FLAGS_DELIVER)) continue; - for (uint8 j = 0; j < QUEST_OBJECTIVES_COUNT; ++j) + for (uint8 j = 0; j < QUEST_ITEM_OBJECTIVES_COUNT; ++j) { uint32 reqitem = qInfo->ReqItemId[j]; if (reqitem == entry) @@ -13981,7 +14090,7 @@ void Player::ItemRemovedQuestCheck( uint32 entry, uint32 count) if( !qInfo->HasFlag(QUEST_TRINITY_FLAGS_DELIVER)) continue; - for (uint8 j = 0; j < QUEST_OBJECTIVES_COUNT; ++j) + for (uint8 j = 0; j < QUEST_ITEM_OBJECTIVES_COUNT; ++j) { uint32 reqitem = qInfo->ReqItemId[j]; if (reqitem == entry) @@ -14295,7 +14404,7 @@ bool Player::HasQuestForItem(uint32 itemid) const // There should be no mixed ReqItem/ReqSource drop // This part for ReqItem drop - for (uint8 j = 0; j < QUEST_OBJECTIVES_COUNT; ++j) + for (uint8 j = 0; j < QUEST_ITEM_OBJECTIVES_COUNT; ++j) { if (itemid == qinfo->ReqItemId[j] && q_status.m_itemcount[j] < qinfo->ReqItemCount[j]) return true; @@ -14369,7 +14478,7 @@ void Player::SendQuestFailed( uint32 quest_id ) if( quest_id ) { WorldPacket data( SMSG_QUESTGIVER_QUEST_FAILED, 4+4 ); - data << quest_id; + data << uint32(quest_id); data << uint32(0); // failed reason (4 for inventory is full) GetSession()->SendPacket( &data ); sLog.outDebug("WORLD: Sent SMSG_QUESTGIVER_QUEST_FAILED"); @@ -14381,7 +14490,7 @@ void Player::SendQuestTimerFailed( uint32 quest_id ) if( quest_id ) { WorldPacket data( SMSG_QUESTUPDATE_FAILEDTIMER, 4 ); - data << quest_id; + data << uint32(quest_id); GetSession()->SendPacket( &data ); sLog.outDebug("WORLD: Sent SMSG_QUESTUPDATE_FAILEDTIMER"); } @@ -14522,7 +14631,7 @@ void Player::_LoadDeclinedNames(QueryResult* result) void Player::_LoadArenaTeamInfo(QueryResult *result) { // arenateamid, played_week, played_season, personal_rating - memset((void*)&m_uint32Values[PLAYER_FIELD_ARENA_TEAM_INFO_1_1], 0, sizeof(uint32)*18); + memset((void*)&m_uint32Values[PLAYER_FIELD_ARENA_TEAM_INFO_1_1], 0, sizeof(uint32) * MAX_ARENA_SLOT * ARENA_TEAM_END); if (!result) return; @@ -14533,22 +14642,24 @@ void Player::_LoadArenaTeamInfo(QueryResult *result) uint32 arenateamid = fields[0].GetUInt32(); uint32 played_week = fields[1].GetUInt32(); uint32 played_season = fields[2].GetUInt32(); - uint32 personal_rating = fields[3].GetUInt32(); + uint32 wons_season = fields[3].GetUInt32(); + uint32 personal_rating = fields[4].GetUInt32(); ArenaTeam* aTeam = objmgr.GetArenaTeamById(arenateamid); if(!aTeam) { - sLog.outError("Player::_LoadArenaTeamInfo: couldn't load arenateam %u, week %u, season %u, rating %u", arenateamid, played_week, played_season, personal_rating); + sLog.outError("Player::_LoadArenaTeamInfo: couldn't load arenateam %u", arenateamid); continue; } uint8 arenaSlot = aTeam->GetSlot(); - m_uint32Values[PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + arenaSlot * 6] = arenateamid; // TeamID - m_uint32Values[PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + arenaSlot * 6 + 1] = ((aTeam->GetCaptain() == GetGUID()) ? (uint32)0 : (uint32)1); // Captain 0, member 1 - m_uint32Values[PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + arenaSlot * 6 + 2] = played_week; // Played Week - m_uint32Values[PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + arenaSlot * 6 + 3] = played_season; // Played Season - m_uint32Values[PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + arenaSlot * 6 + 4] = 0; // Unk - m_uint32Values[PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + arenaSlot * 6 + 5] = personal_rating; // Personal Rating + m_uint32Values[PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (arenaSlot * ARENA_TEAM_END) + ARENA_TEAM_ID] = arenateamid; // TeamID + m_uint32Values[PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (arenaSlot * ARENA_TEAM_END) + ARENA_TEAM_TYPE] = aTeam->GetType(); // team type + m_uint32Values[PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (arenaSlot * ARENA_TEAM_END) + ARENA_TEAM_MEMBER] = ((aTeam->GetCaptain() == GetGUID()) ? (uint32)0 : (uint32)1); // Captain 0, member 1 + m_uint32Values[PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (arenaSlot * ARENA_TEAM_END) + ARENA_TEAM_GAMES_WEEK] = played_week; // Played Week + m_uint32Values[PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (arenaSlot * ARENA_TEAM_END) + ARENA_TEAM_GAMES_SEASON] = played_season; // Played Season + m_uint32Values[PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (arenaSlot * ARENA_TEAM_END) + ARENA_TEAM_WINS_SEASON] = wons_season; // wins season + m_uint32Values[PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (arenaSlot * ARENA_TEAM_END) + ARENA_TEAM_PERSONAL_RATING] = personal_rating; // Personal Rating }while (result->NextRow()); delete result; @@ -14661,37 +14772,6 @@ float Player::GetFloatValueFromArray(Tokens const& data, uint16 index) uint32 Player::GetUInt32ValueFromDB(uint16 index, uint64 guid) { - // todo: cleanup in this, move to a separate function. - if( index == PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 0 * 6 + 5 - || index == PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 1 * 6 + 5 - || index == PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 2 * 6 + 5 - || index == PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (0 * 6) - || index == PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (1 * 6) - || index == PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (2 * 6) - || index == UNIT_FIELD_LEVEL) - { - CachePlayerInfoMap::iterator _iter = objmgr.m_mPlayerInfoMap.find(GUID_LOPART(guid)); - if(_iter != objmgr.m_mPlayerInfoMap.end()) - { - switch(index) - { - case (PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 0 * 6 + 5): - return _iter->second->unArenaInfoSlot0; - case (PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 1 * 6 + 5): - return _iter->second->unArenaInfoSlot1; - case (PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 2 * 6 + 5): - return _iter->second->unArenaInfoSlot2; - case (PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (0 * 6)): - return _iter->second->unArenaInfoId0; - case (PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (1 * 6)): - return _iter->second->unArenaInfoId1; - case (PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (2 * 6)): - return _iter->second->unArenaInfoId2; - case (UNIT_FIELD_LEVEL): - return _iter->second->unLevel; - } - } - } Tokens data; if(!LoadValuesArrayFromDB(data,guid)) return 0; @@ -14811,7 +14891,11 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder ) Relocate(fields[13].GetFloat(),fields[14].GetFloat(),fields[15].GetFloat(),fields[17].GetFloat()); uint32 mapId = fields[16].GetUInt32(); uint32 instanceId = fields[41].GetFloat(); - SetDifficulty(fields[39].GetUInt32()); // may be changed in _LoadGroup + + uint32 difficulty = fields[39].GetUInt32(); + if(difficulty >= MAX_DUNGEON_DIFFICULTY) + difficulty = DUNGEON_DIFFICULTY_NORMAL; + SetDungeonDifficulty(Difficulty(difficulty)); // may be changed in _LoadGroup std::string taxi_nodes = fields[38].GetCppString(); #define RelocateToHomebind(){ mapId = m_homebindMapId; instanceId = 0; Relocate(m_homebindX, m_homebindY, m_homebindZ); } @@ -14839,7 +14923,7 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder ) // arena team not exist or not member, cleanup fields for (int j = 0; j < 6; ++j) - SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + arena_slot * 6 + j, 0); + SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (arena_slot * ARENA_TEAM_END) + j, 0); } _LoadBoundInstances(holder->GetResult(PLAYER_LOGIN_QUERY_LOADBOUNDINSTANCES)); @@ -14989,7 +15073,7 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder ) // fix crash (because of if(Map *map = _FindMap(instanceId)) in MapInstanced::CreateInstance) if(instanceId) - if(InstanceSave * save = GetInstanceSave(mapId)) + if(InstanceSave * save = GetInstanceSave(mapId, mapEntry->IsRaid())) if(save->GetInstanceId() != instanceId) instanceId = 0; @@ -15816,7 +15900,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->IsRepeatable()))) + (!questStatusData.m_rewarded || pQuest->IsDaily()))) { SetQuestSlot(slot, quest_id, quest_time); @@ -15935,15 +16019,18 @@ void Player::_LoadGroup(QueryResult *result) uint8 subgroup = group->GetMemberGroup(GetGUID()); SetGroup(group, subgroup); if (getLevel() >= LEVELREQUIREMENT_HEROIC) + { // the group leader may change the instance difficulty while the player is offline - SetDifficulty(group->GetDifficulty()); + SetDungeonDifficulty(group->GetDungeonDifficulty()); + SetRaidDifficulty(group->GetRaidDifficulty()); + } } } } void Player::_LoadBoundInstances(QueryResult *result) { - for (uint8 i = 0; i < TOTAL_DIFFICULTIES; ++i) + for (uint8 i = 0; i < MAX_DIFFICULTY; ++i) m_boundInstances[i].clear(); Group *group = GetGroup(); @@ -15958,6 +16045,7 @@ void Player::_LoadBoundInstances(QueryResult *result) uint32 mapId = fields[2].GetUInt32(); uint32 instanceId = fields[0].GetUInt32(); uint8 difficulty = fields[3].GetUInt8(); + time_t resetTime = (time_t)fields[4].GetUInt64(); // the resettime for normal instances is only saved when the InstanceSave is unloaded // so the value read from the DB may be wrong here but only if the InstanceSave is loaded @@ -15971,6 +16059,22 @@ void Player::_LoadBoundInstances(QueryResult *result) continue; } + if(difficulty >= MAX_DIFFICULTY) + { + sLog.outError("_LoadBoundInstances: player %s(%d) has bind to not existed difficulty %d instance for map %u", GetName(), GetGUIDLow(), difficulty, mapId); + CharacterDatabase.PExecute("DELETE FROM character_instance WHERE guid = '%d' AND instance = '%d'", GetGUIDLow(), instanceId); + continue; + } + + MapDifficulty const* mapDiff = GetMapDifficultyData(mapId,Difficulty(difficulty)); + if(!mapDiff) + { + sLog.outError("_LoadBoundInstances: player %s(%d) has bind to not existed difficulty %d instance for map %u", GetName(), GetGUIDLow(), difficulty, mapId); + CharacterDatabase.PExecute("DELETE FROM character_instance WHERE guid = '%d' AND instance = '%d'", GetGUIDLow(), instanceId); + continue; + } + + if (!perm && group) { sLog.outError("_LoadBoundInstances: player %s(%d) is in group %d but has a non-permanent character bind to map %d,%d,%d", GetName(), GetGUIDLow(), GUID_LOPART(group->GetLeaderGUID()), mapId, instanceId, difficulty); @@ -15979,18 +16083,19 @@ void Player::_LoadBoundInstances(QueryResult *result) } // since non permanent binds are always solo bind, they can always be reset - if (InstanceSave *save = sInstanceSaveManager.AddInstanceSave(mapId, instanceId, difficulty, resetTime, !perm, true)) + if (InstanceSave *save = sInstanceSaveManager.AddInstanceSave(mapId, instanceId, Difficulty(difficulty), resetTime, !perm, true)) BindToInstance(save, perm, true); } while (result->NextRow()); delete result; } } -InstancePlayerBind* Player::GetBoundInstance(uint32 mapid, uint8 difficulty) +InstancePlayerBind* Player::GetBoundInstance(uint32 mapid, Difficulty difficulty) { // some instances only have one difficulty - const MapEntry* entry = sMapStore.LookupEntry(mapid); - if (!entry || !entry->SupportsHeroicMode()) difficulty = DIFFICULTY_NORMAL; + MapDifficulty const* mapDiff = GetMapDifficultyData(mapid,difficulty); + if(!mapDiff) + return NULL; BoundInstancesMap::iterator itr = m_boundInstances[difficulty].find(mapid); if (itr != m_boundInstances[difficulty].end()) @@ -15999,25 +16104,25 @@ InstancePlayerBind* Player::GetBoundInstance(uint32 mapid, uint8 difficulty) return NULL; } -InstanceSave * Player::GetInstanceSave(uint32 mapid) +InstanceSave * Player::GetInstanceSave(uint32 mapid, bool raid) { - InstancePlayerBind *pBind = GetBoundInstance(mapid, GetDifficulty()); + InstancePlayerBind *pBind = GetBoundInstance(mapid, GetDifficulty(raid)); InstanceSave *pSave = pBind ? pBind->save : NULL; if (!pBind || !pBind->perm) if(Group *group = GetGroup()) - if(InstanceGroupBind *groupBind = group->GetBoundInstance(mapid, GetDifficulty())) + if(InstanceGroupBind *groupBind = group->GetBoundInstance(this)) pSave = groupBind->save; return pSave; } -void Player::UnbindInstance(uint32 mapid, uint8 difficulty, bool unload) +void Player::UnbindInstance(uint32 mapid, Difficulty difficulty, bool unload) { BoundInstancesMap::iterator itr = m_boundInstances[difficulty].find(mapid); UnbindInstance(itr, difficulty, unload); } -void Player::UnbindInstance(BoundInstancesMap::iterator &itr, uint8 difficulty, bool unload) +void Player::UnbindInstance(BoundInstancesMap::iterator &itr, Difficulty difficulty, bool unload) { if (itr != m_boundInstances[difficulty].end()) { @@ -16074,7 +16179,7 @@ void Player::SendRaidInfo() time_t now = time(NULL); - for (uint8 i = 0; i < TOTAL_DIFFICULTIES; ++i) + for (uint8 i = 0; i < MAX_DIFFICULTY; ++i) { for (BoundInstancesMap::iterator itr = m_boundInstances[i].begin(); itr != m_boundInstances[i].end(); ++itr) { @@ -16084,8 +16189,9 @@ void Player::SendRaidInfo() data << uint32(save->GetMapId()); // map id data << uint32(save->GetDifficulty()); // difficulty data << uint64(save->GetInstanceId()); // instance id + data << uint8(1); // expired = 0 + data << uint8(0); // extended = 1 data << uint32(save->GetResetTime() - now); // reset time - data << uint32(0); // is extended ++counter; } } @@ -16102,7 +16208,7 @@ void Player::SendSavedInstances() bool hasBeenSaved = false; WorldPacket data; - for (uint8 i = 0; i < TOTAL_DIFFICULTIES; ++i) + for (uint8 i = 0; i < MAX_DIFFICULTY; ++i) { for (BoundInstancesMap::iterator itr = m_boundInstances[i].begin(); itr != m_boundInstances[i].end(); ++itr) { @@ -16122,7 +16228,7 @@ void Player::SendSavedInstances() if (!hasBeenSaved) return; - for (uint8 i = 0; i < TOTAL_DIFFICULTIES; ++i) + for (uint8 i = 0; i < MAX_DIFFICULTY; ++i) { for (BoundInstancesMap::iterator itr = m_boundInstances[i].begin(); itr != m_boundInstances[i].end(); ++itr) { @@ -16155,7 +16261,7 @@ void Player::ConvertInstancesToGroup(Player *player, Group *group, uint64 player if (player) { - for (uint8 i = 0; i < TOTAL_DIFFICULTIES; ++i) + for (uint8 i = 0; i < MAX_DIFFICULTY; ++i) { for (BoundInstancesMap::iterator itr = player->m_boundInstances[i].begin(); itr != player->m_boundInstances[i].end();) { @@ -16165,7 +16271,8 @@ void Player::ConvertInstancesToGroup(Player *player, Group *group, uint64 player // permanent binds are not removed if (!itr->second.perm) { - player->UnbindInstance(itr, i, true); // increments itr + // increments itr in call + player->UnbindInstance(itr, Difficulty(i), true); has_solo = true; } else @@ -16193,7 +16300,7 @@ bool Player::Satisfy(AccessRequirement const *ar, uint32 target_map, bool report { if (ar->levelMin && getLevel() < ar->levelMin) LevelMin = ar->levelMin; - if (ar->heroicLevelMin && GetDifficulty() == DIFFICULTY_HEROIC && getLevel() < ar->heroicLevelMin) + if(ar->heroicLevelMin && GetDungeonDifficulty() == DUNGEON_DIFFICULTY_HEROIC && getLevel() < ar->heroicLevelMin) LevelMin = ar->heroicLevelMin; if (ar->levelMax && getLevel() > ar->levelMax) LevelMax = ar->levelMax; @@ -16209,9 +16316,17 @@ bool Player::Satisfy(AccessRequirement const *ar, uint32 target_map, bool report else if(ar->item2 && !HasItemCount(ar->item2, 1)) missingItem = ar->item2; + MapEntry const* mapEntry = sMapStore.LookupEntry(target_map); + if(!mapEntry) + return false; + + bool isNormalTargetMap = mapEntry->IsRaid() + ? (GetRaidDifficulty() == RAID_DIFFICULTY_10MAN_NORMAL) + : (GetDungeonDifficulty() == DUNGEON_DIFFICULTY_NORMAL); + uint32 missingKey = 0; uint32 missingHeroicQuest = 0; - if (GetDifficulty() == DIFFICULTY_HEROIC) + if(!isNormalTargetMap) { if (ar->heroicKey) { @@ -16237,7 +16352,7 @@ bool Player::Satisfy(AccessRequirement const *ar, uint32 target_map, bool report if (missingItem) GetSession()->SendAreaTriggerMessage(GetSession()->GetTrinityString(LANG_LEVEL_MINREQUIRED_AND_ITEM), LevelMin, objmgr.GetItemPrototype(missingItem)->Name1); else if (missingKey) - SendTransferAborted(target_map, TRANSFER_ABORT_DIFFICULTY); + SendTransferAborted(target_map, TRANSFER_ABORT_DIFFICULTY, isNormalTargetMap ? DUNGEON_DIFFICULTY_NORMAL : DUNGEON_DIFFICULTY_HEROIC); else if (missingHeroicQuest) GetSession()->SendAreaTriggerMessage(ar->heroicQuestFailedText.c_str()); else if (missingQuest) @@ -16352,7 +16467,7 @@ void Player::SaveToDB() { ss << GetMapId() << ", " << (uint32)GetInstanceId() << ", " - << (uint32)GetDifficulty() << ", " + << (uint32)GetDungeonDifficulty() << ", " << finiteAlways(GetPositionX()) << ", " << finiteAlways(GetPositionY()) << ", " << finiteAlways(GetPositionZ()) << ", " @@ -16362,7 +16477,7 @@ void Player::SaveToDB() { ss << GetTeleportDest().GetMapId() << ", " << (uint32)0 << ", " - << (uint32)GetDifficulty() << ", " + << (uint32)GetDungeonDifficulty() << ", " << finiteAlways(GetTeleportDest().GetPositionX()) << ", " << finiteAlways(GetTeleportDest().GetPositionY()) << ", " << finiteAlways(GetTeleportDest().GetPositionZ()) << ", " @@ -16950,7 +17065,17 @@ void Player::SendDungeonDifficulty(bool IsInGroup) { uint8 val = 0x00000001; WorldPacket data(MSG_SET_DUNGEON_DIFFICULTY, 12); - data << (uint32)GetDifficulty(); + data << (uint32)GetDungeonDifficulty(); + data << uint32(val); + data << uint32(IsInGroup); + GetSession()->SendPacket(&data); +} + +void Player::SendRaidDifficulty(bool IsInGroup) +{ + uint8 val = 0x00000001; + WorldPacket data(MSG_SET_RAID_DIFFICULTY, 12); + data << uint32(GetRaidDifficulty()); data << uint32(val); data << uint32(IsInGroup); GetSession()->SendPacket(&data); @@ -16964,18 +17089,18 @@ void Player::SendResetFailedNotify(uint32 mapid) } /// Reset all solo instances and optionally send a message on success for each -void Player::ResetInstances(uint8 method) +void Player::ResetInstances(uint8 method, bool isRaid) { // method can be INSTANCE_RESET_ALL, INSTANCE_RESET_CHANGE_DIFFICULTY, INSTANCE_RESET_GROUP_JOIN // we assume that when the difficulty changes, all instances that can be reset will be - uint8 dif = GetDifficulty(); + Difficulty diff = GetDifficulty(isRaid); - for (BoundInstancesMap::iterator itr = m_boundInstances[dif].begin(); itr != m_boundInstances[dif].end();) + for (BoundInstancesMap::iterator itr = m_boundInstances[diff].begin(); itr != m_boundInstances[diff].end(); ) { InstanceSave *p = itr->second.save; const MapEntry *entry = sMapStore.LookupEntry(itr->first); - if(!entry || !p->CanReset()) + if(!entry || entry->IsRaid() != isRaid || !p->CanReset()) { ++itr; continue; @@ -16984,7 +17109,7 @@ void Player::ResetInstances(uint8 method) if(method == INSTANCE_RESET_ALL) { // the "reset all instances" method can only reset normal maps - if(dif == DIFFICULTY_HEROIC || entry->map_type == MAP_RAID) + if(entry->map_type == MAP_RAID || diff == DUNGEON_DIFFICULTY_HEROIC) { ++itr; continue; @@ -17005,7 +17130,7 @@ void Player::ResetInstances(uint8 method) SendResetInstanceSuccess(p->GetMapId()); p->DeleteFromDB(); - m_boundInstances[dif].erase(itr++); + m_boundInstances[diff].erase(itr++); // the following should remove the instance save from the manager and delete it as well p->RemovePlayer(this); @@ -17085,7 +17210,12 @@ Pet* Player::GetPet() const if(!IS_PET_GUID(pet_guid)) return NULL; - if(Pet* pet = ObjectAccessor::GetPet(pet_guid)) + Pet* pet = ObjectAccessor::GetPet(pet_guid); + + if (!pet) + return NULL; + + if(IsInWorld() && pet) return pet; //there may be a guardian in slot @@ -17395,6 +17525,10 @@ void Player::VehicleSpellInitialize() if(!veh) return; + // GetPosition_ is not a member of 'Vehicle', SetPosition is a member of 'Player': SetPosition(GetVehicle()->GetPositionX(), GetVehicle()->GetPositionY(), GetVehicle()->GetPositionZ(), GetVehicle()->GetOrientation()); + + // GetPosition_ is not a member of 'Vehicle', SetPosition is a member of 'Player': SetPosition(GetVehicle()->GetPositionX(), GetVehicle()->GetPositionY(), GetVehicle()->GetPositionZ(), GetVehicle()->GetOrientation()); + WorldPacket data(SMSG_PET_SPELLS, 8+2+4+4+4*10+1+1); data << uint64(veh->GetGUID()); data << uint16(0); @@ -18329,17 +18463,32 @@ bool Player::BuyItemFromVendor(uint64 vendorguid, uint32 item, uint8 count, uint } ModifyMoney( -(int32)price ); + uint32 arenaPoints = 0; + uint32 honorPoints = 0; + uint32 extendedCost[5] = {0,0,0,0,0}; + uint32 extendedCostCount[5] = {0,0,0,0,0}; + if (crItem->ExtendedCost) // case for new honor system { ItemExtendedCostEntry const* iece = sItemExtendedCostStore.LookupEntry(crItem->ExtendedCost); if (iece->reqhonorpoints) - ModifyHonorPoints( - int32(iece->reqhonorpoints * count)); + { + honorPoints = iece->reqhonorpoints * count; + ModifyHonorPoints( - int32(honorPoints) ); + } if (iece->reqarenapoints) - ModifyArenaPoints( - int32(iece->reqarenapoints * count)); + { + arenaPoints = iece->reqarenapoints * count; + ModifyArenaPoints( - int32(arenaPoints) ); + } for (uint8 i = 0; i < 5; ++i) { if (iece->reqitem[i]) + { DestroyItemCount(iece->reqitem[i], (iece->reqitemcount[i] * count), true); + extendedCost[i] = iece->reqitem[i]; + extendedCostCount[i] = iece->reqitemcount[i]; + } } } @@ -18348,13 +18497,22 @@ bool Player::BuyItemFromVendor(uint64 vendorguid, uint32 item, uint8 count, uint uint32 new_count = pCreature->UpdateVendorItemCurrentCount(crItem,pProto->BuyCount * count); WorldPacket data(SMSG_BUY_ITEM, (8+4+4+4)); - data << pCreature->GetGUID(); - data << (uint32)(vendor_slot+1); // numbered from 1 at client - data << (uint32)(crItem->maxcount > 0 ? new_count : 0xFFFFFFFF); - data << (uint32)count; + data << uint64(pCreature->GetGUID()); + data << uint32(vendor_slot+1); // numbered from 1 at client + data << uint32(crItem->maxcount > 0 ? new_count : 0xFFFFFFFF); + data << uint32(count); GetSession()->SendPacket(&data); - SendNewItem(it, pProto->BuyCount*count, true, false, false); + + // Item Refund system, only works for non stackable items with extendedcost + if(count == 1 && crItem->ExtendedCost ) + { + it->SetPaidArenaPoints(arenaPoints); + it->SetPaidHonorPoints(honorPoints); + it->SetRefundExpiryTime( time(NULL)+(HOUR*2) ); + for (uint8 i = 0; i < 5; ++i) + it->SetPaidExtendedCost(i, extendedCost[i], extendedCostCount[i]); + } } } else if (IsEquipmentPos(bag, slot)) @@ -18393,10 +18551,10 @@ bool Player::BuyItemFromVendor(uint64 vendorguid, uint32 item, uint8 count, uint uint32 new_count = pCreature->UpdateVendorItemCurrentCount(crItem,pProto->BuyCount * count); WorldPacket data(SMSG_BUY_ITEM, (8+4+4+4)); - data << pCreature->GetGUID(); - data << (uint32)(vendor_slot+1); // numbered from 1 at client - data << (uint32)(crItem->maxcount > 0 ? new_count : 0xFFFFFFFF); - data << (uint32)count; + data << uint64(pCreature->GetGUID()); + data << uint32(vendor_slot + 1); // numbered from 1 at client + data << uint32(crItem->maxcount > 0 ? new_count : 0xFFFFFFFF); + data << uint32(count); GetSession()->SendPacket(&data); SendNewItem(it, pProto->BuyCount*count, true, false, false); @@ -18423,9 +18581,9 @@ uint32 Player::GetMaxPersonalArenaRatingRequirement() { if(ArenaTeam * at = objmgr.GetArenaTeamById(GetArenaTeamId(i))) { - uint32 p_rating = GetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (i * 6) + 5); + uint32 p_rating = GetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (i * ARENA_TEAM_END) + ARENA_TEAM_PERSONAL_RATING); uint32 t_rating = at->GetRating(); - p_rating = p_rating<t_rating? p_rating : t_rating; + p_rating = p_rating < t_rating ? p_rating : t_rating; if(max_personal_rating < p_rating) max_personal_rating = p_rating; } @@ -18465,7 +18623,7 @@ void Player::UpdateHomebindTime(uint32 time) m_HomebindTimer = 60000; // send message to player WorldPacket data(SMSG_RAID_GROUP_ONLY, 4+4); - data << m_HomebindTimer; + data << uint32(m_HomebindTimer); data << uint32(1); GetSession()->SendPacket(&data); sLog.outDebug("PLAYER: Player '%s' (GUID: %u) will be teleported to homebind in 60 seconds", GetName(),GetGUIDLow()); @@ -18634,8 +18792,8 @@ void Player::SendCooldownEvent(SpellEntry const *spellInfo, uint32 itemId, Spell // Send activate cooldown timer (possible 0) at client side WorldPacket data(SMSG_COOLDOWN_EVENT, (4+8)); - data << spellInfo->Id; - data << GetGUID(); + data << uint32(spellInfo->Id); + data << uint64(GetGUID()); SendDirectMessage(&data); } @@ -19077,14 +19235,16 @@ bool Player::IsVisibleInGridForPlayer( Player const * pl ) const // It seems in battleground everyone sees everyone, except the enemy-faction ghosts if (InBattleGround()) { - if (!(isAlive() || m_deathTimer > 0) && !IsFriendlyTo(pl)) + if (!(isAlive() || m_deathTimer > 0) && !IsFriendlyTo(pl) ) return false; return true; } // Live player see live player or dead player with not realized corpse - if (pl->isAlive() || pl->m_deathTimer > 0) + if(pl->isAlive() || pl->m_deathTimer > 0) + { return isAlive() || m_deathTimer > 0; + } // Ghost see other friendly ghosts, that's for sure if(!(isAlive() || m_deathTimer > 0) && IsFriendlyTo(pl)) @@ -19275,7 +19435,7 @@ void Player::SendComboPoints() void Player::AddComboPoints(Unit* target, int8 count, Spell * spell) { - if (!count) + if(!count) return; int8 * comboPoints = spell ? &spell->m_comboPointGain : &m_comboPoints; @@ -19283,7 +19443,7 @@ void Player::AddComboPoints(Unit* target, int8 count, Spell * spell) // without combo points lost (duration checked in aura) RemoveAurasByType(SPELL_AURA_RETAIN_COMBO_POINTS); - if (target->GetGUID() == m_comboTarget) + if (target->GetGUID() == m_comboTarget) *comboPoints += count; else { @@ -19355,23 +19515,26 @@ void Player::SetGroup(Group *group, int8 subgroup) void Player::SendInitialPacketsBeforeAddToMap() { - WorldPacket data(SMSG_SET_REST_START_OBSOLETE, 4); - data << uint32(0); // unknown, may be rest state time or experience - GetSession()->SendPacket(&data); - GetSocial()->SendSocialList(); + // guild bank list wtf? + // Homebind - data.Initialize(SMSG_BINDPOINTUPDATE, 5*4); + WorldPacket data(SMSG_BINDPOINTUPDATE, 5*4); data << m_homebindX << m_homebindY << m_homebindZ; data << (uint32) m_homebindMapId; data << (uint32) m_homebindZoneId; GetSession()->SendPacket(&data); // SMSG_SET_PROFICIENCY + // SMSG_SET_PCT_SPELL_MODIFIER + // SMSG_SET_FLAT_SPELL_MODIFIER // SMSG_UPDATE_AURA_DURATION SendTalentsInfoData(false); + + // SMSG_INSTANCE_DIFFICULTY + SendInitialSpells(); data.Initialize(SMSG_SEND_UNLEARN_SPELLS, 4); @@ -19389,6 +19552,14 @@ void Player::SendInitialPacketsBeforeAddToMap() data << (float)0.01666667f; // game speed data << uint32(0); // added in 3.1.2 GetSession()->SendPacket( &data ); + + GetReputationMgr().SendForceReactions(); // SMSG_SET_FORCED_REACTIONS + + // SMSG_TALENTS_INFO x 2 for pet (unspent points and talents in separate packets...) + // SMSG_PET_GUIDS + // SMSG_UPDATE_WORLD_STATE + // SMSG_POWER_UPDATE + } void Player::SendInitialPacketsAfterAddToMap() @@ -19468,7 +19639,7 @@ void Player::SendTransferAborted(uint32 mapid, uint8 reason, uint8 arg) GetSession()->SendPacket(&data); } -void Player::SendInstanceResetWarning( uint32 mapid, uint32 difficulty, uint32 time ) +void Player::SendInstanceResetWarning( uint32 mapid, Difficulty difficulty, uint32 time ) { // type of warning, based on the time remaining until reset uint32 type; @@ -19800,12 +19971,8 @@ bool Player::GetBGAccessByLevel(BattleGroundTypeId bgTypeId) const BGQueueIdBasedOnLevel Player::GetBattleGroundQueueIdFromLevel(BattleGroundTypeId bgTypeId) const { - //returned to hardcoded version of this function, because there is no way to code it dynamic - uint8 level = getLevel(); - if (bgTypeId == BATTLEGROUND_AV) - level--; - - uint32 queue_id = (level / 10) - 1; // for ranges 0 - 19, 20 - 29, 30 - 39, 40 - 49, 50 - 59, 60 - 69, 70 -79, 80 + // for ranges 0 - 19, 20 - 29, 30 - 39, 40 - 49, 50 - 59, 60 - 69, 70 - 79, 80 + uint32 queue_id = ( getLevel() / 10) - 1; if (queue_id >= MAX_BATTLEGROUND_QUEUES) { sLog.outError("BattleGround: too high queue_id %u this shouldn't happen", queue_id); @@ -20740,7 +20907,8 @@ bool Player::CanCaptureTowerPoint() ); } -uint32 Player::GetBarberShopCost(uint8 newhairstyle, uint8 newhaircolor, uint8 newfacialhair) +uint32 Player::GetBarberShopCost(uint8 newhairstyle, uint8 newhaircolor, uint8 newfacialhair, BarberShopStyleEntry const* newSkin ) + { uint8 level = getLevel(); @@ -20750,8 +20918,9 @@ uint32 Player::GetBarberShopCost(uint8 newhairstyle, uint8 newhaircolor, uint8 n uint8 hairstyle = GetByteValue(PLAYER_BYTES, 2); uint8 haircolor = GetByteValue(PLAYER_BYTES, 3); uint8 facialhair = GetByteValue(PLAYER_BYTES_2, 0); + uint8 skincolor = GetByteValue(PLAYER_BYTES, 0); - if((hairstyle == newhairstyle) && (haircolor == newhaircolor) && (facialhair == newfacialhair)) + if((hairstyle == newhairstyle) && (haircolor == newhaircolor) && (facialhair == newfacialhair) && (!newSkin || (newSkin->hair_id == skincolor))) return 0; GtBarberShopCostBaseEntry const *bsc = sGtBarberShopCostBaseStore.LookupEntry(level - 1); @@ -20770,6 +20939,9 @@ uint32 Player::GetBarberShopCost(uint8 newhairstyle, uint8 newhaircolor, uint8 n if(facialhair != newfacialhair) cost += bsc->cost * 0.75f; // +3/4 of price + if(newSkin && skincolor != newSkin->hair_id) + cost += bsc->cost * 0.75f; // +5/6 of price + return uint32(cost); } @@ -21259,7 +21431,7 @@ void Player::HandleFall(MovementInfo const& movementInfo) DEBUG_LOG("FALLDAMAGE z=%f sz=%f pZ=%f FallTime=%d mZ=%f damage=%d SF=%d" , movementInfo.z, height, GetPositionZ(), movementInfo.fallTime, height, damage, safe_fall); } } - RemoveAura(44795); // No fly zone - Parachute + RemoveAura(61243); // No fly zone - Parachute } void Player::UpdateAchievementCriteria( AchievementCriteriaTypes type, uint32 miscvalue1/*=0*/, uint32 miscvalue2/*=0*/, Unit *unit/*=NULL*/, uint32 time/*=0*/ ) @@ -22196,3 +22368,10 @@ std::string Player::GetGuildName() { return objmgr.GetGuildById(GetGuildId())->GetName(); } + +void Player::SendDuelCountdown(uint32 counter) +{ + WorldPacket data(SMSG_DUEL_COUNTDOWN, 4); + data << uint32(counter); // seconds + GetSession()->SendPacket(&data); +} diff --git a/src/game/Player.h b/src/game/Player.h index 4b3cf3245f7..9038c8926b9 100644 --- a/src/game/Player.h +++ b/src/game/Player.h @@ -38,6 +38,7 @@ #include "AchievementMgr.h" #include "ReputationMgr.h" #include "BattleGround.h" +#include "DBCEnums.h" #include<string> #include<vector> @@ -178,7 +179,7 @@ struct ActionButton } }; -#define MAX_ACTION_BUTTONS 132 //checked in 2.3.0 +#define MAX_ACTION_BUTTONS 144 //checked in 3.2.0 typedef std::map<uint8,ActionButton> ActionButtonList; @@ -339,10 +340,10 @@ enum LfgType enum LfgRoles { - LEADER = 1, - TANK = 2, - HEALER = 4, - DAMAGE = 8 + LEADER = 0x01, + TANK = 0x02, + HEALER = 0x04, + DAMAGE = 0x08 }; struct LookingForGroupSlot @@ -438,7 +439,9 @@ enum PlayerFlags PLAYER_FLAGS_UNK22 = 0x00200000, PLAYER_FLAGS_UNK23 = 0x00400000, PLAYER_ALLOW_ONLY_ABILITY = 0x00800000, // used by bladestorm and killing spree - PLAYER_FLAGS_UNK25 = 0x01000000 // disabled all melee ability on tab include autoattack + PLAYER_FLAGS_UNK25 = 0x01000000, // disabled all melee ability on tab include autoattack + + PLAYER_FLAGS_NO_XP_GAIN = 0x02000000 }; // used for PLAYER__FIELD_KNOWN_TITLES field (uint64), (1<<bit_index) without (-1) @@ -734,6 +737,9 @@ enum TransferAbortReason TRANSFER_ABORT_NEED_GROUP = 0x0B, // 3.1 TRANSFER_ABORT_NOT_FOUND2 = 0x0C, // 3.1 TRANSFER_ABORT_NOT_FOUND3 = 0x0D, // 3.1 + TRANSFER_ABORT_NOT_FOUND4 = 0x0E, // 3.2 + TRANSFER_ABORT_REALM_ONLY = 0x0F, // All players on party must be from the same realm. + TRANSFER_ABORT_MAP_NOT_ALLOWED = 0x10, // Map can't be entered at this time. }; enum InstanceResetWarningType @@ -745,6 +751,19 @@ enum InstanceResetWarningType RAID_INSTANCE_EXPIRED = 5 }; +// PLAYER_FIELD_ARENA_TEAM_INFO_1_1 offsets +enum ArenaTeamInfoType +{ + ARENA_TEAM_ID = 0, + ARENA_TEAM_TYPE = 1, // new in 3.2 - team type? + ARENA_TEAM_MEMBER = 2, // 0 - captain, 1 - member + ARENA_TEAM_GAMES_WEEK = 3, + ARENA_TEAM_GAMES_SEASON = 4, + ARENA_TEAM_WINS_SEASON = 5, + ARENA_TEAM_PERSONAL_RATING = 6, + ARENA_TEAM_END = 7 +}; + class InstanceSave; enum RestType @@ -827,8 +846,8 @@ enum PlayerDelayedOperations DELAYED_SAVE_PLAYER = 0x01, DELAYED_RESURRECT_PLAYER = 0x02, DELAYED_SPELL_CAST_DESERTER = 0x04, - DELAYED_BG_MOUNT_RESTORE = 0x08, ///< Flag to restore mount state after teleport from BG - DELAYED_BG_TAXI_RESTORE = 0x10, ///< Flag to restore taxi state after teleport from BG + DELAYED_BG_MOUNT_RESTORE = 0x08, ///< Flag to restore mount state after teleport from BG + DELAYED_BG_TAXI_RESTORE = 0x10, ///< Flag to restore taxi state after teleport from BG DELAYED_END }; @@ -988,12 +1007,11 @@ class MANGOS_DLL_SPEC Player : public Unit bool IsInWater() const { return m_isInWater; } bool IsUnderWater() const; - bool IsFalling() { return GetPositionZ() < m_lastFallZ; } void SendInitialPacketsBeforeAddToMap(); void SendInitialPacketsAfterAddToMap(); void SendTransferAborted(uint32 mapid, uint8 reason, uint8 arg = 0); - void SendInstanceResetWarning(uint32 mapid, uint32 difficulty, uint32 time); + void SendInstanceResetWarning(uint32 mapid, Difficulty difficulty, uint32 time); Creature* GetNPCIfCanInteractWith(uint64 guid, uint32 npcflagmask); bool CanInteractWithNPCs(bool alive = true) const; @@ -1001,13 +1019,13 @@ class MANGOS_DLL_SPEC Player : public Unit bool ToggleAFK(); bool ToggleDND(); - bool isAFK() const { return HasFlag(PLAYER_FLAGS,PLAYER_FLAGS_AFK); }; - bool isDND() const { return HasFlag(PLAYER_FLAGS,PLAYER_FLAGS_DND); }; + bool isAFK() const { return HasFlag(PLAYER_FLAGS,PLAYER_FLAGS_AFK); } + bool isDND() const { return HasFlag(PLAYER_FLAGS,PLAYER_FLAGS_DND); } uint8 chatTag() const; std::string afkMsg; std::string dndMsg; - uint32 GetBarberShopCost(uint8 newhairstyle, uint8 newhaircolor, uint8 newfacialhair); + uint32 GetBarberShopCost(uint8 newhairstyle, uint8 newhaircolor, uint8 newfacialhair, BarberShopStyleEntry const* newSkin=NULL); PlayerSocial *GetSocial() { return m_social; } @@ -1039,8 +1057,8 @@ class MANGOS_DLL_SPEC Player : public Unit time_t m_logintime; time_t m_Last_tick; uint32 m_Played_time[MAX_PLAYED_TIME_INDEX]; - uint32 GetTotalPlayedTime() { return m_Played_time[PLAYED_TIME_TOTAL]; }; - uint32 GetLevelPlayedTime() { return m_Played_time[PLAYED_TIME_LEVEL]; }; + uint32 GetTotalPlayedTime() { return m_Played_time[PLAYED_TIME_TOTAL]; } + uint32 GetLevelPlayedTime() { return m_Played_time[PLAYED_TIME_LEVEL]; } void setDeathState(DeathState s); // overwrite Unit::setDeathState @@ -1051,21 +1069,21 @@ class MANGOS_DLL_SPEC Player : public Unit inn_pos_y = y; inn_pos_z = z; time_inn_enter = time; - }; + } - float GetRestBonus() const { return m_rest_bonus; }; + float GetRestBonus() const { return m_rest_bonus; } void SetRestBonus(float rest_bonus_new); - RestType GetRestType() const { return rest_type; }; - void SetRestType(RestType n_r_type) { rest_type = n_r_type; }; + RestType GetRestType() const { return rest_type; } + void SetRestType(RestType n_r_type) { rest_type = n_r_type; } - uint32 GetInnPosMapId() const { return inn_pos_mapid; }; - float GetInnPosX() const { return inn_pos_x; }; - float GetInnPosY() const { return inn_pos_y; }; - float GetInnPosZ() const { return inn_pos_z; }; + uint32 GetInnPosMapId() const { return inn_pos_mapid; } + float GetInnPosX() const { return inn_pos_x; } + float GetInnPosY() const { return inn_pos_y; } + float GetInnPosZ() const { return inn_pos_z; } - int GetTimeInnEnter() const { return time_inn_enter; }; - void UpdateInnerTime (int time) { time_inn_enter = time; }; + int GetTimeInnEnter() const { return time_inn_enter; } + void UpdateInnerTime (int time) { time_inn_enter = time; } Pet* GetPet() const; Pet* SummonPet(uint32 entry, float x, float y, float z, float ang, PetType petType, uint32 despwtime); @@ -1324,12 +1342,12 @@ class MANGOS_DLL_SPEC Player : public Unit void SendQuestUpdateAddItem( Quest const* pQuest, uint32 item_idx, uint32 count ); void SendQuestUpdateAddCreatureOrGo( Quest const* pQuest, uint64 guid, uint32 creatureOrGO_idx, uint32 old_count, uint32 add_count ); - uint64 GetDivider() { return m_divider; }; - void SetDivider( uint64 guid ) { m_divider = guid; }; + uint64 GetDivider() { return m_divider; } + void SetDivider( uint64 guid ) { m_divider = guid; } - uint32 GetInGameTime() { return m_ingametime; }; + uint32 GetInGameTime() { return m_ingametime; } - void SetInGameTime( uint32 time ) { m_ingametime = time; }; + void SetInGameTime( uint32 time ) { m_ingametime = time; } void AddTimedQuest( uint32 quest_id ) { m_timedquests.insert(quest_id); } void RemoveTimedQuest( uint32 quest_id ) { m_timedquests.erase(quest_id); } @@ -1421,15 +1439,14 @@ class MANGOS_DLL_SPEC Player : public Unit void AddNewMailDeliverTime(time_t deliver_time); bool IsMailsLoaded() const { return m_mailsLoaded; } - //void SetMail(Mail *m); void RemoveMail(uint32 id); void AddMail(Mail* mail) { m_mail.push_front(mail);}// for call from WorldSession::SendMailTo - uint32 GetMailSize() { return m_mail.size();}; + uint32 GetMailSize() { return m_mail.size();} Mail* GetMail(uint32 id); - PlayerMails::iterator GetMailBegin() { return m_mail.begin();}; - PlayerMails::iterator GetMailEnd() { return m_mail.end();}; + PlayerMails::iterator GetMailBegin() { return m_mail.begin();} + PlayerMails::iterator GetMailEnd() { return m_mail.end();} /*********************************************************/ /*** MAILED ITEMS SYSTEM ***/ @@ -1575,7 +1592,7 @@ class MANGOS_DLL_SPEC Player : public Unit m_resurrectZ = Z; m_resurrectHealth = health; m_resurrectMana = mana; - }; + } void clearResurrectRequestData() { setResurrectRequestData(0,0,0.0f,0.0f,0.0f,0,0); } bool isRessurectRequestedBy(uint64 guid) const { return m_resurrectGUID == guid; } bool isRessurectRequested() const { return m_resurrectGUID != 0; } @@ -1626,6 +1643,7 @@ class MANGOS_DLL_SPEC Player : public Unit void UpdateDuelFlag(time_t currTime); void CheckDuelDistance(time_t currTime); void DuelComplete(DuelCompleteType type); + void SendDuelCountdown(uint32 counter); bool IsGroupVisibleFor(Player* p) const; bool IsInSameGroupWith(Player const* p) const; @@ -1646,19 +1664,22 @@ class MANGOS_DLL_SPEC Player : public Unit static void RemovePetitionsAndSigns(uint64 guid, uint32 type); // Arena Team - void SetInArenaTeam(uint32 ArenaTeamId, uint8 slot) + void SetInArenaTeam(uint32 ArenaTeamId, uint8 slot, uint8 type) { - SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (slot * 6), ArenaTeamId); + SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (slot * ARENA_TEAM_END) + ARENA_TEAM_ID, ArenaTeamId); + SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (slot * ARENA_TEAM_END) + ARENA_TEAM_TYPE, type); } - uint32 GetArenaTeamId(uint8 slot) { return GetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (slot * 6)); } + uint32 GetArenaTeamId(uint8 slot) { return GetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (slot * ARENA_TEAM_END)); } static uint32 GetArenaTeamIdFromDB(uint64 guid, uint8 slot); void SetArenaTeamIdInvited(uint32 ArenaTeamId) { m_ArenaTeamIdInvited = ArenaTeamId; } uint32 GetArenaTeamIdInvited() { return m_ArenaTeamIdInvited; } static void LeaveAllArenaTeams(uint64 guid); - void SetDifficulty(uint32 dungeon_difficulty) { m_dungeonDifficulty = dungeon_difficulty; } - uint8 GetDifficulty() { return m_dungeonDifficulty; } - bool IsHeroic() { return m_dungeonDifficulty == DIFFICULTY_HEROIC; } + Difficulty GetDifficulty(bool isRaid) const { return isRaid ? m_raidDifficulty : m_dungeonDifficulty; } + Difficulty GetDungeonDifficulty() const { return m_dungeonDifficulty; } + Difficulty GetRaidDifficulty() const { return m_raidDifficulty; } + void SetDungeonDifficulty(Difficulty dungeon_difficulty) { m_dungeonDifficulty = dungeon_difficulty; } + void SetRaidDifficulty(Difficulty raid_difficulty) { m_raidDifficulty = raid_difficulty; } bool UpdateSkill(uint32 skill_id, uint32 step); bool UpdateSkillPro(uint16 SkillId, int32 Chance, uint32 step); @@ -1701,9 +1722,11 @@ class MANGOS_DLL_SPEC Player : public Unit float GetRatingCoefficient(CombatRating cr) const; float GetRatingBonusValue(CombatRating cr) const; uint32 GetMeleeCritDamageReduction(uint32 damage) const; + uint32 GetMeleeDamageReduction(uint32 damage) const; uint32 GetRangedCritDamageReduction(uint32 damage) const; + uint32 GetRangedDamageReduction(uint32 damage) const; uint32 GetSpellCritDamageReduction(uint32 damage) const; - uint32 GetDotDamageReduction(uint32 damage) const; + uint32 GetSpellDamageReduction(uint32 damage) const; uint32 GetBaseSpellPowerBonus() { return m_baseSpellPower; } float GetExpertiseDodgeOrParryReduction(WeaponAttackType attType) const; @@ -1721,6 +1744,7 @@ class MANGOS_DLL_SPEC Player : public Unit void UpdateArmorPenetration(int32 amount); void UpdateExpertise(WeaponAttackType attType); void ApplyManaRegenBonus(int32 amount, bool apply); + void ApplyHealthRegenBonus(int32 amount, bool apply); void UpdateManaRegen(); const uint64& GetLootGUID() const { return m_lootGuid; } @@ -1746,7 +1770,8 @@ class MANGOS_DLL_SPEC Player : public Unit void SendExplorationExperience(uint32 Area, uint32 Experience); void SendDungeonDifficulty(bool IsInGroup); - void ResetInstances(uint8 method); + void SendRaidDifficulty(bool IsInGroup); + void ResetInstances(uint8 method, bool isRaid); void SendResetInstanceSuccess(uint32 MapId); void SendResetInstanceFailed(uint32 reason, uint32 MapId); void SendResetFailedNotify(uint32 mapid); @@ -2049,8 +2074,8 @@ class MANGOS_DLL_SPEC Player : public Unit bool isRested() const { return GetRestTime() >= 10*IN_MILISECONDS; } uint32 GetXPRestBonus(uint32 xp); - uint32 GetRestTime() const { return m_restTime;}; - void SetRestTime(uint32 v) { m_restTime = v;}; + uint32 GetRestTime() const { return m_restTime;} + void SetRestTime(uint32 v) { m_restTime = v;} /*********************************************************/ /*** ENVIROMENTAL SYSTEM ***/ @@ -2163,12 +2188,12 @@ class MANGOS_DLL_SPEC Player : public Unit uint32 m_HomebindTimer; bool m_InstanceValid; // permanent binds and solo binds by difficulty - BoundInstancesMap m_boundInstances[TOTAL_DIFFICULTIES]; - InstancePlayerBind* GetBoundInstance(uint32 mapid, uint8 difficulty); - BoundInstancesMap& GetBoundInstances(uint8 difficulty) { return m_boundInstances[difficulty]; } - InstanceSave * GetInstanceSave(uint32 mapid); - void UnbindInstance(uint32 mapid, uint8 difficulty, bool unload = false); - void UnbindInstance(BoundInstancesMap::iterator &itr, uint8 difficulty, bool unload = false); + BoundInstancesMap m_boundInstances[MAX_DIFFICULTY]; + InstancePlayerBind* GetBoundInstance(uint32 mapid, Difficulty difficulty); + BoundInstancesMap& GetBoundInstances(Difficulty difficulty) { return m_boundInstances[difficulty]; } + InstanceSave * GetInstanceSave(uint32 mapid, bool raid); + void UnbindInstance(uint32 mapid, Difficulty difficulty, bool unload = false); + void UnbindInstance(BoundInstancesMap::iterator &itr, Difficulty difficulty, bool unload = false); InstancePlayerBind* BindToInstance(InstanceSave *save, bool permanent, bool load = false); void SendRaidInfo(); void SendSavedInstances(); @@ -2239,6 +2264,11 @@ class MANGOS_DLL_SPEC Player : public Unit //bool isActiveObject() const { return true; } bool canSeeSpellClickOn(Creature const* creature) const; + uint32 GetActionButtonSpell(uint8 button) const + { + ActionButtonList::const_iterator ab = m_actionButtons.find(button); + return ab != m_actionButtons.end() && ab->second.uState != ACTIONBUTTON_DELETED && ab->second.GetType() == ACTION_BUTTON_SPELL ? ab->second.GetAction() : 0; + } uint32 GetChampioningFaction() const { return m_ChampioningFaction; } void SetChampioningFaction(uint32 faction) { m_ChampioningFaction = faction; } @@ -2342,7 +2372,8 @@ Spell * m_spellModTakingSpell; uint32 m_nextSave; time_t m_speakTime; uint32 m_speakCount; - uint32 m_dungeonDifficulty; + Difficulty m_dungeonDifficulty; + Difficulty m_raidDifficulty; uint32 m_atLoginFlags; @@ -2382,6 +2413,7 @@ Spell * m_spellModTakingSpell; uint16 m_baseSpellPower; uint16 m_baseFeralAP; uint16 m_baseManaRegen; + uint16 m_baseHealthRegen; SpellModList m_spellMods[MAX_SPELLMOD]; //uint32 m_pad; @@ -2407,8 +2439,6 @@ Spell * m_spellModTakingSpell; uint16 tradeItems[TRADE_SLOT_COUNT]; uint32 tradeGold; - time_t m_nextThinkTime; - bool m_DailyQuestChanged; time_t m_lastDailyQuestTime; @@ -2442,7 +2472,6 @@ Spell * m_spellModTakingSpell; float m_rest_bonus; RestType rest_type; ////////////////////Rest System///////////////////// - uint32 m_resetTalentsCost; time_t m_resetTalentsTime; uint32 m_usedTalentCount; diff --git a/src/game/PoolHandler.cpp b/src/game/PoolHandler.cpp index ff7d0146b3d..da2f432fa40 100644 --- a/src/game/PoolHandler.cpp +++ b/src/game/PoolHandler.cpp @@ -28,13 +28,6 @@ INSTANTIATE_SINGLETON_1(PoolHandler); //////////////////////////////////////////////////////////// // Methods of template class PoolGroup -template <class T> -PoolGroup<T>::PoolGroup() -{ - m_SpawnedPoolAmount = 0; - m_LastDespawnedNode = 0; -} - // Method to add a gameobject/creature guid to the proper list depending on pool type and chance value template <class T> void PoolGroup<T>::AddEntry(PoolObject& poolitem, uint32 maxentries) @@ -73,26 +66,39 @@ bool PoolGroup<T>::IsSpawnedObject(uint32 guid) return false; } -// Method that return a guid of a rolled creature or gameobject -// Note: Copy from loot system because it's very similar and only few things change template <class T> -uint32 PoolGroup<T>::RollOne(void) +void PoolGroup<T>::RollOne(int32& index, PoolObjectList** store, uint32 triggerFrom) { - if (!ExplicitlyChanced.empty()) // First explicitly chanced entries are checked + if (!ExplicitlyChanced.empty()) { - float roll = rand_chance(); + float roll = (float)rand_chance(); for (uint32 i=0; i<ExplicitlyChanced.size(); ++i) { roll -= ExplicitlyChanced[i].chance; - if (roll < 0) - return ExplicitlyChanced[i].guid; + // 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].spawned || ExplicitlyChanced[i].guid == triggerFrom)) + { + index = i; + *store = &ExplicitlyChanced; + return; + } } } if (!EqualChanced.empty()) - return EqualChanced[irand(0, EqualChanced.size()-1)].guid; + { + 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].spawned || EqualChanced[index].guid == triggerFrom) + { + *store = &EqualChanced; + return; + } + } - return 0; // None found + index = -1; } // Main method to despawn a creature or gameobject in a pool @@ -107,10 +113,7 @@ void PoolGroup<T>::DespawnObject(uint32 guid) { if (!guid || EqualChanced[i].guid == guid) { - if (guid) - m_LastDespawnedNode = EqualChanced[i].guid; - else - Despawn1Object(EqualChanced[i].guid); + Despawn1Object(EqualChanced[i].guid); EqualChanced[i].spawned = false; if (m_SpawnedPoolAmount > 0) @@ -118,6 +121,21 @@ void PoolGroup<T>::DespawnObject(uint32 guid) } } } + + for (size_t i = 0; i < ExplicitlyChanced.size(); ++i) + { + if (ExplicitlyChanced[i].spawned) + { + if (!guid || ExplicitlyChanced[i].guid == guid) + { + Despawn1Object(ExplicitlyChanced[i].guid); + ExplicitlyChanced[i].spawned = false; + + if (m_SpawnedPoolAmount > 0) + --m_SpawnedPoolAmount; + } + } + } } // Method that is actualy doing the removal job on one creature @@ -175,53 +193,48 @@ void PoolGroup<Pool>::RemoveOneRelation(uint16 child_pool_id) } } -// Method that Spawn 1+ creatures or gameobject -// if cache is false (initialization or event start), X creatures are spawned with X <= limit (< if limit higher that the number of creatures in pool) -// if cache is true, this means only one has to be spawned (or respawned if the rolled one is same as cached one) template <class T> -void PoolGroup<T>::SpawnObject(uint32 limit, bool cache) +void PoolGroup<T>::SpawnObject(uint32 limit, uint32 triggerFrom) { - if (limit == 1) // This is the only case where explicit chance is used - { - uint32 roll = RollOne(); - if (cache && m_LastDespawnedNode != roll) - Despawn1Object(m_LastDespawnedNode); + uint32 lastDespawned = 0; + int count = limit - m_SpawnedPoolAmount; - m_LastDespawnedNode = 0; - Spawn1Object(roll); - } - else if (limit < EqualChanced.size() && m_SpawnedPoolAmount < limit) + // If triggered from some object respawn this object is still marked as spawned + // and also counted into m_SpawnedPoolAmount so we need increase count to be + // spawned by 1 + if (triggerFrom) + ++count; + + // This will try to spawn the rest of pool, not guaranteed + for (int i = 0; i < count; ++i) { - std::vector<uint32> IndexList; - for (size_t i=0; i<EqualChanced.size(); ++i) - if (!EqualChanced[i].spawned) - IndexList.push_back(i); + int index; + PoolObjectList* store; - while (m_SpawnedPoolAmount < limit && IndexList.size() > 0) - { - uint32 roll = urand(1, IndexList.size()) - 1; - uint32 index = IndexList[roll]; - if (!cache || (cache && EqualChanced[index].guid != m_LastDespawnedNode)) - { - if (cache) - Despawn1Object(m_LastDespawnedNode); - EqualChanced[index].spawned = Spawn1Object(EqualChanced[index].guid); - } - else - EqualChanced[index].spawned = ReSpawn1Object(EqualChanced[index].guid); + RollOne(index, &store, triggerFrom); + if (index == -1) + continue; + if ((*store)[index].guid == lastDespawned) + continue; - if (EqualChanced[index].spawned) - ++m_SpawnedPoolAmount; // limited group use the Spawned variable to store the number of actualy spawned creatures + if ((*store)[index].guid == triggerFrom) + { + (*store)[index].spawned = ReSpawn1Object(triggerFrom); + triggerFrom = 0; + continue; + } + else + (*store)[index].spawned = Spawn1Object((*store)[index].guid); - std::vector<uint32>::iterator itr = IndexList.begin()+roll; - IndexList.erase(itr); + if (triggerFrom) + { + // One spawn one despawn no count increase + DespawnObject(triggerFrom); + lastDespawned = triggerFrom; + triggerFrom = 0; } - m_LastDespawnedNode = 0; - } - else // Not enough objects in pool, so spawn all - { - for (size_t i=0; i<EqualChanced.size(); ++i) - EqualChanced[i].spawned = Spawn1Object(EqualChanced[i].guid); + else + ++m_SpawnedPoolAmount; } } @@ -241,7 +254,10 @@ bool PoolGroup<Creature>::Spawn1Object(uint32 guid) Creature* pCreature = new Creature; //sLog.outDebug("Spawning creature %u",guid); if (!pCreature->LoadFromDB(guid, map)) + { delete pCreature; + return false; + } else map->Add(pCreature); } @@ -266,7 +282,10 @@ bool PoolGroup<GameObject>::Spawn1Object(uint32 guid) GameObject* pGameobject = new GameObject; //sLog.outDebug("Spawning gameobject %u", guid); if (!pGameobject->LoadFromDB(guid, map)) + { delete pGameobject; + return false; + } else { if (pGameobject->isSpawnedByDefault()) @@ -282,7 +301,9 @@ bool PoolGroup<GameObject>::Spawn1Object(uint32 guid) template <> bool PoolGroup<Pool>::Spawn1Object(uint32 child_pool_id) { - poolhandler.SpawnPool(child_pool_id); + poolhandler.SpawnPool(child_pool_id, 0, 0); + poolhandler.SpawnPool(child_pool_id, 0, TYPEID_GAMEOBJECT); + poolhandler.SpawnPool(child_pool_id, 0, TYPEID_UNIT); return true; } @@ -290,8 +311,7 @@ bool PoolGroup<Pool>::Spawn1Object(uint32 child_pool_id) template <> bool PoolGroup<Creature>::ReSpawn1Object(uint32 guid) { - CreatureData const* data = objmgr.GetCreatureData(guid); - if (data) + if (CreatureData const* data = objmgr.GetCreatureData(guid)) { if (Creature* pCreature = ObjectAccessor::Instance().GetObjectInWorld(MAKE_NEW_GUID(guid, data->id, HIGHGUID_UNIT), (Creature*)NULL)) pCreature->GetMap()->Add(pCreature); @@ -304,8 +324,7 @@ bool PoolGroup<Creature>::ReSpawn1Object(uint32 guid) template <> bool PoolGroup<GameObject>::ReSpawn1Object(uint32 guid) { - GameObjectData const* data = objmgr.GetGOData(guid); - if (data) + if (GameObjectData const* data = objmgr.GetGOData(guid)) { if (GameObject* pGameobject = ObjectAccessor::Instance().GetObjectInWorld(MAKE_NEW_GUID(guid, data->id, HIGHGUID_GAMEOBJECT), (GameObject*)NULL)) pGameobject->GetMap()->Add(pGameobject); @@ -613,7 +632,9 @@ void PoolHandler::Initialize() 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); continue; } - SpawnPool(pool_entry); + SpawnPool(pool_entry, 0, 0); + SpawnPool(pool_entry, 0, TYPEID_GAMEOBJECT); + SpawnPool(pool_entry, 0, TYPEID_UNIT); count++; } while (result->NextRow()); delete result; @@ -625,25 +646,35 @@ void PoolHandler::Initialize() // Call to spawn a pool, if cache if true the method will spawn only if cached entry is different // If it's same, the gameobject/creature is respawned only (added back to map) -void PoolHandler::SpawnPool(uint16 pool_id, bool cache) +void PoolHandler::SpawnPool(uint16 pool_id, uint32 guid, uint32 type) { - if (!mPoolPoolGroups[pool_id].isEmpty()) - mPoolPoolGroups[pool_id].SpawnObject(mPoolTemplate[pool_id].MaxLimit, cache); - if (!mPoolGameobjectGroups[pool_id].isEmpty()) - mPoolGameobjectGroups[pool_id].SpawnObject(mPoolTemplate[pool_id].MaxLimit, cache); - if (!mPoolCreatureGroups[pool_id].isEmpty()) - mPoolCreatureGroups[pool_id].SpawnObject(mPoolTemplate[pool_id].MaxLimit, cache); + switch (type) + { + case TYPEID_UNIT: + if (!mPoolCreatureGroups[pool_id].isEmpty()) + mPoolCreatureGroups[pool_id].SpawnObject(mPoolTemplate[pool_id].MaxLimit, guid); + break; + case TYPEID_GAMEOBJECT: + if (!mPoolGameobjectGroups[pool_id].isEmpty()) + mPoolGameobjectGroups[pool_id].SpawnObject(mPoolTemplate[pool_id].MaxLimit, guid); + break; + default: + if (!mPoolPoolGroups[pool_id].isEmpty()) + mPoolPoolGroups[pool_id].SpawnObject(mPoolTemplate[pool_id].MaxLimit, guid); + } } // Call to despawn a pool, all gameobjects/creatures in this pool are removed void PoolHandler::DespawnPool(uint16 pool_id) { - if (!mPoolPoolGroups[pool_id].isEmpty()) - mPoolPoolGroups[pool_id].DespawnObject(); - if (!mPoolGameobjectGroups[pool_id].isEmpty()) - mPoolGameobjectGroups[pool_id].DespawnObject(); if (!mPoolCreatureGroups[pool_id].isEmpty()) mPoolCreatureGroups[pool_id].DespawnObject(); + + if (!mPoolGameobjectGroups[pool_id].isEmpty()) + mPoolGameobjectGroups[pool_id].DespawnObject(); + + if (!mPoolPoolGroups[pool_id].isEmpty()) + mPoolPoolGroups[pool_id].DespawnObject(); } // Call to update the pool when a gameobject/creature part of pool [pool_id] is ready to respawn @@ -651,19 +682,10 @@ void PoolHandler::DespawnPool(uint16 pool_id) // Then the spawn pool call will use this cache to decide void PoolHandler::UpdatePool(uint16 pool_id, uint32 guid, uint32 type) { - uint16 motherpoolid = IsPartOfAPool(pool_id, 0); - - if (motherpoolid) - mPoolPoolGroups[motherpoolid].DespawnObject(pool_id); - else if (type == TYPEID_GAMEOBJECT && !mPoolGameobjectGroups[pool_id].isEmpty()) - mPoolGameobjectGroups[pool_id].DespawnObject(guid); - else if (type != TYPEID_GAMEOBJECT && !mPoolCreatureGroups[pool_id].isEmpty()) - mPoolCreatureGroups[pool_id].DespawnObject(guid); - - if (motherpoolid) - SpawnPool(motherpoolid, true); + if (uint16 motherpoolid = IsPartOfAPool(pool_id, 0)) + SpawnPool(motherpoolid, 0, 0); else - SpawnPool(pool_id, true); + SpawnPool(pool_id, guid, type); } // Method that tell if the gameobject/creature is part of a pool and return the pool id if yes diff --git a/src/game/PoolHandler.h b/src/game/PoolHandler.h index 652d8e2cf3b..a3f6755bfde 100644 --- a/src/game/PoolHandler.h +++ b/src/game/PoolHandler.h @@ -40,25 +40,24 @@ struct PoolObject template <class T> class PoolGroup { + typedef std::vector<PoolObject> PoolObjectList; public: - PoolGroup(); + PoolGroup() : m_SpawnedPoolAmount(0) {} ~PoolGroup() {}; bool isEmpty() { return ExplicitlyChanced.empty() && EqualChanced.empty(); } void AddEntry(PoolObject& poolitem, uint32 maxentries); bool CheckPool(void); - uint32 RollOne(void); + void RollOne(int32& index, PoolObjectList** store, uint32 triggerFrom); bool IsSpawnedObject(uint32 guid); void DespawnObject(uint32 guid=0); void Despawn1Object(uint32 guid); - void SpawnObject(uint32 limit, bool cache=false); + void SpawnObject(uint32 limit, uint32 triggerFrom); bool Spawn1Object(uint32 guid); bool ReSpawn1Object(uint32 guid); void RemoveOneRelation(uint16 child_pool_id); private: - typedef std::vector<PoolObject> PoolObjectList; PoolObjectList ExplicitlyChanced; PoolObjectList EqualChanced; - uint32 m_LastDespawnedNode; // Store the guid of the removed creature/gameobject during a pool update uint32 m_SpawnedPoolAmount; // Used to know the number of spawned objects }; @@ -75,7 +74,7 @@ class PoolHandler uint16 IsPartOfAPool(uint32 guid, uint32 type); bool IsSpawnedObject(uint16 pool_id, uint32 guid, uint32 type); bool CheckPool(uint16 pool_id); - void SpawnPool(uint16 pool_id, bool cache=false); + void SpawnPool(uint16 pool_id, uint32 guid, uint32 type); void DespawnPool(uint16 pool_id); void UpdatePool(uint16 pool_id, uint32 guid, uint32 type); void Initialize(); diff --git a/src/game/QueryHandler.cpp b/src/game/QueryHandler.cpp index f3ceb16dc6b..e428b66cee4 100644 --- a/src/game/QueryHandler.cpp +++ b/src/game/QueryHandler.cpp @@ -38,7 +38,6 @@ void WorldSession::SendNameQueryOpcode(Player *p) { if(!p) return; - // guess size WorldPacket data( SMSG_NAME_QUERY_RESPONSE, (8+1+1+1+1+1+10) ); data.append(p->GetPackGUID()); // player guid @@ -102,7 +101,6 @@ void WorldSession::SendNameQueryOpcodeFromDBCallBack(QueryResult *result, uint32 pGender = fields[3].GetUInt8(); pClass = fields[4].GetUInt8(); } - // guess size WorldPacket data( SMSG_NAME_QUERY_RESPONSE, (8+1+1+1+1+1+1+10) ); data.appendPackGUID(MAKE_NEW_GUID(guid, 0, HIGHGUID_PLAYER)); @@ -154,7 +152,8 @@ void WorldSession::HandleCreatureQueryOpcode( WorldPacket & recv_data ) { uint32 entry; recv_data >> entry; - recv_data.read_skip<uint64>(); // guid + uint64 guid; + recv_data >> guid; CreatureInfo const *ci = objmgr.GetCreatureTemplate(entry); if (ci) @@ -205,9 +204,6 @@ void WorldSession::HandleCreatureQueryOpcode( WorldPacket & recv_data ) } else { - uint64 guid; - recv_data >> guid; - sLog.outDebug("WORLD: CMSG_CREATURE_QUERY - NO CREATURE INFO! (GUID: %u, ENTRY: %u)", GUID_LOPART(guid), entry); WorldPacket data( SMSG_CREATURE_QUERY_RESPONSE, 4 ); @@ -222,7 +218,8 @@ void WorldSession::HandleGameObjectQueryOpcode( WorldPacket & recv_data ) { uint32 entryID; recv_data >> entryID; - recv_data.read_skip<uint64>(); // guid + uint64 guid; + recv_data >> guid; const GameObjectInfo *info = objmgr.GetGameObjectInfo(entryID); if(info) @@ -260,16 +257,12 @@ void WorldSession::HandleGameObjectQueryOpcode( WorldPacket & recv_data ) data.append(info->raw.data, 24); data << float(info->size); // go size for (uint32 i = 0; i < 6; ++i) - data << uint32(info->questItems[i]); // itemId[6], quest drop + data << uint32(info->questItems[i]); // itemId[6], quest drop SendPacket( &data ); sLog.outDebug( "WORLD: Sent SMSG_GAMEOBJECT_QUERY_RESPONSE" ); } else { - - uint64 guid; - recv_data >> guid; - sLog.outDebug( "WORLD: CMSG_GAMEOBJECT_QUERY - Missing gameobject info for (GUID: %u, ENTRY: %u)", GUID_LOPART(guid), entryID ); WorldPacket data ( SMSG_GAMEOBJECT_QUERY_RESPONSE, 4 ); @@ -418,10 +411,12 @@ void WorldSession::HandleNpcTextQueryOpcode( WorldPacket & recv_data ) void WorldSession::HandlePageTextQueryOpcode( WorldPacket & recv_data ) { - uint32 pageID; + sLog.outDetail("WORLD: Received CMSG_PAGE_TEXT_QUERY"); + recv_data.hexlike(); + uint32 pageID; recv_data >> pageID; - sLog.outDetail("WORLD: Received CMSG_PAGE_TEXT_QUERY for pageID '%u'", pageID); + recv_data.read_skip<uint64>(); // guid while (pageID) { @@ -461,3 +456,17 @@ void WorldSession::HandlePageTextQueryOpcode( WorldPacket & recv_data ) } } +void WorldSession::HandleCorpseMapPositionQuery( WorldPacket & recv_data ) +{ + sLog.outDebug( "WORLD: Recv CMSG_CORPSE_MAP_POSITION_QUERY" ); + + uint32 unk; + recv_data >> unk; + + WorldPacket data(CMSG_CORPSE_MAP_POSITION_QUERY_RESPONSE, 4+4+4+4); + data << float(0); + data << float(0); + data << float(0); + data << float(0); + SendPacket(&data); +} diff --git a/src/game/QuestDef.cpp b/src/game/QuestDef.cpp index 1c429178fda..dcbedf62eec 100644 --- a/src/game/QuestDef.cpp +++ b/src/game/QuestDef.cpp @@ -63,74 +63,74 @@ Quest::Quest(Field * questRecord) for (int i = 0; i < QUEST_OBJECTIVES_COUNT; ++i) ObjectiveText[i] = questRecord[35+i].GetCppString(); - for (int i = 0; i < QUEST_OBJECTIVES_COUNT; ++i) + for (int i = 0; i < QUEST_ITEM_OBJECTIVES_COUNT; ++i) ReqItemId[i] = questRecord[39+i].GetUInt32(); - for (int i = 0; i < QUEST_OBJECTIVES_COUNT; ++i) - ReqItemCount[i] = questRecord[43+i].GetUInt32(); + for (int i = 0; i < QUEST_ITEM_OBJECTIVES_COUNT; ++i) + ReqItemCount[i] = questRecord[45+i].GetUInt32(); for (int i = 0; i < QUEST_SOURCE_ITEM_IDS_COUNT; ++i) - ReqSourceId[i] = questRecord[47+i].GetUInt32(); + ReqSourceId[i] = questRecord[51+i].GetUInt32(); for (int i = 0; i < QUEST_SOURCE_ITEM_IDS_COUNT; ++i) - ReqSourceCount[i] = questRecord[51+i].GetUInt32(); + ReqSourceCount[i] = questRecord[55+i].GetUInt32(); for (int i = 0; i < QUEST_OBJECTIVES_COUNT; ++i) - ReqCreatureOrGOId[i] = questRecord[55+i].GetInt32(); + ReqCreatureOrGOId[i] = questRecord[59+i].GetInt32(); for (int i = 0; i < QUEST_OBJECTIVES_COUNT; ++i) - ReqCreatureOrGOCount[i] = questRecord[59+i].GetUInt32(); + ReqCreatureOrGOCount[i] = questRecord[63+i].GetUInt32(); for (int i = 0; i < QUEST_OBJECTIVES_COUNT; ++i) - ReqSpell[i] = questRecord[63+i].GetUInt32(); + ReqSpell[i] = questRecord[67+i].GetUInt32(); for (int i = 0; i < QUEST_REWARD_CHOICES_COUNT; ++i) - RewChoiceItemId[i] = questRecord[67+i].GetUInt32(); + RewChoiceItemId[i] = questRecord[71+i].GetUInt32(); for (int i = 0; i < QUEST_REWARD_CHOICES_COUNT; ++i) - RewChoiceItemCount[i] = questRecord[73+i].GetUInt32(); + RewChoiceItemCount[i] = questRecord[77+i].GetUInt32(); for (int i = 0; i < QUEST_REWARDS_COUNT; ++i) - RewItemId[i] = questRecord[79+i].GetUInt32(); + RewItemId[i] = questRecord[83+i].GetUInt32(); for (int i = 0; i < QUEST_REWARDS_COUNT; ++i) - RewItemCount[i] = questRecord[83+i].GetUInt32(); + RewItemCount[i] = questRecord[87+i].GetUInt32(); for (int i = 0; i < QUEST_REPUTATIONS_COUNT; ++i) - RewRepFaction[i] = questRecord[87+i].GetUInt32(); + RewRepFaction[i] = questRecord[91+i].GetUInt32(); for (int i = 0; i < QUEST_REPUTATIONS_COUNT; ++i) - RewRepValue[i] = questRecord[92+i].GetInt32(); - - RewHonorableKills = questRecord[97].GetUInt32(); - RewOrReqMoney = questRecord[98].GetInt32(); - RewMoneyMaxLevel = questRecord[99].GetUInt32(); - RewSpell = questRecord[100].GetUInt32(); - RewSpellCast = questRecord[101].GetUInt32(); - RewMailTemplateId = questRecord[102].GetUInt32(); - RewMailDelaySecs = questRecord[103].GetUInt32(); - PointMapId = questRecord[104].GetUInt32(); - PointX = questRecord[105].GetFloat(); - PointY = questRecord[106].GetFloat(); - PointOpt = questRecord[107].GetUInt32(); + RewRepValue[i] = questRecord[96+i].GetInt32(); + + RewHonorableKills = questRecord[101].GetUInt32(); + RewOrReqMoney = questRecord[102].GetInt32(); + RewMoneyMaxLevel = questRecord[103].GetUInt32(); + RewSpell = questRecord[104].GetUInt32(); + RewSpellCast = questRecord[105].GetUInt32(); + RewMailTemplateId = questRecord[106].GetUInt32(); + RewMailDelaySecs = questRecord[107].GetUInt32(); + PointMapId = questRecord[108].GetUInt32(); + PointX = questRecord[109].GetFloat(); + PointY = questRecord[110].GetFloat(); + PointOpt = questRecord[111].GetUInt32(); for (int i = 0; i < QUEST_EMOTE_COUNT; ++i) - DetailsEmote[i] = questRecord[108+i].GetUInt32(); + DetailsEmote[i] = questRecord[112+i].GetUInt32(); for (int i = 0; i < QUEST_EMOTE_COUNT; ++i) - DetailsEmoteDelay[i] = questRecord[112+i].GetUInt32(); + DetailsEmoteDelay[i] = questRecord[116+i].GetUInt32(); - IncompleteEmote = questRecord[116].GetUInt32(); - CompleteEmote = questRecord[117].GetUInt32(); + IncompleteEmote = questRecord[120].GetUInt32(); + CompleteEmote = questRecord[121].GetUInt32(); for (int i = 0; i < QUEST_EMOTE_COUNT; ++i) - OfferRewardEmote[i] = questRecord[118+i].GetInt32(); + OfferRewardEmote[i] = questRecord[122+i].GetInt32(); for (int i = 0; i < QUEST_EMOTE_COUNT; ++i) - OfferRewardEmoteDelay[i] = questRecord[122+i].GetInt32(); + OfferRewardEmoteDelay[i] = questRecord[126+i].GetInt32(); - QuestStartScript = questRecord[126].GetUInt32(); - QuestCompleteScript = questRecord[127].GetUInt32(); + QuestStartScript = questRecord[130].GetUInt32(); + QuestCompleteScript = questRecord[131].GetUInt32(); QuestFlags |= SpecialFlags << 16; @@ -139,10 +139,14 @@ Quest::Quest(Field * questRecord) m_rewitemscount = 0; m_rewchoiceitemscount = 0; - for (int i=0; i < QUEST_OBJECTIVES_COUNT; ++i) + for (int i=0; i < QUEST_ITEM_OBJECTIVES_COUNT; ++i) { if ( ReqItemId[i] ) ++m_reqitemscount; + } + + for (int i=0; i < QUEST_OBJECTIVES_COUNT; ++i) + { if ( ReqCreatureOrGOId[i] ) ++m_reqCreatureOrGOcount; } @@ -208,4 +212,3 @@ int32 Quest::GetRewOrReqMoney() const return int32(RewOrReqMoney * sWorld.getRate(RATE_DROP_MONEY)); } - diff --git a/src/game/QuestDef.h b/src/game/QuestDef.h index 264acff95b8..f9eab231b68 100644 --- a/src/game/QuestDef.h +++ b/src/game/QuestDef.h @@ -34,6 +34,7 @@ class ObjectMgr; #define MAX_QUEST_LOG_SIZE 25 #define QUEST_OBJECTIVES_COUNT 4 +#define QUEST_ITEM_OBJECTIVES_COUNT 6 #define QUEST_SOURCE_ITEM_IDS_COUNT 4 #define QUEST_REWARD_CHOICES_COUNT 6 #define QUEST_REWARDS_COUNT 4 @@ -231,8 +232,8 @@ class Quest // multiple values std::string ObjectiveText[QUEST_OBJECTIVES_COUNT]; - uint32 ReqItemId[QUEST_OBJECTIVES_COUNT]; - uint32 ReqItemCount[QUEST_OBJECTIVES_COUNT]; + uint32 ReqItemId[QUEST_ITEM_OBJECTIVES_COUNT]; + uint32 ReqItemCount[QUEST_ITEM_OBJECTIVES_COUNT]; uint32 ReqSourceId[QUEST_SOURCE_ITEM_IDS_COUNT]; uint32 ReqSourceCount[QUEST_SOURCE_ITEM_IDS_COUNT]; int32 ReqCreatureOrGOId[QUEST_OBJECTIVES_COUNT]; // >0 Creature <0 Gameobject @@ -332,7 +333,7 @@ struct QuestStatusData : m_status(QUEST_STATUS_NONE),m_rewarded(false), m_explored(false), m_timer(0), uState(QUEST_NEW) { - memset(m_itemcount, 0, QUEST_OBJECTIVES_COUNT * sizeof(uint32)); + memset(m_itemcount, 0, QUEST_ITEM_OBJECTIVES_COUNT * sizeof(uint32)); memset(m_creatureOrGOcount, 0, QUEST_OBJECTIVES_COUNT * sizeof(uint32)); } @@ -342,8 +343,7 @@ struct QuestStatusData uint32 m_timer; QuestUpdateState uState; - uint32 m_itemcount[ QUEST_OBJECTIVES_COUNT ]; + uint32 m_itemcount[ QUEST_ITEM_OBJECTIVES_COUNT ]; uint32 m_creatureOrGOcount[ QUEST_OBJECTIVES_COUNT ]; }; #endif - diff --git a/src/game/QuestHandler.cpp b/src/game/QuestHandler.cpp index b60e901417d..cc8d3e4a87c 100644 --- a/src/game/QuestHandler.cpp +++ b/src/game/QuestHandler.cpp @@ -173,7 +173,7 @@ void WorldSession::HandleQuestgiverAcceptQuestOpcode( WorldPacket & recv_data ) // destroy not required for quest finish quest starting item bool destroyItem = true; - for (int i = 0; i < QUEST_OBJECTIVES_COUNT; ++i) + for (int i = 0; i < QUEST_ITEM_OBJECTIVES_COUNT; ++i) { if ((qInfo->ReqItemId[i] == ((Item*)pObject)->GetEntry()) && (((Item*)pObject)->GetProto()->MaxCount > 0)) { @@ -638,4 +638,3 @@ void WorldSession::HandleQuestgiverStatusMultipleQuery(WorldPacket& /*recvPacket data.put<uint32>(0, count); // write real count SendPacket(&data); } - diff --git a/src/game/SharedDefines.h b/src/game/SharedDefines.h index eaeb583d0e9..c6cf5debe77 100644 --- a/src/game/SharedDefines.h +++ b/src/game/SharedDefines.h @@ -47,7 +47,7 @@ enum Races RACE_TROLL = 8, //RACE_GOBLIN = 9, RACE_BLOODELF = 10, - RACE_DRAENEI = 11, + RACE_DRAENEI = 11 //RACE_FEL_ORC = 12, //RACE_NAGA = 13, //RACE_BROKEN = 14, @@ -82,7 +82,7 @@ enum Classes CLASS_MAGE = 8, CLASS_WARLOCK = 9, //CLASS_UNK = 10, - CLASS_DRUID = 11, + CLASS_DRUID = 11 }; // max+1 for player class @@ -98,7 +98,7 @@ enum Classes #define CLASSMASK_WAND_USERS ((1<<(CLASS_PRIEST-1))|(1<<(CLASS_MAGE-1))|(1<<(CLASS_WARLOCK-1))) -#define PLAYER_MAX_BATTLEGROUND_QUEUES 3 +#define PLAYER_MAX_BATTLEGROUND_QUEUES 2 enum ReputationRank { @@ -661,7 +661,7 @@ enum SpellEffects SPELL_EFFECT_SELF_RESURRECT = 94, SPELL_EFFECT_SKINNING = 95, SPELL_EFFECT_CHARGE = 96, - SPELL_EFFECT_97 = 97, + SPELL_EFFECT_CAST_BUTTON = 97, SPELL_EFFECT_KNOCK_BACK = 98, SPELL_EFFECT_DISENCHANT = 99, SPELL_EFFECT_INEBRIATE = 100, @@ -732,192 +732,193 @@ enum SpellEffects enum SpellCastResult { - SPELL_FAILED_AFFECTING_COMBAT = 0x00, - SPELL_FAILED_ALREADY_AT_FULL_HEALTH = 0x01, - SPELL_FAILED_ALREADY_AT_FULL_MANA = 0x02, - SPELL_FAILED_ALREADY_AT_FULL_POWER = 0x03, - SPELL_FAILED_ALREADY_BEING_TAMED = 0x04, - SPELL_FAILED_ALREADY_HAVE_CHARM = 0x05, - SPELL_FAILED_ALREADY_HAVE_SUMMON = 0x06, - SPELL_FAILED_ALREADY_OPEN = 0x07, - SPELL_FAILED_AURA_BOUNCED = 0x08, - SPELL_FAILED_AUTOTRACK_INTERRUPTED = 0x09, - SPELL_FAILED_BAD_IMPLICIT_TARGETS = 0x0A, - SPELL_FAILED_BAD_TARGETS = 0x0B, - SPELL_FAILED_CANT_BE_CHARMED = 0x0C, - SPELL_FAILED_CANT_BE_DISENCHANTED = 0x0D, - SPELL_FAILED_CANT_BE_DISENCHANTED_SKILL = 0x0E, - SPELL_FAILED_CANT_BE_MILLED = 0x0F, - SPELL_FAILED_CANT_BE_PROSPECTED = 0x10, - SPELL_FAILED_CANT_CAST_ON_TAPPED = 0x11, - SPELL_FAILED_CANT_DUEL_WHILE_INVISIBLE = 0x12, - SPELL_FAILED_CANT_DUEL_WHILE_STEALTHED = 0x13, - SPELL_FAILED_CANT_STEALTH = 0x14, - SPELL_FAILED_CASTER_AURASTATE = 0x15, - SPELL_FAILED_CASTER_DEAD = 0x16, - SPELL_FAILED_CHARMED = 0x17, - SPELL_FAILED_CHEST_IN_USE = 0x18, - SPELL_FAILED_CONFUSED = 0x19, - SPELL_FAILED_DONT_REPORT = 0x1A, - SPELL_FAILED_EQUIPPED_ITEM = 0x1B, - SPELL_FAILED_EQUIPPED_ITEM_CLASS = 0x1C, - SPELL_FAILED_EQUIPPED_ITEM_CLASS_MAINHAND = 0x1D, - SPELL_FAILED_EQUIPPED_ITEM_CLASS_OFFHAND = 0x1E, - SPELL_FAILED_ERROR = 0x1F, - SPELL_FAILED_FIZZLE = 0x20, - SPELL_FAILED_FLEEING = 0x21, - SPELL_FAILED_FOOD_LOWLEVEL = 0x22, - SPELL_FAILED_HIGHLEVEL = 0x23, - SPELL_FAILED_HUNGER_SATIATED = 0x24, - SPELL_FAILED_IMMUNE = 0x25, - SPELL_FAILED_INCORRECT_AREA = 0x26, - SPELL_FAILED_INTERRUPTED = 0x27, - SPELL_FAILED_INTERRUPTED_COMBAT = 0x28, - SPELL_FAILED_ITEM_ALREADY_ENCHANTED = 0x29, - SPELL_FAILED_ITEM_GONE = 0x2A, - SPELL_FAILED_ITEM_NOT_FOUND = 0x2B, - SPELL_FAILED_ITEM_NOT_READY = 0x2C, - SPELL_FAILED_LEVEL_REQUIREMENT = 0x2D, - SPELL_FAILED_LINE_OF_SIGHT = 0x2E, - SPELL_FAILED_LOWLEVEL = 0x2F, - SPELL_FAILED_LOW_CASTLEVEL = 0x30, - SPELL_FAILED_MAINHAND_EMPTY = 0x31, - SPELL_FAILED_MOVING = 0x32, - SPELL_FAILED_NEED_AMMO = 0x33, - SPELL_FAILED_NEED_AMMO_POUCH = 0x34, - SPELL_FAILED_NEED_EXOTIC_AMMO = 0x35, - SPELL_FAILED_NEED_MORE_ITEMS = 0x36, - SPELL_FAILED_NOPATH = 0x37, - SPELL_FAILED_NOT_BEHIND = 0x38, - SPELL_FAILED_NOT_FISHABLE = 0x39, - SPELL_FAILED_NOT_FLYING = 0x3A, - SPELL_FAILED_NOT_HERE = 0x3B, - SPELL_FAILED_NOT_INFRONT = 0x3C, - SPELL_FAILED_NOT_IN_CONTROL = 0x3D, - SPELL_FAILED_NOT_KNOWN = 0x3E, - SPELL_FAILED_NOT_MOUNTED = 0x3F, - SPELL_FAILED_NOT_ON_TAXI = 0x40, - SPELL_FAILED_NOT_ON_TRANSPORT = 0x41, - SPELL_FAILED_NOT_READY = 0x42, - SPELL_FAILED_NOT_SHAPESHIFT = 0x43, - SPELL_FAILED_NOT_STANDING = 0x44, - SPELL_FAILED_NOT_TRADEABLE = 0x45, - SPELL_FAILED_NOT_TRADING = 0x46, - SPELL_FAILED_NOT_UNSHEATHED = 0x47, - SPELL_FAILED_NOT_WHILE_GHOST = 0x48, - SPELL_FAILED_NOT_WHILE_LOOTING = 0x49, - SPELL_FAILED_NO_AMMO = 0x4A, - SPELL_FAILED_NO_CHARGES_REMAIN = 0x4B, - SPELL_FAILED_NO_CHAMPION = 0x4C, - SPELL_FAILED_NO_COMBO_POINTS = 0x4D, - SPELL_FAILED_NO_DUELING = 0x4E, - SPELL_FAILED_NO_ENDURANCE = 0x4F, - SPELL_FAILED_NO_FISH = 0x50, - SPELL_FAILED_NO_ITEMS_WHILE_SHAPESHIFTED = 0x51, - SPELL_FAILED_NO_MOUNTS_ALLOWED = 0x52, - SPELL_FAILED_NO_PET = 0x53, - SPELL_FAILED_NO_POWER = 0x54, - SPELL_FAILED_NOTHING_TO_DISPEL = 0x55, - SPELL_FAILED_NOTHING_TO_STEAL = 0x56, - SPELL_FAILED_ONLY_ABOVEWATER = 0x57, - SPELL_FAILED_ONLY_DAYTIME = 0x58, - SPELL_FAILED_ONLY_INDOORS = 0x59, - SPELL_FAILED_ONLY_MOUNTED = 0x5A, - SPELL_FAILED_ONLY_NIGHTTIME = 0x5B, - SPELL_FAILED_ONLY_OUTDOORS = 0x5C, - SPELL_FAILED_ONLY_SHAPESHIFT = 0x5D, - SPELL_FAILED_ONLY_STEALTHED = 0x5E, - SPELL_FAILED_ONLY_UNDERWATER = 0x5F, - SPELL_FAILED_OUT_OF_RANGE = 0x60, - SPELL_FAILED_PACIFIED = 0x61, - SPELL_FAILED_POSSESSED = 0x62, - SPELL_FAILED_REAGENTS = 0x63, - SPELL_FAILED_REQUIRES_AREA = 0x64, - SPELL_FAILED_REQUIRES_SPELL_FOCUS = 0x65, - SPELL_FAILED_ROOTED = 0x66, - SPELL_FAILED_SILENCED = 0x67, - SPELL_FAILED_SPELL_IN_PROGRESS = 0x68, - SPELL_FAILED_SPELL_LEARNED = 0x69, - SPELL_FAILED_SPELL_UNAVAILABLE = 0x6A, - SPELL_FAILED_STUNNED = 0x6B, - SPELL_FAILED_TARGETS_DEAD = 0x6C, - SPELL_FAILED_TARGET_AFFECTING_COMBAT = 0x6D, - SPELL_FAILED_TARGET_AURASTATE = 0x6E, - SPELL_FAILED_TARGET_DUELING = 0x6F, - SPELL_FAILED_TARGET_ENEMY = 0x70, - SPELL_FAILED_TARGET_ENRAGED = 0x71, - SPELL_FAILED_TARGET_FRIENDLY = 0x72, - SPELL_FAILED_TARGET_IN_COMBAT = 0x73, - SPELL_FAILED_TARGET_IS_PLAYER = 0x74, - SPELL_FAILED_TARGET_IS_PLAYER_CONTROLLED = 0x75, - SPELL_FAILED_TARGET_NOT_DEAD = 0x76, - SPELL_FAILED_TARGET_NOT_IN_PARTY = 0x77, - SPELL_FAILED_TARGET_NOT_LOOTED = 0x78, - SPELL_FAILED_TARGET_NOT_PLAYER = 0x79, - SPELL_FAILED_TARGET_NO_POCKETS = 0x7A, - SPELL_FAILED_TARGET_NO_WEAPONS = 0x7B, - SPELL_FAILED_TARGET_NO_RANGED_WEAPONS = 0x7C, - SPELL_FAILED_TARGET_UNSKINNABLE = 0x7D, - SPELL_FAILED_THIRST_SATIATED = 0x7E, - SPELL_FAILED_TOO_CLOSE = 0x7F, - SPELL_FAILED_TOO_MANY_OF_ITEM = 0x80, - SPELL_FAILED_TOTEM_CATEGORY = 0x81, - SPELL_FAILED_TOTEMS = 0x82, - SPELL_FAILED_TRY_AGAIN = 0x83, - SPELL_FAILED_UNIT_NOT_BEHIND = 0x84, - SPELL_FAILED_UNIT_NOT_INFRONT = 0x85, - SPELL_FAILED_WRONG_PET_FOOD = 0x86, - SPELL_FAILED_NOT_WHILE_FATIGUED = 0x87, - SPELL_FAILED_TARGET_NOT_IN_INSTANCE = 0x88, - SPELL_FAILED_NOT_WHILE_TRADING = 0x89, - SPELL_FAILED_TARGET_NOT_IN_RAID = 0x8A, - SPELL_FAILED_TARGET_FREEFORALL = 0x8B, - SPELL_FAILED_NO_EDIBLE_CORPSES = 0x8C, - SPELL_FAILED_ONLY_BATTLEGROUNDS = 0x8D, - SPELL_FAILED_TARGET_NOT_GHOST = 0x8E, - SPELL_FAILED_TRANSFORM_UNUSABLE = 0x8F, - SPELL_FAILED_WRONG_WEATHER = 0x90, - SPELL_FAILED_DAMAGE_IMMUNE = 0x91, - SPELL_FAILED_PREVENTED_BY_MECHANIC = 0x92, - SPELL_FAILED_PLAY_TIME = 0x93, - SPELL_FAILED_REPUTATION = 0x94, - SPELL_FAILED_MIN_SKILL = 0x95, - SPELL_FAILED_NOT_IN_ARENA = 0x96, - SPELL_FAILED_NOT_ON_SHAPESHIFT = 0x97, - SPELL_FAILED_NOT_ON_STEALTHED = 0x98, - SPELL_FAILED_NOT_ON_DAMAGE_IMMUNE = 0x99, - SPELL_FAILED_NOT_ON_MOUNTED = 0x9A, - SPELL_FAILED_TOO_SHALLOW = 0x9B, - SPELL_FAILED_TARGET_NOT_IN_SANCTUARY = 0x9C, - SPELL_FAILED_TARGET_IS_TRIVIAL = 0x9D, - SPELL_FAILED_BM_OR_INVISGOD = 0x9E, - SPELL_FAILED_EXPERT_RIDING_REQUIREMENT = 0x9F, - SPELL_FAILED_ARTISAN_RIDING_REQUIREMENT = 0xA0, - SPELL_FAILED_NOT_IDLE = 0xA1, - SPELL_FAILED_NOT_INACTIVE = 0xA2, - SPELL_FAILED_PARTIAL_PLAYTIME = 0xA3, - SPELL_FAILED_NO_PLAYTIME = 0xA4, - SPELL_FAILED_NOT_IN_BATTLEGROUND = 0xA5, - SPELL_FAILED_NOT_IN_RAID_INSTANCE = 0xA6, - SPELL_FAILED_ONLY_IN_ARENA = 0xA7, - SPELL_FAILED_TARGET_LOCKED_TO_RAID_INSTANCE = 0xA8, - SPELL_FAILED_ON_USE_ENCHANT = 0xA9, - SPELL_FAILED_NOT_ON_GROUND = 0xAA, - SPELL_FAILED_CUSTOM_ERROR = 0xAB, - SPELL_FAILED_CANT_DO_THAT_RIGHT_NOW = 0xAC, - SPELL_FAILED_TOO_MANY_SOCKETS = 0xAD, - SPELL_FAILED_INVALID_GLYPH = 0xAE, - SPELL_FAILED_UNIQUE_GLYPH = 0xAF, - SPELL_FAILED_GLYPH_SOCKET_LOCKED = 0xB0, - SPELL_FAILED_NO_VALID_TARGETS = 0xB1, - SPELL_FAILED_ITEM_AT_MAX_CHARGES = 0xB2, - SPELL_FAILED_NOT_IN_BARBERSHOP = 0xB3, - SPELL_FAILED_FISHING_TOO_LOW = 0xB4, - SPELL_FAILED_ITEM_ENCHANT_TRADE_WINDOW = 0xB5, - SPELL_FAILED_SUMMON_PENDING = 0xB6, - SPELL_FAILED_MAX_SOCKETS = 0xB7, - SPELL_FAILED_PET_CAN_RENAME = 0xB8, - SPELL_FAILED_UNKNOWN = 0xB9, + SPELL_FAILED_SUCCESS = 0x00, + SPELL_FAILED_AFFECTING_COMBAT = 0x01, + SPELL_FAILED_ALREADY_AT_FULL_HEALTH = 0x02, + SPELL_FAILED_ALREADY_AT_FULL_MANA = 0x03, + SPELL_FAILED_ALREADY_AT_FULL_POWER = 0x04, + SPELL_FAILED_ALREADY_BEING_TAMED = 0x05, + SPELL_FAILED_ALREADY_HAVE_CHARM = 0x06, + SPELL_FAILED_ALREADY_HAVE_SUMMON = 0x07, + SPELL_FAILED_ALREADY_OPEN = 0x08, + SPELL_FAILED_AURA_BOUNCED = 0x09, + SPELL_FAILED_AUTOTRACK_INTERRUPTED = 0x0A, + SPELL_FAILED_BAD_IMPLICIT_TARGETS = 0x0B, + SPELL_FAILED_BAD_TARGETS = 0x0C, + SPELL_FAILED_CANT_BE_CHARMED = 0x0D, + SPELL_FAILED_CANT_BE_DISENCHANTED = 0x0E, + SPELL_FAILED_CANT_BE_DISENCHANTED_SKILL = 0x0F, + SPELL_FAILED_CANT_BE_MILLED = 0x10, + SPELL_FAILED_CANT_BE_PROSPECTED = 0x11, + SPELL_FAILED_CANT_CAST_ON_TAPPED = 0x12, + SPELL_FAILED_CANT_DUEL_WHILE_INVISIBLE = 0x13, + SPELL_FAILED_CANT_DUEL_WHILE_STEALTHED = 0x14, + SPELL_FAILED_CANT_STEALTH = 0x15, + SPELL_FAILED_CASTER_AURASTATE = 0x16, + SPELL_FAILED_CASTER_DEAD = 0x17, + SPELL_FAILED_CHARMED = 0x18, + SPELL_FAILED_CHEST_IN_USE = 0x19, + SPELL_FAILED_CONFUSED = 0x1A, + SPELL_FAILED_DONT_REPORT = 0x1B, + SPELL_FAILED_EQUIPPED_ITEM = 0x1C, + SPELL_FAILED_EQUIPPED_ITEM_CLASS = 0x1D, + SPELL_FAILED_EQUIPPED_ITEM_CLASS_MAINHAND = 0x1E, + SPELL_FAILED_EQUIPPED_ITEM_CLASS_OFFHAND = 0x1F, + SPELL_FAILED_ERROR = 0x20, + SPELL_FAILED_FIZZLE = 0x21, + SPELL_FAILED_FLEEING = 0x22, + SPELL_FAILED_FOOD_LOWLEVEL = 0x23, + SPELL_FAILED_HIGHLEVEL = 0x24, + SPELL_FAILED_HUNGER_SATIATED = 0x25, + SPELL_FAILED_IMMUNE = 0x26, + SPELL_FAILED_INCORRECT_AREA = 0x27, + SPELL_FAILED_INTERRUPTED = 0x28, + SPELL_FAILED_INTERRUPTED_COMBAT = 0x29, + SPELL_FAILED_ITEM_ALREADY_ENCHANTED = 0x2A, + SPELL_FAILED_ITEM_GONE = 0x2B, + SPELL_FAILED_ITEM_NOT_FOUND = 0x2C, + SPELL_FAILED_ITEM_NOT_READY = 0x2D, + SPELL_FAILED_LEVEL_REQUIREMENT = 0x2E, + SPELL_FAILED_LINE_OF_SIGHT = 0x2F, + SPELL_FAILED_LOWLEVEL = 0x30, + SPELL_FAILED_LOW_CASTLEVEL = 0x31, + SPELL_FAILED_MAINHAND_EMPTY = 0x32, + SPELL_FAILED_MOVING = 0x33, + SPELL_FAILED_NEED_AMMO = 0x34, + SPELL_FAILED_NEED_AMMO_POUCH = 0x35, + SPELL_FAILED_NEED_EXOTIC_AMMO = 0x36, + SPELL_FAILED_NEED_MORE_ITEMS = 0x37, + SPELL_FAILED_NOPATH = 0x38, + SPELL_FAILED_NOT_BEHIND = 0x39, + SPELL_FAILED_NOT_FISHABLE = 0x3A, + SPELL_FAILED_NOT_FLYING = 0x3B, + SPELL_FAILED_NOT_HERE = 0x3C, + SPELL_FAILED_NOT_INFRONT = 0x3D, + SPELL_FAILED_NOT_IN_CONTROL = 0x3E, + SPELL_FAILED_NOT_KNOWN = 0x3F, + SPELL_FAILED_NOT_MOUNTED = 0x40, + SPELL_FAILED_NOT_ON_TAXI = 0x41, + SPELL_FAILED_NOT_ON_TRANSPORT = 0x42, + SPELL_FAILED_NOT_READY = 0x43, + SPELL_FAILED_NOT_SHAPESHIFT = 0x44, + SPELL_FAILED_NOT_STANDING = 0x45, + SPELL_FAILED_NOT_TRADEABLE = 0x46, + SPELL_FAILED_NOT_TRADING = 0x47, + SPELL_FAILED_NOT_UNSHEATHED = 0x48, + SPELL_FAILED_NOT_WHILE_GHOST = 0x49, + SPELL_FAILED_NOT_WHILE_LOOTING = 0x4A, + SPELL_FAILED_NO_AMMO = 0x4B, + SPELL_FAILED_NO_CHARGES_REMAIN = 0x4C, + SPELL_FAILED_NO_CHAMPION = 0x4D, + SPELL_FAILED_NO_COMBO_POINTS = 0x4E, + SPELL_FAILED_NO_DUELING = 0x4F, + SPELL_FAILED_NO_ENDURANCE = 0x50, + SPELL_FAILED_NO_FISH = 0x51, + SPELL_FAILED_NO_ITEMS_WHILE_SHAPESHIFTED = 0x52, + SPELL_FAILED_NO_MOUNTS_ALLOWED = 0x53, + SPELL_FAILED_NO_PET = 0x54, + SPELL_FAILED_NO_POWER = 0x55, + SPELL_FAILED_NOTHING_TO_DISPEL = 0x56, + SPELL_FAILED_NOTHING_TO_STEAL = 0x57, + SPELL_FAILED_ONLY_ABOVEWATER = 0x58, + SPELL_FAILED_ONLY_DAYTIME = 0x59, + SPELL_FAILED_ONLY_INDOORS = 0x5A, + SPELL_FAILED_ONLY_MOUNTED = 0x5B, + SPELL_FAILED_ONLY_NIGHTTIME = 0x5C, + SPELL_FAILED_ONLY_OUTDOORS = 0x5D, + SPELL_FAILED_ONLY_SHAPESHIFT = 0x5E, + SPELL_FAILED_ONLY_STEALTHED = 0x5F, + SPELL_FAILED_ONLY_UNDERWATER = 0x60, + SPELL_FAILED_OUT_OF_RANGE = 0x61, + SPELL_FAILED_PACIFIED = 0x62, + SPELL_FAILED_POSSESSED = 0x63, + SPELL_FAILED_REAGENTS = 0x64, + SPELL_FAILED_REQUIRES_AREA = 0x65, + SPELL_FAILED_REQUIRES_SPELL_FOCUS = 0x66, + SPELL_FAILED_ROOTED = 0x67, + SPELL_FAILED_SILENCED = 0x68, + SPELL_FAILED_SPELL_IN_PROGRESS = 0x69, + SPELL_FAILED_SPELL_LEARNED = 0x6A, + SPELL_FAILED_SPELL_UNAVAILABLE = 0x6B, + SPELL_FAILED_STUNNED = 0x6C, + SPELL_FAILED_TARGETS_DEAD = 0x6D, + SPELL_FAILED_TARGET_AFFECTING_COMBAT = 0x6E, + SPELL_FAILED_TARGET_AURASTATE = 0x6F, + SPELL_FAILED_TARGET_DUELING = 0x70, + SPELL_FAILED_TARGET_ENEMY = 0x71, + SPELL_FAILED_TARGET_ENRAGED = 0x72, + SPELL_FAILED_TARGET_FRIENDLY = 0x73, + SPELL_FAILED_TARGET_IN_COMBAT = 0x74, + SPELL_FAILED_TARGET_IS_PLAYER = 0x75, + SPELL_FAILED_TARGET_IS_PLAYER_CONTROLLED = 0x76, + SPELL_FAILED_TARGET_NOT_DEAD = 0x77, + SPELL_FAILED_TARGET_NOT_IN_PARTY = 0x78, + SPELL_FAILED_TARGET_NOT_LOOTED = 0x79, + SPELL_FAILED_TARGET_NOT_PLAYER = 0x7A, + SPELL_FAILED_TARGET_NO_POCKETS = 0x7B, + SPELL_FAILED_TARGET_NO_WEAPONS = 0x7C, + SPELL_FAILED_TARGET_NO_RANGED_WEAPONS = 0x7D, + SPELL_FAILED_TARGET_UNSKINNABLE = 0x7E, + SPELL_FAILED_THIRST_SATIATED = 0x7F, + SPELL_FAILED_TOO_CLOSE = 0x80, + SPELL_FAILED_TOO_MANY_OF_ITEM = 0x81, + SPELL_FAILED_TOTEM_CATEGORY = 0x82, + SPELL_FAILED_TOTEMS = 0x83, + SPELL_FAILED_TRY_AGAIN = 0x84, + SPELL_FAILED_UNIT_NOT_BEHIND = 0x85, + SPELL_FAILED_UNIT_NOT_INFRONT = 0x86, + SPELL_FAILED_WRONG_PET_FOOD = 0x87, + SPELL_FAILED_NOT_WHILE_FATIGUED = 0x88, + SPELL_FAILED_TARGET_NOT_IN_INSTANCE = 0x89, + SPELL_FAILED_NOT_WHILE_TRADING = 0x8A, + SPELL_FAILED_TARGET_NOT_IN_RAID = 0x8B, + SPELL_FAILED_TARGET_FREEFORALL = 0x8C, + SPELL_FAILED_NO_EDIBLE_CORPSES = 0x8D, + SPELL_FAILED_ONLY_BATTLEGROUNDS = 0x8E, + SPELL_FAILED_TARGET_NOT_GHOST = 0x8F, + SPELL_FAILED_TRANSFORM_UNUSABLE = 0x90, + SPELL_FAILED_WRONG_WEATHER = 0x91, + SPELL_FAILED_DAMAGE_IMMUNE = 0x92, + SPELL_FAILED_PREVENTED_BY_MECHANIC = 0x93, + SPELL_FAILED_PLAY_TIME = 0x94, + SPELL_FAILED_REPUTATION = 0x95, + SPELL_FAILED_MIN_SKILL = 0x96, + SPELL_FAILED_NOT_IN_ARENA = 0x97, + SPELL_FAILED_NOT_ON_SHAPESHIFT = 0x98, + SPELL_FAILED_NOT_ON_STEALTHED = 0x99, + SPELL_FAILED_NOT_ON_DAMAGE_IMMUNE = 0x9A, + SPELL_FAILED_NOT_ON_MOUNTED = 0x9B, + SPELL_FAILED_TOO_SHALLOW = 0x9C, + SPELL_FAILED_TARGET_NOT_IN_SANCTUARY = 0x9D, + SPELL_FAILED_TARGET_IS_TRIVIAL = 0x9E, + SPELL_FAILED_BM_OR_INVISGOD = 0x9F, + SPELL_FAILED_EXPERT_RIDING_REQUIREMENT = 0xA0, + SPELL_FAILED_ARTISAN_RIDING_REQUIREMENT = 0xA1, + SPELL_FAILED_NOT_IDLE = 0xA2, + SPELL_FAILED_NOT_INACTIVE = 0xA3, + SPELL_FAILED_PARTIAL_PLAYTIME = 0xA4, + SPELL_FAILED_NO_PLAYTIME = 0xA5, + SPELL_FAILED_NOT_IN_BATTLEGROUND = 0xA6, + SPELL_FAILED_NOT_IN_RAID_INSTANCE = 0xA7, + SPELL_FAILED_ONLY_IN_ARENA = 0xA8, + SPELL_FAILED_TARGET_LOCKED_TO_RAID_INSTANCE = 0xA9, + SPELL_FAILED_ON_USE_ENCHANT = 0xAA, + SPELL_FAILED_NOT_ON_GROUND = 0xAB, + SPELL_FAILED_CUSTOM_ERROR = 0xAC, + SPELL_FAILED_CANT_DO_THAT_RIGHT_NOW = 0xAD, + SPELL_FAILED_TOO_MANY_SOCKETS = 0xAE, + SPELL_FAILED_INVALID_GLYPH = 0xAF, + SPELL_FAILED_UNIQUE_GLYPH = 0xB0, + SPELL_FAILED_GLYPH_SOCKET_LOCKED = 0xB1, + SPELL_FAILED_NO_VALID_TARGETS = 0xB2, + SPELL_FAILED_ITEM_AT_MAX_CHARGES = 0xB3, + SPELL_FAILED_NOT_IN_BARBERSHOP = 0xB4, + SPELL_FAILED_FISHING_TOO_LOW = 0xB5, + SPELL_FAILED_ITEM_ENCHANT_TRADE_WINDOW = 0xB6, + SPELL_FAILED_SUMMON_PENDING = 0xB7, + SPELL_FAILED_MAX_SOCKETS = 0xB8, + SPELL_FAILED_PET_CAN_RENAME = 0xB9, + SPELL_FAILED_UNKNOWN = 0xBA, SPELL_CAST_OK = 0xFF // custom value, don't must be send to client }; @@ -2363,8 +2364,8 @@ enum ChatMsg CHAT_MSG_OFFICER = 0x05, CHAT_MSG_YELL = 0x06, CHAT_MSG_WHISPER = 0x07, - CHAT_MSG_WHISPER_INFORM = 0x08, - CHAT_MSG_REPLY = 0x09, + CHAT_MSG_WHISPER_INFORM = 0x08, // WHISPER_FOREIGN? + CHAT_MSG_REPLY = 0x09, // WHISPER_INFORM? CHAT_MSG_EMOTE = 0x0A, CHAT_MSG_TEXT_EMOTE = 0x0B, CHAT_MSG_MONSTER_SAY = 0x0C, @@ -2437,10 +2438,10 @@ enum PetDiet #define CHAIN_SPELL_JUMP_RADIUS 10 // Max values for Guild & Guild Bank -#define GUILD_BANK_MAX_TABS 6 +#define GUILD_BANK_MAX_TABS 6 // send by client for money log also #define GUILD_BANK_MAX_SLOTS 98 #define GUILD_BANK_MAX_LOGS 25 -#define GUILD_BANK_MONEY_LOGS_TAB 100 +#define GUILD_BANK_MONEY_LOGS_TAB 100 // used for money log in DB #define GUILD_EVENTLOG_MAX_RECORDS 100 #define GUILD_RANKS_MIN_COUNT 5 #define GUILD_RANKS_MAX_COUNT 10 @@ -2487,14 +2488,7 @@ enum DiminishingGroup DIMINISHING_TAUNT, DIMINISHING_LIMITONLY // Don't Diminish, but limit duration to 10s }; - -enum DungeonDifficulties -{ - DIFFICULTY_NORMAL = 0, - DIFFICULTY_HEROIC = 1, - TOTAL_DIFFICULTIES -}; - + enum SummonCategory { SUMMON_CATEGORY_WILD = 0, @@ -2596,42 +2590,51 @@ enum ResponseCodes CHAR_CREATE_EXPANSION_CLASS = 0x3A, CHAR_CREATE_LEVEL_REQUIREMENT = 0x3B, CHAR_CREATE_UNIQUE_CLASS_LIMIT = 0x3C, - - CHAR_DELETE_IN_PROGRESS = 0x3D, - CHAR_DELETE_SUCCESS = 0x3E, - CHAR_DELETE_FAILED = 0x3F, - CHAR_DELETE_FAILED_LOCKED_FOR_TRANSFER = 0x40, - CHAR_DELETE_FAILED_GUILD_LEADER = 0x41, - CHAR_DELETE_FAILED_ARENA_CAPTAIN = 0x42, - - CHAR_LOGIN_IN_PROGRESS = 0x43, - CHAR_LOGIN_SUCCESS = 0x44, - CHAR_LOGIN_NO_WORLD = 0x45, - CHAR_LOGIN_DUPLICATE_CHARACTER = 0x46, - CHAR_LOGIN_NO_INSTANCES = 0x47, - CHAR_LOGIN_FAILED = 0x48, - CHAR_LOGIN_DISABLED = 0x49, - CHAR_LOGIN_NO_CHARACTER = 0x4A, - CHAR_LOGIN_LOCKED_FOR_TRANSFER = 0x4B, - CHAR_LOGIN_LOCKED_BY_BILLING = 0x4C, - - CHAR_NAME_SUCCESS = 0x4D, - CHAR_NAME_FAILURE = 0x4E, - CHAR_NAME_NO_NAME = 0x4F, - CHAR_NAME_TOO_SHORT = 0x50, - CHAR_NAME_TOO_LONG = 0x51, - CHAR_NAME_INVALID_CHARACTER = 0x52, - CHAR_NAME_MIXED_LANGUAGES = 0x53, - CHAR_NAME_PROFANE = 0x54, - CHAR_NAME_RESERVED = 0x55, - CHAR_NAME_INVALID_APOSTROPHE = 0x56, - CHAR_NAME_MULTIPLE_APOSTROPHES = 0x57, - CHAR_NAME_THREE_CONSECUTIVE = 0x58, - CHAR_NAME_INVALID_SPACE = 0x59, - CHAR_NAME_CONSECUTIVE_SPACES = 0x5A, - CHAR_NAME_RUSSIAN_CONSECUTIVE_SILENT_CHARACTERS = 0x5B, - CHAR_NAME_RUSSIAN_SILENT_CHARACTER_AT_BEGINNING_OR_END = 0x5C, - CHAR_NAME_DECLENSION_DOESNT_MATCH_BASE_NAME = 0x5D + CHAR_CREATE_CHARACTER_IN_GUILD = 0x3D, + CHAR_CREATE_RESTRICTED_RACECLASS = 0x3E, + CHAR_CREATE_CHARACTER_CHOOSE_RACE = 0x3F, + CHAR_CREATE_CHARACTER_ARENA_LEADER = 0x40, + CHAR_CREATE_CHARACTER_DELETE_MAIL = 0x41, + CHAR_CREATE_CHARACTER_SWAP_FACTION = 0x42, + CHAR_CREATE_CHARACTER_RACE_ONLY = 0x43, + + CHAR_CREATE_CHARACTER_GOLD_LIMIT = 0x44, + + CHAR_DELETE_IN_PROGRESS = 0x45, + CHAR_DELETE_SUCCESS = 0x46, + CHAR_DELETE_FAILED = 0x47, + CHAR_DELETE_FAILED_LOCKED_FOR_TRANSFER = 0x48, + CHAR_DELETE_FAILED_GUILD_LEADER = 0x49, + CHAR_DELETE_FAILED_ARENA_CAPTAIN = 0x4A, + + CHAR_LOGIN_IN_PROGRESS = 0x4B, + CHAR_LOGIN_SUCCESS = 0x4C, + CHAR_LOGIN_NO_WORLD = 0x4D, + CHAR_LOGIN_DUPLICATE_CHARACTER = 0x4E, + CHAR_LOGIN_NO_INSTANCES = 0x4F, + CHAR_LOGIN_FAILED = 0x50, + CHAR_LOGIN_DISABLED = 0x51, + CHAR_LOGIN_NO_CHARACTER = 0x52, + CHAR_LOGIN_LOCKED_FOR_TRANSFER = 0x53, + CHAR_LOGIN_LOCKED_BY_BILLING = 0x54, + + CHAR_NAME_SUCCESS = 0x55, + CHAR_NAME_FAILURE = 0x56, + CHAR_NAME_NO_NAME = 0x57, + CHAR_NAME_TOO_SHORT = 0x58, + CHAR_NAME_TOO_LONG = 0x59, + CHAR_NAME_INVALID_CHARACTER = 0x5A, + CHAR_NAME_MIXED_LANGUAGES = 0x5B, + CHAR_NAME_PROFANE = 0x5C, + CHAR_NAME_RESERVED = 0x5D, + CHAR_NAME_INVALID_APOSTROPHE = 0x5E, + CHAR_NAME_MULTIPLE_APOSTROPHES = 0x5F, + CHAR_NAME_THREE_CONSECUTIVE = 0x60, + CHAR_NAME_INVALID_SPACE = 0x61, + CHAR_NAME_CONSECUTIVE_SPACES = 0x62, + CHAR_NAME_RUSSIAN_CONSECUTIVE_SILENT_CHARACTERS = 0x63, + CHAR_NAME_RUSSIAN_SILENT_CHARACTER_AT_BEGINNING_OR_END = 0x64, + CHAR_NAME_DECLENSION_DOESNT_MATCH_BASE_NAME = 0x65 }; /// Ban function modes @@ -2664,9 +2667,12 @@ enum BattleGroundTypeId BATTLEGROUND_RL = 8, BATTLEGROUND_SA = 9, BATTLEGROUND_DS = 10, - BATTLEGROUND_RV = 11 + BATTLEGROUND_RV = 11, + BATTLEGROUND_IC = 30, + BATTLEGROUND_ABG = 32 }; -#define MAX_BATTLEGROUND_TYPE_ID 12 + +#define MAX_BATTLEGROUND_TYPE_ID 33 enum MailResponseType { @@ -2719,4 +2725,3 @@ enum SpellFamilyNames }; #endif - diff --git a/src/game/Spell.cpp b/src/game/Spell.cpp index 20c4bd379d9..d5918134ec8 100644 --- a/src/game/Spell.cpp +++ b/src/game/Spell.cpp @@ -255,7 +255,10 @@ bool SpellCastTargets::read ( WorldPacket * data, Unit *caster ) if( m_targetMask & TARGET_FLAG_SOURCE_LOCATION ) { - if(data->rpos() + 4 + 4 + 4 > data->size()) + if(data->rpos() + 1 + 4 + 4 + 4 > data->size()) + return false; + + if(!data->readPackGUID(m_unitTargetGUID)) return false; *data >> m_srcPos.m_positionX >> m_srcPos.m_positionY >> m_srcPos.m_positionZ; @@ -341,7 +344,14 @@ void SpellCastTargets::write ( WorldPacket * data ) } if( m_targetMask & TARGET_FLAG_SOURCE_LOCATION ) + { + if(m_unitTarget) + data->append(m_unitTarget->GetPackGUID()); + else + *data << uint8(0); + *data << m_srcPos.m_positionX << m_srcPos.m_positionY << m_srcPos.m_positionZ; + } if( m_targetMask & TARGET_FLAG_DEST_LOCATION ) { @@ -1022,7 +1032,7 @@ void Spell::AddItemTarget(Item* pitem, uint32 effIndex) void Spell::DoAllEffectOnTarget(TargetInfo *target) { - if (!target || target->processed) // Check target + if (!target || target == (TargetInfo*)0x10 || target->processed) return; target->processed = true; // Target checked in apply effects procedure @@ -2901,7 +2911,7 @@ void Spell::cast(bool skipCheck) continue; SpellEntry const *auraSpellInfo = (*i)->GetSpellProto(); uint32 auraSpellIdx = (*i)->GetEffIndex(); - if (SpellEntry const *spellInfo = sSpellStore.LookupEntry(auraSpellInfo->EffectTriggerSpell[auraSpellIdx])) + if(SpellEntry const *spellInfo = sSpellStore.LookupEntry(auraSpellInfo->EffectTriggerSpell[auraSpellIdx])) { // Calculate chance at that moment (can be depend for example from combo points) int32 chance = m_caster->CalculateSpellDamage(auraSpellInfo, auraSpellIdx, (*i)->GetBasePoints(), NULL); @@ -2909,7 +2919,7 @@ void Spell::cast(bool skipCheck) } } - if (m_customAttr & SPELL_ATTR_CU_DIRECT_DAMAGE) + if(m_customAttr & SPELL_ATTR_CU_DIRECT_DAMAGE) CalculateDamageDoneForAllTargets(); // CAST SPELL @@ -2917,11 +2927,11 @@ void Spell::cast(bool skipCheck) //SendCastResult(castResult); SendSpellGo(); // we must send smsg_spell_go packet before m_castItem delete in TakeCastItem()... - if (m_customAttr & SPELL_ATTR_CU_CHARGE) + if(m_customAttr & SPELL_ATTR_CU_CHARGE) { for (uint32 i = 0; i < 3; ++i) { - switch (m_spellInfo->Effect[i]) + switch(m_spellInfo->Effect[i]) { case SPELL_EFFECT_CHARGE: case SPELL_EFFECT_JUMP: @@ -2994,10 +3004,18 @@ void Spell::handle_immediate() _handle_immediate_phase(); for (std::list<TargetInfo>::iterator ihit= m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit) + { DoAllEffectOnTarget(&(*ihit)); + if(m_UniqueTargetInfo.end()==ihit) + break; + } for (std::list<GOTargetInfo>::iterator ihit= m_UniqueGOTargetInfo.begin(); ihit != m_UniqueGOTargetInfo.end(); ++ihit) + { DoAllEffectOnTarget(&(*ihit)); + if(m_UniqueGOTargetInfo.end()==ihit) + break; + } // spell is finished, perform some last features of the spell here _handle_finish_phase(); @@ -3189,7 +3207,7 @@ void Spell::SendSpellCooldown() } // have infinity cooldown but set at aura apply // do not set cooldown for triggered spells (needed by reincarnation) - if(m_spellInfo->Attributes & SPELL_ATTR_DISABLED_WHILE_ACTIVE || m_IsTriggeredSpell) + if(m_spellInfo->Attributes & (SPELL_ATTR_DISABLED_WHILE_ACTIVE | SPELL_ATTR_PASSIVE ) || m_IsTriggeredSpell) return; _player->AddSpellAndCategoryCooldowns(m_spellInfo,m_CastItem ? m_CastItem->GetEntry() : 0, this); @@ -3492,6 +3510,12 @@ void Spell::SendSpellStart() if ( castFlags & CAST_FLAG_AMMO ) WriteAmmoToPacket(&data); + if ( castFlags & CAST_FLAG_UNKNOWN21 ) + { + data << uint32(0); + data << uint32(0); + } + m_caster->SendMessageToSet(&data, true); } @@ -4287,9 +4311,10 @@ void Spell::HandleThreatSpells(uint32 spellId) DEBUG_LOG("Spell %u, rank %u, added an additional %i threat", spellId, spellmgr.GetSpellRank(spellId), threat); } -void Spell::HandleEffects(Unit *pUnitTarget, Item *pItemTarget, GameObject *pGOTarget, uint32 i) +void Spell::HandleEffects(Unit *pUnitTarget,Item *pItemTarget,GameObject *pGOTarget,uint32 i) { - if (!Script->OnSpellCast(pUnitTarget, pItemTarget, pGOTarget, i, m_spellInfo)) + + if (!Script->OnSpellCast(pUnitTarget,pItemTarget,pGOTarget,i,m_spellInfo)) return; //effect has been handled, skip it @@ -4302,12 +4327,12 @@ void Spell::HandleEffects(Unit *pUnitTarget, Item *pItemTarget, GameObject *pGOT uint8 eff = m_spellInfo->Effect[i]; - sLog.outDebug("Spell: %u Effect : %u", m_spellInfo->Id, eff); + sLog.outDebug( "Spell: %u Effect : %u", m_spellInfo->Id, eff); //we do not need DamageMultiplier here. damage = CalculateDamage(i, NULL); - if (eff < TOTAL_SPELL_EFFECTS) + if(eff < TOTAL_SPELL_EFFECTS) { //sLog.outDebug( "WORLD: Spell FX %d < TOTAL_SPELL_EFFECTS ", eff); (this->*SpellEffects[eff])(i); @@ -4316,7 +4341,7 @@ void Spell::HandleEffects(Unit *pUnitTarget, Item *pItemTarget, GameObject *pGOT void Spell::TriggerSpell() { - for (TriggerSpells::iterator si = m_TriggerSpells.begin(); si!=m_TriggerSpells.end(); ++si) + for (TriggerSpells::iterator si=m_TriggerSpells.begin(); si!=m_TriggerSpells.end(); ++si) { Spell* spell = new Spell(m_caster, (*si), true, m_originalCasterGUID, m_selfContainer, true); spell->prepare(&m_targets); // use original spell original targets @@ -4326,7 +4351,7 @@ void Spell::TriggerSpell() SpellCastResult Spell::CheckCast(bool strict) { // check cooldowns to prevent cheating - if(m_caster->GetTypeId() == TYPEID_PLAYER) + if(m_caster->GetTypeId() == TYPEID_PLAYER && !(m_spellInfo->Attributes & SPELL_ATTR_PASSIVE)) { //can cast triggered (by aura only?) spells while have this flag if (!m_IsTriggeredSpell && ((Player*)m_caster)->HasFlag(PLAYER_FLAGS, PLAYER_ALLOW_ONLY_ABILITY)) @@ -4518,16 +4543,19 @@ SpellCastResult Spell::CheckCast(bool strict) } */ - if(IsPositiveSpell(m_spellInfo->Id)) - if(target->IsImmunedToSpell(m_spellInfo)) - return SPELL_FAILED_TARGET_AURASTATE; + if(target) + if(IsPositiveSpell(m_spellInfo->Id)) + if(target->IsImmunedToSpell(m_spellInfo)) + return SPELL_FAILED_TARGET_AURASTATE; //Must be behind the target. if( m_spellInfo->AttributesEx2 == 0x100000 && (m_spellInfo->AttributesEx & 0x200) == 0x200 && target->HasInArc(M_PI, m_caster) //Exclusion for Pounce: Facing Limitation was removed in 2.0.1, but it still uses the same, old Ex-Flags && (!(m_spellInfo->SpellFamilyName == SPELLFAMILY_DRUID && m_spellInfo->SpellFamilyFlags.IsEqual(0x20000,0,0))) //Mutilate no longer requires you be behind the target as of patch 3.0.3 - && (!(m_spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE && m_spellInfo->SpellFamilyFlags[1] & 0x200000))) + && (!(m_spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE && m_spellInfo->SpellFamilyFlags[1] & 0x200000)) + //Exclusion for Throw: Facing limitation was added in 3.2.x, but that shouldn't be + && (!(m_spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE && m_spellInfo->SpellFamilyFlags[0] & 0x00000001))) { SendInterrupted(2); return SPELL_FAILED_NOT_BEHIND; @@ -5094,15 +5122,6 @@ SpellCastResult Spell::CheckCast(bool strict) break; } - case 44795: // Parachute - { - float x, y, z; - m_caster->GetPosition(x, y, z); - float ground_Z = m_caster->GetMap()->GetVmapHeight(x, y, z, true); - if (fabs(ground_Z - z) < 0.1f) - return SPELL_FAILED_DONT_REPORT; - break; - } default: break; } @@ -5192,8 +5211,8 @@ SpellCastResult Spell::CheckCast(bool strict) // allow always ghost flight spells if (m_originalCaster && m_originalCaster->GetTypeId() == TYPEID_PLAYER && m_originalCaster->isAlive()) { - // 4197 = Wintergrasp || 4395 = Dalaran && 4564 = Krasus Landing - if (m_originalCaster->GetZoneId() == 4197 || m_originalCaster->GetZoneId() == 4395 && m_originalCaster->GetAreaId() != 4564) + //if (!((Player*)m_originalCaster)->IsKnowHowFlyIn(m_originalCaster->GetMapId(),m_originalCaster->GetZoneId())) + if (m_originalCaster->GetZoneId() == 4197 || m_originalCaster->GetZoneId() == 4395) return m_IsTriggeredSpell ? SPELL_FAILED_DONT_REPORT : SPELL_FAILED_NOT_HERE; } break; @@ -6056,9 +6075,7 @@ bool Spell::CheckTargetCreatureType(Unit* target) const uint32 spellCreatureTargetMask = m_spellInfo->TargetCreatureType; // Curse of Doom & Exorcism: not find another way to fix spell target check :/ - if (m_spellInfo->SpellFamilyName==SPELLFAMILY_WARLOCK && m_spellInfo->Category == 1179 || - // TODO: will be removed in 3.2.x - m_spellInfo->SpellFamilyName==SPELLFAMILY_PALADIN && m_spellInfo->Category == 19) + if (m_spellInfo->SpellFamilyName==SPELLFAMILY_WARLOCK && m_spellInfo->Category == 1179) { // not allow cast at player if(target->GetTypeId() == TYPEID_PLAYER) @@ -6375,7 +6392,7 @@ bool Spell::IsValidSingleTargetSpell(Unit const* target) const } for (uint8 i = 0; i < 3; ++i) { - if (!IsValidSingleTargetEffect(target, Targets(m_spellInfo->EffectImplicitTargetA[i]))) + if(!IsValidSingleTargetEffect(target, Targets(m_spellInfo->EffectImplicitTargetA[i]))) return false; // Need to check B? //if(!IsValidSingleTargetEffect(m_spellInfo->EffectImplicitTargetB[i], target) @@ -6394,8 +6411,8 @@ void Spell::CalculateDamageDoneForAllTargets() // Get multiplier multiplier[i] = m_spellInfo->DmgMultiplier[i]; // Apply multiplier mods - if (m_originalCaster) - if (Player *modOwner = m_originalCaster->GetSpellModOwner()) + if(m_originalCaster) + if(Player* modOwner = m_originalCaster->GetSpellModOwner()) modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_EFFECT_PAST_FIRST, multiplier[i], this); } } @@ -6408,7 +6425,7 @@ void Spell::CalculateDamageDoneForAllTargets() usesAmmo=false; } - for (std::list<TargetInfo>::iterator ihit = m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit) + for (std::list<TargetInfo>::iterator ihit= m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit) { TargetInfo &target = *ihit; @@ -6422,8 +6439,8 @@ void Spell::CalculateDamageDoneForAllTargets() if (usesAmmo) { - bool ammoTaken = false; - for (uint8 i = 0; i < 3; ++i) + bool ammoTaken=false; + for (uint8 i=0; i<3; i++) { if (!(mask & 1<<i)) continue; @@ -6434,7 +6451,7 @@ void Spell::CalculateDamageDoneForAllTargets() case SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL: case SPELL_EFFECT_NORMALIZED_WEAPON_DMG: case SPELL_EFFECT_WEAPON_PERCENT_DAMAGE: - ammoTaken = true; + ammoTaken=true; TakeAmmo(); } if (ammoTaken) @@ -6442,14 +6459,14 @@ void Spell::CalculateDamageDoneForAllTargets() } } - if (target.missCondition == SPELL_MISS_NONE) // In case spell hit target, do all effect on that target + if (target.missCondition==SPELL_MISS_NONE) // In case spell hit target, do all effect on that target { target.damage += CalculateDamageDone(unit, mask, multiplier); target.crit = m_caster->isSpellCrit(unit, m_spellInfo, m_spellSchoolMask, m_attackType); } else if (target.missCondition == SPELL_MISS_REFLECT) // In case spell reflect from target, do all effect on caster (if hit) { - if (target.reflectResult == SPELL_MISS_NONE) // If reflected spell hit caster -> do all effect on him + if (target.reflectResult == SPELL_MISS_NONE) // If reflected spell hit caster -> do all effect on him { target.damage += CalculateDamageDone(m_caster, mask, multiplier); target.crit = m_caster->isSpellCrit(m_caster, m_spellInfo, m_spellSchoolMask, m_attackType); @@ -6485,11 +6502,11 @@ int32 Spell::CalculateDamageDone(Unit *unit, const uint32 effectMask, float *mul break; } - if (m_damage > 0) + if(m_damage > 0) { - if (IsAreaEffectTarget[m_spellInfo->EffectImplicitTargetA[i]] || IsAreaEffectTarget[m_spellInfo->EffectImplicitTargetB[i]]) + if(IsAreaEffectTarget[m_spellInfo->EffectImplicitTargetA[i]] || IsAreaEffectTarget[m_spellInfo->EffectImplicitTargetB[i]]) { - if (int32 reducedPct = unit->GetMaxNegativeAuraModifier(SPELL_AURA_MOD_AOE_DAMAGE_AVOIDANCE)) + if(int32 reducedPct = unit->GetMaxNegativeAuraModifier(SPELL_AURA_MOD_AOE_DAMAGE_AVOIDANCE)) m_damage = m_damage * (100 + reducedPct) / 100; } } @@ -6519,13 +6536,13 @@ SpellCastResult Spell::CanOpenLock(uint32 effIndex, uint32 lockId, SkillType& sk bool reqKey = false; // some locks not have reqs - for (uint8 j = 0; j < 8; ++j) + for (int j = 0; j < 8; ++j) { - switch (lockInfo->Type[j]) + switch(lockInfo->Type[j]) { // check key item (many fit cases can be) case LOCK_KEY_ITEM: - if (lockInfo->Index[j] && m_CastItem && m_CastItem->GetEntry()==lockInfo->Index[j]) + if(lockInfo->Index[j] && m_CastItem && m_CastItem->GetEntry()==lockInfo->Index[j]) return SPELL_CAST_OK; reqKey = true; break; @@ -6535,12 +6552,12 @@ SpellCastResult Spell::CanOpenLock(uint32 effIndex, uint32 lockId, SkillType& sk reqKey = true; // wrong locktype, skip - if (uint32(m_spellInfo->EffectMiscValue[effIndex]) != lockInfo->Index[j]) + if(uint32(m_spellInfo->EffectMiscValue[effIndex]) != lockInfo->Index[j]) continue; skillId = SkillByLockType(LockType(lockInfo->Index[j])); - if (skillId != SKILL_NONE) + if ( skillId != SKILL_NONE ) { // skill bonus provided by casting spell (mostly item spells) // add the damage modifier from the spell casted (cheat lock / skeleton key etc.) (use m_currentBasePoints, CalculateDamage returns wrong value) @@ -6562,7 +6579,7 @@ SpellCastResult Spell::CanOpenLock(uint32 effIndex, uint32 lockId, SkillType& sk } } - if (reqKey) + if(reqKey) return SPELL_FAILED_BAD_TARGETS; return SPELL_CAST_OK; diff --git a/src/game/Spell.h b/src/game/Spell.h index 85d8c46771e..dc640438032 100644 --- a/src/game/Spell.h +++ b/src/game/Spell.h @@ -77,7 +77,8 @@ enum SpellCastFlags CAST_FLAG_UNKNOWN10 = 0x00040000, CAST_FLAG_UNKNOWN5 = 0x00080000, // wotlk CAST_FLAG_UNKNOWN20 = 0x00100000, - CAST_FLAG_UNKNOWN7 = 0x00200000 // wotlk, rune cooldown list + CAST_FLAG_UNKNOWN7 = 0x00200000, // wotlk, rune cooldown list + CAST_FLAG_UNKNOWN21 = 0x04000000 }; enum SpellRangeFlag @@ -362,6 +363,7 @@ class Spell void EffectPlayMusic(uint32 i); void EffectSpecCount(uint32 i); void EffectActivateSpec(uint32 i); + void EffectCastButtons(uint32 i); typedef std::set<Aura *> UsedSpellMods; @@ -732,11 +734,11 @@ namespace Trinity i_data->push_back(target); break; case PUSH_IN_FRONT: - if(i_source->isInFrontInMap(target, i_radius, M_PI/3)) + if(i_source->isInFront(target, i_radius, M_PI/3)) i_data->push_back(target); break; case PUSH_IN_BACK: - if(i_source->isInBackInMap(target, i_radius, M_PI/3)) + if(i_source->isInBack(target, i_radius, M_PI/3)) i_data->push_back(target); break; case PUSH_IN_LINE: @@ -780,4 +782,3 @@ class SpellEvent : public BasicEvent Spell* m_Spell; }; #endif - diff --git a/src/game/SpellAuraDefines.h b/src/game/SpellAuraDefines.h index fb840620397..633a81bf362 100644 --- a/src/game/SpellAuraDefines.h +++ b/src/game/SpellAuraDefines.h @@ -318,7 +318,7 @@ enum AuraType SPELL_AURA_MOD_ABILITY_IGNORE_TARGET_RESIST = 270, // Possibly need swap vs 195 aura used only in 1 spell Chaos Bolt Passive SPELL_AURA_MOD_DAMAGE_FROM_CASTER = 271, SPELL_AURA_272 = 272, - SPELL_AURA_273 = 273, + SPELL_AURA_X_RAY = 273, SPELL_AURA_ABILITY_CONSUME_NO_AMMO = 274, SPELL_AURA_MOD_IGNORE_SHAPESHIFT = 275, SPELL_AURA_276 = 276, // Only "Test Mod Damage % Mechanic" spell, possible mod damage done @@ -332,15 +332,27 @@ enum AuraType SPELL_AURA_LINKED = 284, SPELL_AURA_MOD_ATTACK_POWER_OF_ARMOR = 285, SPELL_AURA_ABILITY_PERIODIC_CRIT = 286, - SPELL_AURA_DEFLECT_SPELLS, - SPELL_AURA_IGNORE_HIT_DIRECTION, - SPELL_AURA_289, - SPELL_AURA_MOD_CRIT_PCT, - SPELL_AURA_MOD_XP_QUEST_PCT, - SPELL_AURA_292, - SPELL_AURA_293, - SPELL_AURA_PREVENT_REGENERATE_POWER, - TOTAL_AURAS = 295 + SPELL_AURA_DEFLECT_SPELLS = 287, + SPELL_AURA_IGNORE_HIT_DIRECTION = 288, + SPELL_AURA_289 = 289, + SPELL_AURA_MOD_CRIT_PCT = 290, + SPELL_AURA_MOD_XP_QUEST_PCT = 291, + SPELL_AURA_292 = 292, + SPELL_AURA_293 = 293, + SPELL_AURA_PREVENT_REGENERATE_POWER = 294, + SPELL_AURA_295 = 295, + SPELL_AURA_296 = 296, + SPELL_AURA_297 = 297, + SPELL_AURA_298 = 298, + SPELL_AURA_299 = 299, + SPELL_AURA_300 = 300, + SPELL_AURA_301 = 301, + SPELL_AURA_302 = 302, + SPELL_AURA_303 = 303, + SPELL_AURA_304 = 304, + SPELL_AURA_MOD_MINIMUM_SPEED = 305, + SPELL_AURA_306 = 306, + TOTAL_AURAS = 307 }; enum AreaAuraType @@ -353,4 +365,3 @@ enum AreaAuraType AREA_AURA_OWNER }; #endif - diff --git a/src/game/SpellAuras.cpp b/src/game/SpellAuras.cpp index f4df205e7e2..7f54d5ad294 100644 --- a/src/game/SpellAuras.cpp +++ b/src/game/SpellAuras.cpp @@ -122,7 +122,7 @@ pAuraHandler AuraHandler[TOTAL_AURAS]= &Aura::HandleFeignDeath, // 66 SPELL_AURA_FEIGN_DEATH &Aura::HandleAuraModDisarm, // 67 SPELL_AURA_MOD_DISARM &Aura::HandleAuraModStalked, // 68 SPELL_AURA_MOD_STALKED - &Aura::HandleNoImmediateEffect, // 69 SPELL_AURA_SCHOOL_ABSORB implemented in Unit::CalcAbsorbResist + &Aura::HandleSchoolAbsorb, // 69 SPELL_AURA_SCHOOL_ABSORB implemented in Unit::CalcAbsorbResist &Aura::HandleUnused, // 70 SPELL_AURA_EXTRA_ATTACKS Useless, used by only one spell that has only visual effect &Aura::HandleModSpellCritChanceShool, // 71 SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL &Aura::HandleModPowerCostPCT, // 72 SPELL_AURA_MOD_POWER_COST_SCHOOL_PCT @@ -258,7 +258,7 @@ pAuraHandler AuraHandler[TOTAL_AURAS]= &Aura::HandleNoImmediateEffect, //202 SPELL_AURA_CANNOT_BE_DODGED implemented in Unit::RollPhysicalOutcomeAgainst &Aura::HandleNoImmediateEffect, //203 SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_DAMAGE implemented in Unit::CalculateMeleeDamage and Unit::CalculateSpellDamage &Aura::HandleNoImmediateEffect, //204 SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_DAMAGE implemented in Unit::CalculateMeleeDamage and Unit::CalculateSpellDamage - &Aura::HandleNULL, //205 SPELL_AURA_MOD_SCHOOL_CRIT_DMG_TAKEN + &Aura::HandleNoImmediateEffect, //205 SPELL_AURA_MOD_SCHOOL_CRIT_DMG_TAKEN &Aura::HandleAuraModIncreaseFlightSpeed, //206 SPELL_AURA_MOD_INCREASE_VEHICLE_FLIGHT_SPEED &Aura::HandleAuraModIncreaseFlightSpeed, //207 SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED &Aura::HandleAuraModIncreaseFlightSpeed, //208 SPELL_AURA_MOD_INCREASE_FLIGHT_SPEED @@ -326,7 +326,7 @@ pAuraHandler AuraHandler[TOTAL_AURAS]= &Aura::HandleNoImmediateEffect, //270 SPELL_AURA_MOD_ABILITY_IGNORE_TARGET_RESIST implemented in Unit::CalcAbsorbResist and CalcArmorReducedDamage &Aura::HandleNoImmediateEffect, //271 SPELL_AURA_MOD_DAMAGE_FROM_CASTER implemented in Unit::SpellDamageBonus &Aura::HandleNULL, //272 unknown - &Aura::HandleUnused, //273 clientside + &Aura::HandleNoImmediateEffect, //273 SPELL_AURA_X_RAY (client side implementation) &Aura::HandleNoImmediateEffect, //274 SPELL_AURA_CONSUME_NO_AMMO implemented in spell::CalculateDamageDoneForAllTargets &Aura::HandleNoImmediateEffect, //275 SPELL_AURA_MOD_IGNORE_SHAPESHIFT Use SpellClassMask for spell select &Aura::HandleNULL, //276 mod damage % mechanic? @@ -337,17 +337,29 @@ pAuraHandler AuraHandler[TOTAL_AURAS]= &Aura::HandleNoImmediateEffect, //281 SPELL_AURA_MOD_HONOR_GAIN_PCT implemented in Player::RewardHonor &Aura::HandleAuraIncreaseBaseHealthPercent, //282 SPELL_AURA_INCREASE_BASE_HEALTH_PERCENT &Aura::HandleNoImmediateEffect, //283 SPELL_AURA_MOD_HEALING_RECEIVED implemented in Unit::SpellHealingBonus - &Aura::HandleAuraLinked, //284 SPELL_AURA_LINKED + &Aura::HandleAuraLinked, //284 SPELL_AURA_LINKED 51 spells using &Aura::HandleAuraModAttackPowerOfArmor, //285 SPELL_AURA_MOD_ATTACK_POWER_OF_ARMOR implemented in Player::UpdateAttackPowerAndDamage &Aura::HandleNoImmediateEffect, //286 SPELL_AURA_ABILITY_PERIODIC_CRIT implemented in AuraEffect::PeriodicTick &Aura::HandleNoImmediateEffect, //287 SPELL_AURA_DEFLECT_SPELLS implemented in Unit::MagicSpellHitResult and Unit::MeleeSpellHitResult - &Aura::HandleNoImmediateEffect, //288 SPELL_AURA_IGNORE_HIT_DIRECTION implemented in Unit::MagicSpellHitResult and Unit::MeleeSpellHitResult Unit::RollMeleeOutcomeAgainst + &Aura::HandleNoImmediateEffect, //288 SPELL_AURA_IGNORE_HIT_DIRECTION implemented in Unit::MagicSpellHitResult and Unit::MeleeSpellHitResult Unit::RollMeleeOutcomeAgainst &Aura::HandleNULL, //289 unused &Aura::HandleAuraModCritPct, //290 SPELL_AURA_MOD_CRIT_PCT &Aura::HandleNoImmediateEffect, //291 SPELL_AURA_MOD_XP_QUEST_PCT implemented in Player::RewardQuest &Aura::HandleNULL, //292 call stabled pet &Aura::HandleNULL, //293 2 test spells - &Aura::HandleNoImmediateEffect //294 SPELL_AURA_PREVENT_REGENERATE_POWER implemented in Player::Regenerate(Powers power) + &Aura::HandleNoImmediateEffect, //294 SPELL_AURA_PREVENT_REGENERATE_POWER implemented in Player::Regenerate(Powers power) + &Aura::HandleNULL, //295 unused + &Aura::HandleNULL, //296 2 spells + &Aura::HandleNULL, //297 1 spell (counter spell school?) + &Aura::HandleNULL, //298 unused + &Aura::HandleNULL, //299 unused + &Aura::HandleNULL, //300 3 spells (share damage?) + &Aura::HandleNULL, //301 5 spells + &Aura::HandleNULL, //302 unused + &Aura::HandleNULL, //303 17 spells + &Aura::HandleNULL, //304 2 spells (alcohol effect?) + &Aura::HandleAuraModIncreaseSpeed, //305 SPELL_AURA_MOD_MINIMUM_SPEED + &Aura::HandleNULL //306 1 spell }; #undef Aura @@ -931,6 +943,131 @@ void AuraEffect::CleanupTriggeredSpells() m_target->RemoveAurasDueToSpell(tSpellId, GetCasterGUID()); } +void AuraEffect::HandleSchoolAbsorb(bool apply, bool Real, bool changeAmount) +{ + if(!Real) + return; + + Unit* caster = GetCaster(); + if(!caster) + return; + + if (apply) + { + // prevent double apply bonuses + if (m_target->GetTypeId()!=TYPEID_PLAYER || !((Player*)m_target)->GetSession()->PlayerLoading()) + { + float DoneActualBenefit = 0.0f; + switch(m_spellProto->SpellFamilyName) + { + case SPELLFAMILY_PRIEST: + // Power Word: Shield + if (m_spellProto->SpellFamilyFlags & UI64LIT(0x0000000000000001)) + //+80.68% from +spell bonus + DoneActualBenefit = caster->SpellBaseHealingBonus(GetSpellSchoolMask(m_spellProto)) * 0.8068f; + break; + case SPELLFAMILY_MAGE: + // Frost Ward, Fire Ward + if (m_spellProto->SpellFamilyFlags & UI64LIT(0x0000000000000108)) + //+10% from +spell bonus + DoneActualBenefit = caster->SpellBaseDamageBonus(GetSpellSchoolMask(m_spellProto)) * 0.1f; + // Ice Barrier + else if (m_spellProto->SpellFamilyFlags & UI64LIT(0x0000000100000000)) + //+80.67% from +spell bonus + DoneActualBenefit = caster->SpellBaseDamageBonus(GetSpellSchoolMask(m_spellProto)) * 0.8067f; + break; + case SPELLFAMILY_WARLOCK: + // Shadow Ward + if (m_spellProto->SpellIconID == 207) + //+30% from +spell bonus + DoneActualBenefit = caster->SpellBaseDamageBonus(GetSpellSchoolMask(m_spellProto)) * 0.30f; + break; + case SPELLFAMILY_PALADIN: + // Sacred Shield + // (check not strictly needed, only Sacred Shield has SPELL_AURA_SCHOOL_ABSORB in SPELLFAMILY_PALADIN at this time) + if (m_spellProto->SpellFamilyFlags & UI64LIT(0x0008000000000000)) + { + // +75% from spell power + DoneActualBenefit = caster->SpellBaseHealingBonus(GetSpellSchoolMask(m_spellProto)) * 0.75f; + } + break; + default: + break; + } + + DoneActualBenefit *= caster->CalculateLevelPenalty(GetSpellProto()); + + m_amount += (int32)DoneActualBenefit; + } + } + else + { + if (caster && + // Power Word: Shield + m_spellProto->SpellFamilyName == SPELLFAMILY_PRIEST && m_spellProto->Mechanic == MECHANIC_SHIELD && + (m_spellProto->SpellFamilyFlags & UI64LIT(0x0000000000000001)) && + // completely absorbed or dispelled + ((m_parentAura->GetRemoveMode() == AURA_REMOVE_BY_DEFAULT && m_amount) || m_parentAura->GetRemoveMode() == AURA_REMOVE_BY_EXPIRE)) + { + Unit::AuraEffectList const& vDummyAuras = caster->GetAurasByType(SPELL_AURA_DUMMY); + for(Unit::AuraEffectList::const_iterator itr = vDummyAuras.begin(); itr != vDummyAuras.end(); ++itr) + { + SpellEntry const* vSpell = (*itr)->GetSpellProto(); + + // Rapture (main spell) + if(vSpell->SpellFamilyName == SPELLFAMILY_PRIEST && vSpell->SpellIconID == 2894 && vSpell->Effect[1]) + { + switch((*itr)->m_effIndex) + { + case 0: + { + // energize caster + int32 manapct1000 = 5 * ((*itr)->m_amount + spellmgr.GetSpellRank(vSpell->Id)); + int32 basepoints0 = caster->GetMaxPower(POWER_MANA) * manapct1000 / 1000; + caster->CastCustomSpell(caster, 47755, &basepoints0, NULL, NULL, true); + break; + } + case 1: + { + // energize target + if (!roll_chance_i((*itr)->m_amount) || caster->HasAura(63853)) + break; + + switch(m_target->getPowerType()) + { + case POWER_RUNIC_POWER: + m_target->CastSpell(m_target, 63652, true, NULL, NULL, GetCasterGUID()); + break; + case POWER_RAGE: + m_target->CastSpell(m_target, 63653, true, NULL, NULL, GetCasterGUID()); + break; + case POWER_MANA: + { + int32 basepoints0 = m_target->GetMaxPower(POWER_MANA) * 2 / 100; + m_target->CastCustomSpell(m_target, 63654, &basepoints0, NULL, NULL, true); + break; + } + case POWER_ENERGY: + m_target->CastSpell(m_target, 63655, true, NULL, NULL, GetCasterGUID()); + break; + default: + break; + } + + //cooldwon aura + caster->CastSpell(caster, 63853, true); + break; + } + default: + sLog.outError("Changes in R-dummy spell???: effect 3"); + break; + } + } + } + } + } +} + void Aura::ApplyAllModifiers(bool apply, bool Real) { for (uint8 i = 0; i<MAX_SPELL_EFFECTS; ++i) @@ -1504,6 +1641,9 @@ void AuraEffect::HandleAuraEffectSpecificMods(bool apply, bool Real, bool change // Innervate else if (m_spellProto->Id == 29166 && GetAuraName() == SPELL_AURA_PERIODIC_ENERGIZE) m_amount = m_target->GetCreatePowers(POWER_MANA) * m_amount / (GetTotalTicks() * 100.0f); + // Owlkin Frenzy + else if (m_spellProto->Id == 48391) + m_amount = m_target->GetCreatePowers(POWER_MANA) * 2 / 100; // Thorns else if (m_spellProto->SpellFamilyFlags[0] & 0x100 && GetAuraName() == SPELL_AURA_DAMAGE_SHIELD) // 3.3% from sp bonus @@ -1534,7 +1674,13 @@ void AuraEffect::HandleAuraEffectSpecificMods(bool apply, bool Real, bool change if (m_spellProto->SpellFamilyFlags[1] & 0x80000 && GetAuraName() == SPELL_AURA_SCHOOL_ABSORB) { // 0.75 from sp bonus - DoneActualBenefit = caster->SpellBaseHealingBonus(GetSpellSchoolMask(m_spellProto)) * 0.75f; + float koef = 1.0f; + if (caster->HasAura(53527)) + koef = 1.1f; + if (caster->HasAura(53530)) + koef = 1.2f; + + DoneActualBenefit = caster->SpellBaseHealingBonus(GetSpellSchoolMask(m_spellProto)) * 0.75f * koef; } break; case SPELLFAMILY_SHAMAN: @@ -1579,26 +1725,6 @@ void AuraEffect::HandleAuraEffectSpecificMods(bool apply, bool Real, bool change DoneActualBenefit *= caster->CalculateLevelPenalty(GetSpellProto()); m_amount += (int32)DoneActualBenefit; } - - // we have exact amount now so apply mods affecting all boni - switch (m_spellProto->SpellFamilyName) - { - case SPELLFAMILY_PRIEST: - // Glyph of Power Word: Shield - if (m_spellProto->SpellFamilyFlags[0] & 0x1 && m_spellProto->SpellFamilyFlags[2] & 0x400 && - GetAuraName() == SPELL_AURA_SCHOOL_ABSORB) - { - if (AuraEffect* glyph = caster->GetAuraEffect(55672,0)) - { - // instantly heal m_amount% of the absorb-value - int32 heal = (glyph->GetAmount() * m_amount)/100; - caster->CastCustomSpell(m_target, 56160, &heal, NULL, NULL, true, 0, this); - } - } - break; - default: - break; - } } } } @@ -2079,8 +2205,10 @@ void AuraEffect::HandleShapeshiftBoosts(bool apply) case FORM_SHADOW: spellId = 49868; break; - case FORM_GHOUL: case FORM_GHOSTWOLF: + spellId = 67116; + break; + case FORM_GHOUL: case FORM_AMBIENT: case FORM_STEALTH: case FORM_CREATURECAT: @@ -2287,7 +2415,6 @@ void AuraEffect::HandleAddModifier(bool apply, bool Real, bool changeAmount) mod->value = m_amount; mod->type = SpellModType(m_auraName); // SpellModType value == spell aura types mod->spellId = GetId(); - mod->mask = m_spellProto->EffectSpellClassMask[m_effIndex]; mod->charges = GetParentAura()->GetAuraCharges(); @@ -2922,7 +3049,7 @@ void AuraEffect::HandleAuraDummy(bool apply, bool Real, bool changeAmount) { if (m_target->GetMap()->IsDungeon()) { - uint32 spellId = m_target->GetMap()->IsHeroic() ? 46163 : 44190; + uint32 spellId = ((InstanceMap*)m_target->GetMap())->GetDifficulty() == REGULAR_DIFFICULTY ? 44190 : 46163; m_target->CastSpell(m_target, spellId, true, NULL, this); } @@ -2959,6 +3086,30 @@ void AuraEffect::HandleAuraDummy(bool apply, bool Real, bool changeAmount) return; } break; + case SPELLFAMILY_PALADIN: + switch (GetSpellProto()->SpellIconID) + { + // Blessing of Sanctuary + // Greater Blessing of Sanctuary + case 19: + case 1804: + { + if (!caster || !m_target) + return; + + if (apply) + { + // Greater Blessing of Sanctuary does not provide strength bonus + int32 bp1 = 0; + caster->CastCustomSpell(m_target, 67480, NULL, (GetSpellProto()->SpellIconID == 1804) ? &bp1 : NULL, NULL, true); + } + else + m_target->RemoveAurasDueToSpell(67480); + + return; + } + } + break; case SPELLFAMILY_PRIEST: // Vampiric Touch if (m_spellProto->SpellFamilyFlags[1] & 0x0400 && GetParentAura()->GetRemoveMode() == AURA_REMOVE_BY_ENEMY_SPELL) @@ -3371,7 +3522,30 @@ void AuraEffect::HandleAuraFeatherFall(bool apply, bool Real, bool /*changeAmoun WorldPacket data; if (apply) + { + Unit* caster = GetCaster(); + if (!caster) + return; + + if (caster->GetGUID() == m_target->GetGUID()) + { + m_target->RemoveAurasByType(SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED); + m_target->RemoveAurasByType(SPELL_AURA_FLY); + } + + if (GetId() == 61243) // No fly zone - Parachute + { + float x, y, z; + caster->GetPosition(x, y, z); + float ground_Z = caster->GetMap()->GetVmapHeight(x, y, z, true); + if (fabs(ground_Z - z) < 0.1f) + { + m_target->RemoveAura(GetId()); + return; + } + } data.Initialize(SMSG_MOVE_FEATHER_FALL, 8+4); + } else data.Initialize(SMSG_MOVE_NORMAL_FALL, 8+4); data.append(m_target->GetPackGUID()); @@ -3417,89 +3591,37 @@ void AuraEffect::HandleAuraModShapeshift(bool apply, bool Real, bool changeAmoun switch(form) { case FORM_CAT: - if(Player::TeamForRace(m_target->getRace())==ALLIANCE) - modelid = 892; - else - modelid = 8571; - PowerType = POWER_ENERGY; - break; - case FORM_TRAVEL: - modelid = 632; - break; - case FORM_AQUA: - if(Player::TeamForRace(m_target->getRace())==ALLIANCE) - modelid = 2428; - else - modelid = 2428; - break; - case FORM_BEAR: - if(Player::TeamForRace(m_target->getRace())==ALLIANCE) - modelid = 2281; - else - modelid = 2289; - PowerType = POWER_RAGE; - break; case FORM_GHOUL: - modelid = 24994; PowerType = POWER_ENERGY; break; + case FORM_BEAR: case FORM_DIREBEAR: - if(Player::TeamForRace(m_target->getRace())==ALLIANCE) - modelid = 2281; - else - modelid = 2289; + case FORM_BATTLESTANCE: + case FORM_BERSERKERSTANCE: + case FORM_DEFENSIVESTANCE: PowerType = POWER_RAGE; break; + case FORM_TRAVEL: + case FORM_AQUA: case FORM_CREATUREBEAR: - modelid = 902; - break; case FORM_GHOSTWOLF: - modelid = 4613; - break; case FORM_FLIGHT: - if(Player::TeamForRace(m_target->getRace())==ALLIANCE) - modelid = 20857; - else - modelid = 20872; - break; case FORM_MOONKIN: - if(Player::TeamForRace(m_target->getRace())==ALLIANCE) - modelid = 15374; - else - modelid = 15375; - break; case FORM_FLIGHT_EPIC: - if(Player::TeamForRace(m_target->getRace())==ALLIANCE) - modelid = 21243; - else - modelid = 21244; - break; - case FORM_MASTER_ANGLER: - modelid = 15234; - break; case FORM_METAMORPHOSIS: - modelid = 25277; - break; + case FORM_MASTER_ANGLER: case FORM_AMBIENT: case FORM_SHADOW: case FORM_STEALTH: case FORM_UNDEAD: case FORM_SHADOW_DANCE: - break; case FORM_TREE: - modelid = 864; - break; - case FORM_BATTLESTANCE: - case FORM_BERSERKERSTANCE: - case FORM_DEFENSIVESTANCE: - PowerType = POWER_RAGE; - break; case FORM_SPIRITOFREDEMPTION: - modelid = 16031; break; default: sLog.outError("Auras: Unknown Shapeshift Type: %u", GetMiscValue()); } + modelid = m_target->GetModelForForm(form); // remove polymorph before changing display id to keep new display id switch ( form ) @@ -3566,7 +3688,10 @@ void AuraEffect::HandleAuraModShapeshift(bool apply, bool Real, bool changeAmoun case FORM_BEAR: case FORM_DIREBEAR: if (urand(0,99) < FurorChance) - m_target->CastSpell(m_target, 17057, true); + { + int32 basePoints = 100; // Not sure if 100 is correct basePoints, maybe it should be 10? + m_target->CastCustomSpell(m_target, 17057, &basePoints, NULL, NULL, true, NULL, this); + } default: { uint32 newEnergy = std::min(m_target->GetPower(POWER_ENERGY), FurorChance); @@ -4632,21 +4757,26 @@ void AuraEffect::HandleAuraModStalked(bool apply, bool Real, bool /*changeAmount void AuraEffect::HandlePeriodicTriggerSpell(bool apply, bool Real, bool /*changeAmount*/) { m_isPeriodic = apply; + if (!apply) + { + switch(m_spellProto->Id) + { + case 66: // Invisibility + m_target->CastSpell(m_target, 32612, true, NULL, this); + + return; + case 42783: //Wrath of the Astrom... + m_target->CastSpell(m_target, m_spellProto->CalculateSimpleValue(GetEffIndex()+1), true); + return; + default: + break; + } + } } void AuraEffect::HandlePeriodicTriggerSpellWithValue(bool apply, bool Real, bool /*changeAmount*/) { m_isPeriodic = apply; - - SpellEntry const* spell = GetSpellProto(); - switch (spell->Id) - { - case 58730: // No fly zone - Wintergrasp (3.1.3 only 3.2.2 Does not call this aura) - if (apply) - if (m_target->GetTypeId() == TYPEID_PLAYER) - ((Player *)m_target)->GetSession()->SendNotification(LANG_ZONE_NOFLYZONE); - break; - } } void AuraEffect::HandlePeriodicEnergize(bool apply, bool Real, bool changeAmount) @@ -4668,30 +4798,22 @@ void AuraEffect::HandleAuraPeriodicDummy(bool apply, bool Real, bool changeAmoun Unit* caster = GetCaster(); SpellEntry const*spell = GetSpellProto(); - switch(spell->SpellFamilyName) + switch( spell->SpellFamilyName) { case SPELLFAMILY_GENERIC: { - switch(spell->Id) + if(spell->Id == 62399) // Overload Circuit { - case 62399: // Overload Circuit - if(m_target->GetMap()->IsDungeon() && m_target->GetAuras().count(62399) >= (m_target->GetMap()->IsHeroic() ? 4 : 2)) - { - m_target->CastSpell(m_target, 62475, true); // System Shutdown - if(Unit *veh = m_target->GetVehicleBase()) - veh->CastSpell(m_target, 62475, true); - } - break; - case 58600: // No fly zone - Dalaran - if (apply && m_target->GetTypeId() == TYPEID_PLAYER) - ((Player *)m_target)->GetSession()->SendNotification(LANG_ZONE_NOFLYZONE); - break; - default: - break; + if(m_target->GetMap()->IsDungeon()) + if(m_target->GetAuras().count(62399) >= (((InstanceMap*)m_target->GetMap())->GetDifficulty() == REGULAR_DIFFICULTY ? 2 : 4)) + { + m_target->CastSpell(m_target, 62475, true); // System Shutdown + if(Unit *veh = m_target->GetVehicleBase()) + veh->CastSpell(m_target, 62475, true); + } } break; } - case SPELLFAMILY_WARLOCK: { switch (spell->Id) @@ -4704,12 +4826,11 @@ void AuraEffect::HandleAuraPeriodicDummy(bool apply, bool Real, bool changeAmoun // to prevent remove GO added by new spell // old one is already removed if (GetParentAura()->GetRemoveMode()!=AURA_REMOVE_BY_STACK) - m_target->RemoveGameObject(spell->Id, true); + m_target->RemoveGameObject(spell->Id,true); m_target->RemoveAura(62388); } break; } - break; } case SPELLFAMILY_DEATHKNIGHT: { @@ -5934,11 +6055,10 @@ void AuraEffect::PeriodicTick() bool crit = IsPeriodicTickCrit(pCaster); if (crit) pdamage = pCaster->SpellCriticalDamageBonus(m_spellProto, pdamage, m_target); - - //As of 2.2 resilience reduces damage from DoT ticks as much as the chance to not be critically hit - // Reduce dot damage from resilience for players + + // Reduce dot damage from resilience for players. if (m_target->GetTypeId() == TYPEID_PLAYER) - pdamage-=((Player*)m_target)->GetDotDamageReduction(pdamage); + pdamage-=((Player*)m_target)->GetSpellDamageReduction(pdamage); pCaster->CalcAbsorbResist(m_target, GetSpellSchoolMask(GetSpellProto()), DOT, pdamage, &absorb, &resist, m_spellProto); @@ -6006,11 +6126,10 @@ void AuraEffect::PeriodicTick() cleanDamage.mitigated_damage += pdamage - pdamageReductedArmor; pdamage = pdamageReductedArmor; } - - //As of 2.2 resilience reduces damage from DoT ticks as much as the chance to not be critically hit - // Reduce dot damage from resilience for players + + // Reduce dot damage from resilience for players. if (m_target->GetTypeId() == TYPEID_PLAYER) - pdamage-=((Player*)m_target)->GetDotDamageReduction(pdamage); + pdamage-=((Player*)m_target)->GetSpellDamageReduction(pdamage); pCaster->CalcAbsorbResist(m_target, GetSpellSchoolMask(GetSpellProto()), DOT, pdamage, &absorb, &resist, m_spellProto); @@ -6566,24 +6685,6 @@ void AuraEffect::PeriodicDummyTick() // 7053 Forsaken Skill: Shadow return; } - case 45472: // Parachute - if (m_target->GetTypeId() == TYPEID_PLAYER) - { - Player *plr = (Player*)m_target; - if (plr->IsFalling()) - { - plr->RemoveAurasDueToSpell(45472); - plr->CastSpell(plr, 44795, true); - } - } - break; - case 58600: // No fly Zone - Dalaran - if (10 == m_tickNumber) - { - m_target->RemoveAurasByType(SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED); - m_target->RemoveAurasByType(SPELL_AURA_FLY); - } - break; case 58549: // Tenacity case 59911: // Tenacity (vehicle) GetParentAura()->RefreshAura(); diff --git a/src/game/SpellAuras.h b/src/game/SpellAuras.h index 3730107461a..9fdff04f05f 100644 --- a/src/game/SpellAuras.h +++ b/src/game/SpellAuras.h @@ -321,6 +321,7 @@ class TRINITY_DLL_SPEC AuraEffect void HandleForceMoveForward(bool apply, bool Real, bool changeAmount); void HandleAuraModResistenceOfStatPercent(bool apply, bool Real, bool changeAmount); void HandleAuraPowerBurn(bool apply, bool Real, bool changeAmount); + void HandleSchoolAbsorb(bool apply, bool Real, bool changeAmount); void HandlePreventFleeing(bool apply, bool Real, bool changeAmount); void HandleArenaPreparation(bool apply, bool Real, bool changeAmount); void HandleAuraConvertRune(bool apply, bool Real, bool changeAmount); diff --git a/src/game/SpellEffects.cpp b/src/game/SpellEffects.cpp index 3f90a52c7df..c3a633c5ffc 100644 --- a/src/game/SpellEffects.cpp +++ b/src/game/SpellEffects.cpp @@ -161,7 +161,7 @@ pEffect SpellEffects[TOTAL_SPELL_EFFECTS]= &Spell::EffectSelfResurrect, // 94 SPELL_EFFECT_SELF_RESURRECT &Spell::EffectSkinning, // 95 SPELL_EFFECT_SKINNING &Spell::EffectCharge, // 96 SPELL_EFFECT_CHARGE - &Spell::EffectUnused, // 97 SPELL_EFFECT_97 + &Spell::EffectCastButtons, // 97 SPELL_EFFECT_CAST_BUTTON (totem bar since 3.2.2a) &Spell::EffectKnockBack, // 98 SPELL_EFFECT_KNOCK_BACK &Spell::EffectDisEnchant, // 99 SPELL_EFFECT_DISENCHANT &Spell::EffectInebriate, //100 SPELL_EFFECT_INEBRIATE @@ -377,7 +377,7 @@ void Spell::SpellDamageSchoolDmg(uint32 effect_idx) break; // Consumption case 28865: - damage = (m_caster->GetMap()->IsHeroic() ? 4250 : 2750); + damage = (((InstanceMap*)m_caster->GetMap())->GetDifficulty() == REGULAR_DIFFICULTY ? 2750 : 4250); break; // percent from health with min case 25599: // Thundercrash @@ -420,8 +420,7 @@ void Spell::SpellDamageSchoolDmg(uint32 effect_idx) damage = unitTarget->GetMaxHealth() / 10; break; } - // Gargoyle Strike - case 51963: + case 51963: // Gargoyle Strike { // about +4 base spell dmg per level damage = (m_caster->getLevel() - 60) * 4 + 60; @@ -535,7 +534,23 @@ void Spell::SpellDamageSchoolDmg(uint32 effect_idx) if (unitTarget->GetAura(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_PRIEST, 0x100000, 0, 0, m_caster->GetGUID())) damage += damage * aurEff->GetAmount() / 100; } - + // Improved Mind Blast (Mind Blast in shadow form bonus) + else if (m_caster->m_form == FORM_SHADOW && (m_spellInfo->SpellFamilyFlags[0] & 0x00002000)) + { + Unit::AuraEffectList const& ImprMindBlast = m_caster->GetAurasByType(SPELL_AURA_ADD_FLAT_MODIFIER); + for(Unit::AuraEffectList::const_iterator i = ImprMindBlast.begin(); i != ImprMindBlast.end(); ++i) + { + if ((*i)->GetSpellProto()->SpellFamilyName == SPELLFAMILY_PRIEST && + ((*i)->GetSpellProto()->SpellIconID == 95)) + { + int chance = (*i)->GetSpellProto()->CalculateSimpleValue(1); + if (roll_chance_i(chance)) + // Mind Trauma + m_caster->CastSpell(unitTarget, 48301, true, 0); + break; + } + } + } break; } case SPELLFAMILY_DRUID: @@ -687,12 +702,12 @@ void Spell::SpellDamageSchoolDmg(uint32 effect_idx) damage += int32(0.25f*ap + 0.4f*sp); } // Judgement of Wisdom, Light, Justice - else if (m_spellInfo->SpellFamilyFlags[0] & 0x00800000 && m_spellInfo->Id != 31804 && m_spellInfo->Id != 53733) + else if(m_spellInfo->Id == 54158) { float ap = m_caster->GetTotalAttackPowerValue(BASE_ATTACK); float sp = m_caster->SpellBaseDamageBonus(GetSpellSchoolMask(m_spellInfo)); damage += int32(0.16f*ap + 0.25f*sp); - } + } break; } case SPELLFAMILY_DEATHKNIGHT: @@ -850,6 +865,22 @@ void Spell::EffectDummy(uint32 i) m_caster->CastSpell(unitTarget,spell_id,true,NULL); return; } + case 67019: // Flask of the North + { + if (m_caster->GetTypeId() != TYPEID_PLAYER) + return; + + uint32 spell_id; + switch(urand(1, 3)) + { + case 1: spell_id = 67016; break; + case 2: spell_id = 67017; break; + default:spell_id = 67018; break; + } + + m_caster->CastSpell(m_caster, spell_id, true, NULL); + return; + } case 13280: // Gnomish Death Ray { if (!unitTarget) @@ -945,10 +976,6 @@ void Spell::EffectDummy(uint32 i) creatureTarget->ForcedDespawn(); - WorldPacket data(SMSG_GAMEOBJECT_SPAWN_ANIM_OBSOLETE, 8); - data << uint64(Crystal_Prison->GetGUID()); - m_caster->SendMessageToSet(&data, true); - return; } case 23074: // Arcanite Dragonling @@ -1351,16 +1378,28 @@ void Spell::EffectDummy(uint32 i) m_caster->CastSpell(m_caster, 54586, true); return; } + // Great Feast + case 57337: + { + if (!unitTarget) + return; + + unitTarget->CastSpell(unitTarget, 58067, true); + break; + } + //Fish Feast + case 57397: + { + if (!unitTarget) + return; + + unitTarget->CastSpell(unitTarget, 58648, true); + unitTarget->CastSpell(unitTarget, 57398, true); + break; + } case 58418: // Portal to Orgrimmar case 58420: // Portal to Stormwind return; // implemented in EffectScript[0] - case 58601: - if (Player *plr = (Player*)unitTarget) - { - plr->RemoveAurasByType(SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED); - plr->RemoveAurasByType(SPELL_AURA_FLY); - } - break; case 59640: // Underbelly Elixir { if(m_caster->GetTypeId() != TYPEID_PLAYER) @@ -1426,29 +1465,6 @@ void Spell::EffectDummy(uint32 i) } } - //All IconID Check in there - switch(m_spellInfo->SpellIconID) - { - // Berserking (troll racial traits) - case 1661: - { - uint32 healthPerc = uint32((float(m_caster->GetHealth())/m_caster->GetMaxHealth())*100); - int32 melee_mod = 10; - if (healthPerc <= 40) - melee_mod = 30; - if (healthPerc < 100 && healthPerc > 40) - melee_mod = 10+(100-healthPerc)/3; - - int32 hasteModBasePoints0 = melee_mod; // (EffectBasePoints[0]+1)-1+(5-melee_mod) = (melee_mod-1+1)-1+5-melee_mod = 5-1 - int32 hasteModBasePoints1 = (5-melee_mod); - int32 hasteModBasePoints2 = 5; - - // FIXME: custom spell required this aura state by some unknown reason, we not need remove it anyway - m_caster->ModifyAuraState(AURA_STATE_BERSERKING,true); - m_caster->CastCustomSpell(m_caster, 26635, &hasteModBasePoints0, &hasteModBasePoints1, &hasteModBasePoints2, true, NULL); - return; - } - } break; } case SPELLFAMILY_MAGE: @@ -1501,6 +1517,10 @@ void Spell::EffectDummy(uint32 i) { int32 chargeBasePoints0 = damage; m_caster->CastCustomSpell(m_caster, 34846, &chargeBasePoints0, NULL, NULL, true); + + //Juggernaut crit bonus + if(m_caster->HasAura(64976)) + m_caster->CastSpell(m_caster, 65156, true); return; } //Slam @@ -1533,8 +1553,8 @@ void Spell::EffectDummy(uint32 i) } else { - rage += m_caster->GetPower(POWER_RAGE); - m_caster->SetPower(POWER_RAGE,0); + rage += m_powerCost; + m_caster->ModifyPower(POWER_RAGE,- m_powerCost); } bp = damage+int32(rage * m_spellInfo->DmgMultiplier[i] + @@ -1629,9 +1649,9 @@ void Spell::EffectDummy(uint32 i) if (!unitTarget || !unitTarget->isAlive()) return; - uint32 hurt = 0; - uint32 heal = 0; - switch (m_spellInfo->Id) + int hurt = 0; + int heal = 0; + switch(m_spellInfo->Id) { case 47540: hurt = 47758; heal = 47757; break; case 53005: hurt = 53001; heal = 52986; break; @@ -1653,15 +1673,15 @@ void Spell::EffectDummy(uint32 i) if (m_spellInfo->SpellFamilyFlags[2] & 0x100) { //Shapeshifting into an animal form or mounting cancels the effect. - if (m_caster->GetCreatureType() == CREATURE_TYPE_BEAST || m_caster->IsMounted()) + if(m_caster->GetCreatureType() == CREATURE_TYPE_BEAST || m_caster->IsMounted()) { - if (m_triggeredByAuraSpell) + if(m_triggeredByAuraSpell) m_caster->RemoveAurasDueToSpell(m_triggeredByAuraSpell->Id); return; } //Any effect which causes you to lose control of your character will supress the starfall effect. - if (m_caster->hasUnitState(UNIT_STAT_STUNNED | UNIT_STAT_FLEEING | UNIT_STAT_ROOT | UNIT_STAT_CONFUSED)) + if(m_caster->hasUnitState(UNIT_STAT_STUNNED | UNIT_STAT_FLEEING | UNIT_STAT_ROOT | UNIT_STAT_CONFUSED)) return; m_caster->CastSpell(unitTarget, damage, true); @@ -1675,35 +1695,35 @@ void Spell::EffectDummy(uint32 i) m_caster->CastSpell(m_caster, 63848, true); break; } - switch(m_spellInfo->Id) + switch(m_spellInfo->Id ) { case 5938: // Shiv { - if (m_caster->GetTypeId() != TYPEID_PLAYER) + if(m_caster->GetTypeId() != TYPEID_PLAYER) return; Player *pCaster = ((Player*)m_caster); Item *item = pCaster->GetWeaponForAttack(OFF_ATTACK); - if (!item) + if(!item) return; // all poison enchantments is temporary uint32 enchant_id = item->GetEnchantmentId(TEMP_ENCHANTMENT_SLOT); - if (!enchant_id) + if(!enchant_id) return; SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id); - if (!pEnchant) + if(!pEnchant) return; - for (uint8 s = 0; s < 3; ++s) + for (int s=0; s<3; s++) { - if(pEnchant->type[s] != ITEM_ENCHANTMENT_TYPE_COMBAT_SPELL) + if(pEnchant->type[s]!=ITEM_ENCHANTMENT_TYPE_COMBAT_SPELL) continue; - SpellEntry const *combatEntry = sSpellStore.LookupEntry(pEnchant->spellid[s]); - if (!combatEntry || combatEntry->Dispel != DISPEL_POISON) + SpellEntry const* combatEntry = sSpellStore.LookupEntry(pEnchant->spellid[s]); + if(!combatEntry || combatEntry->Dispel != DISPEL_POISON) continue; m_caster->CastSpell(unitTarget, combatEntry, true, item); @@ -1714,7 +1734,7 @@ void Spell::EffectDummy(uint32 i) } case 14185: // Preparation { - if (m_caster->GetTypeId() != TYPEID_PLAYER) + if(m_caster->GetTypeId() != TYPEID_PLAYER) return; //immediately finishes the cooldown on certain Rogue abilities @@ -1738,14 +1758,21 @@ void Spell::EffectDummy(uint32 i) } break; case SPELLFAMILY_HUNTER: - switch (m_spellInfo->Id) + switch(m_spellInfo->Id) { case 781: // Disengage { - if (m_caster->GetTypeId() != TYPEID_PLAYER || !m_caster->isInCombat()) // Does not require a target, but m_caster must be in combat (3.0.3?) + if (m_caster->GetTypeId() != TYPEID_PLAYER) return; - m_caster->JumpTo(15.0f, 7.0f, false); + WorldPacket data(SMSG_MOVE_KNOCK_BACK, 50); + data.append(m_caster->GetPackGUID()); + data << getMSTime(); + data << float(cosf(m_caster->GetOrientation()+M_PI)); + data << float(sinf(m_caster->GetOrientation()+M_PI)); + data << float(15); + data << float(-7.0f); + ((Player*)m_caster)->GetSession()->SendPacket(&data); return; } case 23989: // Readiness talent @@ -1759,7 +1786,7 @@ void Spell::EffectDummy(uint32 i) { SpellEntry const *spellInfo = sSpellStore.LookupEntry(itr->first); - if (spellInfo->SpellFamilyName == SPELLFAMILY_HUNTER && spellInfo->Id != 23989 && GetSpellRecoveryTime(spellInfo) > 0) + if (spellInfo->SpellFamilyName == SPELLFAMILY_HUNTER && spellInfo->Id != 23989 && spellInfo->Id != 19574 && GetSpellRecoveryTime(spellInfo) > 0 ) ((Player*)m_caster)->RemoveSpellCooldown((itr++)->first,true); else ++itr; @@ -1812,10 +1839,10 @@ void Spell::EffectDummy(uint32 i) if (!unitTarget) return; - uint32 hurt = 0; - uint32 heal = 0; + int hurt = 0; + int heal = 0; - switch (m_spellInfo->Id) + switch(m_spellInfo->Id) { case 20473: hurt = 25912; heal = 25914; break; case 20929: hurt = 25911; heal = 25913; break; @@ -1825,7 +1852,7 @@ void Spell::EffectDummy(uint32 i) case 48824: hurt = 48822; heal = 48820; break; case 48825: hurt = 48823; heal = 48821; break; default: - sLog.outError("Spell::EffectDummy: Spell %u not handled in Holy Shock",m_spellInfo->Id); + sLog.outError("Spell::EffectDummy: Spell %u not handled in HS",m_spellInfo->Id); return; } @@ -1858,13 +1885,26 @@ void Spell::EffectDummy(uint32 i) } case 31789: // Righteous Defense (step 1) { + if (m_caster->GetTypeId() != TYPEID_PLAYER) + { + SendCastResult(SPELL_FAILED_TARGET_AFFECTING_COMBAT); + return; + } + // 31989 -> dummy effect (step 1) + dummy effect (step 2) -> 31709 (taunt like spell for each target) + Unit* friendTarget = !unitTarget || unitTarget->IsFriendlyTo(m_caster) ? unitTarget : unitTarget->getVictim(); + if (friendTarget) + { + Player* player = friendTarget->GetCharmerOrOwnerPlayerOrPlayerItself(); + if (!player || !player->IsInSameRaidWith((Player*)m_caster)) + friendTarget = NULL; + } + // non-standard cast requirement check - if (!unitTarget || unitTarget->getAttackers().empty()) + if (!friendTarget || friendTarget->getAttackers().empty()) { - if (m_caster->GetTypeId() == TYPEID_PLAYER) - ((Player*)m_caster)->RemoveSpellCooldown(m_spellInfo->Id,true); + ((Player*)m_caster)->RemoveSpellCooldown(m_spellInfo->Id,true); SendCastResult(SPELL_FAILED_TARGET_AFFECTING_COMBAT); return; } @@ -1874,18 +1914,16 @@ void Spell::EffectDummy(uint32 i) for (std::list<TargetInfo>::iterator ihit = m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit) ihit->effectMask &= ~(1<<1); - // not empty (checked) - Unit::AttackerSet const& attackers = unitTarget->getAttackers(); + // not empty (checked), copy + Unit::AttackerSet attackers = friendTarget->getAttackers(); - // chance to be selected from list - float chance = 100.0f / attackers.size(); - uint32 count = 0; - for (Unit::AttackerSet::const_iterator aItr = attackers.begin(); aItr != attackers.end() && count < 3; ++aItr) + // selected from list 3 + for(int i = 0; i < std::min(size_t(3),attackers.size()); ++i) { - if (!roll_chance_f(chance)) - continue; - ++count; + Unit::AttackerSet::iterator aItr = attackers.begin(); + std::advance(aItr, rand() % attackers.size()); AddUnitTarget((*aItr), 1); + attackers.erase(aItr); } // now let next effect cast spell at each target. @@ -1912,55 +1950,6 @@ void Spell::EffectDummy(uint32 i) } break; case SPELLFAMILY_SHAMAN: - // Rockbiter Weapon - if (m_spellInfo->SpellFamilyFlags[0] & 0x400000) - { - // TODO: use expect spell for enchant (if exist talent) - // In 3.0.3 no mods present for rockbiter - uint32 spell_id = 0; - switch (m_spellInfo->Id) - { - case 8017: spell_id = 36494; break; // Rank 1 - case 8018: spell_id = 36750; break; // Rank 2 - case 8019: spell_id = 36755; break; // Rank 3 - case 10399: spell_id = 36759; break; // Rank 4 - default: - sLog.outError("Spell::EffectDummy: Spell %u not handled in RW", m_spellInfo->Id); - return; - } - - SpellEntry const *spellInfo = sSpellStore.LookupEntry( spell_id ); - - if (!spellInfo) - { - sLog.outError("WORLD: unknown spell id %i", spell_id); - return; - } - - if (m_caster->GetTypeId() != TYPEID_PLAYER) - return; - - for (uint8 j = BASE_ATTACK; j <= OFF_ATTACK; ++j) - { - if (Item* item = ((Player*)m_caster)->GetWeaponForAttack(WeaponAttackType(j))) - { - if (item->IsFitToSpellRequirements(m_spellInfo)) - { - Spell *spell = new Spell(m_caster, spellInfo, true); - - // enchanting spell selected by calculated damage-per-sec in enchanting effect - // at calculation applied affect from Elemental Weapons talent - // real enchantment damage-1 - spell->m_currentBasePoints[1] = damage-1; - - SpellCastTargets targets; - targets.setItemTarget(item); - spell->prepare(&targets); - } - } - } - return; - } // Cleansing Totem Pulse if (m_spellInfo->SpellFamilyFlags[0] & 0x04000000 && m_spellInfo->SpellIconID==1673) { @@ -3377,6 +3366,7 @@ void Spell::EffectOpenLock(uint32 effIndex) return; } } + // TODO: Add script for spell 41920 - Filling, becouse server it freze when use this spell // handle outdoor pvp object opening, return true if go was registered for handling // these objects must have been spawned by outdoorpvp! else if(gameObjTarget->GetGOInfo()->type == GAMEOBJECT_TYPE_GOOBER && sOutdoorPvPMgr.HandleOpenGo(player, gameObjTarget->GetGUID())) @@ -4111,64 +4101,61 @@ void Spell::EffectEnchantItemTmp(uint32 i) Player* p_caster = (Player*)m_caster; + // Rockbiter Weapon apply to both weapon if (!itemTarget) - return; - - uint32 enchant_id = m_spellInfo->EffectMiscValue[i]; - - // Shaman Rockbiter Weapon - if (i == 0 && m_spellInfo->Effect[1] == SPELL_EFFECT_DUMMY) + return; + if (m_spellInfo->SpellFamilyName == SPELLFAMILY_SHAMAN && m_spellInfo->SpellFamilyFlags[0] & 0x400000) { - int32 enchnting_damage = CalculateDamage(1, NULL);//+1; + uint32 spell_id = 0; - // enchanting id selected by calculated damage-per-sec stored in Effect[1] base value - // with already applied percent bonus from Elemental Weapons talent + // enchanting spell selected by calculated damage-per-sec stored in Effect[1] base value // Note: damage calculated (correctly) with rounding int32(float(v)) but // RW enchantments applied damage int32(float(v)+0.5), this create 0..1 difference sometime - switch (enchnting_damage) + switch(damage) { // Rank 1 - case 2: enchant_id = 29; break; // 0% [ 7% == 2, 14% == 2, 20% == 2] + case 2: spell_id = 36744; break; // 0% [ 7% == 2, 14% == 2, 20% == 2] // Rank 2 - case 4: enchant_id = 6; break; // 0% [ 7% == 4, 14% == 4] - case 5: enchant_id = 3025; break; // 20% + case 4: spell_id = 36753; break; // 0% [ 7% == 4, 14% == 4] + case 5: spell_id = 36751; break; // 20% // Rank 3 - case 6: enchant_id = 1; break; // 0% [ 7% == 6, 14% == 6] - case 7: enchant_id = 3027; break; // 20% + case 6: spell_id = 36754; break; // 0% [ 7% == 6, 14% == 6] + case 7: spell_id = 36755; break; // 20% // Rank 4 - case 9: enchant_id = 3032; break; // 0% [ 7% == 6] - case 10: enchant_id = 503; break; // 14% - case 11: enchant_id = 3031; break; // 20% - // Rank 5 - case 15: enchant_id = 3035; break; // 0% - case 16: enchant_id = 1663; break; // 7% - case 17: enchant_id = 3033; break; // 14% - case 18: enchant_id = 3034; break; // 20% - // Rank 6 - case 28: enchant_id = 3038; break; // 0% - case 29: enchant_id = 683; break; // 7% - case 31: enchant_id = 3036; break; // 14% - case 33: enchant_id = 3037; break; // 20% - // Rank 7 - case 40: enchant_id = 3041; break; // 0% - case 42: enchant_id = 1664; break; // 7% - case 45: enchant_id = 3039; break; // 14% - case 48: enchant_id = 3040; break; // 20% - // Rank 8 - case 49: enchant_id = 3044; break; // 0% - case 52: enchant_id = 2632; break; // 7% - case 55: enchant_id = 3042; break; // 14% - case 58: enchant_id = 3043; break; // 20% - // Rank 9 - case 62: enchant_id = 2633; break; // 0% - case 66: enchant_id = 3018; break; // 7% - case 70: enchant_id = 3019; break; // 14% - case 74: enchant_id = 3020; break; // 20% + case 9: spell_id = 36761; break; // 0% [ 7% == 6] + case 10: spell_id = 36758; break; // 14% + case 11: spell_id = 36760; break; // 20% default: - sLog.outError("Spell::EffectEnchantItemTmp: Damage %u not handled in S'RW",enchnting_damage); + sLog.outError("Spell::EffectEnchantItemTmp: Damage %u not handled in S'RW",damage); return; } + + SpellEntry const *spellInfo = sSpellStore.LookupEntry(spell_id); + if (!spellInfo) + { + sLog.outError("Spell::EffectEnchantItemTmp: unknown spell id %i", spell_id); + return; + } + + for(int j = BASE_ATTACK; j <= OFF_ATTACK; ++j) + { + if (Item* item = p_caster->GetWeaponForAttack(WeaponAttackType(j))) + { + if (item->IsFitToSpellRequirements(m_spellInfo)) + { + Spell *spell = new Spell(m_caster, spellInfo, true); + SpellCastTargets targets; + targets.setItemTarget( item ); + spell->prepare(&targets); + } + } + } + return; } + if (!itemTarget) + return; + + uint32 enchant_id = m_spellInfo->EffectMiscValue[i]; if (!enchant_id) { @@ -4402,6 +4389,13 @@ void Spell::EffectTaunt(uint32 /*i*/) return; } + if (m_spellInfo->Id == 62124) + { + int32 damageDone = 1 + m_caster->GetTotalAttackPowerValue(BASE_ATTACK) * 0.5f; + m_caster->DealDamage(unitTarget, damageDone, NULL, SPELL_DIRECT_DAMAGE, SPELL_SCHOOL_MASK_HOLY, m_spellInfo, false); + m_caster->SendSpellNonMeleeDamageLog(unitTarget, m_spellInfo->Id, damageDone, SPELL_SCHOOL_MASK_HOLY, 0, 0, false, false, false); + } + // Also use this effect to set the taunter's threat to the taunted creature's highest value if (unitTarget->getThreatManager().getCurrentVictim()) { @@ -4583,15 +4577,6 @@ void Spell::SpellDamageWeaponDmg(uint32 i) else m_caster->CastCustomSpell(m_caster, 53725, &damagePoint, NULL, NULL, true); } - // Seal of Blood/of the Martyr backlash damage (10%) - else if (m_spellInfo->SpellIconID==2293) - { - int32 damagePoint = m_damage * 10 / 100; - if(m_spellInfo->Id == 31893) - m_caster->CastCustomSpell(m_caster, 32221, &damagePoint, NULL, NULL, true); - else - m_caster->CastCustomSpell(m_caster, 53718, &damagePoint, NULL, NULL, true); - } } case SPELLFAMILY_SHAMAN: { @@ -4676,10 +4661,10 @@ void Spell::SpellDamageWeaponDmg(uint32 i) } bool normalized = false; - float weaponDamagePercentMod = 1.0f; - for (uint8 j = 0; j < 3; ++j) + float weaponDamagePercentMod = 1.0; + for (int j = 0; j < 3; ++j) { - switch (m_spellInfo->Effect[j]) + switch(m_spellInfo->Effect[j]) { case SPELL_EFFECT_WEAPON_DAMAGE: case SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL: @@ -4698,10 +4683,10 @@ void Spell::SpellDamageWeaponDmg(uint32 i) } // apply to non-weapon bonus weapon total pct effect, weapon total flat effect included in weapon damage - if (fixed_bonus || spell_bonus) + if(fixed_bonus || spell_bonus) { UnitMods unitMod; - switch (m_attackType) + switch(m_attackType) { default: case BASE_ATTACK: unitMod = UNIT_MOD_DAMAGE_MAINHAND; break; @@ -4710,23 +4695,23 @@ void Spell::SpellDamageWeaponDmg(uint32 i) } float weapon_total_pct = 1.0f; - if (m_spellInfo->SchoolMask & SPELL_SCHOOL_MASK_NORMAL) + if ( m_spellInfo->SchoolMask & SPELL_SCHOOL_MASK_NORMAL ) weapon_total_pct = m_caster->GetModifierValue(unitMod, TOTAL_PCT); - if (fixed_bonus) + if(fixed_bonus) fixed_bonus = int32(fixed_bonus * weapon_total_pct); - if (spell_bonus) + if(spell_bonus) spell_bonus = int32(spell_bonus * weapon_total_pct); } int32 weaponDamage = m_caster->CalculateDamage(m_attackType, normalized, true); // Sequence is important - for (uint8 j = 0; j < 3; ++j) + for (int j = 0; j < 3; ++j) { // We assume that a spell have at most one fixed_bonus // and at most one weaponDamagePercentMod - switch (m_spellInfo->Effect[j]) + switch(m_spellInfo->Effect[j]) { case SPELL_EFFECT_WEAPON_DAMAGE: case SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL: @@ -4753,7 +4738,7 @@ void Spell::SpellDamageWeaponDmg(uint32 i) // Add melee damage bonuses (also check for negative) m_caster->MeleeDamageBonus(unitTarget, &eff_damage, m_attackType, m_spellInfo); - m_damage += eff_damage; + m_damage+= eff_damage; } void Spell::EffectThreat(uint32 /*i*/) @@ -5218,11 +5203,17 @@ void Spell::EffectScriptEffect(uint32 effIndex) switch(((Player*)unitTarget)->GetBaseSkillValue(762)) { - case 75: unitTarget->CastSpell(unitTarget, 51621, true); break;; - case 150: unitTarget->CastSpell(unitTarget, 48024, true); break; - case 225: unitTarget->CastSpell(unitTarget, 51617, true); break; - case 300: unitTarget->CastSpell(unitTarget, 48023, true); break; - default: break; + case 75: unitTarget->CastSpell(unitTarget, 51621, true); break;; + case 150: unitTarget->CastSpell(unitTarget, 48024, true); break; + case 225: + if(((Player*)unitTarget)->GetMapId()==571 || ((Player*)unitTarget)->GetMapId()==530) + unitTarget->CastSpell(unitTarget, 51617, true); + break; + case 300: + if(((Player*)unitTarget)->GetMapId()==571 || ((Player*)unitTarget)->GetMapId()==530) + unitTarget->CastSpell(unitTarget, 48023, true); + break; + default: break; } break; } @@ -5492,25 +5483,6 @@ void Spell::EffectScriptEffect(uint32 effIndex) } return; } - // Great Feast - case 57337: - { - if (!unitTarget) - return; - - unitTarget->CastSpell(unitTarget, 58067, true); - break; - } - //Fish Feast - case 57397: - { - if (!unitTarget) - return; - - unitTarget->CastSpell(unitTarget, 58648, true); - unitTarget->CastSpell(unitTarget, 57398, true); - break; - } case 58418: // Portal to Orgrimmar case 58420: // Portal to Stormwind { @@ -5553,15 +5525,15 @@ void Spell::EffectScriptEffect(uint32 effIndex) m_originalCaster->CastSpell(unitTarget, 58689, true); m_originalCaster->CastSpell(unitTarget, 58692, true); } - if(m_originalCaster->GetMap()->IsHeroic()) + if(((InstanceMap*)m_originalCaster->GetMap())->GetDifficulty() == REGULAR_DIFFICULTY) { - m_originalCaster->CastSpell(unitTarget, 60883, true); - m_originalCaster->CastSpell(unitTarget, 60884, true); + m_originalCaster->CastSpell(unitTarget, 58695, true); + m_originalCaster->CastSpell(unitTarget, 58696, true); } else { - m_originalCaster->CastSpell(unitTarget, 58695, true); - m_originalCaster->CastSpell(unitTarget, 58696, true); + m_originalCaster->CastSpell(unitTarget, 60883, true); + m_originalCaster->CastSpell(unitTarget, 60884, true); } } return; @@ -5611,12 +5583,15 @@ void Spell::EffectScriptEffect(uint32 effIndex) return; } case 62428: // Load into Catapult + { if(Vehicle *seat = m_caster->GetVehicleKit()) if(Unit *passenger = seat->GetPassenger(0)) if(Unit *demolisher = m_caster->GetVehicleBase()) passenger->CastSpell(demolisher, damage, true); return; + } case 62482: // Grab Crate + { if(unitTarget) { if(Vehicle *seat = m_caster->GetVehicleKit()) @@ -5629,6 +5604,7 @@ void Spell::EffectScriptEffect(uint32 effIndex) } } return; + } case 60123: // Lightwell { if (m_caster->GetTypeId() != TYPEID_UNIT || !((Creature*)m_caster)->isSummon()) @@ -5803,9 +5779,6 @@ void Spell::EffectScriptEffect(uint32 effIndex) AuraDivinePlea->RefreshAura(); return; } - case 45634: //Neural Needle - unitTarget->CastSpell(unitTarget, 45702, true); //Neural Needle Impact - return; } break; } @@ -6067,7 +6040,7 @@ void Spell::EffectScriptEffect(uint32 effIndex) case SPELLFAMILY_WARRIOR: { // Shattering Throw - if ( m_spellInfo->SpellFamilyFlags[1] & 0x1 ) + if (m_spellInfo->SpellFamilyFlags[1] & 0x00400000) { if(!unitTarget) return; @@ -6098,7 +6071,7 @@ void Spell::EffectSanctuary(uint32 /*i*/) if(!(*iter)->hasUnitState(UNIT_STAT_CASTING)) continue; - for (uint32 i = CURRENT_FIRST_NON_MELEE_SPELL; i < CURRENT_MAX_SPELL; ++i) + for (uint32 i = CURRENT_FIRST_NON_MELEE_SPELL; i < CURRENT_MAX_SPELL; i++) { if((*iter)->GetCurrentSpell(i) && (*iter)->GetCurrentSpell(i)->m_targets.getUnitTargetGUID() == unitTarget->GetGUID()) @@ -6497,9 +6470,6 @@ void Spell::EffectSummonObject(uint32 i) m_caster->AddGameObject(pGameObj); map->Add(pGameObj); - WorldPacket data(SMSG_GAMEOBJECT_SPAWN_ANIM_OBSOLETE, 8); - data << uint64(pGameObj->GetGUID()); - m_caster->SendMessageToSet(&data, true); m_caster->m_ObjectSlot[slot] = pGameObj->GetGUID(); } @@ -7089,10 +7059,6 @@ void Spell::EffectTransmitted(uint32 effIndex) cMap->Add(pGameObj); - WorldPacket data(SMSG_GAMEOBJECT_SPAWN_ANIM_OBSOLETE, 8); - data << uint64(pGameObj->GetGUID()); - m_caster->SendMessageToSet(&data,true); - if(uint32 linkedEntry = pGameObj->GetGOInfo()->GetLinkedGameObjectEntry()) { GameObject* linkedGO = new GameObject; @@ -7399,6 +7365,7 @@ void Spell::SummonGuardian(uint32 i, uint32 entry, SummonPropertiesEntry const * } else summon->SetDisplayId(1126); + summon->AI()->EnterEvadeMode(); } } @@ -7484,3 +7451,34 @@ void Spell::EffectActivateSpec(uint32 /*eff_idx*/) ((Player*)unitTarget)->ActivateSpec(damage-1); // damage is 1 or 2, spec is 0 or 1 } +void Spell::EffectCastButtons(uint32 i) +{ + if (!unitTarget || m_caster->GetTypeId() != TYPEID_PLAYER) + return; + + Player *p_caster = (Player*)m_caster; + uint32 button_id = m_spellInfo->EffectMiscValue[i] + 132; + uint32 n_buttons = m_spellInfo->EffectMiscValueB[i]; + + for (; n_buttons; n_buttons--, button_id++) + { + if (uint32 spell_id = p_caster->GetActionButtonSpell(button_id)) + { + if (!spell_id) + continue; + + if (p_caster->HasSpellCooldown(spell_id)) + continue; + + SpellEntry const *spellInfo = sSpellStore.LookupEntry(spell_id); + uint32 cost = CalculatePowerCost(spellInfo, m_caster, GetSpellSchoolMask(spellInfo)); + + if (m_caster->GetPower(POWER_MANA) < cost) + break; + + m_caster->CastSpell(unitTarget, spell_id, true); + m_caster->ModifyPower(POWER_MANA, -(int32)cost); + p_caster->AddSpellAndCategoryCooldowns(spellInfo, 0); + } + } +} diff --git a/src/game/SpellHandler.cpp b/src/game/SpellHandler.cpp index 1fd07ff19e8..a9a28511d0c 100644 --- a/src/game/SpellHandler.cpp +++ b/src/game/SpellHandler.cpp @@ -325,7 +325,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 ((mover->GetTypeId() == TYPEID_UNIT && !((Creature*)mover)->HasSpell(spellId)) || IsPassiveSpell(spellId)) { //cheater? kick? ban? recvPacket.rpos(recvPacket.wpos()); // prevent spam at ignore packet @@ -356,10 +356,18 @@ void WorldSession::HandleCastSpellOpcode(WorldPacket& recvPacket) { //recvPacket.read_skip<float>(); // unk1, coords? //recvPacket.read_skip<float>(); // unk1, coords? - recvPacket.read_skip<uint8>(); // >> 1 - recvPacket.read_skip<uint32>(); // >> MSG_MOVE_STOP - MovementInfo movementInfo; - ReadMovementInfo(recvPacket, &movementInfo); + uint8 unk1; + recvPacket >> unk1; // >> 1 or 0 + if(unk1) + { + recvPacket.read_skip<uint32>(); // >> MSG_MOVE_STOP + uint64 guid; // guid - unused + if(!recvPacket.readPackGUID(guid)) + return; + + MovementInfo movementInfo; + ReadMovementInfo(recvPacket, &movementInfo); + } } // auto-selection buff level base at target level (in spellInfo) @@ -632,4 +640,3 @@ void WorldSession::HandleMirrrorImageDataRequest( WorldPacket & recv_data ) } SendPacket( &data ); } - diff --git a/src/game/SpellMgr.cpp b/src/game/SpellMgr.cpp index dc6bbc728df..5600f1d2bf2 100644 --- a/src/game/SpellMgr.cpp +++ b/src/game/SpellMgr.cpp @@ -819,6 +819,7 @@ bool SpellMgr::_isPositiveEffect(uint32 spellId, uint32 effIndex, bool deep) con case 38638: // Nether Exhaustion (green) case 38639: // Nether Exhaustion (blue) case 11196: // Recently Bandaged + case 44689: // Relay Race Accept Hidden Debuff - DND return false; default: break; @@ -3030,31 +3031,17 @@ bool SpellArea::IsFitToRequirements(Player const* player, uint32 newZone, uint32 return false; } - if (auraSpell) + if(auraSpell) { // not have expected aura - if (!player || auraSpell > 0 && !player->HasAura(auraSpell) || auraSpell < 0 && player->HasAura(-auraSpell)) + if(!player) return false; - } - - // Extra conditions - switch(spellId) - { - case 58045: // Essence of Wintergrasp - Wintergrasp - case 57940: // Essence of Wintergrasp - Northrend - if (!player || player->GetTeamId() != sWorld.getState(WORLDSTATE_WINTERGRASP_CONTROLING_FACTION)) - return false; - break; - case 58600: // No fly Zone - Dalaran (Krasus Landing exception) - if (!player || player->GetAreaId() == 4564 || !player->HasAuraType(SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED) && !player->HasAuraType(SPELL_AURA_FLY) - || player->HasAura(44795)) - return false; - break; - case 58730: // No fly Zone - Wintergrasp - if (!player || !player->HasAuraType(SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED) && !player->HasAuraType(SPELL_AURA_FLY) - || player->HasAura(45472) || player->HasAura(44795)) - return false; - break; + if(auraSpell > 0) + // have expected aura + return player->HasAura(auraSpell); + else + // not have expected aura + return !player->HasAura(-auraSpell); } return true; @@ -3656,6 +3643,10 @@ void SpellMgr::LoadSpellCustomAttr() case 32182: spellInfo->excludeCasterAuraSpell = 57723; // Exhaustion break; + // Bloodlust + case 2825: + spellInfo->excludeCasterAuraSpell = 57724; // Sated + break; // Heart of the Crusader case 20335: case 20336: diff --git a/src/game/SpellMgr.h b/src/game/SpellMgr.h index b3f98ec7fe3..f95da00ccb2 100644 --- a/src/game/SpellMgr.h +++ b/src/game/SpellMgr.h @@ -810,7 +810,7 @@ class SpellMgr uint32 GetSpellElixirMask(uint32 spellid) const { SpellElixirMap::const_iterator itr = mSpellElixirs.find(spellid); - if (itr == mSpellElixirs.end()) + if(itr==mSpellElixirs.end()) return 0x0; return itr->second; @@ -819,13 +819,13 @@ class SpellMgr SpellSpecific GetSpellElixirSpecific(uint32 spellid) const { uint32 mask = GetSpellElixirMask(spellid); - if ((mask & ELIXIR_FLASK_MASK) == ELIXIR_FLASK_MASK) + if((mask & ELIXIR_FLASK_MASK)==ELIXIR_FLASK_MASK) return SPELL_FLASK_ELIXIR; - else if (mask & ELIXIR_BATTLE_MASK) + else if(mask & ELIXIR_BATTLE_MASK) return SPELL_BATTLE_ELIXIR; - else if (mask & ELIXIR_GUARDIAN_MASK) + else if(mask & ELIXIR_GUARDIAN_MASK) return SPELL_GUARDIAN_ELIXIR; - else if (mask & ELIXIR_WELL_FED) + else if(mask & ELIXIR_WELL_FED) return SPELL_WELL_FED; else return SPELL_NORMAL; @@ -834,7 +834,7 @@ class SpellMgr uint16 GetSpellThreat(uint32 spellid) const { SpellThreatMap::const_iterator itr = mSpellThreatMap.find(spellid); - if (itr == mSpellThreatMap.end()) + if(itr==mSpellThreatMap.end()) return 0; return itr->second; @@ -844,7 +844,7 @@ class SpellMgr SpellProcEventEntry const* GetSpellProcEvent(uint32 spellId) const { SpellProcEventMap::const_iterator itr = mSpellProcEventMap.find(spellId); - if (itr != mSpellProcEventMap.end()) + if( itr != mSpellProcEventMap.end( ) ) return &itr->second; return NULL; } @@ -854,7 +854,7 @@ class SpellMgr SpellEnchantProcEntry const* GetSpellEnchantProcEvent(uint32 enchId) const { SpellEnchantProcEventMap::const_iterator itr = mSpellEnchantProcEventMap.find(enchId); - if (itr != mSpellEnchantProcEventMap.end()) + if( itr != mSpellEnchantProcEventMap.end( ) ) return &itr->second; return NULL; } @@ -864,13 +864,13 @@ class SpellMgr { // Lookup data SpellBonusMap::const_iterator itr = mSpellBonusMap.find(spellId); - if (itr != mSpellBonusMap.end()) + if( itr != mSpellBonusMap.end( ) ) return &itr->second; // Not found, try lookup for 1 spell rank if exist if (uint32 rank_1 = GetFirstSpellInChain(spellId)) { SpellBonusMap::const_iterator itr2 = mSpellBonusMap.find(rank_1); - if (itr2 != mSpellBonusMap.end()) + if( itr2 != mSpellBonusMap.end( ) ) return &itr2->second; } return NULL; @@ -880,7 +880,7 @@ class SpellMgr SpellTargetPosition const* GetSpellTargetPosition(uint32 spell_id) const { SpellTargetPositionMap::const_iterator itr = mSpellTargetPositions.find( spell_id ); - if (itr != mSpellTargetPositions.end()) + if( itr != mSpellTargetPositions.end( ) ) return &itr->second; return NULL; } @@ -889,7 +889,7 @@ class SpellMgr SpellChainNode const* GetSpellChainNode(uint32 spell_id) const { SpellChainMap::const_iterator itr = mSpellChains.find(spell_id); - if (itr == mSpellChains.end()) + if(itr == mSpellChains.end()) return NULL; return &itr->second; @@ -1009,7 +1009,7 @@ class SpellMgr { SpellLearnSpellMapBounds bounds = GetSpellLearnSpellMapBounds(spell_id1); for (SpellLearnSpellMap::const_iterator i = bounds.first; i != bounds.second; ++i) - if (i->second.spell == spell_id2) + if (i->second.spell==spell_id2) return true; return false; } @@ -1191,4 +1191,3 @@ class SpellMgr #define spellmgr SpellMgr::Instance() #endif - diff --git a/src/game/StatSystem.cpp b/src/game/StatSystem.cpp index ef7edc71cc8..3f4f9200e05 100644 --- a/src/game/StatSystem.cpp +++ b/src/game/StatSystem.cpp @@ -242,7 +242,7 @@ void Player::UpdateMaxPower(Powers power) { UnitMods unitMod = UnitMods(UNIT_MOD_POWER_START + power); - float bonusPower = (power == POWER_MANA) ? GetManaBonusFromIntellect() : 0; + float bonusPower = (power == POWER_MANA && GetCreatePowers(power) > 0) ? GetManaBonusFromIntellect() : 0; float value = GetModifierValue(unitMod, BASE_VALUE) + GetCreatePowers(power); value *= GetModifierValue(unitMod, BASE_PCT); @@ -694,6 +694,11 @@ void Player::ApplyManaRegenBonus(int32 amount, bool apply) UpdateManaRegen(); } +void Player::ApplyHealthRegenBonus(int32 amount, bool apply) +{ + m_baseHealthRegen+= apply ? amount : -amount; +} + void Player::UpdateManaRegen() { float Intellect = GetStat(STAT_INTELLECT); @@ -918,9 +923,9 @@ bool Guardian::UpdateStats(Stats stat) Unit *owner = GetOwner(); // Handle Death Knight Glyphs and Talents + float mod = 0.75f; if (IsPetGhoul() && (stat == STAT_STAMINA || stat == STAT_STRENGTH)) { - float mod = 0.0f; switch (stat) { case STAT_STAMINA: mod = 0.3f; break; // Default Owner's Stamina scale @@ -945,7 +950,24 @@ bool Guardian::UpdateStats(Stats stat) if (owner->getClass() == CLASS_WARLOCK && isPet()) value += float(owner->GetStat(STAT_STAMINA)) * 0.75f; else - value += float(owner->GetStat(stat)) * 0.3f; + { + mod = 0.3f; + if (((Creature*)this)->isPet()) + { + PetSpellMap::const_iterator itr = (((Pet*)this)->m_spells.find(62758)); //Wild Hunt rank1 + if (itr == ((Pet*)this)->m_spells.end()) + { + itr = ((Pet*)this)->m_spells.find(62762); //Wild Hunt rank2 + } + if (itr != ((Pet*)this)->m_spells.end()) // If pet has Wild Hunt + { + + SpellEntry const* sProto = sSpellStore.LookupEntry(itr->first); // Then get the SpellProto and add the dummy effect value + mod += mod * (sProto->EffectBasePoints[0] / 100.0f); + } + } + value += float(owner->GetStat(stat)) * mod; + } } //warlock's and mage's pets gain 30% of owner's intellect else if (stat == STAT_INTELLECT) @@ -1095,8 +1117,23 @@ void Guardian::UpdateAttackPowerAndDamage(bool ranged) { if(isHunterPet()) //hunter pets benefit from owner's attack power { - bonusAP = owner->GetTotalAttackPowerValue(RANGED_ATTACK) * 0.22f; - SetBonusDamage( int32(owner->GetTotalAttackPowerValue(RANGED_ATTACK) * 0.1287f)); + float mod = 1.0f; //Hunter contribution modifier + if (((Creature*)this)->isPet()) + { + PetSpellMap::const_iterator itr = ((Pet*)this)->m_spells.find(62758); //Wild Hunt rank1 + if (itr == ((Pet*)this)->m_spells.end()) + { + itr = ((Pet*)this)->m_spells.find(62762); //Wild Hunt rank2 + } + if (itr != ((Pet*)this)->m_spells.end()) // If pet has Wild Hunt + { + + SpellEntry const* sProto = sSpellStore.LookupEntry(itr->first); // Then get the SpellProto and add the dummy effect value + mod += (sProto->EffectBasePoints[1] / 100.0f); + } + } + bonusAP = owner->GetTotalAttackPowerValue(RANGED_ATTACK) * 0.22f * mod; + SetBonusDamage( int32(owner->GetTotalAttackPowerValue(RANGED_ATTACK) * 0.1287f * mod)); } else if (IsPetGhoul()) //ghouls benefit from deathknight's attack power (may be summon pet or not) { @@ -1220,4 +1257,3 @@ void Guardian::UpdateDamagePhysical(WeaponAttackType attType) SetStatFloatValue(UNIT_FIELD_MINDAMAGE, mindamage); SetStatFloatValue(UNIT_FIELD_MAXDAMAGE, maxdamage); } - diff --git a/src/game/TaxiHandler.cpp b/src/game/TaxiHandler.cpp index a1f0bedf329..e0a1c2512a8 100644 --- a/src/game/TaxiHandler.cpp +++ b/src/game/TaxiHandler.cpp @@ -162,9 +162,9 @@ void WorldSession::HandleActivateTaxiExpressOpcode ( WorldPacket & recv_data ) sLog.outDebug( "WORLD: Received CMSG_ACTIVATETAXIEXPRESS" ); uint64 guid; - uint32 node_count, _totalcost; + uint32 node_count; - recv_data >> guid >> _totalcost >> node_count; + recv_data >> guid >> node_count; Creature *npc = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_FLIGHTMASTER); if (!npc) @@ -197,6 +197,7 @@ void WorldSession::HandleMoveSplineDoneOpcode(WorldPacket& /*recv_data*/) // 1) end taxi path in far (multi-node) flight // 2) switch from one map to other in case multim-map taxi path // we need process only (1) + uint32 curDest = GetPlayer()->m_taxi.GetTaxiDestination(); if(!curDest) return; @@ -275,4 +276,3 @@ void WorldSession::HandleActivateTaxiOpcode( WorldPacket & recv_data ) GetPlayer()->ActivateTaxiPathTo(nodes, npc); } - diff --git a/src/game/Totem.cpp b/src/game/Totem.cpp index c7ea9b1f123..a82f273bdbc 100644 --- a/src/game/Totem.cpp +++ b/src/game/Totem.cpp @@ -99,10 +99,6 @@ void Totem::InitStats(uint32 duration) void Totem::InitSummon() { - WorldPacket data(SMSG_GAMEOBJECT_SPAWN_ANIM_OBSOLETE, 8); - data << GetGUID(); - SendMessageToSet(&data, true); - if(m_type == TOTEM_PASSIVE) CastSpell(this, GetSpell(), true); @@ -113,8 +109,6 @@ void Totem::InitSummon() void Totem::UnSummon() { - SendObjectDeSpawnAnim(GetGUID()); - CombatStop(); RemoveAurasDueToSpell(GetSpell()); @@ -134,6 +128,7 @@ void Totem::UnSummon() Group *pGroup = NULL; if (m_owner->GetTypeId() == TYPEID_PLAYER) { + ((Player*)m_owner)->SendAutoRepeatCancel(this); // Not only the player can summon the totem (scripted AI) pGroup = ((Player*)m_owner)->GetGroup(); if (pGroup) diff --git a/src/game/Unit.cpp b/src/game/Unit.cpp index 90836cd23ea..457439e3d08 100644 --- a/src/game/Unit.cpp +++ b/src/game/Unit.cpp @@ -926,7 +926,7 @@ void Unit::CastStop(uint32 except_spellid) void Unit::CastSpell(Unit* Victim, uint32 spellId, bool triggered, Item *castItem, AuraEffect* triggeredByAura, uint64 originalCaster) { - SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId); + SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId ); if (!spellInfo) { @@ -934,10 +934,10 @@ void Unit::CastSpell(Unit* Victim, uint32 spellId, bool triggered, Item *castIte return; } - CastSpell(Victim, spellInfo, triggered, castItem, triggeredByAura, originalCaster); + CastSpell(Victim,spellInfo,triggered,castItem,triggeredByAura, originalCaster); } -void Unit::CastSpell(Unit* Victim, SpellEntry const *spellInfo, bool triggered, Item *castItem, AuraEffect* triggeredByAura, uint64 originalCaster) +void Unit::CastSpell(Unit* Victim,SpellEntry const *spellInfo, bool triggered, Item *castItem, AuraEffect* triggeredByAura, uint64 originalCaster) { if (!spellInfo) { @@ -1241,6 +1241,9 @@ void Unit::CalculateSpellDamageTaken(SpellNonMeleeDamage *damageInfo, int32 dama if (damageSchoolMask & SPELL_SCHOOL_MASK_NORMAL) damage = CalcArmorReducedDamage(pVictim, damage, spellInfo, attackType); + if (GetTypeId() == TYPEID_PLAYER && pVictim->GetTypeId() == TYPEID_PLAYER) + damage -= ((Player*)pVictim)->GetSpellDamageReduction(damage); + // Calculate absorb resist if (damage > 0) { @@ -1488,6 +1491,14 @@ void Unit::CalculateMeleeDamage(Unit *pVictim, uint32 damage, CalcDamageInfo *da break; } + if (GetTypeId() == TYPEID_PLAYER && pVictim->GetTypeId() == TYPEID_PLAYER) + { + if (attackType != RANGED_ATTACK) + damage-=((Player*)pVictim)->GetMeleeDamageReduction(damage); + else + damage-=((Player*)pVictim)->GetRangedDamageReduction(damage); + } + // Calculate absorb resist if (int32(damageInfo->damage) > 0) { @@ -1749,34 +1760,53 @@ void Unit::CalcAbsorbResist(Unit *pVictim, SpellSchoolMask schoolMask, DamageEff // Magic damage, check for resists if ((schoolMask & SPELL_SCHOOL_MASK_NORMAL) == 0) { - // Get base victim resistance for school - float tmpvalue2 = (float)pVictim->GetResistance(GetFirstSchoolInMask(schoolMask)); - // Ignore resistance by self SPELL_AURA_MOD_TARGET_RESISTANCE aura - tmpvalue2 += (float)GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_TARGET_RESISTANCE, schoolMask); - - tmpvalue2 *= (float)(0.15f / getLevel()); - if (tmpvalue2 < 0.0f) - tmpvalue2 = 0.0f; - if (tmpvalue2 > 0.75f) - tmpvalue2 = 0.75f; - uint32 ran = urand(0, 100); - uint32 faq[4] = {24,6,4,6}; - uint8 m = 0; - float Binom = 0.0f; - for (uint8 i = 0; i < 4; ++i) - { - Binom += 2400 *( powf(tmpvalue2, i) * powf( (1-tmpvalue2), (4-i)))/faq[i]; - if (ran > Binom) - ++m; - else - break; + float baseVictimResistance = (float) pVictim->GetResistance(GetFirstSchoolInMask(schoolMask)); + float ignoredResistance = (float) GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_TARGET_RESISTANCE, schoolMask); + float victimResistance = baseVictimResistance + ignoredResistance; + + uint32 BOSS_LEVEL = 83; + float BOSS_RESISTANCE_CONSTANT = 510.0; + uint32 level = getLevel(); + float resistanceConstant = 0.0f; + + if (level == BOSS_LEVEL) + { + resistanceConstant = BOSS_RESISTANCE_CONSTANT; } - if (damagetype == DOT && m == 4) - *resist += uint32(damage - 1); else - *resist += uint32(damage * m / 4); - if (*resist > damage) - *resist = damage; + { + resistanceConstant = level * 5.0f; + } + + float averageResist = victimResistance / (victimResistance + resistanceConstant); + float discreteResistProbability[11]; + for (int i = 0; i < 11; i++) + { + discreteResistProbability[i] = 0.5f - 2.5f * abs(0.1f * i - averageResist); + if (discreteResistProbability[i] < 0.0f) + { + discreteResistProbability[i] = 0.0f; + } + } + + if (averageResist <= 0.1f) + { + discreteResistProbability[0] = 1.0f - 7.5f * averageResist; + discreteResistProbability[1] = 5.0f * averageResist; + discreteResistProbability[2] = 2.5f * averageResist; + } + + float r = rand_norm(); + int i = 0; + float probabilitySum = discreteResistProbability[0]; + while (r >= probabilitySum && i < 10) + { + i++; + probabilitySum += discreteResistProbability[i]; + } + uint32 damageResisted = damage * i / 10; + + *resist += damageResisted; AuraEffectList const &ResIgnoreAurasAb = GetAurasByType(SPELL_AURA_MOD_ABILITY_IGNORE_TARGET_RESIST); for (AuraEffectList::const_iterator j = ResIgnoreAurasAb.begin(); j != ResIgnoreAurasAb.end(); ++j) @@ -1924,6 +1954,13 @@ void Unit::CalcAbsorbResist(Unit *pVictim, SpellSchoolMask schoolMask, DamageEff Unit* caster = (*i)->GetCaster(); if (!caster) break; + // Glyph of Power Word: Shield + if (Aura *glyph = pVictim->GetAura(55672,0)) + { + int32 heal = int32(glyph->GetPartAura(0)->GetAmount() * + (RemainingDamage >= currentAbsorb ? currentAbsorb : RemainingDamage) / 100); + pVictim->CastCustomSpell(pVictim, 56160, &heal, NULL, NULL, true, 0, *i); + } // Reflective Shield if (AuraEffect const * aurEff = caster->GetDummyAura(SPELLFAMILY_PRIEST, 566, 0)) { @@ -4478,9 +4515,7 @@ GameObject* Unit::GetGameObject(uint32 spellId) const void Unit::AddGameObject(GameObject* gameObj) { - if(!gameObj || !gameObj->GetOwnerGUID()==0) - return; - + if(!gameObj || !gameObj->GetOwnerGUID()==0) return; m_gameObj.push_back(gameObj); gameObj->SetOwnerGUID(GetGUID()); @@ -4496,8 +4531,7 @@ void Unit::AddGameObject(GameObject* gameObj) void Unit::RemoveGameObject(GameObject* gameObj, bool del) { - if(!gameObj || !gameObj->GetOwnerGUID()==GetGUID()) - return; + if(!gameObj || !gameObj->GetOwnerGUID()==GetGUID()) return; gameObj->SetOwnerGUID(0); @@ -4892,8 +4926,6 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger uint32 triggered_spell_id = 0; Unit* target = pVictim; int32 basepoints0 = 0; - int32 basepoints1 = 0; - int32 basepoints2 = 0; uint64 originalCaster = 0; // Master of subtlety (checked here because ranks have different spellfamilynames) @@ -4982,6 +5014,17 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger triggered_spell_id = 58374; break; } + // Glyph of Devastate + if (dummySpell->Id == 58388) + { + if (!pVictim || !pVictim->isAlive()) + return false; + + if (Aura* aur = pVictim->GetAura(58567,0)) + aur->modStackAmount(1); + + return true; + } // Unstable Power case 24658: { @@ -5286,12 +5329,22 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger target = this; break; } + // Shadowfiend Death (Gain mana if pet dies with Glyph of Shadowfiend) + case 57989: + { + Unit *owner = GetOwner(); + if (!owner || owner->GetTypeId() != TYPEID_PLAYER) + return false; + // Glyph of Shadowfiend (need cast as self cast for owner, no hidden cooldown) + owner->CastSpell(owner,58227,true,castItem,triggeredByAura); + return true; + } // Divine purpose case 31871: case 31872: { // Roll chane - if (!roll_chance_i(triggerAmount)) + if (!pVictim || !pVictim->isAlive() || !roll_chance_i(triggerAmount)) return false; // Remove any stun effect on target @@ -5324,7 +5377,7 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger // mana cost save int32 cost = procSpell->manaCost + procSpell->ManaCostPercentage * GetCreateMana() / 100; basepoints0 = cost * triggerAmount/100; - if (basepoints0 <= 0) + if( basepoints0 <=0 ) return false; target = this; @@ -5414,6 +5467,12 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger target->RemoveAurasByType(SPELL_AURA_PERIODIC_DAMAGE_PERCENT); return true; } + // Glyph of Drain Soul + case 58070: + { + triggered_spell_id = 58068; + break; + } // Glyph of Icy Veins case 56374: { @@ -5453,7 +5512,7 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger return true; // charge counting (will removed) } - CastSpell(this, 28682, true, castItem, triggeredByAura); + CastSpell(this, 11129, true, castItem, triggeredByAura); return (procEx & PROC_EX_CRITICAL_HIT);// charge update only at crit hits, no hidden cooldowns } // Glyph of Ice Block @@ -5523,9 +5582,9 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger switch (dummySpell->Id) { - case 29838: triggered_spell_id = 29842; break; - case 29834: triggered_spell_id = 29841; break; - case 42770: triggered_spell_id = 42771; break; + case 29838: triggered_spell_id=29842; break; + case 29834: triggered_spell_id=29841; break; + case 42770: triggered_spell_id=42771; break; default: sLog.outError("Unit::HandleDummyAuraProc: non handled spell id: %u (SW)",dummySpell->Id); return false; @@ -5549,10 +5608,10 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger // Seed of Corruption if (dummySpell->SpellFamilyFlags[1] & 0x00000010) { - if (procSpell && procSpell->Id == 27285) + if(procSpell && procSpell->Id == 27285) return false; // if damage is more than need or target die from damage deal finish spell - if (triggeredByAura->GetAmount() <= damage || GetHealth() <= damage) + if( triggeredByAura->GetAmount() <= damage || GetHealth() <= damage ) { // remember guid before aura delete uint64 casterGuid = triggeredByAura->GetCasterGUID(); @@ -5561,7 +5620,7 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger RemoveAurasDueToSpell(triggeredByAura->GetId()); // Cast finish spell (triggeredByAura already not exist!) - if (Unit *caster = GetUnit(*this, casterGuid)) + if(Unit* caster = GetUnit(*this, casterGuid)) caster->CastSpell(this, 27285, true, castItem); return true; // no hidden cooldown } @@ -5574,7 +5633,7 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger if (dummySpell->SpellFamilyFlags.IsEqual(0,0,0) && dummySpell->SpellIconID == 1932) { // if damage is more than need deal finish spell - if (triggeredByAura->GetAmount() <= damage) + if( triggeredByAura->GetAmount() <= damage ) { // remember guid before aura delete uint64 casterGuid = triggeredByAura->GetCasterGUID(); @@ -5583,7 +5642,7 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger RemoveAurasDueToSpell(triggeredByAura->GetId()); // Cast finish spell (triggeredByAura already not exist!) - if (Unit *caster = GetUnit(*this, casterGuid)) + if(Unit* caster = GetUnit(*this, casterGuid)) caster->CastSpell(this, 32865, true, castItem); return true; // no hidden cooldown } @@ -5726,7 +5785,7 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger if(!pVictim || !pVictim->isAlive()) return false; - if (effIndex != 0) + if (effIndex!=0) return false; // pVictim is caster of aura @@ -5744,6 +5803,16 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger triggered_spell_id = 47753; break; } + // Body and Soul + if (dummySpell->SpellIconID == 2218) + { + // Proc only from Abolish desease on self cast + if (procSpell->Id != 552 || pVictim != this || !roll_chance_i(triggerAmount)) + return false; + triggered_spell_id = 64136; + target = this; + break; + } switch(dummySpell->Id) { // Vampiric Embrace @@ -5767,6 +5836,9 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger case 15272: case 15320: { + if (!target) + return false; + basepoints0 = triggerAmount * target->GetCreateMana() / 100; triggered_spell_id = 64103; break; @@ -5775,10 +5847,10 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger case 40438: { // Shadow Word: Pain - if (procSpell->SpellFamilyFlags[0] & 0x8000) + if( procSpell->SpellFamilyFlags[0] & 0x8000 ) triggered_spell_id = 40441; // Renew - else if (procSpell->SpellFamilyFlags[0] & 0x40) + else if( procSpell->SpellFamilyFlags[0] & 0x40 ) triggered_spell_id = 40440; else return false; @@ -5796,7 +5868,7 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger return false; int EffIndex = 0; - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + for (uint8 i = 0; i < MAX_SPELL_EFFECTS; i++) { if(GoPoH->Effect[i] == SPELL_EFFECT_APPLY_AURA) { @@ -5805,7 +5877,7 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger } } int32 tickcount = GetSpellMaxDuration(GoPoH) / GoPoH->EffectAmplitude[EffIndex]; - if (!tickcount) + if(!tickcount) return false; basepoints0 = damage * triggerAmount / tickcount / 100; @@ -5864,7 +5936,7 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger // Dispel Magic shares spellfamilyflag with abolish disease if (procSpell->SpellIconID != 74) return false; - if(!target->IsFriendlyTo(this)) + if(!target || !target->IsFriendlyTo(this)) return false; basepoints0 = int32(target->GetMaxHealth() * triggerAmount / 100); @@ -5883,7 +5955,7 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger // Frozen Shadoweave (Shadow's Embrace set) warning! its not only priest set case 39372: { - if (!procSpell || (GetSpellSchoolMask(procSpell) & (SPELL_SCHOOL_MASK_FROST | SPELL_SCHOOL_MASK_SHADOW)) == 0) + if(!procSpell || (GetSpellSchoolMask(procSpell) & (SPELL_SCHOOL_MASK_FROST | SPELL_SCHOOL_MASK_SHADOW))==0 ) return false; // heal amount @@ -5912,7 +5984,7 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger } case SPELLFAMILY_DRUID: { - switch (dummySpell->Id) + switch(dummySpell->Id) { // Glyph of Innervate case 54832: @@ -5968,11 +6040,11 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger triggered_spell_id = 34299; if (triggeredByAura->GetCasterGUID() != GetGUID()) break; - int32 _basepoints0 = triggerAmount * 2; + int32 basepoints1 = triggerAmount * 2; // Improved Leader of the Pack // Check cooldown of heal spell cooldown if (GetTypeId() == TYPEID_PLAYER && !((Player *)this)->HasSpellCooldown(34299)) - CastCustomSpell(this, 60889, &_basepoints0, NULL, NULL, true, 0, triggeredByAura); + CastCustomSpell(this,60889,&basepoints1,0,0,true,0,triggeredByAura); break; } // Healing Touch (Dreamwalker Raiment set) @@ -6054,7 +6126,7 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger if (!procSpell) return false; // Only 0 aura can proc - if (effIndex != 0) + if (effIndex!=0) return false; // Wrath crit if (procSpell->SpellFamilyFlags[0] & 0x1) @@ -6087,7 +6159,7 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger else if (dummySpell->SpellIconID == 2850) { // Effect 0 - mod damage while having Enrage - if (effIndex == 0) + if (effIndex==0) { if (!(procSpell->SpellFamilyFlags[0] & 0x00080000)) return false; @@ -6097,7 +6169,7 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger break; } // Effect 1 - Tiger's Fury restore energy - else if (effIndex == 1) + else if (effIndex==1) { if (!(procSpell->SpellFamilyFlags[2] & 0x00000800)) return false; @@ -6111,7 +6183,7 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger } case SPELLFAMILY_ROGUE: { - switch (dummySpell->Id) + switch(dummySpell->Id) { // Glyph of Backstab case 56800: @@ -6227,7 +6299,7 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger // Seal of Righteousness - melee proc dummy (addition ${$MWS*(0.022*$AP+0.044*$SPH)} damage) if (dummySpell->SpellFamilyFlags[0]&0x8000000) { - if (effIndex != 0) + if (effIndex!=0) return false; triggered_spell_id = 25742; float ap = GetTotalAttackPowerValue(BASE_ATTACK); @@ -6237,7 +6309,7 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger break; } // Light's Beacon - Beacon of Light - if (dummySpell->Id == 53651) + if ( dummySpell->Id == 53651 ) { if (Unit *source = triggeredByAura->GetParentAura()->GetUnitSource()) { @@ -6275,8 +6347,8 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger triggered_spell_id = 57318; target = this; basepoints0 = triggerAmount; - basepoints1 = triggerAmount; - break; + CastCustomSpell(target,triggered_spell_id,&basepoints0,&basepoints0,NULL,true,castItem,triggeredByAura); + return true; } // Sacred Shield if (dummySpell->SpellFamilyFlags[1]&0x00080000) @@ -6316,13 +6388,18 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger // Judgement of Light case 20185: { - pVictim->CastCustomSpell(pVictim, 20267, &basepoints0, 0, 0, true, 0, triggeredByAura); - return true; + if (pVictim->getPowerType() == POWER_MANA) + { + // 2% of base mana + basepoints0 = int32(pVictim->GetMaxHealth() * 2 / 100); + pVictim->CastCustomSpell(pVictim, 20267, &basepoints0, 0, 0, true, 0, triggeredByAura); + } + return true; } // Judgement of Wisdom case 20186: { - if (pVictim->getPowerType() == POWER_MANA) + if (pVictim && pVictim->isAlive() && pVictim->getPowerType() == POWER_MANA) { // 2% of base mana basepoints0 = int32(pVictim->GetCreateMana() * 2 / 100); @@ -6361,6 +6438,20 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger } break; } + case 25899: // Greater Blessing of Sanctuary + case 20911: // Blessing of Sanctuary + { + target = this; + switch (target->getPowerType()) + { + case POWER_MANA: + triggered_spell_id = 57319; + break; + default: + return false; + } + break; + } // Seal of Vengeance (damage calc on apply aura) case 31801: { @@ -6384,51 +6475,33 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger case 33776: { // if healed by another unit (pVictim) - if (this == pVictim) + if(this == pVictim) return false; // heal amount basepoints0 = triggerAmount*damage/100; target = this; - if (basepoints0) + if(basepoints0) triggered_spell_id = 31786; break; } - // Seal of Blood do damage trigger - case 31892: - { - if (effIndex == 0 && procFlag & PROC_FLAG_SUCCESSFUL_MELEE_HIT) // 0 effect - is proc on enemy - triggered_spell_id = 31893; - else - return true; - break; - } - // Seal of the Martyr do damage trigger - case 53720: - { - if (effIndex == 0 && procFlag & PROC_FLAG_SUCCESSFUL_MELEE_HIT) // 0 effect - is proc on enemy - triggered_spell_id = 53719; - else - return true; - break; - } // Paladin Tier 6 Trinket (Ashtongue Talisman of Zeal) case 40470: { - if (!procSpell) + if( !procSpell ) return false; float chance; // Flash of light/Holy light - if (procSpell->SpellFamilyFlags[0] & 0xC0000000) + if( procSpell->SpellFamilyFlags[0] & 0xC0000000) { triggered_spell_id = 40471; chance = 15.0f; } // Judgement (any) - else if (GetSpellSpecific(procSpell->Id) == SPELL_JUDGEMENT) + else if (GetSpellSpecific(procSpell->Id)==SPELL_JUDGEMENT) { triggered_spell_id = 40472; chance = 50.0f; @@ -6445,15 +6518,14 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger case 54939: { // Lookup base amount mana restore - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + for (uint8 i=0; i<MAX_SPELL_EFFECTS; i++) if (procSpell->Effect[i] == SPELL_EFFECT_ENERGIZE) { - basepoints1 = procSpell->EffectBasePoints[i]; // Not sure if this is right, maybe basepoints0? - triggered_spell_id = 54986; - target = this; + int32 mana = procSpell->EffectBasePoints[i]; + CastCustomSpell(this, 54986, 0, &mana, 0, true, castItem, triggeredByAura); break; } - break; + return true; } // Glyph of Flash of Light case 54936: @@ -6494,7 +6566,7 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger // Totemic Power (The Earthshatterer set) case 28823: { - if (!pVictim) + if( !pVictim ) return false; // Set class defined buff @@ -6532,17 +6604,32 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger // Windfury Weapon (Passive) 1-5 Ranks case 33757: { - if (GetTypeId() != TYPEID_PLAYER) + if(GetTypeId()!=TYPEID_PLAYER || !castItem || !castItem->IsEquipped() || !pVictim || !pVictim->isAlive()) return false; - if (!castItem || !castItem->IsEquipped()) + // custom cooldown processing case + if( cooldown && ((Player*)this)->HasSpellCooldown(dummySpell->Id)) return false; - // custom cooldown processing case - if (cooldown && ((Player*)this)->HasSpellCooldown(dummySpell->Id)) + if(triggeredByAura->GetParentAura() && castItem->GetGUID() != triggeredByAura->GetParentAura()->GetCastItemGUID()) return false; - if (triggeredByAura->GetParentAura() && castItem->GetGUID() != triggeredByAura->GetParentAura()->GetCastItemGUID()) + WeaponAttackType attType = WeaponAttackType(((Player*)this)->GetAttackBySlot(castItem->GetSlot())); + if ((attType != BASE_ATTACK && attType != OFF_ATTACK) || !isAttackReady(attType)) + return false; + + // Now compute real proc chance... + Aura* aur = GetAura(55445, 0); + uint32 chance = 20/* + (aur ? aur->GetAmount()->m_amount : 0)*/; + ((Player*)this)->ApplySpellMod(dummySpell->Id,SPELLMOD_CHANCE_OF_SUCCESS,chance); + + Item* addWeapon = ((Player*)this)->GetWeaponForAttack(attType == BASE_ATTACK ? OFF_ATTACK : BASE_ATTACK, true); + uint32 enchant_id_add = addWeapon ? addWeapon->GetEnchantmentId(EnchantmentSlot(TEMP_ENCHANTMENT_SLOT)) : 0; + SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id_add); + if (pEnchant && pEnchant->spellid[0] == dummySpell->Id) + chance += 14; + + if (!roll_chance_i(chance)) return false; // Now amount of extra power stored in 1 effect of Enchant spell @@ -6575,30 +6662,17 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger int32 extra_attack_power = CalculateSpellDamage(windfurySpellEntry, 1, windfurySpellEntry->EffectBasePoints[1], pVictim); - // Main-Hand case - if (castItem->GetSlot() == EQUIPMENT_SLOT_MAINHAND && isAttackReady(BASE_ATTACK)) - { - // Value gained from additional AP - basepoints0 = int32(extra_attack_power/14.0f * GetAttackTime(BASE_ATTACK)/1000); - triggered_spell_id = 25504; - } - // Off-Hand case - else if (castItem->GetSlot() == EQUIPMENT_SLOT_OFFHAND && isAttackReady(OFF_ATTACK)) - { - // Value gained from additional AP - basepoints0 = int32(extra_attack_power/14.0f * GetAttackTime(OFF_ATTACK)/1000/2); - triggered_spell_id = 33750; - } - else - return false; + // Value gained from additional AP + basepoints0 = int32(extra_attack_power/14.0f * GetAttackTime(BASE_ATTACK)/1000); + triggered_spell_id = 25504; // apply cooldown before cast to prevent processing itself - if (cooldown) - ((Player*)this)->AddSpellCooldown(dummySpell->Id, 0, time(NULL) + cooldown); + if( cooldown ) + ((Player*)this)->AddSpellCooldown(dummySpell->Id,0,time(NULL) + cooldown); // Attack Twice - for (uint8 i = 0; i < 2; ++i) - CastCustomSpell(pVictim, triggered_spell_id, &basepoints0, NULL, NULL, true, castItem, triggeredByAura); + for (uint32 i = 0; i<2; ++i ) + CastCustomSpell(pVictim,triggered_spell_id,&basepoints0,NULL,NULL,true,castItem,triggeredByAura); return true; } @@ -6658,7 +6732,7 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger // Shaman T8 Elemental 4P Bonus case 64928: { - basepoints0 = triggerAmount * damage / 100; + basepoints0 = int32( triggerAmount * damage / 100 ); triggered_spell_id = 64930; // Electrified break; } @@ -6666,7 +6740,7 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger // Frozen Power if (dummySpell->SpellIconID == 3780) { - if (GetDistance(target) < 15.0f) + if (this->GetDistance(target) < 15.0f) return false; float chance = triggerAmount; if (!roll_chance_f(chance)) @@ -6698,7 +6772,7 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger break; } // Earth Shield - if (dummySpell->SpellFamilyFlags[1] & 0x00000400) + if(dummySpell->SpellFamilyFlags[1] & 0x00000400) { // 3.0.8: Now correctly uses the Shaman's own spell critical strike chance to determine the chance of a critical heal. originalCaster = triggeredByAura->GetCasterGUID(); @@ -6717,10 +6791,7 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger // Flametongue Weapon (Passive) if (dummySpell->SpellFamilyFlags[0] & 0x200000) { - if(GetTypeId() != TYPEID_PLAYER) - return false; - - if(!castItem || !castItem->IsEquipped()) + if(GetTypeId()!=TYPEID_PLAYER || !pVictim || !pVictim->isAlive() || !castItem || !castItem->IsEquipped()) return false; // firehit = dummySpell->EffectBasePoints[0] / ((4*19.25) * 1.3); @@ -6738,24 +6809,26 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger float BaseWeaponSpeed = GetAttackTime(OFF_ATTACK)/1000.0; // Value1: add the tooltip damage by swingspeed + Value2: add spelldmg by swingspeed - basepoints0 = int32((fire_onhit * BaseWeaponSpeed) + (add_spellpower * BaseWeaponSpeed)); + basepoints0 = int32( (fire_onhit * BaseWeaponSpeed) + (add_spellpower * BaseWeaponSpeed) ); triggered_spell_id = 10444; } + // Enchant on Main-Hand and ready? - else if (castItem->GetSlot() == EQUIPMENT_SLOT_MAINHAND && isAttackReady(BASE_ATTACK)) + else if ( castItem->GetSlot() == EQUIPMENT_SLOT_MAINHAND && isAttackReady(BASE_ATTACK)) { float BaseWeaponSpeed = GetAttackTime(BASE_ATTACK)/1000.0; // Value1: add the tooltip damage by swingspeed + Value2: add spelldmg by swingspeed - basepoints0 = int32((fire_onhit * BaseWeaponSpeed) + (add_spellpower * BaseWeaponSpeed)); + basepoints0 = int32( (fire_onhit * BaseWeaponSpeed) + (add_spellpower * BaseWeaponSpeed) ); triggered_spell_id = 10444; } - // If not ready, we should return, shouldn't we?! + + // If not ready, we should return, shouldn't we?! else return false; - target = pVictim; - break; + CastCustomSpell(pVictim,triggered_spell_id,&basepoints0,NULL,NULL,true,castItem,triggeredByAura); + return true; } // Improved Water Shield if (dummySpell->SpellIconID == 2287) @@ -6776,34 +6849,66 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger // Lightning Overload if (dummySpell->SpellIconID == 2018) // only this spell have SpellFamily Shaman SpellIconID == 2018 and dummy aura { - if(!procSpell || GetTypeId() != TYPEID_PLAYER || !pVictim) + if(!procSpell || GetTypeId() != TYPEID_PLAYER || !pVictim ) return false; // custom cooldown processing case - if (cooldown && GetTypeId() == TYPEID_PLAYER && ((Player*)this)->HasSpellCooldown(dummySpell->Id)) + if( cooldown && GetTypeId() == TYPEID_PLAYER && ((Player*)this)->HasSpellCooldown(dummySpell->Id)) return false; - uint32 spell; - if (procSpell->SpellFamilyFlags[0] & 0x2) - spell = 45297; - else - spell = 45284; - uint32 spellId = spellmgr.GetSpellWithRank(spell, spellmgr.GetSpellRank(procSpell->Id)); + uint32 spellId = 0; + // Every Lightning Bolt and Chain Lightning spell have duplicate vs half damage and zero cost + switch (procSpell->Id) + { + // Lightning Bolt + case 403: spellId = 45284; break; // Rank 1 + case 529: spellId = 45286; break; // Rank 2 + case 548: spellId = 45287; break; // Rank 3 + case 915: spellId = 45288; break; // Rank 4 + case 943: spellId = 45289; break; // Rank 5 + case 6041: spellId = 45290; break; // Rank 6 + case 10391: spellId = 45291; break; // Rank 7 + case 10392: spellId = 45292; break; // Rank 8 + case 15207: spellId = 45293; break; // Rank 9 + case 15208: spellId = 45294; break; // Rank 10 + case 25448: spellId = 45295; break; // Rank 11 + case 25449: spellId = 45296; break; // Rank 12 + case 49237: spellId = 49239; break; // Rank 13 + case 49238: spellId = 49240; break; // Rank 14 + // Chain Lightning + case 421: spellId = 45297; break; // Rank 1 + case 930: spellId = 45298; break; // Rank 2 + case 2860: spellId = 45299; break; // Rank 3 + case 10605: spellId = 45300; break; // Rank 4 + case 25439: spellId = 45301; break; // Rank 5 + case 25442: spellId = 45302; break; // Rank 6 + case 49270: spellId = 49268; break; // Rank 7 + case 49271: spellId = 49269; break; // Rank 8 + default: + sLog.outError("Unit::HandleDummyAuraProc: non handled spell id: %u (LO)", procSpell->Id); + return false; + } + // No thread generated mod + // TODO: exist special flag in spell attributes for this, need found and use! + SpellModifier *mod = new SpellModifier; + mod->op = SPELLMOD_THREAT; + mod->value = -100; + mod->type = SPELLMOD_PCT; + mod->spellId = dummySpell->Id; + mod->mask[0] = 0x02; + mod->mask[2] = 0x00; + ((Player*)this)->AddSpellMod(mod, true); // Remove cooldown (Chain Lightning - have Category Recovery time) if (procSpell->SpellFamilyFlags[0] & 0x2) ((Player*)this)->RemoveSpellCooldown(spellId); - // do not reduce damage-spells have correct basepoints - basepoints1 = 0; - - // Apply spellmod - CastCustomSpell(this, 39805, NULL, &basepoints1, NULL, true, castItem, triggeredByAura); - CastSpell(pVictim, spellId, true, castItem, triggeredByAura); - if (cooldown && GetTypeId() == TYPEID_PLAYER) - ((Player*)this)->AddSpellCooldown(dummySpell->Id, 0, time(NULL) + cooldown); + ((Player*)this)->AddSpellMod(mod, false); + + if( cooldown && GetTypeId() == TYPEID_PLAYER ) + ((Player*)this)->AddSpellCooldown(dummySpell->Id,0,time(NULL) + cooldown); return true; } @@ -6827,6 +6932,9 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger // Blood-Caked Strike - Blood-Caked Blade if (dummySpell->SpellIconID == 138) { + if (!target || !target->isAlive()) + return false; + triggered_spell_id = dummySpell->EffectTriggerSpell[effIndex]; break; } @@ -6850,7 +6958,7 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger if (dummySpell->Id == 49028) { // 1 dummy aura for dismiss rune blade - if (effIndex != 2) + if (effIndex!=2) return false; uint64 PetGUID = NULL; for (ControlList::const_iterator itr = m_Controlled.begin(); itr != m_Controlled.end(); ++itr) //Find Rune Weapon @@ -6891,6 +6999,62 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger triggered_spell_id = 51460; break; } + // Threat of Thassarian + if (dummySpell->SpellIconID == 2023) + { + // Must Dual Wield + if (!procSpell || !haveOffhandWeapon()) + return false; + // Chance as basepoints for dummy aura + if (!roll_chance_i(triggerAmount)) + return false; + + switch (procSpell->Id) + { + // Obliterate + case 49020: triggered_spell_id = 66198; break; // Rank 1 + case 51423: triggered_spell_id = 66972; break; // Rank 2 + case 51424: triggered_spell_id = 66973; break; // Rank 3 + case 51425: triggered_spell_id = 66974; break; // Rank 4 + + // Frost Strike + case 49143: triggered_spell_id = 66196; break; // Rank 1 + case 51416: triggered_spell_id = 66958; break; // Rank 2 + case 51417: triggered_spell_id = 66959; break; // Rank 3 + case 51418: triggered_spell_id = 66960; break; // Rank 4 + case 51419: triggered_spell_id = 66961; break; // Rank 5 + case 51420: triggered_spell_id = 66962; break; // Rank 6 + + // Plague Strike + case 45462: triggered_spell_id = 66216; break; // Rank 1 + case 49917: triggered_spell_id = 66988; break; // Rank 2 + case 49918: triggered_spell_id = 66989; break; // Rank 3 + case 49919: triggered_spell_id = 66990; break; // Rank 4 + case 49920: triggered_spell_id = 66991; break; // Rank 5 + case 49921: triggered_spell_id = 66992; break; // Rank 6 + + // Death Strike + case 49998: triggered_spell_id = 66188; break; // Rank 1 + case 49999: triggered_spell_id = 66950; break; // Rank 2 + case 45463: triggered_spell_id = 66951; break; // Rank 3 + case 49923: triggered_spell_id = 66952; break; // Rank 4 + case 49924: triggered_spell_id = 66953; break; // Rank 5 + + // Rune Strike + case 56815: triggered_spell_id = 66217; break; // Rank 1 + + // Blood Strike + case 45902: triggered_spell_id = 66215; break; // Rank 1 + case 49926: triggered_spell_id = 66975; break; // Rank 2 + case 49927: triggered_spell_id = 66976; break; // Rank 3 + case 49928: triggered_spell_id = 66977; break; // Rank 4 + case 49929: triggered_spell_id = 66978; break; // Rank 5 + case 49930: triggered_spell_id = 66979; break; // Rank 6 + default: + return false; + } + break; + } // Runic Power Back on Snare/Root if (dummySpell->Id == 61257) { @@ -6958,17 +7122,21 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger { if (procSpell->SpellFamilyName == SPELLFAMILY_POTION) { - for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + for (uint8 i=0; i<MAX_SPELL_EFFECTS; i++) { - if (procSpell->Effect[i] == SPELL_EFFECT_HEAL) + if (procSpell->Effect[i]==SPELL_EFFECT_HEAL) + { triggered_spell_id = 21399; - else if (procSpell->Effect[i] == SPELL_EFFECT_ENERGIZE) + } + else if (procSpell->Effect[i]==SPELL_EFFECT_ENERGIZE) + { triggered_spell_id = 21400; + } else continue; - basepoints0 = CalculateSpellDamage(procSpell, i, procSpell->EffectBasePoints[i], this) * 0.4f; - CastCustomSpell(this, triggered_spell_id, &basepoints0, NULL, NULL, true, NULL, triggeredByAura); + basepoints0 = CalculateSpellDamage(procSpell,i,procSpell->EffectBasePoints[i],this) * 0.4f; + CastCustomSpell(this,triggered_spell_id,&basepoints0,NULL,NULL,true,NULL,triggeredByAura); } return true; } @@ -6989,7 +7157,7 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger { triggered_spell_id = 54445; target = this; - pVictim->AddThreat(this, procSpell->EffectBasePoints[0]*triggerAmount/100.0f); + pVictim->AddThreat(this,procSpell->EffectBasePoints[0]*triggerAmount/100.0f); break; } break; @@ -6999,30 +7167,30 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger } // processed charge only counting case - if (!triggered_spell_id) + if(!triggered_spell_id) return true; SpellEntry const* triggerEntry = sSpellStore.LookupEntry(triggered_spell_id); - if (!triggerEntry) + if(!triggerEntry) { - sLog.outError("Unit::HandleDummyAuraProc: Spell %u have not existed triggered spell %u", dummySpell->Id, triggered_spell_id); + sLog.outError("Unit::HandleDummyAuraProc: Spell %u have not existed triggered spell %u",dummySpell->Id,triggered_spell_id); return false; } // default case - if ((!target && !spellmgr.IsSrcTargetSpell(triggerEntry)) || (target && target!=this && !target->isAlive())) + if((!target && !spellmgr.IsSrcTargetSpell(triggerEntry)) || (target && target!=this && !target->isAlive())) return false; - if (cooldown && GetTypeId() == TYPEID_PLAYER && ((Player*)this)->HasSpellCooldown(triggered_spell_id)) + if( cooldown && GetTypeId() == TYPEID_PLAYER && ((Player*)this)->HasSpellCooldown(triggered_spell_id)) return false; - if (basepoints0 || basepoints1 || basepoints2) - CastCustomSpell(target, triggered_spell_id, &basepoints0, &basepoints1, &basepoints2, true, castItem, triggeredByAura, originalCaster); + if(basepoints0) + CastCustomSpell(target,triggered_spell_id,&basepoints0,NULL,NULL,true,castItem,triggeredByAura, originalCaster); else - CastSpell(target, triggered_spell_id, true, castItem, triggeredByAura, originalCaster); + CastSpell(target,triggered_spell_id,true,castItem,triggeredByAura, originalCaster); - if (cooldown && GetTypeId() == TYPEID_PLAYER) + if( cooldown && GetTypeId() == TYPEID_PLAYER ) ((Player*)this)->AddSpellCooldown(triggered_spell_id,0,time(NULL) + cooldown); return true; @@ -7273,7 +7441,25 @@ bool Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, AuraEffect* trig // intellect if (GetStat(STAT_INTELLECT)> stat) { trigger_spell_id = 60234;stat = GetStat(STAT_INTELLECT);} // spirit - if (GetStat(STAT_SPIRIT) > stat) { trigger_spell_id = 60235;stat = GetStat(STAT_SPIRIT); } + if (GetStat(STAT_SPIRIT) > stat) { trigger_spell_id = 60235; } + break; + } + case 67702: // Death's Choice, Item - Coliseum 25 Normal Melee Trinket + { + float stat = 0.0f; + // strength + if (GetStat(STAT_STRENGTH) > stat) { trigger_spell_id = 67708;stat = GetStat(STAT_STRENGTH); } + // agility + if (GetStat(STAT_AGILITY) > stat) { trigger_spell_id = 67703; } + break; + } + case 67771: // Death's Choice (heroic), Item - Coliseum 25 Heroic Melee Trinket + { + float stat = 0.0f; + // strength + if (GetStat(STAT_STRENGTH) > stat) { trigger_spell_id = 67773;stat = GetStat(STAT_STRENGTH); } + // agility + if (GetStat(STAT_AGILITY) > stat) { trigger_spell_id = 67772; } break; } // Mana Drain Trigger @@ -7390,6 +7576,18 @@ bool Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, AuraEffect* trig return false; } } + // Druid T9 Feral Relic (Lacerate, Swipe, Mangle, and Shred) + else if (auraSpellInfo->Id==67353) + { + switch(m_form) + { + case FORM_CAT: trigger_spell_id = 67355; break; + case FORM_BEAR: + case FORM_DIREBEAR: trigger_spell_id = 67354; break; + default: + return false; + } + } break; } case SPELLFAMILY_HUNTER: @@ -7626,18 +7824,11 @@ bool Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, AuraEffect* trig trigger_spell_id = 26470; break; } - // Unyielding Knights - case 38164: - { - if (pVictim->GetEntry() != 19457) // Proc only if you target is Grillok - return false; - break; - } // Deflection case 52420: { - if (GetHealth()*100 / GetMaxHealth() >= 35) - return false; + if(GetHealth()*100 / GetMaxHealth() >= 35) + return false; break; } @@ -7653,7 +7844,7 @@ bool Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, AuraEffect* trig case 31255: { // whenever you deal damage to a target who is below 20% health. - if (pVictim->GetHealth() > pVictim->GetMaxHealth() / 5) + if (!pVictim || !pVictim->isAlive() || (pVictim->GetHealth() > pVictim->GetMaxHealth() / 5)) return false; target = this; @@ -7662,6 +7853,9 @@ bool Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, AuraEffect* trig // Greater Heal Refund (Avatar Raiment set) case 37594: { + if (!pVictim || !pVictim->isAlive()) + return false; + // Not give if target already have full health if (pVictim->GetHealth() == pVictim->GetMaxHealth()) return false; @@ -7674,7 +7868,7 @@ bool Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, AuraEffect* trig case 40971: { // If your target is below $s1% health - if (pVictim->GetHealth() > pVictim->GetMaxHealth() * triggerAmount / 100) + if (!pVictim || !pVictim->isAlive() || (pVictim->GetHealth() > pVictim->GetMaxHealth() * triggerAmount / 100)) return false; break; } @@ -7695,6 +7889,14 @@ bool Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, AuraEffect* trig return false; break; } + // Blessing of Ancient Kings (Val'anyr, Hammer of Ancient Kings) + case 64411: + { + basepoints0 = damage * 15 / 100; + target = pVictim; + trigger_spell_id = 26470; + break; + } // Decimation case 63156: case 63158: @@ -7768,7 +7970,6 @@ bool Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, AuraEffect* trig { if (!pVictim || pVictim == this) return false; - // Need add combopoint AFTER finish movie (or they dropped in finish phase) break; } @@ -7888,6 +8089,15 @@ bool Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, AuraEffect* trig basepoints0 = int32(GetTotalAttackPowerValue(BASE_ATTACK) * triggerAmount / 100.0f); break; } + // Body and Soul + case 64128: + case 65081: + { + // Proc only from PW:S cast + if (!(procSpell->SpellFamilyFlags[0] & 0x00000001)) + return false; + break; + } } if( cooldown && GetTypeId() == TYPEID_PLAYER && ((Player*)this)->HasSpellCooldown(trigger_spell_id)) @@ -8388,7 +8598,7 @@ bool Unit::Attack(Unit *victim, bool meleeAttack) m_attacking = victim; m_attacking->_addAttacker(this); - //Set our target + // Set our target SetUInt64Value(UNIT_FIELD_TARGET, victim->GetGUID()); if (meleeAttack) @@ -8434,7 +8644,7 @@ bool Unit::AttackStop() m_attacking->_removeAttacker(this); m_attacking = NULL; - //Clear our target + // Clear our target SetUInt64Value(UNIT_FIELD_TARGET, 0); clearUnitState(UNIT_STAT_MELEE_ATTACKING); @@ -8528,7 +8738,7 @@ void Unit::ModifyAuraState(AuraState flag, bool apply) Pet *pet = ((Pet*)this); for (PetSpellMap::const_iterator itr = pet->m_spells.begin(); itr != pet->m_spells.end(); ++itr) { - if (itr->second.state == PLAYERSPELL_REMOVED) continue; + if (itr->second.state == PETSPELL_REMOVED) continue; SpellEntry const *spellInfo = sSpellStore.LookupEntry(itr->first); if (!spellInfo || !IsPassiveSpell(itr->first)) continue; if (spellInfo->CasterAuraState == flag) @@ -9709,12 +9919,7 @@ bool Unit::isSpellCrit(Unit *pVictim, SpellEntry const *spellProto, SpellSchoolM if (spellProto->SpellFamilyFlags[1] & 0x00001000) { if (AuraEffect const* flameShock = pVictim->GetAura(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_SHAMAN, 0x10000000, 0,0, GetGUID())) - { - // Consume shock aura if not have Glyph of Flame Shock - if (!GetAuraEffect(55447, 0)) - pVictim->RemoveAurasDueToSpell(flameShock->GetId(), GetGUID()); return true; - } break; } break; @@ -10458,6 +10663,18 @@ void Unit::MeleeDamageBonus(Unit *pVictim, uint32 *pdamage, WeaponAttackType att TakenTotalMod *= (mod+100.0f)/100.0f; } break; + // Blessing of Sanctuary + // Greater Blessing of Sanctuary + case 19: + case 1804: + { + if ((*i)->GetSpellProto()->SpellFamilyName != SPELLFAMILY_PALADIN) + continue; + + if ((*i)->GetMiscValue() & (spellProto ? GetSpellSchoolMask(spellProto) : 0)) + TakenTotalMod *= ((*i)->GetAmount() + 100.0f) / 100.0f; + break; + } // Ebon Plague case 1933: if ((*i)->GetMiscValue() & (spellProto ? GetSpellSchoolMask(spellProto) : 0)) @@ -10637,7 +10854,7 @@ void Unit::Unmount() { if (Pet *pPet = ((Player*)this)->GetPet()) { - if (pPet->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED) && !pPet->hasUnitState(UNIT_STAT_STUNNED)) + if (pPet && pPet->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED) && !pPet->hasUnitState(UNIT_STAT_STUNNED)) pPet->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED); } else @@ -11066,7 +11283,7 @@ void Unit::UpdateSpeed(UnitMoveType mtype, bool forced) stack_bonus = GetTotalAuraMultiplier(SPELL_AURA_MOD_MOUNTED_FLIGHT_SPEED_ALWAYS); } else // Use not mount (shapeshift for example) auras (should stack) - main_speed_mod = GetTotalAuraModifier(SPELL_AURA_MOD_INCREASE_FLIGHT_SPEED); + main_speed_mod = GetTotalAuraModifier(SPELL_AURA_MOD_INCREASE_FLIGHT_SPEED) + GetTotalAuraModifier(SPELL_AURA_MOD_INCREASE_VEHICLE_FLIGHT_SPEED); non_stack_bonus = (100.0 + GetMaxPositiveAuraModifier(SPELL_AURA_MOD_FLIGHT_SPEED_NOT_STACK))/100.0f; @@ -11113,7 +11330,12 @@ void Unit::UpdateSpeed(UnitMoveType mtype, bool forced) // Apply strongest slow aura mod to speed int32 slow = GetMaxNegativeAuraModifier(SPELL_AURA_MOD_DECREASE_SPEED); if (slow) + { speed *=(100.0f + slow)/100.0f; + float min_speed = (float)GetMaxPositiveAuraModifier(SPELL_AURA_MOD_MINIMUM_SPEED) / 100.0f; + if (speed < min_speed) + speed = min_speed; + } SetSpeed(mtype, speed, forced); } @@ -12312,6 +12534,9 @@ void Unit::RemoveFromWorld() RemoveBindSightAuras(); RemoveNotOwnSingleTargetAuras(); + RemoveAllGameObjects(); + RemoveAllDynObjects(); + ExitVehicle(); UnsummonAllTotems(); RemoveAllControlled(); @@ -12351,8 +12576,6 @@ void Unit::CleanupsBeforeDelete() ClearComboPointHolders(); DeleteThreatList(); getHostilRefManager().setOnlineOfflineState(false); - RemoveAllGameObjects(); - RemoveAllDynObjects(); GetMotionMaster()->Clear(false); // remove different non-standard movement generators. if (IsInWorld()) @@ -12602,12 +12825,12 @@ void CharmInfo::LoadPetActionBar(const std::string& data ) Tokens tokens = StrSplit(data, " "); - if (tokens.size() != (ACTION_BAR_INDEX_PET_SPELL_END-ACTION_BAR_INDEX_PET_SPELL_START)*2) + if (tokens.size() != (ACTION_BAR_INDEX_END-ACTION_BAR_INDEX_START)*2) return; // non critical, will reset to default uint8 index; Tokens::iterator iter; - for (iter = tokens.begin(), index = ACTION_BAR_INDEX_PET_SPELL_START; index < ACTION_BAR_INDEX_PET_SPELL_END; ++iter, ++index ) + for (iter = tokens.begin(), index = ACTION_BAR_INDEX_START; index < ACTION_BAR_INDEX_END; ++iter, ++index) { // use unsigned cast to avoid sign negative format use at long-> ActiveStates (int) conversion uint8 type = atol((*iter).c_str()); @@ -13843,6 +14066,14 @@ void Unit::Kill(Unit *pVictim, bool durabilityLoss) // call kill spell proc event (before real die and combat stop to triggering auras removed at death/combat stop) if (bRewardIsAllowed && player && player!=pVictim) { + WorldPacket data(SMSG_PARTYKILLLOG, (8+8)); //send event PARTY_KILL + data << uint64(player->GetGUID()); //player with killing blow + data << uint64(pVictim->GetGUID()); //victim + if (Group *group = player->GetGroup()) + group->BroadcastPacket(&data, group->GetMemberGroup(player->GetGUID())); + else + player->SendDirectMessage(&data); + if (player->RewardPlayerAndGroupAtKill(pVictim)) player->ProcDamageAndSpell(pVictim, PROC_FLAG_KILL, PROC_FLAG_KILLED, PROC_EX_NONE, 0); else @@ -13943,7 +14174,7 @@ void Unit::Kill(Unit *pVictim, bool durabilityLoss) if (m->IsDungeon() && creditedPlayer) { - if (m->IsRaid() || m->IsHeroic()) + if (m->IsRaidOrHeroicDungeon()) { if (cVictim->GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_INSTANCE_BIND) ((InstanceMap *)m)->PermBindAllPlayers(creditedPlayer); @@ -14805,7 +15036,9 @@ void Unit::KnockbackFrom(float x, float y, float speedXY, float speedZ) } if (!player) + { GetMotionMaster()->MoveKnockbackFrom(x, y, speedXY, speedZ); + } else { float vcos, vsin; @@ -14823,6 +15056,208 @@ void Unit::KnockbackFrom(float x, float y, float speedXY, float speedZ) } } +uint32 Unit::GetModelForForm(ShapeshiftForm form) +{ + switch(form) + { + case FORM_CAT: + // Based on Hair color + if (getRace() == RACE_NIGHTELF) + { + uint8 hairColor = GetByteValue(PLAYER_BYTES, 3); + switch (hairColor) + { + case 7: // Violet + case 8: + return 29405; + case 3: // Light Blue + return 29406; + case 0: // Green + case 1: // Light Green + case 2: // Dark Green + return 29407; + case 4: // White + return 29408; + default: // original - Dark Blue + return 892; + } + } + // Based on Skin color + else if (getRace() == RACE_TAUREN) + { + uint8 skinColor = GetByteValue(PLAYER_BYTES, 0); + // Male + if (getGender() == GENDER_MALE) + { + switch(skinColor) + { + case 12: // White + case 13: + case 14: + case 18: // Completly White + return 29409; + case 9: // Light Brown + case 10: + case 11: + return 29410; + case 6: // Brown + case 7: + case 8: + return 29411; + case 0: // Dark + case 1: + case 2: + case 3: // Dark Grey + case 4: + case 5: + return 29412; + default: // original - Grey + return 8571; + } + } + // Female + else switch (skinColor) + { + case 10: // White + return 29409; + case 6: // Light Brown + case 7: + return 29410; + case 4: // Brown + case 5: + return 29411; + case 0: // Dark + case 1: + case 2: + case 3: + return 29412; + default: // original - Grey + return 8571; + } + } + else if(Player::TeamForRace(getRace())==ALLIANCE) + return 892; + else + return 8571; + case FORM_DIREBEAR: + case FORM_BEAR: + // Based on Hair color + if (getRace() == RACE_NIGHTELF) + { + uint8 hairColor = GetByteValue(PLAYER_BYTES, 3); + switch (hairColor) + { + case 0: // Green + case 1: // Light Green + case 2: // Dark Green + return 29413; // 29415? + case 6: // Dark Blue + return 29414; + case 4: // White + return 29416; + case 3: // Light Blue + return 29417; + default: // original - Violet + return 2281; + } + } + // Based on Skin color + else if (getRace() == RACE_TAUREN) + { + uint8 skinColor = GetByteValue(PLAYER_BYTES, 0); + // Male + if (getGender() == GENDER_MALE) + { + switch (skinColor) + { + case 0: // Dark (Black) + case 1: + case 2: + return 29418; + case 3: // White + case 4: + case 5: + case 12: + case 13: + case 14: + return 29419; + case 9: // Light Brown/Grey + case 10: + case 11: + case 15: + case 16: + case 17: + return 29420; + case 18: // Completly White + return 29421; + default: // original - Brown + return 2289; + } + } + // Female + else switch (skinColor) + { + case 0: // Dark (Black) + case 1: + return 29418; + case 2: // White + case 3: + return 29419; + case 6: // Light Brown/Grey + case 7: + case 8: + case 9: + return 29420; + case 10: // Completly White + return 29421; + default: // original - Brown + return 2289; + } + } + else if(Player::TeamForRace(getRace())==ALLIANCE) + return 2281; + else + return 2289; + case FORM_TRAVEL: + return 632; + case FORM_AQUA: + if(Player::TeamForRace(getRace())==ALLIANCE) + return 2428; + else + return 2428; + case FORM_GHOUL: + return 24994; + case FORM_CREATUREBEAR: + return 902; + case FORM_GHOSTWOLF: + return 4613; + case FORM_FLIGHT: + if(Player::TeamForRace(getRace())==ALLIANCE) + return 20857; + else + return 20872; + case FORM_MOONKIN: + if(Player::TeamForRace(getRace())==ALLIANCE) + return 15374; + else + return 15375; + case FORM_FLIGHT_EPIC: + if(Player::TeamForRace(getRace())==ALLIANCE) + return 21243; + else + return 21244; + case FORM_METAMORPHOSIS: + return 25277; + case FORM_MASTER_ANGLER: + return 15234; + case FORM_TREE: + return 864; + case FORM_SPIRITOFREDEMPTION: + return 16031; + } + return 0; +} + void Unit::JumpTo(float speedXY, float speedZ, bool forward) { float angle = forward ? 0 : M_PI; diff --git a/src/game/Unit.h b/src/game/Unit.h index b54fd00f1de..b439cf35dc6 100644 --- a/src/game/Unit.h +++ b/src/game/Unit.h @@ -715,6 +715,7 @@ enum MonsterMovementFlags struct MovementInfo { // common + uint64 guid; uint32 flags; uint16 unk1; uint32 time; @@ -1623,18 +1624,6 @@ class TRINITY_DLL_SPEC Unit : public WorldObject SetOrientation(GetAngle(target)); } bool isInBackInMap(Unit const* target, float distance, float arc = M_PI) const; - void ChangeOrient(float fAngle, Unit* pUnit = NULL) - { - if(!this) - return; - - if(!pUnit) - this->SetOrientation(fAngle); - else - this->SetInFront(pUnit); - - this->SendMovementFlagUpdate(); - } // Visibility system UnitVisibility GetVisibility() const { return m_Visibility; } @@ -1852,6 +1841,8 @@ class TRINITY_DLL_SPEC Unit : public WorldObject void AddPetAura(PetAura const* petSpell); void RemovePetAura(PetAura const* petSpell); + uint32 GetModelForForm(ShapeshiftForm form); + // relocation notification void SetToNotify(); bool m_Notified; @@ -2030,4 +2021,3 @@ namespace Trinity } #endif - diff --git a/src/game/UpdateFields.h b/src/game/UpdateFields.h index 8fa05a4cb86..d8b6ae9d284 100644 --- a/src/game/UpdateFields.h +++ b/src/game/UpdateFields.h @@ -21,7 +21,7 @@ #ifndef _UPDATEFIELDS_AUTO_H #define _UPDATEFIELDS_AUTO_H -// Auto generated for version 3, 1, 3, 9947 +// Auto generated for version 3, 2, 2, 10505 enum EObjectFields { @@ -72,7 +72,7 @@ enum EItemFields ITEM_FIELD_ITEM_TEXT_ID = OBJECT_END + 0x0036, // Size: 1, Type: INT, Flags: OWNER ITEM_FIELD_DURABILITY = OBJECT_END + 0x0037, // Size: 1, Type: INT, Flags: OWNER, ITEM_OWNER ITEM_FIELD_MAXDURABILITY = OBJECT_END + 0x0038, // Size: 1, Type: INT, Flags: OWNER, ITEM_OWNER - ITEM_FIELD_PAD = OBJECT_END + 0x0039, // Size: 1, Type: INT, Flags: NONE + ITEM_FIELD_CREATE_PLAYED_TIME = OBJECT_END + 0x0039, // Size: 1, Type: INT, Flags: PUBLIC ITEM_END = OBJECT_END + 0x003A, }; @@ -325,7 +325,7 @@ enum EUnitFields PLAYER_VISIBLE_ITEM_19_ENTRYID = UNIT_END + 0x0092, // Size: 1, Type: INT, Flags: PUBLIC PLAYER_VISIBLE_ITEM_19_ENCHANTMENT = UNIT_END + 0x0093, // Size: 1, Type: TWO_SHORT, Flags: PUBLIC PLAYER_CHOSEN_TITLE = UNIT_END + 0x0094, // Size: 1, Type: INT, Flags: PUBLIC - PLAYER_FIELD_PAD_0 = UNIT_END + 0x0095, // Size: 1, Type: INT, Flags: NONE + PLAYER_FAKE_INEBRIATION = UNIT_END + 0x0095, // Size: 1, Type: INT, Flags: PUBLIC PLAYER_FIELD_INV_SLOT_HEAD = UNIT_END + 0x0096, // Size: 46, Type: LONG, Flags: PRIVATE PLAYER_FIELD_PACK_SLOT_1 = UNIT_END + 0x00C4, // Size: 32, Type: LONG, Flags: PRIVATE PLAYER_FIELD_BANK_SLOT_1 = UNIT_END + 0x00E4, // Size: 56, Type: LONG, Flags: PRIVATE @@ -363,32 +363,35 @@ enum EUnitFields PLAYER_FIELD_MOD_DAMAGE_DONE_NEG = UNIT_END + 0x03EC, // Size: 7, Type: INT, Flags: PRIVATE PLAYER_FIELD_MOD_DAMAGE_DONE_PCT = UNIT_END + 0x03F3, // Size: 7, Type: INT, Flags: PRIVATE PLAYER_FIELD_MOD_HEALING_DONE_POS = UNIT_END + 0x03FA, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_FIELD_MOD_TARGET_RESISTANCE = UNIT_END + 0x03FB, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_FIELD_MOD_TARGET_PHYSICAL_RESISTANCE = UNIT_END + 0x03FC, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_FIELD_BYTES = UNIT_END + 0x03FD, // Size: 1, Type: BYTES, Flags: PRIVATE - PLAYER_AMMO_ID = UNIT_END + 0x03FE, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_SELF_RES_SPELL = UNIT_END + 0x03FF, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_FIELD_PVP_MEDALS = UNIT_END + 0x0400, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_FIELD_BUYBACK_PRICE_1 = UNIT_END + 0x0401, // Size: 12, Type: INT, Flags: PRIVATE - PLAYER_FIELD_BUYBACK_TIMESTAMP_1 = UNIT_END + 0x040D, // Size: 12, Type: INT, Flags: PRIVATE - PLAYER_FIELD_KILLS = UNIT_END + 0x0419, // Size: 1, Type: TWO_SHORT, Flags: PRIVATE - PLAYER_FIELD_TODAY_CONTRIBUTION = UNIT_END + 0x041A, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_FIELD_YESTERDAY_CONTRIBUTION = UNIT_END + 0x041B, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_FIELD_LIFETIME_HONORABLE_KILLS = UNIT_END + 0x041C, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_FIELD_BYTES2 = UNIT_END + 0x041D, // Size: 1, Type: BYTES, Flags: PRIVATE - PLAYER_FIELD_WATCHED_FACTION_INDEX = UNIT_END + 0x041E, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_FIELD_COMBAT_RATING_1 = UNIT_END + 0x041F, // Size: 25, Type: INT, Flags: PRIVATE - PLAYER_FIELD_ARENA_TEAM_INFO_1_1 = UNIT_END + 0x0438, // Size: 18, Type: INT, Flags: PRIVATE - PLAYER_FIELD_HONOR_CURRENCY = UNIT_END + 0x044A, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_FIELD_ARENA_CURRENCY = UNIT_END + 0x044B, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_FIELD_MAX_LEVEL = UNIT_END + 0x044C, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_FIELD_DAILY_QUESTS_1 = UNIT_END + 0x044D, // Size: 25, Type: INT, Flags: PRIVATE - PLAYER_RUNE_REGEN_1 = UNIT_END + 0x0466, // Size: 4, Type: FLOAT, Flags: PRIVATE - PLAYER_NO_REAGENT_COST_1 = UNIT_END + 0x046A, // Size: 3, Type: INT, Flags: PRIVATE - PLAYER_FIELD_GLYPH_SLOTS_1 = UNIT_END + 0x046D, // Size: 6, Type: INT, Flags: PRIVATE - PLAYER_FIELD_GLYPHS_1 = UNIT_END + 0x0473, // Size: 6, Type: INT, Flags: PRIVATE - PLAYER_GLYPHS_ENABLED = UNIT_END + 0x0479, // Size: 1, Type: INT, Flags: PRIVATE - PLAYER_END = UNIT_END + 0x047A, + PLAYER_FIELD_MOD_HEALING_PCT = UNIT_END + 0x03FB, // Size: 1, Type: FLOAT, Flags: PRIVATE + PLAYER_FIELD_MOD_HEALING_DONE_PCT = UNIT_END + 0x03FC, // Size: 1, Type: FLOAT, Flags: PRIVATE + PLAYER_FIELD_MOD_TARGET_RESISTANCE = UNIT_END + 0x03FD, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_FIELD_MOD_TARGET_PHYSICAL_RESISTANCE = UNIT_END + 0x03FE, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_FIELD_BYTES = UNIT_END + 0x03FF, // Size: 1, Type: BYTES, Flags: PRIVATE + PLAYER_AMMO_ID = UNIT_END + 0x0400, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_SELF_RES_SPELL = UNIT_END + 0x0401, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_FIELD_PVP_MEDALS = UNIT_END + 0x0402, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_FIELD_BUYBACK_PRICE_1 = UNIT_END + 0x0403, // Size: 12, Type: INT, Flags: PRIVATE + PLAYER_FIELD_BUYBACK_TIMESTAMP_1 = UNIT_END + 0x040F, // Size: 12, Type: INT, Flags: PRIVATE + PLAYER_FIELD_KILLS = UNIT_END + 0x041B, // Size: 1, Type: TWO_SHORT, Flags: PRIVATE + PLAYER_FIELD_TODAY_CONTRIBUTION = UNIT_END + 0x041C, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_FIELD_YESTERDAY_CONTRIBUTION = UNIT_END + 0x041D, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_FIELD_LIFETIME_HONORABLE_KILLS = UNIT_END + 0x041E, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_FIELD_BYTES2 = UNIT_END + 0x041F, // Size: 1, Type: 6, Flags: PRIVATE + PLAYER_FIELD_WATCHED_FACTION_INDEX = UNIT_END + 0x0420, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_FIELD_COMBAT_RATING_1 = UNIT_END + 0x0421, // Size: 25, Type: INT, Flags: PRIVATE + PLAYER_FIELD_ARENA_TEAM_INFO_1_1 = UNIT_END + 0x043A, // Size: 21, Type: INT, Flags: PRIVATE + PLAYER_FIELD_HONOR_CURRENCY = UNIT_END + 0x044F, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_FIELD_ARENA_CURRENCY = UNIT_END + 0x0450, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_FIELD_MAX_LEVEL = UNIT_END + 0x0451, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_FIELD_DAILY_QUESTS_1 = UNIT_END + 0x0452, // Size: 25, Type: INT, Flags: PRIVATE + PLAYER_RUNE_REGEN_1 = UNIT_END + 0x046B, // Size: 4, Type: FLOAT, Flags: PRIVATE + PLAYER_NO_REAGENT_COST_1 = UNIT_END + 0x046F, // Size: 3, Type: INT, Flags: PRIVATE + PLAYER_FIELD_GLYPH_SLOTS_1 = UNIT_END + 0x0472, // Size: 6, Type: INT, Flags: PRIVATE + PLAYER_FIELD_GLYPHS_1 = UNIT_END + 0x0478, // Size: 6, Type: INT, Flags: PRIVATE + PLAYER_GLYPHS_ENABLED = UNIT_END + 0x047E, // Size: 1, Type: INT, Flags: PRIVATE + PLAYER_FIELD_PADDING = UNIT_END + 0x047F, // Size: 1, Type: INT, Flags: NONE + PLAYER_END = UNIT_END + 0x0480, }; enum EGameObjectFields @@ -410,12 +413,8 @@ enum EDynamicObjectFields DYNAMICOBJECT_BYTES = OBJECT_END + 0x0002, // Size: 1, Type: BYTES, Flags: PUBLIC DYNAMICOBJECT_SPELLID = OBJECT_END + 0x0003, // Size: 1, Type: INT, Flags: PUBLIC DYNAMICOBJECT_RADIUS = OBJECT_END + 0x0004, // Size: 1, Type: FLOAT, Flags: PUBLIC - DYNAMICOBJECT_POS_X = OBJECT_END + 0x0005, // Size: 1, Type: FLOAT, Flags: PUBLIC - DYNAMICOBJECT_POS_Y = OBJECT_END + 0x0006, // Size: 1, Type: FLOAT, Flags: PUBLIC - DYNAMICOBJECT_POS_Z = OBJECT_END + 0x0007, // Size: 1, Type: FLOAT, Flags: PUBLIC - DYNAMICOBJECT_FACING = OBJECT_END + 0x0008, // Size: 1, Type: FLOAT, Flags: PUBLIC - DYNAMICOBJECT_CASTTIME = OBJECT_END + 0x0009, // Size: 1, Type: INT, Flags: PUBLIC - DYNAMICOBJECT_END = OBJECT_END + 0x000A, + DYNAMICOBJECT_CASTTIME = OBJECT_END + 0x0005, // Size: 1, Type: INT, Flags: PUBLIC + DYNAMICOBJECT_END = OBJECT_END + 0x0006, }; enum ECorpseFields @@ -433,4 +432,3 @@ enum ECorpseFields CORPSE_END = OBJECT_END + 0x001E, }; #endif - diff --git a/src/game/World.cpp b/src/game/World.cpp index a822d202288..7d103c0457f 100644 --- a/src/game/World.cpp +++ b/src/game/World.cpp @@ -259,6 +259,8 @@ World::AddSession_ (WorldSession* s) pkt << uint32(sWorld.getConfig(CONFIG_CLIENTCACHE_VERSION)); s->SendPacket(&pkt); + s->SendAccountDataTimes(GLOBAL_CACHE_MASK); + s->SendTutorialsData(); UpdateMaxSessionCounters (); @@ -269,7 +271,6 @@ World::AddSession_ (WorldSession* s) float popu = GetActiveSessionCount (); // updated number of users on the server popu /= pLimit; popu *= 2; - loginDatabase.PExecute ("UPDATE realmlist SET population = '%f' WHERE id = '%d'", popu, realmID); sLog.outDetail ("Server Population (%f).", popu); } } @@ -365,6 +366,7 @@ bool World::RemoveQueuedPlayer(WorldSession* sess) pkt << uint32(sWorld.getConfig(CONFIG_CLIENTCACHE_VERSION)); pop_sess->SendPacket(&pkt); + pop_sess->SendAccountDataTimes(GLOBAL_CACHE_MASK); pop_sess->SendTutorialsData(); m_QueuedPlayer.pop_front(); @@ -553,41 +555,40 @@ void World::LoadConfigSettings(bool reload) rate_values[RATE_DURABILITY_LOSS_ON_DEATH] = sConfig.GetFloatDefault("DurabilityLoss.OnDeath", 10.0f); if (rate_values[RATE_DURABILITY_LOSS_ON_DEATH] < 0.0f) { - sLog.outError("DurabilityLoss.OnDeath (%f) must be >= 0. Using 0.0 instead.",rate_values[RATE_DURABILITY_LOSS_ON_DEATH]); + sLog.outError("DurabilityLoss.OnDeath (%f) must be >=0. Using 0.0 instead.",rate_values[RATE_DURABILITY_LOSS_ON_DEATH]); rate_values[RATE_DURABILITY_LOSS_ON_DEATH] = 0.0f; } if (rate_values[RATE_DURABILITY_LOSS_ON_DEATH] > 100.0f) { - sLog.outError("DurabilityLoss.OnDeath (%f) must be <= 100. Using 100.0 instead.",rate_values[RATE_DURABILITY_LOSS_ON_DEATH]); - rate_values[RATE_DURABILITY_LOSS_ON_DEATH] = 100.0f; + sLog.outError("DurabilityLoss.OnDeath (%f) must be <=100. Using 100.0 instead.",rate_values[RATE_DURABILITY_LOSS_ON_DEATH]); + rate_values[RATE_DURABILITY_LOSS_ON_DEATH] = 0.0f; } rate_values[RATE_DURABILITY_LOSS_ON_DEATH] = rate_values[RATE_DURABILITY_LOSS_ON_DEATH] / 100.0f; rate_values[RATE_DURABILITY_LOSS_DAMAGE] = sConfig.GetFloatDefault("DurabilityLossChance.Damage",0.5f); if (rate_values[RATE_DURABILITY_LOSS_DAMAGE] < 0.0f) { - sLog.outError("DurabilityLossChance.Damage (%f) must be >= 0. Using 0.0 instead.",rate_values[RATE_DURABILITY_LOSS_DAMAGE]); + sLog.outError("DurabilityLossChance.Damage (%f) must be >=0. Using 0.0 instead.",rate_values[RATE_DURABILITY_LOSS_DAMAGE]); rate_values[RATE_DURABILITY_LOSS_DAMAGE] = 0.0f; } rate_values[RATE_DURABILITY_LOSS_ABSORB] = sConfig.GetFloatDefault("DurabilityLossChance.Absorb",0.5f); if (rate_values[RATE_DURABILITY_LOSS_ABSORB] < 0.0f) { - sLog.outError("DurabilityLossChance.Absorb (%f) must be >= 0. Using 0.0 instead.",rate_values[RATE_DURABILITY_LOSS_ABSORB]); + sLog.outError("DurabilityLossChance.Absorb (%f) must be >=0. Using 0.0 instead.",rate_values[RATE_DURABILITY_LOSS_ABSORB]); rate_values[RATE_DURABILITY_LOSS_ABSORB] = 0.0f; } rate_values[RATE_DURABILITY_LOSS_PARRY] = sConfig.GetFloatDefault("DurabilityLossChance.Parry",0.05f); if (rate_values[RATE_DURABILITY_LOSS_PARRY] < 0.0f) { - sLog.outError("DurabilityLossChance.Parry (%f) must be >= 0. Using 0.0 instead.",rate_values[RATE_DURABILITY_LOSS_PARRY]); + sLog.outError("DurabilityLossChance.Parry (%f) must be >=0. Using 0.0 instead.",rate_values[RATE_DURABILITY_LOSS_PARRY]); rate_values[RATE_DURABILITY_LOSS_PARRY] = 0.0f; } rate_values[RATE_DURABILITY_LOSS_BLOCK] = sConfig.GetFloatDefault("DurabilityLossChance.Block",0.05f); if (rate_values[RATE_DURABILITY_LOSS_BLOCK] < 0.0f) { - sLog.outError("DurabilityLossChance.Block (%f) must be >= 0. Using 0.0 instead.",rate_values[RATE_DURABILITY_LOSS_BLOCK]); + sLog.outError("DurabilityLossChance.Block (%f) must be >=0. Using 0.0 instead.",rate_values[RATE_DURABILITY_LOSS_BLOCK]); rate_values[RATE_DURABILITY_LOSS_BLOCK] = 0.0f; } - ///- Read other configuration items from the config file m_configs[CONFIG_DURABILITY_LOSS_IN_PVP] = sConfig.GetBoolDefault("DurabilityLoss.InPvP", false); @@ -1193,7 +1194,7 @@ void World::LoadConfigSettings(bool reload) m_configs[CONFIG_INTERVAL_LOG_UPDATE] = sConfig.GetIntDefault("RecordUpdateTimeDiffInterval", 60000); m_configs[CONFIG_MIN_LOG_UPDATE] = sConfig.GetIntDefault("MinRecordUpdateTimeDiff", 10); m_configs[CONFIG_CHECK_DB] = sConfig.GetBoolDefault("CheckDB", true); - m_configs[CONFIG_NUMTHREADS] = sConfig.GetIntDefault("MapUpdate.Threads",1); + m_configs[CONFIG_NUMTHREADS] = sConfig.GetIntDefault("MapUpdate.Threads", 1); std::string forbiddenmaps = sConfig.GetStringDefault("ForbiddenMaps", ""); char * forbiddenMaps = new char[forbiddenmaps.length() + 1]; @@ -1303,9 +1304,6 @@ void World::SetInitialWorldSettings() sLog.outString("Loading Page Texts..."); objmgr.LoadPageTexts(); - sLog.outString("Loading Player info in cache..."); - objmgr.LoadPlayerInfoInCache(); - sLog.outString("Loading Game Object Templates..."); // must be after LoadPageTexts objmgr.LoadGameobjectInfo(); @@ -2584,6 +2582,16 @@ void World::LoadDBVersion() m_CreatureEventAIVersion = "Unknown creature EventAI."; } +void World::ProcessStartEvent() +{ + isEventKillStart = true; +} + +void World::ProcessStopEvent() +{ + isEventKillStart = false; +} + void World::UpdateAreaDependentAuras() { SessionMap::const_iterator itr; diff --git a/src/game/World.h b/src/game/World.h index fb73d4ed08c..79c621d9a51 100644 --- a/src/game/World.h +++ b/src/game/World.h @@ -45,6 +45,7 @@ struct ScriptInfo; class SqlResultQueue; class QueryResult; class WorldSocket; +class SystemMgr; // ServerMessages.dbc enum ServerMessageType @@ -81,7 +82,8 @@ enum WorldTimers WUPDATE_EVENTS = 6, WUPDATE_CLEANDB = 7, WUPDATE_AUTOBROADCAST = 8, - WUPDATE_COUNT = 9 + WUPDATE_MAILBOXQUEUE = 9, + WUPDATE_COUNT = 10 }; // States than may change after server started @@ -261,6 +263,7 @@ enum WorldConfigs CONFIG_MIN_LOG_UPDATE, CONFIG_CHECK_DB, CONFIG_ENABLE_SINFO_LOGIN, + CONFIG_PLAYER_ALLOW_COMMANDS, CONFIG_PET_LOS, CONFIG_NUMTHREADS, CONFIG_OFFHAND_CHECK_AT_SPELL_UNLEARN, @@ -610,6 +613,19 @@ class World static float GetVisibleUnitGreyDistance() { return m_VisibleUnitGreyDistance; } static float GetVisibleObjectGreyDistance() { return m_VisibleObjectGreyDistance; } + + void SetWintergrapsTimer(uint32 timer, uint32 state) + { + m_WintergrapsTimer = timer; + m_WintergrapsState = state; + } + + uint32 GetWintergrapsTimer() { return m_WintergrapsTimer; } + uint32 GetWintergrapsState() { return m_WintergrapsState; } + + uint32 m_WintergrapsTimer; + uint32 m_WintergrapsState; + void ProcessCliCommands(); void QueueCliCommand( CliCommandHolder::Print* zprintf, char const* input ) { cliCmdQueue.add(new CliCommandHolder(input, zprintf)); } @@ -638,6 +654,12 @@ class World void LoadAutobroadcasts(); void UpdateAreaDependentAuras(); + + void ProcessStartEvent(); + void ProcessStopEvent(); + bool GetEventKill() { return isEventKillStart; } + + bool isEventKillStart; protected: void _UpdateGameTime(); // callback for UpdateRealmCharacters @@ -728,4 +750,3 @@ extern uint32 realmID; #define sWorld Trinity::Singleton<World>::Instance() #endif /// @} - diff --git a/src/game/WorldSession.cpp b/src/game/WorldSession.cpp index bbcf4fcbf70..569c8fade62 100644 --- a/src/game/WorldSession.cpp +++ b/src/game/WorldSession.cpp @@ -655,13 +655,15 @@ void WorldSession::SetAccountData(AccountDataType type, time_t time_, std::strin m_accountData[type].Data = data; } -void WorldSession::SendAccountDataTimes() +void WorldSession::SendAccountDataTimes(uint32 mask) { - WorldPacket data( SMSG_ACCOUNT_DATA_TIMES, 4+1+8*4 ); // changed in WotLK + WorldPacket data( SMSG_ACCOUNT_DATA_TIMES, 4+1+4+8*4 ); // changed in WotLK data << uint32(time(NULL)); // unix time of something data << uint8(1); - for (int i = 0; i < NUM_ACCOUNT_DATA_TYPES; ++i) - data << uint32(m_accountData[i].Time); // also unix time + data << uint32(mask); // type mask + for(uint32 i = 0; i < NUM_ACCOUNT_DATA_TYPES; ++i) + if(mask & (1 << i)) + data << uint32(GetAccountData(AccountDataType(i))->Time);// also unix time SendPacket(&data); } @@ -768,6 +770,51 @@ void WorldSession::ReadMovementInfo(WorldPacket &data, MovementInfo *mi) } } +void WorldSession::WriteMovementInfo(WorldPacket *data, MovementInfo *mi) +{ + data->appendPackGUID(mi->guid); + + *data << mi->flags; + *data << mi->unk1; + *data << mi->time; + *data << mi->x; + *data << mi->y; + *data << mi->z; + *data << mi->o; + + if(mi->HasMovementFlag(MOVEMENTFLAG_ONTRANSPORT)) + { + data->appendPackGUID(mi->t_guid); + + *data << mi->t_x; + *data << mi->t_y; + *data << mi->t_z; + *data << mi->t_o; + *data << mi->t_time; + *data << mi->t_seat; + } + + if((mi->HasMovementFlag(MovementFlags(MOVEMENTFLAG_SWIMMING | MOVEMENTFLAG_FLYING))) || (mi->unk1 & 0x20)) + { + *data << mi->s_pitch; + } + + *data << mi->fallTime; + + if(mi->HasMovementFlag(MOVEMENTFLAG_JUMPING)) + { + *data << mi->j_zspeed; + *data << mi->j_sinAngle; + *data << mi->j_cosAngle; + *data << mi->j_xyspeed; + } + + if(mi->HasMovementFlag(MOVEMENTFLAG_SPLINE)) + { + *data << mi->u_unk1; + } +} + void WorldSession::ReadAddonsInfo(WorldPacket &data) { if (data.rpos() + 4 > data.size()) diff --git a/src/game/WorldSession.h b/src/game/WorldSession.h index 0e0d5df9480..7e81a3d338f 100644 --- a/src/game/WorldSession.h +++ b/src/game/WorldSession.h @@ -126,6 +126,7 @@ class TRINITY_DLL_SPEC WorldSession void SendAddonsInfo(); void ReadMovementInfo(WorldPacket &data, MovementInfo *mi); + void WriteMovementInfo(WorldPacket *data, MovementInfo *mi); void SendPacket(WorldPacket const* packet); void SendNotification(const char *format,...) ATTR_PRINTF(2,3); @@ -203,7 +204,7 @@ class TRINITY_DLL_SPEC WorldSession // Account Data AccountData *GetAccountData(AccountDataType type) { return &m_accountData[type]; } void SetAccountData(AccountDataType type, time_t time_, std::string data); - void SendAccountDataTimes(); + void SendAccountDataTimes(uint32 mask); void LoadGlobalAccountData(); void LoadAccountData(QueryResult* result, uint32 mask); void LoadTutorialsData(); @@ -222,9 +223,8 @@ class TRINITY_DLL_SPEC WorldSession m_TutorialsChanged = true; } } - //used with item_page table + //used with item_page table bool SendItemInfo( uint32 itemid, WorldPacket data ); - //auction void SendAuctionHello( uint64 guid, Creature * unit ); void SendAuctionCommandResult( uint32 auctionId, uint32 Action, uint32 ErrorCode, uint32 bidError = 0); @@ -573,6 +573,7 @@ class TRINITY_DLL_SPEC WorldSession void HandleReclaimCorpseOpcode( WorldPacket& recvPacket ); void HandleCorpseQueryOpcode( WorldPacket& recvPacket ); + void HandleCorpseMapPositionQuery( WorldPacket& recvPacket ); void HandleResurrectResponseOpcode(WorldPacket& recvPacket); void HandleSummonResponseOpcode(WorldPacket& recv_data); @@ -647,6 +648,7 @@ class TRINITY_DLL_SPEC WorldSession void HandleFarSightOpcode(WorldPacket& recv_data); void HandleSetLfgOpcode(WorldPacket& recv_data); void HandleSetDungeonDifficultyOpcode(WorldPacket& recv_data); + void HandleSetRaidDifficultyOpcode(WorldPacket& recv_data); void HandleMoveSetCanFlyAckOpcode(WorldPacket& recv_data); void HandleLfgSetAutoJoinOpcode(WorldPacket& recv_data); void HandleLfgClearAutoJoinOpcode(WorldPacket& recv_data); @@ -687,6 +689,9 @@ class TRINITY_DLL_SPEC WorldSession void HandleCancelTempEnchantmentOpcode(WorldPacket& recv_data); + void HandleItemRefundInfoRequest(WorldPacket& recv_data); + void HandleItemRefund(WorldPacket& recv_data); + void HandleChannelVoiceOnOpcode(WorldPacket & recv_data); void HandleVoiceSessionEnableOpcode(WorldPacket& recv_data); void HandleSetActiveVoiceChannel(WorldPacket& recv_data); @@ -733,6 +738,7 @@ class TRINITY_DLL_SPEC WorldSession void HandleEquipmentSetSave(WorldPacket& recv_data); void HandleEquipmentSetDelete(WorldPacket& recv_data); void HandleEquipmentSetUse(WorldPacket& recv_data); + void HandleWorldStateUITimerUpdate(WorldPacket& recv_data); void HandleOnPVPKill(Player *killed); bool HandleOnPlayerChat(const char *text); uint32 HandleOnGetXP(uint32 amount); @@ -776,4 +782,3 @@ class TRINITY_DLL_SPEC WorldSession }; #endif /// @} - diff --git a/src/game/WorldSocket.cpp b/src/game/WorldSocket.cpp index 6991e4d112f..680d0515d61 100644 --- a/src/game/WorldSocket.cpp +++ b/src/game/WorldSocket.cpp @@ -255,8 +255,13 @@ int WorldSocket::open (void *a) m_Address = remote_addr.get_host_addr (); // Send startup packet. - WorldPacket packet (SMSG_AUTH_CHALLENGE, 4); + WorldPacket packet (SMSG_AUTH_CHALLENGE, 24); + packet << uint32(1); // 1...31 packet << m_Seed; + packet << uint32(0xF3539DA3); // random data + packet << uint32(0x6E8547B9); // random data + packet << uint32(0x9A6AA2F8); // random data + packet << uint32(0xA4F170F4); // random data if (SendPacket (packet) == -1) return -1; @@ -690,6 +695,7 @@ int WorldSocket::HandleAuthSession (WorldPacket& recvPacket) uint8 digest[20]; uint32 clientSeed; uint32 unk2, unk3; + uint64 unk4; uint32 BuiltNumberClient; uint32 id, security; //uint8 expansion = 0; @@ -717,6 +723,7 @@ int WorldSocket::HandleAuthSession (WorldPacket& recvPacket) recvPacket >> account; recvPacket >> unk3; recvPacket >> clientSeed; + recvPacket >> unk4; recvPacket.read (digest, 20); DEBUG_LOG ("WorldSocket::HandleAuthSession: client %u, unk2 %u, account %s, unk3 %u, clientseed %u", @@ -1066,4 +1073,3 @@ bool WorldSocket::iFlushPacketQueue() return haveone; } - diff --git a/src/shared/Database/SQLStorage.cpp b/src/shared/Database/SQLStorage.cpp index 0ea5c3d826b..0b2c0ffdf84 100644 --- a/src/shared/Database/SQLStorage.cpp +++ b/src/shared/Database/SQLStorage.cpp @@ -27,19 +27,19 @@ extern DatabasePostgre WorldDatabase; extern DatabaseMysql WorldDatabase; #endif -const char CreatureInfosrcfmt[]="iiiiiiiisssiiiiiiiiiiffiffiifiiiiiiiiiiffiiiiiiiiiiiiiiiiiiiiiiiisiiffliiiiiiiliiis"; -const char CreatureInfodstfmt[]="iiiiiiiisssiiiiiiiiiiffiffiifiiiiiiiiiiffiiiiiiiiiiiiiiiiiiiiiiiisiiffliiiiiiiliiii"; +const char CreatureInfosrcfmt[]="iiiiiiiiiisssiiiiiiiiiiffiffiifiiiiiiiiiiffiiiiiiiiiiiiiiiiiiiiiiiisiiffliiiiiiiliiis"; +const char CreatureInfodstfmt[]="iiiiiiiiiisssiiiiiiiiiiffiffiifiiiiiiiiiiffiiiiiiiiiiiiiiiiiiiiiiiisiiffliiiiiiiliiii"; const char CreatureDataAddonInfofmt[]="iiiiiiis"; const char CreatureModelfmt[]="iffbi"; const char CreatureInfoAddonInfofmt[]="iiiiiiis"; const char EquipmentInfofmt[]="iiii"; const char GameObjectInfosrcfmt[]="iiissssiifiiiiiiiiiiiiiiiiiiiiiiiiiiiiiis"; const char GameObjectInfodstfmt[]="iiissssiifiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii"; -const char ItemPrototypesrcfmt[]="iiiisiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiffiffiiiiiiiiiifiiifiiiiiifiiiiiifiiiiiifiiiiiifiiiisiiiiiiiiiiiiiiiiiiiiiiiiifiiisiiii"; -const char ItemPrototypedstfmt[]="iiiisiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiffiffiiiiiiiiiifiiifiiiiiifiiiiiifiiiiiifiiiiiifiiiisiiiiiiiiiiiiiiiiiiiiiiiiifiiiiiiii"; +const char ItemPrototypesrcfmt[]="iiiisiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiffiffiiiiiiiiiifiiifiiiiiifiiiiiifiiiiiifiiiiiifiiiisiiiiiiiiiiiiiiiiiiiiiiiiifiiisiiii"; +const char ItemPrototypedstfmt[]="iiiisiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiffiffiiiiiiiiiifiiifiiiiiifiiiiiifiiiiiifiiiiiifiiiisiiiiiiiiiiiiiiiiiiiiiiiiifiiiiiiii"; const char PageTextfmt[]="isi"; -const char InstanceTemplatesrcfmt[]="iiiiiiffffs"; -const char InstanceTemplatedstfmt[]="iiiiiiffffi"; +const char InstanceTemplatesrcfmt[]="iiiffffs"; +const char InstanceTemplatedstfmt[]="iiiffffi"; SQLStorage sCreatureStorage(CreatureInfosrcfmt, CreatureInfodstfmt, "entry","creature_template"); SQLStorage sCreatureDataAddonStorage(CreatureDataAddonInfofmt,"guid","creature_addon"); @@ -79,4 +79,3 @@ void SQLStorage::Load() SQLStorageLoader loader; loader.Load(*this); } - diff --git a/src/trinityrealm/AuthCodes.h b/src/trinityrealm/AuthCodes.h index 73728898503..53ae2236bcd 100644 --- a/src/trinityrealm/AuthCodes.h +++ b/src/trinityrealm/AuthCodes.h @@ -72,7 +72,8 @@ enum LoginResult //2.4.3 build 8606 //3.1.3 build 9947 //3.1.3 build 10146 Chinese build +//3.2.2a build 10505 -#define EXPECTED_TRINITY_CLIENT_BUILD {10146, 9947, 8606, 5875, 6005, 0} +#define EXPECTED_TRINITY_CLIENT_BUILD {10505, 10146, 9947, 8606, 5875, 6005, 0} #endif diff --git a/src/trinityrealm/AuthSocket.cpp b/src/trinityrealm/AuthSocket.cpp index 90a2a27d5b9..bd79fc5d207 100644 --- a/src/trinityrealm/AuthSocket.cpp +++ b/src/trinityrealm/AuthSocket.cpp @@ -706,7 +706,7 @@ bool AuthSocket::_HandleLogonProof() sha.UpdateBigNumbers(&A, &M, &K, NULL); sha.Finalize(); - if (_build == 8606 || _build == 9947 || _build == 10146)//2.4.3 and 3.1.3 clients (10146 is Chinese build for 3.1.3) + if (_build == 8606 || _build == 9947 || _build == 10146 || _build == 10505)//2.4.3, 3.1.3 and 3.2.2a clients (10146 is Chinese build for 3.1.3) { sAuthLogonProof_S proof; memcpy(proof.M2, sha.GetDigest(), 20); @@ -909,7 +909,7 @@ bool AuthSocket::_HandleRealmList() RealmList built_realmList; for (rlm = m_realmList.begin(); rlm != m_realmList.end(); ++rlm) { - if (_build == 8606 || _build == 9947 || _build == 10146)//2.4.3 and 3.1.3 cliens + if (_build == 8606 || _build == 9947 || _build == 10146 || _build == 10505)//2.4.3, 3.1.3 and 3.2.2a clients { if (rlm->second.gamebuild == _build) built_realmList.AddRealm(rlm->second); @@ -925,7 +925,7 @@ bool AuthSocket::_HandleRealmList() ///- Circle through realms in the RealmList and construct the return packet (including # of user characters in each realm) ByteBuffer pkt; pkt << (uint32) 0; - if (_build == 8606 || _build == 9947 || _build == 10146)//only 2.4.3 and 3.1.3 cliens + if (_build == 8606 || _build == 9947 || _build == 10146 || _build == 10505)//only 2.4.3, 3.1.3 and 3.2.2a clients pkt << (uint16) built_realmList.size(); else pkt << (uint32) built_realmList.size(); @@ -948,7 +948,7 @@ bool AuthSocket::_HandleRealmList() uint8 lock = (i->second.allowedSecurityLevel > _accountSecurityLevel) ? 1 : 0; pkt << i->second.icon; // realm type - if (i->second.gamebuild == 9947 || i->second.gamebuild == 10146 || i->second.gamebuild == 8606)//only 2.4.3 and 3.1.3 cliens + if (i->second.gamebuild == 10505 || i->second.gamebuild == 9947 || i->second.gamebuild == 10146 || i->second.gamebuild == 8606)//only 2.4.3, 3.1.3 and 3.2.2a clients pkt << lock; // if 1, then realm locked pkt << i->second.color; // if 2, then realm is offline pkt << i->first; @@ -956,13 +956,13 @@ bool AuthSocket::_HandleRealmList() pkt << i->second.populationLevel; pkt << AmountOfCharacters; pkt << i->second.timezone; // realm category - if (i->second.gamebuild == 9947 || i->second.gamebuild == 10146 || i->second.gamebuild == 8606)//2.4.3 and 3.1.3 clients + if (i->second.gamebuild == 10505 || i->second.gamebuild == 9947 || i->second.gamebuild == 10146 || i->second.gamebuild == 8606)//2.4.3, 3.1.3 and 3.2.2a clients pkt << (uint8) 0x2C; // unk, may be realm number/id? else pkt << (uint8) 0x0; //1.12.1 and 1.12.2 clients } - if (_build == 9947 || _build == 10146 || _build == 8606)//2.4.3 and 3.1.3 cliens + if (_build == 10505 || _build == 9947 || _build == 10146 || _build == 8606)//2.4.3, 3.1.3 and 3.2.2a clients { pkt << (uint8) 0x10; pkt << (uint8) 0x00; |