diff options
Diffstat (limited to 'src')
112 files changed, 1627 insertions, 1043 deletions
diff --git a/src/server/game/AI/CoreAI/GameObjectAI.h b/src/server/game/AI/CoreAI/GameObjectAI.h index 8d0e0508113..93cd3a6d237 100644 --- a/src/server/game/AI/CoreAI/GameObjectAI.h +++ b/src/server/game/AI/CoreAI/GameObjectAI.h @@ -49,6 +49,7 @@ class GameObjectAI virtual uint32 GetDialogStatus(Player* /*player*/) {return 100;} virtual void Destroyed(Player* /*player*/, uint32 /*eventId*/) {} virtual void SetData(uint32 /*id*/, uint32 /*value*/) {} + virtual void OnGameEvent(bool /*start*/, uint16 /*eventId*/) {} }; class NullGameObjectAI : public GameObjectAI diff --git a/src/server/game/AI/CoreAI/UnitAI.h b/src/server/game/AI/CoreAI/UnitAI.h index 3c16fe493b4..444dce0339e 100755 --- a/src/server/game/AI/CoreAI/UnitAI.h +++ b/src/server/game/AI/CoreAI/UnitAI.h @@ -267,6 +267,7 @@ class UnitAI virtual void sQuestComplete(Player* /*player*/, Quest const* /*quest*/) {} virtual void sQuestReward(Player* /*player*/, Quest const* /*quest*/, uint32 /*opt*/) {} virtual bool sOnDummyEffect(Unit* /*caster*/, uint32 /*spellId*/, SpellEffIndex /*effIndex*/) { return false; } + virtual void sOnGameEvent(bool /*start*/, uint16 /*eventId*/) {} }; class PlayerAI : public UnitAI diff --git a/src/server/game/AI/EventAI/CreatureEventAI.cpp b/src/server/game/AI/EventAI/CreatureEventAI.cpp index be0dd8c3679..1db6bbd550e 100755 --- a/src/server/game/AI/EventAI/CreatureEventAI.cpp +++ b/src/server/game/AI/EventAI/CreatureEventAI.cpp @@ -840,7 +840,7 @@ void CreatureEventAI::ProcessAction(CreatureEventAI_Action const& action, uint32 me->Mount(action.mount.modelId); } else - me->Unmount(); + me->Dismount(); break; } diff --git a/src/server/game/AI/EventAI/CreatureEventAI.h b/src/server/game/AI/EventAI/CreatureEventAI.h index 2fc26bcbd3e..9cc8c8f9c4a 100755 --- a/src/server/game/AI/EventAI/CreatureEventAI.h +++ b/src/server/game/AI/EventAI/CreatureEventAI.h @@ -108,7 +108,7 @@ enum EventAI_ActionType ACTION_T_SET_SHEATH = 40, // Sheath (0-passive, 1-melee, 2-ranged) ACTION_T_FORCE_DESPAWN = 41, // No Params ACTION_T_SET_INVINCIBILITY_HP_LEVEL = 42, // MinHpValue, format(0-flat, 1-percent from max health) - ACTION_T_MOUNT_TO_ENTRY_OR_MODEL = 43, // Creature_template entry(param1) OR ModelId (param2) (or 0 for both to unmount) + ACTION_T_MOUNT_TO_ENTRY_OR_MODEL = 43, // Creature_template entry(param1) OR ModelId (param2) (or 0 for both to dismount) ACTION_T_SET_PHASE_MASK = 97, ACTION_T_SET_STAND_STATE = 98, diff --git a/src/server/game/AI/ScriptedAI/ScriptedEscortAI.cpp b/src/server/game/AI/ScriptedAI/ScriptedEscortAI.cpp index 06c1570ccd9..c5f04d4ff5f 100644 --- a/src/server/game/AI/ScriptedAI/ScriptedEscortAI.cpp +++ b/src/server/game/AI/ScriptedAI/ScriptedEscortAI.cpp @@ -543,7 +543,6 @@ bool npc_escortAI::GetWaypointPosition(uint32 pointId, float& x, float& y, float if (waypoints.empty()) return false; - ScriptPointVector::const_iterator itrEnd = waypoints.end(); for (ScriptPointVector::const_iterator itr = waypoints.begin(); itr != waypoints.end(); ++itr) { if (itr->uiPointId == pointId) diff --git a/src/server/game/AI/SmartScripts/SmartAI.cpp b/src/server/game/AI/SmartScripts/SmartAI.cpp index afa7e9c2932..7dd793a302b 100644 --- a/src/server/game/AI/SmartScripts/SmartAI.cpp +++ b/src/server/game/AI/SmartScripts/SmartAI.cpp @@ -707,7 +707,7 @@ void SmartAI::SetRun(bool run) me->RemoveUnitMovementFlag(MOVEMENTFLAG_WALKING); else me->AddUnitMovementFlag(MOVEMENTFLAG_WALKING); - me->SendMovementFlagUpdate(); + mRun = run; } @@ -811,6 +811,12 @@ void SmartAI::SetScript9(SmartScriptHolder& e, uint32 entry, Unit* invoker) GetScript()->mLastInvoker = invoker->GetGUID(); GetScript()->SetScript9(e, entry); } + +void SmartAI::sOnGameEvent(bool start, uint16 eventId) +{ + GetScript()->ProcessEventsFor(start ? SMART_EVENT_GAME_EVENT_START : SMART_EVENT_GAME_EVENT_END, NULL, eventId); +} + /* SMART_EVENT_UPDATE_OOC SMART_EVENT_SPELLHIT @@ -913,6 +919,11 @@ void SmartGameObjectAI::SetScript9(SmartScriptHolder& e, uint32 entry, Unit* inv GetScript()->SetScript9(e, entry); } +void SmartGameObjectAI::OnGameEvent(bool start, uint16 eventId) +{ + GetScript()->ProcessEventsFor(start ? SMART_EVENT_GAME_EVENT_START : SMART_EVENT_GAME_EVENT_END, NULL, eventId); +} + class SmartTrigger : public AreaTriggerScript { public: diff --git a/src/server/game/AI/SmartScripts/SmartAI.h b/src/server/game/AI/SmartScripts/SmartAI.h index 8bb3bda8dd6..dc1f901d477 100644 --- a/src/server/game/AI/SmartScripts/SmartAI.h +++ b/src/server/game/AI/SmartScripts/SmartAI.h @@ -183,6 +183,7 @@ class SmartAI : public CreatureAI //void sQuestComplete(Player* player, Quest const* quest); void sQuestReward(Player* player, Quest const* quest, uint32 opt); bool sOnDummyEffect(Unit* caster, uint32 spellId, SpellEffIndex effIndex); + void sOnGameEvent(bool start, uint16 eventId); uint32 mEscortQuestID; @@ -249,6 +250,7 @@ public: void Destroyed(Player* player, uint32 eventId); void SetData(uint32 id, uint32 value); void SetScript9(SmartScriptHolder& e, uint32 entry, Unit* invoker); + void OnGameEvent(bool start, uint16 eventId); protected: GameObject* const go; diff --git a/src/server/game/AI/SmartScripts/SmartScript.cpp b/src/server/game/AI/SmartScripts/SmartScript.cpp index c845f6110d6..34d465a5e7e 100644 --- a/src/server/game/AI/SmartScripts/SmartScript.cpp +++ b/src/server/game/AI/SmartScripts/SmartScript.cpp @@ -994,7 +994,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u (*itr)->ToUnit()->Mount(e.action.morphOrMount.model); } else - (*itr)->ToUnit()->Unmount(); + (*itr)->ToUnit()->Dismount(); } delete targets; @@ -1493,7 +1493,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u else if (GameObject* goTarget = (*itr)->ToGameObject()) { if (IsSmartGO(goTarget)) - CAST_AI(SmartGameObjectAI, target->AI())->SetScript9(e, e.action.timedActionList.id, GetLastInvoker()); + CAST_AI(SmartGameObjectAI, goTarget->AI())->SetScript9(e, e.action.timedActionList.id, GetLastInvoker()); } } @@ -1610,7 +1610,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u else if (GameObject* goTarget = (*itr)->ToGameObject()) { if (IsSmartGO(goTarget)) - CAST_AI(SmartGameObjectAI, target->AI())->SetScript9(e, id, GetLastInvoker()); + CAST_AI(SmartGameObjectAI, goTarget->AI())->SetScript9(e, id, GetLastInvoker()); } } @@ -1640,7 +1640,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u else if (GameObject* goTarget = (*itr)->ToGameObject()) { if (IsSmartGO(goTarget)) - CAST_AI(SmartGameObjectAI, target->AI())->SetScript9(e, id, GetLastInvoker()); + CAST_AI(SmartGameObjectAI, goTarget->AI())->SetScript9(e, id, GetLastInvoker()); } } @@ -2595,6 +2595,14 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui ProcessAction(e, unit, var0, var1); break; } + case SMART_EVENT_GAME_EVENT_START: + case SMART_EVENT_GAME_EVENT_END: + { + if (e.event.gameEvent.gameEventId != var0) + return; + ProcessAction(e, NULL, var0); + break; + } default: sLog->outErrorDb("SmartScript::ProcessEvent: Unhandled Event type %u", e.GetEventType()); break; @@ -2996,7 +3004,9 @@ void SmartScript::SetScript9(SmartScriptHolder& e, uint32 entry) mResumeActionList = e.action.timedActionList.dontResume ? false : true; InitTimer((*i)); } -}Unit* SmartScript::GetLastInvoker() +} + +Unit* SmartScript::GetLastInvoker() { return ObjectAccessor::FindUnit(mLastInvoker); } diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp index 011ed75205d..1df5849ca75 100644 --- a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp +++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp @@ -26,6 +26,7 @@ #include "CellImpl.h" #include "InstanceScript.h" #include "ScriptedCreature.h" +#include "GameEventMgr.h" #include "SmartScriptMgr.h" @@ -466,6 +467,14 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e) if (!IsMinMaxValid(e, e.event.behindTarget.cooldownMin, e.event.behindTarget.cooldownMax)) return false; break; + case SMART_EVENT_GAME_EVENT_START: + case SMART_EVENT_GAME_EVENT_END: + { + GameEventMgr::GameEventDataMap const& events = sGameEventMgr->GetEventMap(); + if (e.event.gameEvent.gameEventId >= events.size() || !events[e.event.gameEvent.gameEventId].isValid()) + return false; + break; + } case SMART_EVENT_TIMED_EVENT_TRIGGERED: case SMART_EVENT_INSTANCE_PLAYER_ENTER: case SMART_EVENT_TRANSPORT_RELOCATE: @@ -492,7 +501,6 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e) case SMART_EVENT_WAYPOINT_RESUMED: case SMART_EVENT_WAYPOINT_STOPPED: case SMART_EVENT_WAYPOINT_ENDED: - case SMART_ACTION_PLAYMOVIE: case SMART_EVENT_GOSSIP_SELECT: case SMART_EVENT_GOSSIP_HELLO: case SMART_EVENT_JUST_CREATED: diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.h b/src/server/game/AI/SmartScripts/SmartScriptMgr.h index e80da52ccd3..e8ec80672fc 100644 --- a/src/server/game/AI/SmartScripts/SmartScriptMgr.h +++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.h @@ -152,8 +152,10 @@ enum SMART_EVENT SMART_EVENT_FOLLOW_COMPLETED = 65, //1 // none SMART_EVENT_DUMMY_EFFECT = 66, //1 // spellId, effectIndex SMART_EVENT_IS_BEHIND_TARGET = 67, //1 // cooldownMin, CooldownMax + SMART_EVENT_GAME_EVENT_START = 68, //1 // game_event.Entry + SMART_EVENT_GAME_EVENT_END = 69, //1 // game_event.Entry - SMART_EVENT_END = 68, + SMART_EVENT_END = 70, }; struct SmartEvent @@ -338,6 +340,11 @@ struct SmartEvent uint32 cooldownMax; } behindTarget; + struct + { + uint32 gameEventId; + } gameEvent; + struct { uint32 param1; @@ -401,7 +408,7 @@ enum SMART_ACTION SMART_ACTION_SET_SHEATH = 40, // Sheath (0-unarmed, 1-melee, 2-ranged) SMART_ACTION_FORCE_DESPAWN = 41, // timer SMART_ACTION_SET_INVINCIBILITY_HP_LEVEL = 42, // MinHpValue(+pct, -flat) - SMART_ACTION_MOUNT_TO_ENTRY_OR_MODEL = 43, // Creature_template entry(param1) OR ModelId (param2) (or 0 for both to unmount) + SMART_ACTION_MOUNT_TO_ENTRY_OR_MODEL = 43, // Creature_template entry(param1) OR ModelId (param2) (or 0 for both to dismount) SMART_ACTION_SET_INGAME_PHASE_MASK = 44, // mask SMART_ACTION_SET_DATA = 45, // Field, Data (only creature TODO) @@ -1128,7 +1135,9 @@ const uint32 SmartAIEventMask[SMART_EVENT_END][2] = {SMART_EVENT_GOSSIP_HELLO, SMART_SCRIPT_TYPE_MASK_CREATURE + SMART_SCRIPT_TYPE_MASK_GAMEOBJECT }, {SMART_EVENT_FOLLOW_COMPLETED, SMART_SCRIPT_TYPE_MASK_CREATURE }, {SMART_EVENT_DUMMY_EFFECT, SMART_SCRIPT_TYPE_MASK_SPELL }, - {SMART_EVENT_IS_BEHIND_TARGET, SMART_SCRIPT_TYPE_MASK_CREATURE } + {SMART_EVENT_IS_BEHIND_TARGET, SMART_SCRIPT_TYPE_MASK_CREATURE }, + {SMART_EVENT_GAME_EVENT_START, SMART_SCRIPT_TYPE_MASK_CREATURE + SMART_SCRIPT_TYPE_MASK_GAMEOBJECT }, + {SMART_EVENT_GAME_EVENT_END, SMART_SCRIPT_TYPE_MASK_CREATURE + SMART_SCRIPT_TYPE_MASK_GAMEOBJECT }, }; diff --git a/src/server/game/Achievements/AchievementMgr.cpp b/src/server/game/Achievements/AchievementMgr.cpp index 8967446f199..d22f4b94caa 100755 --- a/src/server/game/Achievements/AchievementMgr.cpp +++ b/src/server/game/Achievements/AchievementMgr.cpp @@ -102,6 +102,7 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria) case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DAILY_QUEST: // only Children's Week achievements case ACHIEVEMENT_CRITERIA_TYPE_USE_ITEM: // only Children's Week achievements case ACHIEVEMENT_CRITERIA_TYPE_GET_KILLING_BLOWS: + case ACHIEVEMENT_CRITERIA_TYPE_REACH_LEVEL: break; default: if (dataType != ACHIEVEMENT_CRITERIA_DATA_TYPE_SCRIPT) @@ -135,13 +136,13 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria) } if (classRace.class_id && ((1 << (classRace.class_id-1)) & CLASSMASK_ALL_PLAYABLE) == 0) { - sLog->outErrorDb("Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_CREATURE (%u) has non-existing class in value1 (%u), ignored.", + sLog->outErrorDb("Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_PLAYER_CLASS_RACE (%u) has non-existing class in value1 (%u), ignored.", criteria->ID, criteria->requiredType, dataType, classRace.class_id); return false; } if (classRace.race_id && ((1 << (classRace.race_id-1)) & RACEMASK_ALL_PLAYABLE) == 0) { - sLog->outErrorDb("Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_CREATURE (%u) has non-existing race in value2 (%u), ignored.", + sLog->outErrorDb("Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_PLAYER_CLASS_RACE (%u) has non-existing race in value2 (%u), ignored.", criteria->ID, criteria->requiredType, dataType, classRace.race_id); return false; } @@ -450,7 +451,7 @@ void AchievementMgr::ResetAchievementCriteria(AchievementCriteriaTypes type, uin continue; // don't update already completed criteria if not forced or achievement already complete - if ((IsCompletedCriteria(achievementCriteria, achievement) && !evenIfCriteriaComplete) || HasAchieved(achievement)) + if ((IsCompletedCriteria(achievementCriteria, achievement) && !evenIfCriteriaComplete) || HasAchieved(achievement->ID)) continue; for (uint8 j = 0; j < MAX_CRITERIA_REQUIREMENTS; ++j) @@ -846,6 +847,9 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui break; } case ACHIEVEMENT_CRITERIA_TYPE_REACH_LEVEL: + if (AchievementCriteriaDataSet const* data = sAchievementMgr->GetCriteriaDataSet(achievementCriteria)) + if (!data->Meets(GetPlayer(), unit)) + continue; SetCriteriaProgress(achievementCriteria, GetPlayer()->getLevel()); break; case ACHIEVEMENT_CRITERIA_TYPE_REACH_SKILL_LEVEL: @@ -1065,14 +1069,9 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui continue; } - if (achievement->ID == 1282) - { - // those requirements couldn't be found in the dbc - AchievementCriteriaDataSet const* data = sAchievementMgr->GetCriteriaDataSet(achievementCriteria); - if (!data || !data->Meets(GetPlayer(), unit)) + if (AchievementCriteriaDataSet const* data = sAchievementMgr->GetCriteriaDataSet(achievementCriteria)) + if (!data->Meets(GetPlayer(), unit)) continue; - break; - } SetCriteriaProgress(achievementCriteria, 1); break; @@ -1597,9 +1596,6 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui } } -static const uint32 achievIdByClass[MAX_CLASSES] = { 0, 459, 465, 462, 458, 464, 461, 467, 460, 463, 0, 466 }; -static const uint32 achievIdByRace[MAX_RACES] = { 0, 1408, 1410, 1407, 1409, 1413, 1411, 1404, 1412, 0, 1405, 1406 }; - bool AchievementMgr::IsCompletedCriteria(AchievementCriteriaEntry const* achievementCriteria, AchievementEntry const* achievement) { // counter can never complete @@ -1624,20 +1620,7 @@ bool AchievementMgr::IsCompletedCriteria(AchievementCriteriaEntry const* achieve case ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE: return progress->counter >= achievementCriteria->kill_creature.creatureCount; case ACHIEVEMENT_CRITERIA_TYPE_REACH_LEVEL: - { - // skip wrong class achievements - for (int i = 1; i < MAX_CLASSES; ++i) - if (achievIdByClass[i] == achievement->ID && i != GetPlayer()->getClass()) - return false; - - // skip wrong race achievements - for (int i = 1; i < MAX_RACES; ++i) - if (achievIdByRace[i] == achievement->ID && i != GetPlayer()->getRace()) - return false; - - // appropriate class/race or not class/race specific return progress->counter >= achievementCriteria->reach_level.level; - } case ACHIEVEMENT_CRITERIA_TYPE_REACH_SKILL_LEVEL: return progress->counter >= achievementCriteria->reach_skill_level.skillLevel; case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_ACHIEVEMENT: @@ -1778,7 +1761,7 @@ void AchievementMgr::CompletedCriteriaFor(AchievementEntry const* achievement) return; // already completed and stored - if (HasAchieved(achievement)) + if (HasAchieved(achievement->ID)) return; if (IsCompletedAchievement(achievement)) @@ -2012,7 +1995,7 @@ void AchievementMgr::CompletedAchievement(AchievementEntry const* achievement) if (m_player->isGameMaster()) return; - if (achievement->flags & ACHIEVEMENT_FLAG_COUNTER || HasAchieved(achievement)) + if (achievement->flags & ACHIEVEMENT_FLAG_COUNTER || HasAchieved(achievement->ID)) return; SendAchievementEarned(achievement); @@ -2127,9 +2110,9 @@ void AchievementMgr::BuildAllDataPacket(WorldPacket* data) const *data << int32(-1); } -bool AchievementMgr::HasAchieved(AchievementEntry const* achievement) const +bool AchievementMgr::HasAchieved(uint32 achievementId) const { - return m_completedAchievements.find(achievement->ID) != m_completedAchievements.end(); + return m_completedAchievements.find(achievementId) != m_completedAchievements.end(); } bool AchievementMgr::CanUpdateCriteria(AchievementCriteriaEntry const* criteria, AchievementEntry const* achievement) @@ -2393,15 +2376,16 @@ void AchievementGlobalMgr::LoadCompletedAchievements() Field* fields = result->Fetch(); uint32 achievement_id = fields[0].GetUInt32(); - if (!sAchievementStore.LookupEntry(achievement_id)) + const AchievementEntry* achievement = sAchievementStore.LookupEntry(achievement_id); + if (!achievement) { // we will remove not existed achievement for all characters sLog->outError("Non-existing achievement %u data removed from table `character_achievement`.", achievement_id); CharacterDatabase.PExecute("DELETE FROM character_achievement WHERE achievement = %u", achievement_id); continue; } - - m_allCompletedAchievements.insert(achievement_id); + else if (achievement->flags & (ACHIEVEMENT_FLAG_REALM_FIRST_REACH | ACHIEVEMENT_FLAG_REALM_FIRST_KILL)) + m_allCompletedAchievements.insert(achievement_id); } while (result->NextRow()); sLog->outString(">> Loaded %lu completed achievements in %u ms", (unsigned long)m_allCompletedAchievements.size(), GetMSTimeDiffToNow(oldMSTime)); diff --git a/src/server/game/Achievements/AchievementMgr.h b/src/server/game/Achievements/AchievementMgr.h index 7f66565622f..f88be974c9d 100755 --- a/src/server/game/Achievements/AchievementMgr.h +++ b/src/server/game/Achievements/AchievementMgr.h @@ -257,7 +257,7 @@ class AchievementMgr void CheckAllAchievementCriteria(); void SendAllAchievementData() const; void SendRespondInspectAchievements(Player* player) const; - bool HasAchieved(AchievementEntry const* achievement) const; + bool HasAchieved(uint32 achievementId) const; Player* GetPlayer() const { return m_player; } void UpdateTimedAchievements(uint32 timeDiff); void StartTimedAchievement(AchievementCriteriaTimedTypes type, uint32 entry, uint32 timeLost = 0); diff --git a/src/server/game/Chat/Channels/Channel.cpp b/src/server/game/Chat/Channels/Channel.cpp index 1968de70f46..244c05ec0ad 100755 --- a/src/server/game/Chat/Channels/Channel.cpp +++ b/src/server/game/Chat/Channels/Channel.cpp @@ -310,18 +310,22 @@ void Channel::KickOrBan(uint64 good, const char *badname, bool ban) bool changeowner = (m_ownerGUID == bad->GetGUID()); WorldPacket data; + bool notify = !(AccountMgr::IsGMAccount(sec) && sWorld->getBoolConfig(CONFIG_SILENTLY_GM_JOIN_TO_CHANNEL)); if (ban && !IsBanned(bad->GetGUID())) { banned.insert(bad->GetGUID()); - MakePlayerBanned(&data, bad->GetGUID(), good); - UpdateChannelInDB(); + + if (notify) + MakePlayerBanned(&data, bad->GetGUID(), good); } - else + else if (notify) MakePlayerKicked(&data, bad->GetGUID(), good); - SendToAll(&data); + if (notify) + SendToAll(&data); + players.erase(bad->GetGUID()); bad->LeftChannel(this); diff --git a/src/server/game/Chat/Chat.cpp b/src/server/game/Chat/Chat.cpp index be43862eaea..185ac487481 100755 --- a/src/server/game/Chat/Chat.cpp +++ b/src/server/game/Chat/Chat.cpp @@ -303,29 +303,29 @@ ChatCommand* ChatHandler::getCommandTable() static ChatCommand ticketResponseCommandTable[] = { - { "append", SEC_MODERATOR, false, OldHandler<&ChatHandler::HandleGMTicketResponseAppendCommand>, "", NULL }, - { "appendln", SEC_MODERATOR, false, OldHandler<&ChatHandler::HandleGMTicketResponseAppendLnCommand>, "", NULL }, + { "append", SEC_MODERATOR, true, OldHandler<&ChatHandler::HandleGMTicketResponseAppendCommand>, "", NULL }, + { "appendln", SEC_MODERATOR, true, OldHandler<&ChatHandler::HandleGMTicketResponseAppendLnCommand>, "", NULL }, { NULL, 0, false, NULL, "", NULL } }; static ChatCommand ticketCommandTable[] = { - { "list", SEC_MODERATOR, false, OldHandler<&ChatHandler::HandleGMTicketListCommand>, "", NULL }, - { "onlinelist", SEC_MODERATOR, false, OldHandler<&ChatHandler::HandleGMTicketListOnlineCommand>, "", NULL }, - { "viewname", SEC_MODERATOR, false, OldHandler<&ChatHandler::HandleGMTicketGetByNameCommand>, "", NULL }, - { "viewid", SEC_MODERATOR, false, OldHandler<&ChatHandler::HandleGMTicketGetByIdCommand>, "", NULL }, - { "close", SEC_MODERATOR, false, OldHandler<&ChatHandler::HandleGMTicketCloseByIdCommand>, "", NULL }, - { "closedlist", SEC_MODERATOR, false, OldHandler<&ChatHandler::HandleGMTicketListClosedCommand>, "", NULL }, - { "escalatedlist", SEC_GAMEMASTER, false, OldHandler<&ChatHandler::HandleGMTicketListEscalatedCommand>, "", NULL }, - { "delete", SEC_ADMINISTRATOR, false, OldHandler<&ChatHandler::HandleGMTicketDeleteByIdCommand>, "", NULL }, - { "reset", SEC_ADMINISTRATOR, false, OldHandler<&ChatHandler::HandleGMTicketResetCommand>, "", NULL }, - { "assign", SEC_GAMEMASTER, false, OldHandler<&ChatHandler::HandleGMTicketAssignToCommand>, "", NULL }, - { "unassign", SEC_GAMEMASTER, false, OldHandler<&ChatHandler::HandleGMTicketUnAssignCommand>, "", NULL }, - { "comment", SEC_MODERATOR, false, OldHandler<&ChatHandler::HandleGMTicketCommentCommand>, "", NULL }, - { "togglesystem", SEC_ADMINISTRATOR, false, OldHandler<&ChatHandler::HandleToggleGMTicketSystem>, "", NULL }, - { "escalate", SEC_MODERATOR, false, OldHandler<&ChatHandler::HandleGMTicketEscalateCommand>, "", NULL }, - { "response", SEC_MODERATOR, false, NULL, "", ticketResponseCommandTable }, - { "complete", SEC_MODERATOR, false, OldHandler<&ChatHandler::HandleGMTicketCompleteCommand>, "", NULL }, + { "list", SEC_MODERATOR, true, OldHandler<&ChatHandler::HandleGMTicketListCommand>, "", NULL }, + { "onlinelist", SEC_MODERATOR, true, OldHandler<&ChatHandler::HandleGMTicketListOnlineCommand>, "", NULL }, + { "viewname", SEC_MODERATOR, true, OldHandler<&ChatHandler::HandleGMTicketGetByNameCommand>, "", NULL }, + { "viewid", SEC_MODERATOR, true, OldHandler<&ChatHandler::HandleGMTicketGetByIdCommand>, "", NULL }, + { "close", SEC_MODERATOR, true, OldHandler<&ChatHandler::HandleGMTicketCloseByIdCommand>, "", NULL }, + { "closedlist", SEC_MODERATOR, true, OldHandler<&ChatHandler::HandleGMTicketListClosedCommand>, "", NULL }, + { "escalatedlist", SEC_GAMEMASTER, true, OldHandler<&ChatHandler::HandleGMTicketListEscalatedCommand>, "", NULL }, + { "delete", SEC_ADMINISTRATOR, true, OldHandler<&ChatHandler::HandleGMTicketDeleteByIdCommand>, "", NULL }, + { "reset", SEC_ADMINISTRATOR, true, OldHandler<&ChatHandler::HandleGMTicketResetCommand>, "", NULL }, + { "assign", SEC_GAMEMASTER, true, OldHandler<&ChatHandler::HandleGMTicketAssignToCommand>, "", NULL }, + { "unassign", SEC_GAMEMASTER, true, OldHandler<&ChatHandler::HandleGMTicketUnAssignCommand>, "", NULL }, + { "comment", SEC_MODERATOR, true, OldHandler<&ChatHandler::HandleGMTicketCommentCommand>, "", NULL }, + { "togglesystem", SEC_ADMINISTRATOR, true, OldHandler<&ChatHandler::HandleToggleGMTicketSystem>, "", NULL }, + { "escalate", SEC_MODERATOR, true, OldHandler<&ChatHandler::HandleGMTicketEscalateCommand>, "", NULL }, + { "response", SEC_MODERATOR, true, NULL, "", ticketResponseCommandTable }, + { "complete", SEC_MODERATOR, true, OldHandler<&ChatHandler::HandleGMTicketCompleteCommand>, "", NULL }, { NULL, 0, false, NULL, "", NULL } }; diff --git a/src/server/game/Chat/Commands/Level0.cpp b/src/server/game/Chat/Commands/Level0.cpp index 338ad49463e..7ff7a82bf58 100755 --- a/src/server/game/Chat/Commands/Level0.cpp +++ b/src/server/game/Chat/Commands/Level0.cpp @@ -84,8 +84,8 @@ bool ChatHandler::HandleStartCommand(const char* /*args*/) bool ChatHandler::HandleServerInfoCommand(const char* /*args*/) { - uint32 PlayersNum = sWorld->GetPlayerCount(); - uint32 MaxPlayersNum = sWorld->GetMaxPlayerCount(); + uint32 playersNum = sWorld->GetPlayerCount(); + uint32 maxPlayersNum = sWorld->GetMaxPlayerCount(); uint32 activeClientsNum = sWorld->GetActiveSessionCount(); uint32 queuedClientsNum = sWorld->GetQueuedSessionCount(); uint32 maxActiveClientsNum = sWorld->GetMaxActiveSessionCount(); @@ -94,10 +94,13 @@ bool ChatHandler::HandleServerInfoCommand(const char* /*args*/) uint32 updateTime = sWorld->GetUpdateTime(); SendSysMessage(_FULLVERSION); - PSendSysMessage(LANG_CONNECTED_PLAYERS, PlayersNum, MaxPlayersNum); + PSendSysMessage(LANG_CONNECTED_PLAYERS, playersNum, maxPlayersNum); PSendSysMessage(LANG_CONNECTED_USERS, activeClientsNum, maxActiveClientsNum, queuedClientsNum, maxQueuedClientsNum); PSendSysMessage(LANG_UPTIME, uptime.c_str()); - PSendSysMessage("Update time diff: %u.", updateTime); + PSendSysMessage(LANG_UPDATE_DIFF, updateTime); + //! Can't use sWorld->ShutdownMsg here in case of console command + if (sWorld->IsShuttingDown()) + PSendSysMessage(LANG_SHUTDOWN_TIMELEFT, secsToTimeString(sWorld->GetShutDownTimeLeft()).c_str()); return true; } @@ -119,7 +122,7 @@ bool ChatHandler::HandleDismountCommand(const char* /*args*/) return false; } - m_session->GetPlayer()->Unmount(); + m_session->GetPlayer()->Dismount(); m_session->GetPlayer()->RemoveAurasByType(SPELL_AURA_MOUNTED); return true; } diff --git a/src/server/game/Chat/Commands/TicketCommands.cpp b/src/server/game/Chat/Commands/TicketCommands.cpp index 7caf63aac2b..d38da9eb97c 100755 --- a/src/server/game/Chat/Commands/TicketCommands.cpp +++ b/src/server/game/Chat/Commands/TicketCommands.cpp @@ -85,12 +85,14 @@ bool ChatHandler::HandleGMTicketGetByNameCommand(const char* args) guid = player->GetGUID(); else guid = sObjectMgr->GetPlayerGUIDByName(name); + // Target must exist if (!guid) { SendSysMessage(LANG_NO_PLAYERS_FOUND); return true; } + // Ticket must exist GmTicket *ticket = sTicketMgr->GetTicketByPlayer(guid); if (!ticket) @@ -119,27 +121,32 @@ bool ChatHandler::HandleGMTicketCloseByIdCommand(const char* args) SendSysMessage(LANG_COMMAND_TICKETNOTEXIST); return true; } - // Ticket must be assigned to player, who tries to close it. - uint64 guid = m_session->GetPlayer()->GetGUID(); - if (ticket->IsAssignedNotTo(guid)) + + // Ticket should be assigned to the player who tries to close it. + // Console can override though + Player* player = m_session ? m_session->GetPlayer() : NULL; + if (player && ticket->IsAssignedNotTo(player->GetGUID())) { PSendSysMessage(LANG_COMMAND_TICKETCANNOTCLOSE, ticket->GetId()); return true; } - sTicketMgr->CloseTicket(ticket->GetId(), guid); + + sTicketMgr->CloseTicket(ticket->GetId(), player ? player->GetGUID() : -1); sTicketMgr->UpdateLastChange(); - std::string msg = ticket->FormatMessageString(*this, m_session->GetPlayer()->GetName(), NULL, NULL, NULL); + std::string msg = ticket->FormatMessageString(*this, player ? player->GetName() : "Console", NULL, NULL, NULL); SendGlobalGMSysMessage(msg.c_str()); // Inform player, who submitted this ticket, that it is closed - if (Player* player = ticket->GetPlayer()) - if (player->IsInWorld()) + if (Player* submitter = ticket->GetPlayer()) + { + if (submitter->IsInWorld()) { WorldPacket data(SMSG_GMTICKET_DELETETICKET, 4); data << uint32(GMTICKET_RESPONSE_TICKET_DELETED); - player->GetSession()->SendPacket(&data); + submitter->GetSession()->SendPacket(&data); } + } return true; } @@ -170,25 +177,30 @@ bool ChatHandler::HandleGMTicketAssignToCommand(const char* args) uint64 targetGuid = sObjectMgr->GetPlayerGUIDByName(target.c_str()); uint64 targetAccId = sObjectMgr->GetPlayerAccountIdByGUID(targetGuid); uint32 targetGmLevel = AccountMgr::GetSecurity(targetAccId, realmID); + // Target must exist and have administrative rights if (!targetGuid || AccountMgr::IsPlayerAccount(targetGmLevel)) { SendSysMessage(LANG_COMMAND_TICKETASSIGNERROR_A); return true; } + // If already assigned, leave if (ticket->IsAssignedTo(targetGuid)) { PSendSysMessage(LANG_COMMAND_TICKETASSIGNERROR_B, ticket->GetId()); return true; } + // If assigned to different player other than current, leave - Player* player = m_session->GetPlayer(); - if (ticket->IsAssignedNotTo(player->GetGUID())) + //! Console can override though + Player* player = m_session ? m_session->GetPlayer() : NULL; + if (player && ticket->IsAssignedNotTo(player->GetGUID())) { PSendSysMessage(LANG_COMMAND_TICKETALREADYASSIGNED, ticket->GetId(), target.c_str()); return true; } + // Assign ticket SQLTransaction trans = SQLTransaction(NULL); ticket->SetAssignedTo(targetGuid, AccountMgr::IsAdminAccount(targetGmLevel)); @@ -218,6 +230,7 @@ bool ChatHandler::HandleGMTicketUnAssignCommand(const char* args) PSendSysMessage(LANG_COMMAND_TICKETNOTASSIGNED, ticket->GetId()); return true; } + // Get security level of player, whom this ticket is assigned to uint32 security = SEC_PLAYER; Player* assignedPlayer = ticket->GetAssignedPlayer(); @@ -229,9 +242,11 @@ bool ChatHandler::HandleGMTicketUnAssignCommand(const char* args) uint32 accountId = sObjectMgr->GetPlayerAccountIdByGUID(guid); security = AccountMgr::GetSecurity(accountId, realmID); } + // Check security - Player* player = m_session->GetPlayer(); - if (security > uint32(player->GetSession()->GetSecurity())) + //! If no m_session present it means we're issuing this command from the console + uint32 mySecurity = m_session ? m_session->GetSecurity() : SEC_CONSOLE; + if (security > mySecurity) { SendSysMessage(LANG_COMMAND_TICKETUNASSIGNSECURITY); return true; @@ -242,7 +257,8 @@ bool ChatHandler::HandleGMTicketUnAssignCommand(const char* args) ticket->SaveToDB(trans); sTicketMgr->UpdateLastChange(); - std::string msg = ticket->FormatMessageString(*this, NULL, ticket->GetAssignedToName().c_str(), player->GetName(), NULL); + std::string msg = ticket->FormatMessageString(*this, NULL, ticket->GetAssignedToName().c_str(), + m_session ? m_session->GetPlayer()->GetName() : "Console", NULL); SendGlobalGMSysMessage(msg.c_str()); return true; } @@ -265,9 +281,11 @@ bool ChatHandler::HandleGMTicketCommentCommand(const char* args) PSendSysMessage(LANG_COMMAND_TICKETNOTEXIST); return true; } + // Cannot comment ticket assigned to someone else - Player* player = m_session->GetPlayer(); - if (ticket->IsAssignedNotTo(player->GetGUID())) + //! Console excluded + Player* player = m_session ? m_session->GetPlayer() : NULL; + if (player && ticket->IsAssignedNotTo(player->GetGUID())) { PSendSysMessage(LANG_COMMAND_TICKETALREADYASSIGNED, ticket->GetId()); return true; @@ -279,7 +297,7 @@ bool ChatHandler::HandleGMTicketCommentCommand(const char* args) sTicketMgr->UpdateLastChange(); std::string msg = ticket->FormatMessageString(*this, NULL, ticket->GetAssignedToName().c_str(), NULL, NULL); - msg += PGetParseString(LANG_COMMAND_TICKETLISTADDCOMMENT, player->GetName(), comment); + msg += PGetParseString(LANG_COMMAND_TICKETLISTADDCOMMENT, player ? player->GetName() : "Console", comment); SendGlobalGMSysMessage(msg.c_str()); return true; @@ -297,19 +315,21 @@ bool ChatHandler::HandleGMTicketDeleteByIdCommand(const char* args) SendSysMessage(LANG_COMMAND_TICKETNOTEXIST); return true; } + if (!ticket->IsClosed()) { SendSysMessage(LANG_COMMAND_TICKETCLOSEFIRST); return true; } - std::string msg = ticket->FormatMessageString(*this, NULL, NULL, NULL, m_session->GetPlayer()->GetName()); + std::string msg = ticket->FormatMessageString(*this, NULL, NULL, NULL, m_session ? m_session->GetPlayer()->GetName() : "Console"); SendGlobalGMSysMessage(msg.c_str()); sTicketMgr->RemoveTicket(ticket->GetId()); sTicketMgr->UpdateLastChange(); if (Player* player = ticket->GetPlayer()) + { if (player->IsInWorld()) { // Force abandon ticket @@ -317,6 +337,7 @@ bool ChatHandler::HandleGMTicketDeleteByIdCommand(const char* args) data << uint32(GMTICKET_RESPONSE_TICKET_DELETED); player->GetSession()->SendPacket(&data); } + } return true; } @@ -406,9 +427,11 @@ inline bool ChatHandler::_HandleGMTicketResponseAppendCommand(const char* args, PSendSysMessage(LANG_COMMAND_TICKETNOTEXIST); return true; } + // Cannot add response to ticket, assigned to someone else - Player* player = m_session->GetPlayer(); - if (ticket->IsAssignedNotTo(player->GetGUID())) + //! Console excluded + Player* player = m_session ? m_session->GetPlayer() : NULL; + if (player && ticket->IsAssignedNotTo(player->GetGUID())) { PSendSysMessage(LANG_COMMAND_TICKETALREADYASSIGNED, ticket->GetId()); return true; diff --git a/src/server/game/Conditions/ConditionMgr.cpp b/src/server/game/Conditions/ConditionMgr.cpp index bfefb3e4e76..cf349044042 100755 --- a/src/server/game/Conditions/ConditionMgr.cpp +++ b/src/server/game/Conditions/ConditionMgr.cpp @@ -67,11 +67,8 @@ bool Condition::Meets(Player* player, Unit* invoker) break; } case CONDITION_ACHIEVEMENT: - { - AchievementEntry const* achievement = GetAchievementStore()->LookupEntry(mConditionValue1); - condMeets = player->GetAchievementMgr().HasAchieved(achievement); + condMeets = player->GetAchievementMgr().HasAchieved(mConditionValue1); break; - } case CONDITION_TEAM: condMeets = player->GetTeam() == mConditionValue1; break; diff --git a/src/server/game/DataStores/DBCEnums.h b/src/server/game/DataStores/DBCEnums.h index dcdc2b2ea0a..78324f8fae2 100755 --- a/src/server/game/DataStores/DBCEnums.h +++ b/src/server/game/DataStores/DBCEnums.h @@ -74,14 +74,14 @@ enum AchievementFlags enum AchievementCriteriaCondition { - ACHIEVEMENT_CRITERIA_CONDITION_NONE = 0, - ACHIEVEMENT_CRITERIA_CONDITION_NO_DEATH = 1, // reset progress on death - ACHIEVEMENT_CRITERIA_CONDITION_UNK1 = 2, // only used in "Complete a daily quest every day for five consecutive days" - ACHIEVEMENT_CRITERIA_CONDITION_BG_MAP = 3, // requires you to be on specific map, reset at change - ACHIEVEMENT_CRITERIA_CONDITION_NO_LOSE = 4, // only used in "Win 10 arenas without losing" - ACHIEVEMENT_CRITERIA_CONDITION_UNK2 = 9, // unk - ACHIEVEMENT_CRITERIA_CONDITION_NOT_IN_GROUP = 10, // requires the player not to be in group - ACHIEVEMENT_CRITERIA_CONDITION_UNK3 = 13, // unk + ACHIEVEMENT_CRITERIA_CONDITION_NONE = 0, + ACHIEVEMENT_CRITERIA_CONDITION_NO_DEATH = 1, // reset progress on death + ACHIEVEMENT_CRITERIA_CONDITION_UNK1 = 2, // only used in "Complete a daily quest every day for five consecutive days" + ACHIEVEMENT_CRITERIA_CONDITION_BG_MAP = 3, // requires you to be on specific map, reset at change + ACHIEVEMENT_CRITERIA_CONDITION_NO_LOSE = 4, // only used in "Win 10 arenas without losing" + ACHIEVEMENT_CRITERIA_CONDITION_NO_SPELL_HIT = 9, // requires the player not to be hit by specific spell + ACHIEVEMENT_CRITERIA_CONDITION_NOT_IN_GROUP = 10, // requires the player not to be in group + ACHIEVEMENT_CRITERIA_CONDITION_UNK3 = 13, // unk }; enum AchievementCriteriaFlags @@ -97,7 +97,7 @@ enum AchievementCriteriaFlags enum AchievementCriteriaTimedTypes { ACHIEVEMENT_TIMED_TYPE_EVENT = 1, // Timer is started by internal event with id in timerStartEvent - ACHIEVEMENT_TIMED_TYPE_QUEST = 2, // Timer is started by acceting quest with entry in timerStartEvent + ACHIEVEMENT_TIMED_TYPE_QUEST = 2, // Timer is started by accepting quest with entry in timerStartEvent ACHIEVEMENT_TIMED_TYPE_SPELL_CASTER = 5, // Timer is started by casting a spell with entry in timerStartEvent ACHIEVEMENT_TIMED_TYPE_SPELL_TARGET = 6, // Timer is started by being target of spell with entry in timerStartEvent ACHIEVEMENT_TIMED_TYPE_CREATURE = 7, // Timer is started by killing creature with entry in timerStartEvent @@ -417,7 +417,7 @@ enum SummonPropFlags enum VehicleSeatFlags { VEHICLE_SEAT_FLAG_HIDE_PASSENGER = 0x00000200, // Passenger is hidden - VEHICLE_SEAT_FLAG_UNK11 = 0x00000400, // needed for CGCamera__SyncFreeLookFacing + VEHICLE_SEAT_FLAG_UNK1 = 0x00000400, // needed for CGCamera__SyncFreeLookFacing VEHICLE_SEAT_FLAG_CAN_CONTROL = 0x00000800, // Lua_UnitInVehicleControlSeat VEHICLE_SEAT_FLAG_CAN_CAST_MOUNT_SPELL = 0x00001000, // Can cast spells with SPELL_AURA_MOUNTED from seat (possibly 4.x only, 0 seats on 3.3.5a) VEHICLE_SEAT_FLAG_UNCONTROLLED = 0x00002000, // can override !& VEHICLE_SEAT_FLAG_CAN_ENTER_OR_EXIT @@ -425,6 +425,7 @@ enum VehicleSeatFlags VEHICLE_SEAT_FLAG_CAN_ENTER_OR_EXIT = 0x02000000, // Lua_CanExitVehicle - can enter and exit at free will VEHICLE_SEAT_FLAG_CAN_SWITCH = 0x04000000, // Lua_CanSwitchVehicleSeats VEHICLE_SEAT_FLAG_CAN_CAST = 0x20000000, // Lua_UnitHasVehicleUI + VEHICLE_SEAT_FLAG_UNK2 = 0x40000000, // checked in conjunction with 0x800 in CastSpell2 }; enum VehicleSeatFlagsB @@ -435,7 +436,7 @@ enum VehicleSeatFlagsB VEHICLE_SEAT_FLAG_B_EJECTABLE = 0x00000020, // ejectable VEHICLE_SEAT_FLAG_B_USABLE_FORCED_2 = 0x00000040, VEHICLE_SEAT_FLAG_B_USABLE_FORCED_3 = 0x00000100, - VEHICLE_SEAT_FLAG_B_CANSWITCH = 0x04000000, // can switch seats + VEHICLE_SEAT_FLAG_B_USABLE_FORCED_4 = 0x02000000, VEHICLE_SEAT_FLAG_B_VEHICLE_PLAYERFRAME_UI = 0x80000000, // Lua_UnitHasVehiclePlayerFrameUI - actually checked for flagsb &~ 0x80000000 }; diff --git a/src/server/game/DataStores/DBCStructure.h b/src/server/game/DataStores/DBCStructure.h index ba7be495c77..5a4dea3a020 100755 --- a/src/server/game/DataStores/DBCStructure.h +++ b/src/server/game/DataStores/DBCStructure.h @@ -1939,9 +1939,10 @@ struct VehicleSeatEntry // 46-57 added in 3.1, floats mostly bool CanEnterOrExit() const { return m_flags & VEHICLE_SEAT_FLAG_CAN_ENTER_OR_EXIT; } - bool CanSwitchFromSeat() const { return m_flags & VEHICLE_SEAT_FLAG_B_CANSWITCH; } + bool CanSwitchFromSeat() const { return m_flags & VEHICLE_SEAT_FLAG_CAN_SWITCH; } bool IsUsableByOverride() const { return (m_flags & VEHICLE_SEAT_FLAG_UNCONTROLLED) - || (m_flagsB & (VEHICLE_SEAT_FLAG_B_USABLE_FORCED | VEHICLE_SEAT_FLAG_B_USABLE_FORCED_2 | VEHICLE_SEAT_FLAG_B_USABLE_FORCED_3)); } + || (m_flagsB & (VEHICLE_SEAT_FLAG_B_USABLE_FORCED | VEHICLE_SEAT_FLAG_B_USABLE_FORCED_2 | + VEHICLE_SEAT_FLAG_B_USABLE_FORCED_3 | VEHICLE_SEAT_FLAG_B_USABLE_FORCED_4)); } bool IsEjectable() const { return m_flagsB & VEHICLE_SEAT_FLAG_B_EJECTABLE; } }; diff --git a/src/server/game/DungeonFinding/LFGMgr.cpp b/src/server/game/DungeonFinding/LFGMgr.cpp index 55f798204db..21ff3c6e4e8 100755 --- a/src/server/game/DungeonFinding/LFGMgr.cpp +++ b/src/server/game/DungeonFinding/LFGMgr.cpp @@ -389,7 +389,7 @@ void LFGMgr::InitializeLockedDungeons(Player* player) locktype = LFG_LOCKSTATUS_TOO_HIGH_LEVEL; else if (locktype == LFG_LOCKSTATUS_OK && ar) { - if (ar->achievement && !player->GetAchievementMgr().HasAchieved(sAchievementStore.LookupEntry(ar->achievement))) + if (ar->achievement && !player->GetAchievementMgr().HasAchieved(ar->achievement)) locktype = LFG_LOCKSTATUS_RAID_LOCKED; // FIXME: Check the correct lock value else if (player->GetTeam() == ALLIANCE && ar->quest_A && !player->GetQuestRewardStatus(ar->quest_A)) locktype = LFG_LOCKSTATUS_QUEST_NOT_COMPLETED; diff --git a/src/server/game/Entities/Corpse/Corpse.cpp b/src/server/game/Entities/Corpse/Corpse.cpp index 31cc21659c9..cd05cba7475 100755 --- a/src/server/game/Entities/Corpse/Corpse.cpp +++ b/src/server/game/Entities/Corpse/Corpse.cpp @@ -26,7 +26,7 @@ #include "GossipDef.h" #include "World.h" -Corpse::Corpse(CorpseType type) : WorldObject() +Corpse::Corpse(CorpseType type) : WorldObject(type != CORPSE_BONES) , m_type(type) { m_objectType |= TYPEMASK_CORPSE; @@ -39,9 +39,6 @@ Corpse::Corpse(CorpseType type) : WorldObject() m_time = time(NULL); lootForBody = false; - - if (type != CORPSE_BONES) - m_isWorldObject = true; } Corpse::~Corpse() @@ -162,20 +159,11 @@ void Corpse::DeleteFromDB(SQLTransaction& trans) trans->Append(stmt); } -bool Corpse::LoadFromDB(uint32 guid, Field* fields) +bool Corpse::LoadCorpseFromDB(uint32 guid, Field* fields) { uint32 ownerGuid = fields[17].GetUInt32(); // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 // SELECT posX, posY, posZ, orientation, mapId, displayId, itemCache, bytes1, bytes2, guildId, flags, dynFlags, time, corpseType, instanceId, phaseMask, corpseGuid, guid FROM corpse WHERE corpseType <> 0 - m_type = CorpseType(fields[13].GetUInt8()); - if (m_type >= MAX_CORPSE_TYPE) - { - sLog->outError("Corpse (guid: %u, owner: %u) have wrong corpse type (%u), not loading.", guid, ownerGuid, m_type); - return false; - } - if (m_type != CORPSE_BONES) - m_isWorldObject = true; - float posX = fields[0].GetFloat(); float posY = fields[1].GetFloat(); float posZ = fields[2].GetFloat(); diff --git a/src/server/game/Entities/Corpse/Corpse.h b/src/server/game/Entities/Corpse/Corpse.h index 2e45606b88f..a704e2243eb 100755 --- a/src/server/game/Entities/Corpse/Corpse.h +++ b/src/server/game/Entities/Corpse/Corpse.h @@ -59,7 +59,7 @@ class Corpse : public WorldObject, public GridObject<Corpse> bool Create(uint32 guidlow, Player* owner); void SaveToDB(); - bool LoadFromDB(uint32 guid, Field* fields); + bool LoadCorpseFromDB(uint32 guid, Field* fields); void DeleteBonesFromWorld(); void DeleteFromDB(SQLTransaction& trans); diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp index 3238d9873a9..f97d01a42a4 100755 --- a/src/server/game/Entities/Creature/Creature.cpp +++ b/src/server/game/Entities/Creature/Creature.cpp @@ -137,7 +137,7 @@ bool ForcedDespawnDelayEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/) return true; } -Creature::Creature(): Unit(), MapCreature(), +Creature::Creature(bool isWorldObject): Unit(isWorldObject), MapCreature(), lootForPickPocketed(false), lootForBody(false), m_groupLootTimer(0), lootingGroupLowGUID(0), m_PlayerDamageReq(0), m_lootMoney(0), m_lootRecipient(0), m_lootRecipientGroup(0), m_corpseRemoveTime(0), m_respawnTime(0), m_respawnDelay(300), m_corpseDelay(60), m_respawnradius(0.0f), m_reactState(REACT_AGGRESSIVE), @@ -160,6 +160,7 @@ m_creatureInfo(NULL), m_creatureData(NULL), m_formation(NULL) ResetLootMode(); // restore default loot mode TriggerJustRespawned = false; + m_isTempWorldObject = false; } Creature::~Creature() diff --git a/src/server/game/Entities/Creature/Creature.h b/src/server/game/Entities/Creature/Creature.h index 6ae9fa97462..d84221f0e63 100755 --- a/src/server/game/Entities/Creature/Creature.h +++ b/src/server/game/Entities/Creature/Creature.h @@ -440,7 +440,7 @@ class Creature : public Unit, public GridObject<Creature>, public MapCreature { public: - explicit Creature(); + explicit Creature(bool isWorldObject = false); virtual ~Creature(); void AddToWorld(); @@ -707,6 +707,9 @@ class Creature : public Unit, public GridObject<Creature>, public MapCreature uint32 GetGUIDTransport() { return guid_transport; } void FarTeleportTo(Map* map, float X, float Y, float Z, float O); + + bool m_isTempWorldObject; //true when possessed + protected: bool CreateFromProto(uint32 guidlow, uint32 Entry, uint32 vehId, uint32 team, const CreatureData* data = NULL); bool InitEntry(uint32 entry, uint32 team=ALLIANCE, const CreatureData* data=NULL); diff --git a/src/server/game/Entities/Creature/TemporarySummon.cpp b/src/server/game/Entities/Creature/TemporarySummon.cpp index b17606b83cc..1b06f0f0b6a 100755 --- a/src/server/game/Entities/Creature/TemporarySummon.cpp +++ b/src/server/game/Entities/Creature/TemporarySummon.cpp @@ -22,8 +22,8 @@ #include "ObjectMgr.h" #include "TemporarySummon.h" -TempSummon::TempSummon(SummonPropertiesEntry const* properties, Unit* owner) : -Creature(), m_Properties(properties), m_type(TEMPSUMMON_MANUAL_DESPAWN), +TempSummon::TempSummon(SummonPropertiesEntry const* properties, Unit* owner, bool isWorldObject) : +Creature(isWorldObject), m_Properties(properties), m_type(TEMPSUMMON_MANUAL_DESPAWN), m_timer(0), m_lifetime(0) { m_summonerGUID = owner ? owner->GetGUID() : 0; @@ -272,7 +272,7 @@ void TempSummon::RemoveFromWorld() Creature::RemoveFromWorld(); } -Minion::Minion(SummonPropertiesEntry const* properties, Unit* owner) : TempSummon(properties, owner) +Minion::Minion(SummonPropertiesEntry const* properties, Unit* owner, bool isWorldObject) : TempSummon(properties, owner, isWorldObject) , m_owner(owner) { ASSERT(m_owner); @@ -306,7 +306,7 @@ bool Minion::IsGuardianPet() const return isPet() || (m_Properties && m_Properties->Category == SUMMON_CATEGORY_PET); } -Guardian::Guardian(SummonPropertiesEntry const* properties, Unit* owner) : Minion(properties, owner) +Guardian::Guardian(SummonPropertiesEntry const* properties, Unit* owner, bool isWorldObject) : Minion(properties, owner, isWorldObject) , m_bonusSpellDamage(0) { memset(m_statFromOwner, 0, sizeof(float)*MAX_STATS); @@ -340,7 +340,7 @@ void Guardian::InitSummon() m_owner->ToPlayer()->CharmSpellInitialize(); } -Puppet::Puppet(SummonPropertiesEntry const* properties, Unit* owner) : Minion(properties, owner) +Puppet::Puppet(SummonPropertiesEntry const* properties, Unit* owner) : Minion(properties, owner, false) //maybe true? { ASSERT(owner->GetTypeId() == TYPEID_PLAYER); m_owner = (Player*)owner; diff --git a/src/server/game/Entities/Creature/TemporarySummon.h b/src/server/game/Entities/Creature/TemporarySummon.h index 1982dec4bb8..69ae8349155 100755 --- a/src/server/game/Entities/Creature/TemporarySummon.h +++ b/src/server/game/Entities/Creature/TemporarySummon.h @@ -24,7 +24,7 @@ class TempSummon : public Creature { public: - explicit TempSummon(SummonPropertiesEntry const* properties, Unit* owner); + explicit TempSummon(SummonPropertiesEntry const* properties, Unit* owner, bool isWorldObject); virtual ~TempSummon() {} void Update(uint32 time); virtual void InitStats(uint32 lifetime); @@ -48,7 +48,7 @@ class TempSummon : public Creature class Minion : public TempSummon { public: - Minion(SummonPropertiesEntry const* properties, Unit* owner); + Minion(SummonPropertiesEntry const* properties, Unit* owner, bool isWorldObject); void InitStats(uint32 duration); void RemoveFromWorld(); Unit* GetOwner() { return m_owner; } @@ -64,7 +64,7 @@ class Minion : public TempSummon class Guardian : public Minion { public: - Guardian(SummonPropertiesEntry const* properties, Unit* owner); + Guardian(SummonPropertiesEntry const* properties, Unit* owner, bool isWorldObject); void InitStats(uint32 duration); bool InitStatsForLevel(uint8 level); void InitSummon(); diff --git a/src/server/game/Entities/DynamicObject/DynamicObject.cpp b/src/server/game/Entities/DynamicObject/DynamicObject.cpp index 30afd43cf14..4e0d2d7d0b9 100755 --- a/src/server/game/Entities/DynamicObject/DynamicObject.cpp +++ b/src/server/game/Entities/DynamicObject/DynamicObject.cpp @@ -27,7 +27,7 @@ #include "GridNotifiersImpl.h" #include "ScriptMgr.h" -DynamicObject::DynamicObject() : WorldObject(), +DynamicObject::DynamicObject(bool isWorldObject) : WorldObject(isWorldObject), _aura(NULL), _removedAura(NULL), _caster(NULL), _duration(0), _isViewpoint(false) { m_objectType |= TYPEMASK_DYNAMICOBJECT; @@ -79,7 +79,7 @@ void DynamicObject::RemoveFromWorld() } } -bool DynamicObject::CreateDynamicObject(uint32 guidlow, Unit* caster, uint32 spellId, Position const& pos, float radius, bool active, DynamicObjectType type) +bool DynamicObject::CreateDynamicObject(uint32 guidlow, Unit* caster, uint32 spellId, Position const& pos, float radius, DynamicObjectType type) { SetMap(caster->GetMap()); Relocate(pos); @@ -105,8 +105,7 @@ bool DynamicObject::CreateDynamicObject(uint32 guidlow, Unit* caster, uint32 spe SetFloatValue(DYNAMICOBJECT_RADIUS, radius); SetUInt32Value(DYNAMICOBJECT_CASTTIME, getMSTime()); - m_isWorldObject = active; - if (active) + if (IsWorldObject()) setActive(true); //must before add to map to be put in world container if (!GetMap()->AddToMap(this)) diff --git a/src/server/game/Entities/DynamicObject/DynamicObject.h b/src/server/game/Entities/DynamicObject/DynamicObject.h index c178fe98d14..bd8c15cdba4 100755 --- a/src/server/game/Entities/DynamicObject/DynamicObject.h +++ b/src/server/game/Entities/DynamicObject/DynamicObject.h @@ -35,13 +35,13 @@ enum DynamicObjectType class DynamicObject : public WorldObject, public GridObject<DynamicObject> { public: - DynamicObject(); + DynamicObject(bool isWorldObject); ~DynamicObject(); void AddToWorld(); void RemoveFromWorld(); - bool CreateDynamicObject(uint32 guidlow, Unit* caster, uint32 spellId, Position const& pos, float radius, bool active, DynamicObjectType type); + bool CreateDynamicObject(uint32 guidlow, Unit* caster, uint32 spellId, Position const& pos, float radius, DynamicObjectType type); void Update(uint32 p_time); void Remove(); void SetDuration(int32 newDuration); diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp index de1b0f84871..036664a2760 100755 --- a/src/server/game/Entities/GameObject/GameObject.cpp +++ b/src/server/game/Entities/GameObject/GameObject.cpp @@ -30,7 +30,7 @@ #include "CreatureAISelector.h" #include "Group.h" -GameObject::GameObject() : WorldObject(), m_goValue(new GameObjectValue), m_AI(NULL) +GameObject::GameObject() : WorldObject(false), m_goValue(new GameObjectValue), m_AI(NULL) { m_objectType |= TYPEMASK_GAMEOBJECT; m_objectTypeId = TYPEID_GAMEOBJECT; diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp index 978d9accb64..d4679928d82 100755 --- a/src/server/game/Entities/Object/Object.cpp +++ b/src/server/game/Entities/Object/Object.cpp @@ -82,7 +82,7 @@ Object::Object() : m_PackGUID(sizeof(uint64)+1) WorldObject::~WorldObject() { // this may happen because there are many !create/delete - if (m_isWorldObject && m_currMap) + if (IsWorldObject() && m_currMap) { if (GetTypeId() == TYPEID_CORPSE) { @@ -1221,8 +1221,8 @@ void MovementInfo::OutDebug() sLog->outString("splineElevation: %f", splineElevation); } -WorldObject::WorldObject(): WorldLocation(), -m_isWorldObject(false), m_name(""), m_isActive(false), m_zoneScript(NULL), +WorldObject::WorldObject(bool isWorldObject): WorldLocation(), +m_isWorldObject(isWorldObject), m_name(""), m_isActive(false), m_zoneScript(NULL), m_transport(NULL), m_currMap(NULL), m_InstanceId(0), m_phaseMask(PHASEMASK_NORMAL), m_notifyflags(0), m_executed_notifies(0) { @@ -1238,6 +1238,17 @@ void WorldObject::SetWorldObject(bool on) GetMap()->AddObjectToSwitchList(this, on); } +bool WorldObject::IsWorldObject() const +{ + if (m_isWorldObject) + return true; + + if (ToCreature() && ToCreature()->m_isTempWorldObject) + return true; + + return false; +} + void WorldObject::setActive(bool on) { if (m_isActive == on) @@ -1642,7 +1653,7 @@ bool WorldObject::canSeeOrDetect(WorldObject const* obj, bool ignoreStealth, boo bool corpseVisibility = false; if (distanceCheck) { - if (const Player* thisPlayer = ToPlayer()) + if (Player const* thisPlayer = ToPlayer()) { if (thisPlayer->isDead() && thisPlayer->GetHealth() > 0 && // Cheap way to check for ghost state !(obj->m_serverSideVisibility.GetValue(SERVERSIDE_VISIBILITY_GHOST) & m_serverSideVisibility.GetValue(SERVERSIDE_VISIBILITY_GHOST) & GHOST_VISIBILITY_GHOST)) @@ -1675,9 +1686,9 @@ bool WorldObject::canSeeOrDetect(WorldObject const* obj, bool ignoreStealth, boo if (!corpseVisibility && !(obj->m_serverSideVisibility.GetValue(SERVERSIDE_VISIBILITY_GHOST) & m_serverSideVisibilityDetect.GetValue(SERVERSIDE_VISIBILITY_GHOST))) { // Alive players can see dead players in some cases, but other objects can't do that - if (const Player* thisPlayer = ToPlayer()) + if (Player const* thisPlayer = ToPlayer()) { - if (const Player* objPlayer = obj->ToPlayer()) + if (Player const* objPlayer = obj->ToPlayer()) { if (thisPlayer->GetTeam() != objPlayer->GetTeam() || !thisPlayer->IsGroupVisibleFor(objPlayer)) return false; @@ -2018,7 +2029,6 @@ void WorldObject::SendMessageToSet(WorldPacket* data, bool self) SendMessageToSetInRange(data, GetVisibilityRange(), self); } - void WorldObject::SendMessageToSetInRange(WorldPacket* data, float dist, bool /*self*/) { Trinity::MessageDistDeliverer notifier(this, data, dist); @@ -2052,7 +2062,7 @@ void WorldObject::SetMap(Map* map) m_currMap = map; m_mapId = map->GetId(); m_InstanceId = map->GetInstanceId(); - if (m_isWorldObject) + if (IsWorldObject()) m_currMap->AddWorldObject(this); } @@ -2060,7 +2070,7 @@ void WorldObject::ResetMap() { ASSERT(m_currMap); ASSERT(!IsInWorld()); - if (m_isWorldObject) + if (IsWorldObject()) m_currMap->RemoveWorldObject(this); m_currMap = NULL; //maybe not for corpse @@ -2150,10 +2160,10 @@ TempSummon* Map::SummonCreature(uint32 entry, Position const& pos, SummonPropert switch (mask) { case UNIT_MASK_SUMMON: - summon = new TempSummon(properties, summoner); + summon = new TempSummon(properties, summoner, false); break; case UNIT_MASK_GUARDIAN: - summon = new Guardian(properties, summoner); + summon = new Guardian(properties, summoner, false); break; case UNIT_MASK_PUPPET: summon = new Puppet(properties, summoner); @@ -2162,7 +2172,7 @@ TempSummon* Map::SummonCreature(uint32 entry, Position const& pos, SummonPropert summon = new Totem(properties, summoner); break; case UNIT_MASK_MINION: - summon = new Minion(properties, summoner); + summon = new Minion(properties, summoner, false); break; default: return NULL; diff --git a/src/server/game/Entities/Object/Object.h b/src/server/game/Entities/Object/Object.h index eab4dbeba99..786b23f6340 100755 --- a/src/server/game/Entities/Object/Object.h +++ b/src/server/game/Entities/Object/Object.h @@ -561,7 +561,7 @@ class FlaggedValuesArray32 class WorldObject : public Object, public WorldLocation { protected: - explicit WorldObject(); + explicit WorldObject(bool isWorldObject); //note: here it means if it is in grid object list or world object list public: virtual ~WorldObject(); @@ -800,6 +800,9 @@ class WorldObject : public Object, public WorldLocation bool isActiveObject() const { return m_isActive; } void setActive(bool isActiveObject); void SetWorldObject(bool apply); + bool IsPermanentWorldObject() const { return m_isWorldObject; } + bool IsWorldObject() const; + template<class NOTIFIER> void VisitNearbyObject(float const& radius, NOTIFIER& notifier) const { if (IsInWorld()) GetMap()->VisitAll(GetPositionX(), GetPositionY(), radius, notifier); } template<class NOTIFIER> void VisitNearbyGridObject(float const& radius, NOTIFIER& notifier) const { if (IsInWorld()) GetMap()->VisitGrid(GetPositionX(), GetPositionY(), radius, notifier); } template<class NOTIFIER> void VisitNearbyWorldObject(float const& radius, NOTIFIER& notifier) const { if (IsInWorld()) GetMap()->VisitWorld(GetPositionX(), GetPositionY(), radius, notifier); } @@ -812,7 +815,6 @@ class WorldObject : public Object, public WorldLocation double rand_chance() const { return GetMap()->mtRand.randExc(100.0);} #endif - bool m_isWorldObject; uint32 LastUsedScriptID; // Transports @@ -830,6 +832,7 @@ class WorldObject : public Object, public WorldLocation protected: std::string m_name; bool m_isActive; + const bool m_isWorldObject; ZoneScript* m_zoneScript; // transports diff --git a/src/server/game/Entities/Pet/Pet.cpp b/src/server/game/Entities/Pet/Pet.cpp index 404fe24d467..4e33142f5ce 100755 --- a/src/server/game/Entities/Pet/Pet.cpp +++ b/src/server/game/Entities/Pet/Pet.cpp @@ -33,7 +33,7 @@ #define PET_XP_FACTOR 0.05f -Pet::Pet(Player* owner, PetType type) : Guardian(NULL, owner), +Pet::Pet(Player* owner, PetType type) : Guardian(NULL, owner, true), m_usedTalentCount(0), m_removed(false), m_owner(owner), m_happinessTimer(7500), m_petType(type), m_duration(0), m_auraRaidUpdateMask(0), m_loading(false), m_declinedname(NULL) @@ -50,8 +50,6 @@ m_auraRaidUpdateMask(0), m_loading(false), m_declinedname(NULL) m_name = "Pet"; m_regenTimer = PET_FOCUS_REGEN_INTERVAL; - - m_isWorldObject = true; } Pet::~Pet() @@ -908,6 +906,7 @@ bool Guardian::InitStatsForLevel(uint8 petlevel) SetCreateHealth(40*petlevel); SetCreateMana(28 + 10*petlevel); } + SetBonusDamage(m_owner->SpellBaseDamageBonus(SPELL_SCHOOL_MASK_FIRE) * 0.5f); SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, float(petlevel * 4 - petlevel)); SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, float(petlevel * 4 + petlevel)); break; diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 0e98eb27596..510813a4e56 100755 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -629,7 +629,7 @@ UpdateMask Player::updateVisualBits; #ifdef _MSC_VER #pragma warning(disable:4355) #endif -Player::Player (WorldSession* session): Unit(), m_achievementMgr(this), m_reputationMgr(this) +Player::Player(WorldSession* session): Unit(true), m_achievementMgr(this), m_reputationMgr(this) { #ifdef _MSC_VER #pragma warning(default:4355) @@ -839,7 +839,6 @@ Player::Player (WorldSession* session): Unit(), m_achievementMgr(this), m_reputa m_grantableLevels = 0; m_ControlledByPlayer = true; - m_isWorldObject = true; sWorld->IncreasePlayerCount(); @@ -1850,7 +1849,7 @@ void Player::setDeathState(DeathState s) SetUInt32Value(PLAYER_SELF_RES_SPELL, 0); } -bool Player::BuildEnumData(QueryResult result, WorldPacket* data) +bool Player::BuildEnumData(PreparedQueryResult result, WorldPacket* data) { // 0 1 2 3 4 5 6 7 // "SELECT characters.guid, characters.name, characters.race, characters.class, characters.gender, characters.playerBytes, characters.playerBytes2, characters.level, " @@ -1894,8 +1893,8 @@ bool Player::BuildEnumData(QueryResult result, WorldPacket* data) *data << uint8(playerBytes2 & 0xFF); // facial hair *data << uint8(fields[7].GetUInt8()); // level - *data << uint32(fields[8].GetUInt32()); // zone - *data << uint32(fields[9].GetUInt32()); // map + *data << uint32(fields[8].GetUInt16()); // zone + *data << uint32(fields[9].GetUInt16()); // map *data << fields[10].GetFloat(); // x *data << fields[11].GetFloat(); // y @@ -2052,28 +2051,6 @@ void Player::SendTeleportAckPacket() GetSession()->SendPacket(&data); } -// this is not used anywhere -void Player::TeleportOutOfMap(Map* oldMap) -{ - while (IsBeingTeleportedFar()) - GetSession()->HandleMoveWorldportAckOpcode(); - - if (GetMap() != oldMap) - return; - - TeleportTo(m_homebindMapId, m_homebindX, m_homebindY, m_homebindZ, GetOrientation()); - - while (IsBeingTeleportedFar()) - GetSession()->HandleMoveWorldportAckOpcode(); - - if (GetMap() == oldMap) - { - sLog->outCrash("Cannot teleport player out of map!"); - ResetMap(); - ASSERT(false); - } -} - bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientation, uint32 options) { if (!MapManager::IsValidMapCoord(mapid, x, y, z, orientation)) @@ -12885,6 +12862,8 @@ void Player::SwapItem(uint16 src, uint16 dst) RemoveItem(srcbag, srcslot, true); StoreItem(dest, pSrcItem, true); + if (IsBankPos(src)) + ItemAddedQuestCheck(pSrcItem->GetEntry(), pSrcItem->GetCount()); } else if (IsBankPos (dst)) { @@ -12898,6 +12877,7 @@ void Player::SwapItem(uint16 src, uint16 dst) RemoveItem(srcbag, srcslot, true); BankItem(dest, pSrcItem, true); + ItemRemovedQuestCheck(pSrcItem->GetEntry(), pSrcItem->GetCount()); } else if (IsEquipmentPos (dst)) { @@ -13322,11 +13302,7 @@ void Player::UpdateSoulboundTradeItems() // also checks for garbage data for (ItemDurationList::iterator itr = m_itemSoulboundTradeable.begin(); itr != m_itemSoulboundTradeable.end();) { - if (!*itr) - { - m_itemSoulboundTradeable.erase(itr++); - continue; - } + ASSERT(*itr); if ((*itr)->GetOwnerGUID() != GetGUID()) { m_itemSoulboundTradeable.erase(itr++); @@ -13341,16 +13317,10 @@ void Player::UpdateSoulboundTradeItems() } } +//TODO: should never allow an item to be added to m_itemSoulboundTradeable twice void Player::RemoveTradeableItem(Item* item) { - for (ItemDurationList::iterator itr = m_itemSoulboundTradeable.begin(); itr != m_itemSoulboundTradeable.end(); ++itr) - { - if ((*itr) == item) - { - m_itemSoulboundTradeable.erase(itr); - break; - } - } + m_itemSoulboundTradeable.remove(item); } void Player::UpdateItemDuration(uint32 time, bool realtimeonly) @@ -15052,11 +15022,11 @@ void Player::FailQuest(uint32 questId) // Destroy quest items on quest failure. for (uint8 i = 0; i < QUEST_OBJECTIVES_COUNT; ++i) if (quest->RequiredItemId[i] > 0 && quest->RequiredItemCount[i] > 0) - // Destroy items recieved on starting the quest. + // Destroy items received on starting the quest. DestroyItemCount(quest->RequiredItemId[i], quest->RequiredItemCount[i], true, true); for (uint8 i = 0; i < QUEST_SOURCE_ITEM_IDS_COUNT; ++i) if (quest->RequiredSourceItemId[i] > 0 && quest->RequiredSourceItemCount[i] > 0) - // Destroy items recieved during the quest. + // Destroy items received during the quest. DestroyItemCount(quest->RequiredSourceItemId[i], quest->RequiredSourceItemCount[i], true, true); } } @@ -18143,8 +18113,14 @@ bool Player::Satisfy(AccessRequirement const* ar, uint32 target_map, bool report missingQuest = ar->quest_H; uint32 missingAchievement = 0; - if (ar->achievement && !GetAchievementMgr().HasAchieved(sAchievementStore.LookupEntry(ar->achievement))) - missingAchievement = ar->achievement; + Player* leader = this; + uint64 leaderGuid = GetGroup() ? GetGroup()->GetLeaderGUID() : GetGUID(); + if (leaderGuid != GetGUID()) + leader = ObjectAccessor::FindPlayer(leaderGuid); + + if (ar->achievement) + if (!leader || !leader->GetAchievementMgr().HasAchieved(ar->achievement)) + missingAchievement = ar->achievement; Difficulty target_difficulty = GetDifficulty(mapEntry->IsRaid()); MapDifficulty const* mapDiff = GetDownscaledMapDifficultyData(target_map, target_difficulty); @@ -18919,7 +18895,7 @@ void Player::_SaveSkills(SQLTransaction& trans) void Player::_SaveSpells(SQLTransaction& trans) { - for (PlayerSpellMap::iterator itr = m_spells.begin(), next = m_spells.begin(); itr != m_spells.end();) + for (PlayerSpellMap::iterator itr = m_spells.begin(); itr != m_spells.end();) { if (itr->second->state == PLAYERSPELL_REMOVED || itr->second->state == PLAYERSPELL_CHANGED) trans->PAppend("DELETE FROM character_spell WHERE guid = '%u' and spell = '%u'", GetGUIDLow(), itr->first); @@ -20221,7 +20197,7 @@ bool Player::ActivateTaxiPathTo(uint32 taxi_path_id, uint32 spellid /*= 0*/) void Player::CleanupAfterTaxiFlight() { m_taxi.ClearTaxiDestinations(); // not destinations, clear source node - Unmount(); + Dismount(); RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_TAXI_FLIGHT); getHostileRefManager().setOnlineOfflineState(true); } diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 651b99e7cb4..8ee7d1a417f 100755 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -1091,13 +1091,10 @@ class Player : public Unit, public GridObject<Player> void RemoveFromWorld(); bool TeleportTo(uint32 mapid, float x, float y, float z, float orientation, uint32 options = 0); - void TeleportOutOfMap(Map* oldMap); - bool TeleportTo(WorldLocation const &loc, uint32 options = 0) { return TeleportTo(loc.GetMapId(), loc.GetPositionX(), loc.GetPositionY(), loc.GetPositionZ(), loc.GetOrientation(), options); } - bool TeleportToBGEntryPoint(); void SetSummonPoint(uint32 mapid, float x, float y, float z) @@ -1114,7 +1111,7 @@ class Player : public Unit, public GridObject<Player> void Update(uint32 time); - static bool BuildEnumData(QueryResult result, WorldPacket* data); + static bool BuildEnumData(PreparedQueryResult result, WorldPacket* data); void SetInWater(bool apply); @@ -2503,7 +2500,7 @@ class Player : public Unit, public GridObject<Player> CreatureDisplayInfoEntry const* mountDisplayInfo = sCreatureDisplayInfoStore.LookupEntry(GetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID)); if (!mountDisplayInfo) return GetCollisionHeight(false); - + CreatureModelDataEntry const* mountModelData = sCreatureModelDataStore.LookupEntry(mountDisplayInfo->ModelId); if (!mountModelData) return GetCollisionHeight(false); diff --git a/src/server/game/Entities/Totem/Totem.cpp b/src/server/game/Entities/Totem/Totem.cpp index 97629e802d4..fc368b1f109 100755 --- a/src/server/game/Entities/Totem/Totem.cpp +++ b/src/server/game/Entities/Totem/Totem.cpp @@ -25,7 +25,7 @@ #include "SpellMgr.h" #include "SpellInfo.h" -Totem::Totem(SummonPropertiesEntry const* properties, Unit* owner) : Minion(properties, owner) +Totem::Totem(SummonPropertiesEntry const* properties, Unit* owner) : Minion(properties, owner, false) { m_unitTypeMask |= UNIT_MASK_TOTEM; m_duration = 0; diff --git a/src/server/game/Entities/Transport/Transport.cpp b/src/server/game/Entities/Transport/Transport.cpp index 008f752306d..d533f6fe5b9 100755 --- a/src/server/game/Entities/Transport/Transport.cpp +++ b/src/server/game/Entities/Transport/Transport.cpp @@ -633,7 +633,8 @@ void Transport::BuildStopMovePacket(Map const* targetMap) uint32 Transport::AddNPCPassenger(uint32 tguid, uint32 entry, float x, float y, float z, float o, uint32 anim) { Map* map = GetMap(); - Creature* creature = new Creature; + //make it world object so it will not be unloaded with grid + Creature* creature = new Creature(true); if (!creature->Create(sObjectMgr->GenerateLowGuid(HIGHGUID_UNIT), map, GetPhaseMask(), entry, 0, GetGOInfo()->faction, 0, 0, 0, 0)) { @@ -666,7 +667,6 @@ uint32 Transport::AddNPCPassenger(uint32 tguid, uint32 entry, float x, float y, map->AddToMap(creature); m_NPCPassengerSet.insert(creature); - creature->SetWorldObject(true); //so it will not be unloaded with grid if (tguid == 0) { diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index 298f9c60af8..fec9a13192c 100755 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -144,7 +144,7 @@ _hitMask(hitMask), _spell(spell), _damageInfo(damageInfo), _healInfo(healInfo) #ifdef _MSC_VER #pragma warning(disable:4355) #endif -Unit::Unit(): WorldObject(), +Unit::Unit(bool isWorldObject): WorldObject(isWorldObject), m_movedPlayer(NULL), m_lastSanctuaryTime(0), IsAIEnabled(false), NeedChangeAI(false), m_ControlledByPlayer(false), i_AI(NULL), i_disabledAI(NULL), m_procDeep(0), m_removedAurasCount(0), i_motionMaster(this), m_ThreatManager(this), m_vehicle(NULL), @@ -1478,9 +1478,13 @@ bool Unit::IsDamageReducedByArmor(SpellSchoolMask schoolMask, SpellInfo const* s return false; // bleeding effects are not reduced by armor - if (effIndex != MAX_SPELL_EFFECTS && spellInfo->Effects[effIndex].ApplyAuraName == SPELL_AURA_PERIODIC_DAMAGE) - if (spellInfo->GetEffectMechanicMask(effIndex) & (1<<MECHANIC_BLEED)) - return false; + if (effIndex != MAX_SPELL_EFFECTS) + { + if (spellInfo->Effects[effIndex].ApplyAuraName == SPELL_AURA_PERIODIC_DAMAGE || + spellInfo->Effects[effIndex].Effect == SPELL_EFFECT_SCHOOL_DAMAGE) + if (spellInfo->GetEffectMechanicMask(effIndex) & (1<<MECHANIC_BLEED)) + return false; + } } return true; } @@ -1922,12 +1926,7 @@ void Unit::AttackerStateUpdate (Unit* victim, WeaponAttackType attType, bool ext CombatStart(victim); RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_MELEE_ATTACK); - uint32 hitInfo; - if (attType == BASE_ATTACK) - hitInfo = HITINFO_NORMALSWING2; - else if (attType == OFF_ATTACK) - hitInfo = HITINFO_LEFTSWING; - else + if (attType != BASE_ATTACK && attType != OFF_ATTACK) return; // ignore ranged case // melee attack spell casted at main hand attack only - no normal melee dmg dealt @@ -5470,7 +5469,7 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere case CLASS_DRUID: RandomSpells.push_back(71484); RandomSpells.push_back(71485); - RandomSpells.push_back(71486); + RandomSpells.push_back(71492); break; case CLASS_HUNTER: RandomSpells.push_back(71486); @@ -5516,7 +5515,7 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere case CLASS_DRUID: RandomSpells.push_back(71561); RandomSpells.push_back(71556); - RandomSpells.push_back(71558); + RandomSpells.push_back(71560); break; case CLASS_HUNTER: RandomSpells.push_back(71558); @@ -6498,7 +6497,7 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere RemoveAura(57934); if (!redirectTarget) break; - redirectTarget->CastSpell(this,59628,true); + CastSpell(this,59628,true); CastSpell(redirectTarget,57933,true); break; } @@ -8920,6 +8919,20 @@ bool Unit::HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* trigg } break; } + case 46916: // Slam! (Bloodsurge proc) + case 52437: // Sudden Death + { + // Item - Warrior T10 Melee 4P Bonus + if (AuraEffect const* aurEff = GetAuraEffect(70847, 0)) + { + if (!roll_chance_i(aurEff->GetAmount())) + break; + CastSpell(this, 70849, true, castItem, triggeredByAura); // Extra Charge! + CastSpell(this, 71072, true, castItem, triggeredByAura); // Slam GCD Reduced + CastSpell(this, 71069, true, castItem, triggeredByAura); // Execute GCD Reduced + } + break; + } // Sword and Board case 50227: { @@ -11929,7 +11942,7 @@ void Unit::Mount(uint32 mount, uint32 VehicleId, uint32 creatureEntry) RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_MOUNT); } -void Unit::Unmount() +void Unit::Dismount() { if (!IsMounted()) return; @@ -11950,7 +11963,7 @@ void Unit::Unmount() data.appendPackGUID(GetGUID()); SendMessageToSet(&data, true); - // unmount as a vehicle + // dismount as a vehicle if (GetTypeId() == TYPEID_PLAYER && GetVehicleKit()) { // Send other players that we are no longer a vehicle @@ -12072,7 +12085,7 @@ void Unit::SetInCombatState(bool PvP, Unit* enemy) } if (!(creature->GetCreatureInfo()->type_flags & CREATURE_TYPEFLAGS_MOUNTED_COMBAT)) - Unmount(); + Dismount(); } for (Unit::ControlList::iterator itr = m_Controlled.begin(); itr != m_Controlled.end(); ++itr) @@ -14300,6 +14313,7 @@ void Unit::ProcDamageAndSpellFor(bool isVictim, Unit* target, uint32 procFlag, u if (procTriggered.empty()) return; + // Note: must SetCantProc(false) before return if (procExtra & (PROC_EX_INTERNAL_TRIGGERED | PROC_EX_INTERNAL_CANT_PROC)) SetCantProc(true); @@ -14324,6 +14338,7 @@ void Unit::ProcDamageAndSpellFor(bool isVictim, Unit* target, uint32 procFlag, u if (GetTypeId() == TYPEID_PLAYER && i->spellProcEvent && i->spellProcEvent->cooldown) cooldown = i->spellProcEvent->cooldown; + // Note: must SetCantProc(false) before return if (spellInfo->AttributesEx3 & SPELL_ATTR3_DISABLE_PROC) SetCantProc(true); @@ -14336,176 +14351,179 @@ void Unit::ProcDamageAndSpellFor(bool isVictim, Unit* target, uint32 procFlag, u } if (!handled) - for (uint8 effIndex = 0; effIndex < MAX_SPELL_EFFECTS; ++effIndex) { - if (!(i->effMask & (1<<effIndex))) - continue; - - AuraEffect* triggeredByAura = i->aura->GetEffect(effIndex); - ASSERT(triggeredByAura); - - switch (triggeredByAura->GetAuraType()) + for (uint8 effIndex = 0; effIndex < MAX_SPELL_EFFECTS; ++effIndex) { - case SPELL_AURA_PROC_TRIGGER_SPELL: - { - sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "ProcDamageAndSpell: casting spell %u (triggered by %s aura of spell %u)", spellInfo->Id, (isVictim?"a victim's":"an attacker's"), triggeredByAura->GetId()); - // Don`t drop charge or add cooldown for not started trigger - if (HandleProcTriggerSpell(target, damage, triggeredByAura, procSpell, procFlag, procExtra, cooldown)) - takeCharges = true; - break; - } - case SPELL_AURA_PROC_TRIGGER_DAMAGE: - { - // target has to be valid - if (!target) - return; - - sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "ProcDamageAndSpell: doing %u damage from spell id %u (triggered by %s aura of spell %u)", triggeredByAura->GetAmount(), spellInfo->Id, (isVictim?"a victim's":"an attacker's"), triggeredByAura->GetId()); - SpellNonMeleeDamage damageInfo(this, target, spellInfo->Id, spellInfo->SchoolMask); - uint32 newDamage = SpellDamageBonus(target, spellInfo, triggeredByAura->GetAmount(), SPELL_DIRECT_DAMAGE); - CalculateSpellDamageTaken(&damageInfo, newDamage, spellInfo); - DealDamageMods(damageInfo.target, damageInfo.damage, &damageInfo.absorb); - SendSpellNonMeleeDamageLog(&damageInfo); - DealSpellDamage(&damageInfo, true); - takeCharges = true; - break; - } - case SPELL_AURA_MANA_SHIELD: - case SPELL_AURA_DUMMY: - { - sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "ProcDamageAndSpell: casting spell id %u (triggered by %s dummy aura of spell %u)", spellInfo->Id, (isVictim?"a victim's":"an attacker's"), triggeredByAura->GetId()); - if (HandleDummyAuraProc(target, damage, triggeredByAura, procSpell, procFlag, procExtra, cooldown)) - takeCharges = true; - break; - } - case SPELL_AURA_OBS_MOD_POWER: - sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "ProcDamageAndSpell: casting spell id %u (triggered by %s aura of spell %u)", spellInfo->Id, (isVictim?"a victim's":"an attacker's"), triggeredByAura->GetId()); - if (HandleObsModEnergyAuraProc(target, damage, triggeredByAura, procSpell, procFlag, procExtra, cooldown)) - takeCharges = true; - break; - case SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN: - sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "ProcDamageAndSpell: casting spell id %u (triggered by %s aura of spell %u)", spellInfo->Id, (isVictim?"a victim's":"an attacker's"), triggeredByAura->GetId()); - if (HandleModDamagePctTakenAuraProc(target, damage, triggeredByAura, procSpell, procFlag, procExtra, cooldown)) - takeCharges = true; - break; - case SPELL_AURA_MOD_MELEE_HASTE: - { - sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "ProcDamageAndSpell: casting spell id %u (triggered by %s haste aura of spell %u)", spellInfo->Id, (isVictim?"a victim's":"an attacker's"), triggeredByAura->GetId()); - if (HandleHasteAuraProc(target, damage, triggeredByAura, procSpell, procFlag, procExtra, cooldown)) - takeCharges = true; - break; - } - case SPELL_AURA_OVERRIDE_CLASS_SCRIPTS: - { - sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "ProcDamageAndSpell: casting spell id %u (triggered by %s aura of spell %u)", spellInfo->Id, (isVictim?"a victim's":"an attacker's"), triggeredByAura->GetId()); - if (HandleOverrideClassScriptAuraProc(target, damage, triggeredByAura, procSpell, cooldown)) - takeCharges = true; - break; - } - case SPELL_AURA_RAID_PROC_FROM_CHARGE_WITH_VALUE: - { - sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "ProcDamageAndSpell: casting mending (triggered by %s dummy aura of spell %u)", - (isVictim?"a victim's":"an attacker's"), triggeredByAura->GetId()); + if (!(i->effMask & (1<<effIndex))) + continue; - HandleAuraRaidProcFromChargeWithValue(triggeredByAura); - takeCharges = true; - break; - } - case SPELL_AURA_RAID_PROC_FROM_CHARGE: - { - sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "ProcDamageAndSpell: casting mending (triggered by %s dummy aura of spell %u)", - (isVictim?"a victim's":"an attacker's"), triggeredByAura->GetId()); + AuraEffect* triggeredByAura = i->aura->GetEffect(effIndex); + ASSERT(triggeredByAura); - HandleAuraRaidProcFromCharge(triggeredByAura); - takeCharges = true; - break; - } - case SPELL_AURA_PROC_TRIGGER_SPELL_WITH_VALUE: + switch (triggeredByAura->GetAuraType()) { - sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "ProcDamageAndSpell: casting spell %u (triggered with value by %s aura of spell %u)", spellInfo->Id, (isVictim?"a victim's":"an attacker's"), triggeredByAura->GetId()); + case SPELL_AURA_PROC_TRIGGER_SPELL: + { + sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "ProcDamageAndSpell: casting spell %u (triggered by %s aura of spell %u)", spellInfo->Id, (isVictim?"a victim's":"an attacker's"), triggeredByAura->GetId()); + // Don`t drop charge or add cooldown for not started trigger + if (HandleProcTriggerSpell(target, damage, triggeredByAura, procSpell, procFlag, procExtra, cooldown)) + takeCharges = true; + break; + } + case SPELL_AURA_PROC_TRIGGER_DAMAGE: + { + // target has to be valid + if (!target) + break; - if (HandleProcTriggerSpell(target, damage, triggeredByAura, procSpell, procFlag, procExtra, cooldown)) - takeCharges = true; - break; - } - case SPELL_AURA_MOD_CASTING_SPEED_NOT_STACK: - // Skip melee hits or instant cast spells - if (procSpell && procSpell->CalcCastTime() != 0) - takeCharges = true; - break; - case SPELL_AURA_REFLECT_SPELLS_SCHOOL: - // Skip Melee hits and spells ws wrong school - if (procSpell && (triggeredByAura->GetMiscValue() & procSpell->SchoolMask)) // School check - takeCharges = true; - break; - case SPELL_AURA_MOD_POWER_COST_SCHOOL_PCT: - case SPELL_AURA_MOD_POWER_COST_SCHOOL: - // Skip melee hits and spells ws wrong school or zero cost - if (procSpell && - (procSpell->ManaCost != 0 || procSpell->ManaCostPercentage != 0) && // Cost check - (triggeredByAura->GetMiscValue() & procSpell->SchoolMask)) // School check - takeCharges = true; - break; - case SPELL_AURA_MECHANIC_IMMUNITY: - // Compare mechanic - if (procSpell && procSpell->Mechanic == uint32(triggeredByAura->GetMiscValue())) - takeCharges = true; - break; - case SPELL_AURA_MOD_MECHANIC_RESISTANCE: - // Compare mechanic - if (procSpell && procSpell->Mechanic == uint32(triggeredByAura->GetMiscValue())) + sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "ProcDamageAndSpell: doing %u damage from spell id %u (triggered by %s aura of spell %u)", triggeredByAura->GetAmount(), spellInfo->Id, (isVictim?"a victim's":"an attacker's"), triggeredByAura->GetId()); + SpellNonMeleeDamage damageInfo(this, target, spellInfo->Id, spellInfo->SchoolMask); + uint32 newDamage = SpellDamageBonus(target, spellInfo, triggeredByAura->GetAmount(), SPELL_DIRECT_DAMAGE); + CalculateSpellDamageTaken(&damageInfo, newDamage, spellInfo); + DealDamageMods(damageInfo.target, damageInfo.damage, &damageInfo.absorb); + SendSpellNonMeleeDamageLog(&damageInfo); + DealSpellDamage(&damageInfo, true); takeCharges = true; - break; - case SPELL_AURA_MOD_DAMAGE_FROM_CASTER: - // Compare casters - if (triggeredByAura->GetCasterGUID() == target->GetGUID()) - takeCharges = true; - break; - case SPELL_AURA_MOD_SPELL_CRIT_CHANCE: - sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "ProcDamageAndSpell: casting spell id %u (triggered by %s spell crit chance aura of spell %u)", spellInfo->Id, (isVictim?"a victim's":"an attacker's"), triggeredByAura->GetId()); - if (procSpell && HandleSpellCritChanceAuraProc(target, damage, triggeredByAura, procSpell, procFlag, procExtra, cooldown)) + break; + } + case SPELL_AURA_MANA_SHIELD: + case SPELL_AURA_DUMMY: + { + sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "ProcDamageAndSpell: casting spell id %u (triggered by %s dummy aura of spell %u)", spellInfo->Id, (isVictim?"a victim's":"an attacker's"), triggeredByAura->GetId()); + if (HandleDummyAuraProc(target, damage, triggeredByAura, procSpell, procFlag, procExtra, cooldown)) + takeCharges = true; + break; + } + case SPELL_AURA_OBS_MOD_POWER: + sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "ProcDamageAndSpell: casting spell id %u (triggered by %s aura of spell %u)", spellInfo->Id, (isVictim?"a victim's":"an attacker's"), triggeredByAura->GetId()); + if (HandleObsModEnergyAuraProc(target, damage, triggeredByAura, procSpell, procFlag, procExtra, cooldown)) + takeCharges = true; + break; + case SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN: + sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "ProcDamageAndSpell: casting spell id %u (triggered by %s aura of spell %u)", spellInfo->Id, (isVictim?"a victim's":"an attacker's"), triggeredByAura->GetId()); + if (HandleModDamagePctTakenAuraProc(target, damage, triggeredByAura, procSpell, procFlag, procExtra, cooldown)) + takeCharges = true; + break; + case SPELL_AURA_MOD_MELEE_HASTE: + { + sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "ProcDamageAndSpell: casting spell id %u (triggered by %s haste aura of spell %u)", spellInfo->Id, (isVictim?"a victim's":"an attacker's"), triggeredByAura->GetId()); + if (HandleHasteAuraProc(target, damage, triggeredByAura, procSpell, procFlag, procExtra, cooldown)) + takeCharges = true; + break; + } + case SPELL_AURA_OVERRIDE_CLASS_SCRIPTS: + { + sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "ProcDamageAndSpell: casting spell id %u (triggered by %s aura of spell %u)", spellInfo->Id, (isVictim?"a victim's":"an attacker's"), triggeredByAura->GetId()); + if (HandleOverrideClassScriptAuraProc(target, damage, triggeredByAura, procSpell, cooldown)) + takeCharges = true; + break; + } + case SPELL_AURA_RAID_PROC_FROM_CHARGE_WITH_VALUE: + { + sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "ProcDamageAndSpell: casting mending (triggered by %s dummy aura of spell %u)", + (isVictim?"a victim's":"an attacker's"), triggeredByAura->GetId()); + + HandleAuraRaidProcFromChargeWithValue(triggeredByAura); takeCharges = true; - break; - // CC Auras which use their amount amount to drop - // Are there any more auras which need this? - case SPELL_AURA_MOD_CONFUSE: - case SPELL_AURA_MOD_FEAR: - case SPELL_AURA_MOD_STUN: - case SPELL_AURA_MOD_ROOT: - case SPELL_AURA_TRANSFORM: - { - // chargeable mods are breaking on hit - if (useCharges) + break; + } + case SPELL_AURA_RAID_PROC_FROM_CHARGE: + { + sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "ProcDamageAndSpell: casting mending (triggered by %s dummy aura of spell %u)", + (isVictim?"a victim's":"an attacker's"), triggeredByAura->GetId()); + + HandleAuraRaidProcFromCharge(triggeredByAura); takeCharges = true; - else + break; + } + case SPELL_AURA_PROC_TRIGGER_SPELL_WITH_VALUE: { - // Spell own direct damage at apply wont break the CC - if (procSpell && (procSpell->Id == triggeredByAura->GetId())) + sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "ProcDamageAndSpell: casting spell %u (triggered with value by %s aura of spell %u)", spellInfo->Id, (isVictim?"a victim's":"an attacker's"), triggeredByAura->GetId()); + + if (HandleProcTriggerSpell(target, damage, triggeredByAura, procSpell, procFlag, procExtra, cooldown)) + takeCharges = true; + break; + } + case SPELL_AURA_MOD_CASTING_SPEED_NOT_STACK: + // Skip melee hits or instant cast spells + if (procSpell && procSpell->CalcCastTime() != 0) + takeCharges = true; + break; + case SPELL_AURA_REFLECT_SPELLS_SCHOOL: + // Skip Melee hits and spells ws wrong school + if (procSpell && (triggeredByAura->GetMiscValue() & procSpell->SchoolMask)) // School check + takeCharges = true; + break; + case SPELL_AURA_MOD_POWER_COST_SCHOOL_PCT: + case SPELL_AURA_MOD_POWER_COST_SCHOOL: + // Skip melee hits and spells ws wrong school or zero cost + if (procSpell && + (procSpell->ManaCost != 0 || procSpell->ManaCostPercentage != 0) && // Cost check + (triggeredByAura->GetMiscValue() & procSpell->SchoolMask)) // School check + takeCharges = true; + break; + case SPELL_AURA_MECHANIC_IMMUNITY: + // Compare mechanic + if (procSpell && procSpell->Mechanic == uint32(triggeredByAura->GetMiscValue())) + takeCharges = true; + break; + case SPELL_AURA_MOD_MECHANIC_RESISTANCE: + // Compare mechanic + if (procSpell && procSpell->Mechanic == uint32(triggeredByAura->GetMiscValue())) + takeCharges = true; + break; + case SPELL_AURA_MOD_DAMAGE_FROM_CASTER: + // Compare casters + if (triggeredByAura->GetCasterGUID() == target->GetGUID()) + takeCharges = true; + break; + case SPELL_AURA_MOD_SPELL_CRIT_CHANCE: + sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "ProcDamageAndSpell: casting spell id %u (triggered by %s spell crit chance aura of spell %u)", spellInfo->Id, (isVictim?"a victim's":"an attacker's"), triggeredByAura->GetId()); + if (procSpell && HandleSpellCritChanceAuraProc(target, damage, triggeredByAura, procSpell, procFlag, procExtra, cooldown)) + takeCharges = true; + break; + // CC Auras which use their amount amount to drop + // Are there any more auras which need this? + case SPELL_AURA_MOD_CONFUSE: + case SPELL_AURA_MOD_FEAR: + case SPELL_AURA_MOD_STUN: + case SPELL_AURA_MOD_ROOT: + case SPELL_AURA_TRANSFORM: + { + // chargeable mods are breaking on hit + if (useCharges) + takeCharges = true; + else { - Aura* aura = triggeredByAura->GetBase(); - // called from spellcast, should not have ticked yet - if (aura->GetDuration() == aura->GetMaxDuration()) - break; + // Spell own direct damage at apply wont break the CC + if (procSpell && (procSpell->Id == triggeredByAura->GetId())) + { + Aura* aura = triggeredByAura->GetBase(); + // called from spellcast, should not have ticked yet + if (aura->GetDuration() == aura->GetMaxDuration()) + break; + } + int32 damageLeft = triggeredByAura->GetAmount(); + // No damage left + if (damageLeft < int32(damage)) + i->aura->Remove(); + else + triggeredByAura->SetAmount(damageLeft - damage); } - int32 damageLeft = triggeredByAura->GetAmount(); - // No damage left - if (damageLeft < int32(damage)) - i->aura->Remove(); - else - triggeredByAura->SetAmount(damageLeft - damage); + break; } - break; - } - //case SPELL_AURA_ADD_FLAT_MODIFIER: - //case SPELL_AURA_ADD_PCT_MODIFIER: - // HandleSpellModAuraProc - //break; - default: - // nothing do, just charges counter - takeCharges = true; - break; - } - } + //case SPELL_AURA_ADD_FLAT_MODIFIER: + //case SPELL_AURA_ADD_PCT_MODIFIER: + // HandleSpellModAuraProc + //break; + default: + // nothing do, just charges counter + takeCharges = true; + break; + } // switch (triggeredByAura->GetAuraType()) + } // for (uint8 effIndex = 0; effIndex < MAX_SPELL_EFFECTS; ++effIndex) + } // if (!handled) + // Remove charge (aura can be removed by triggers) if (useCharges && takeCharges) i->aura->DropCharge(AURA_REMOVE_BY_EXPIRE); @@ -15593,29 +15611,17 @@ void Unit::Kill(Unit* victim, bool durabilityLoss) } // Hook for OnPVPKill Event - if (GetTypeId() == TYPEID_PLAYER) + if (Player* killerPlr = ToPlayer()) { - if (victim->GetTypeId() == TYPEID_PLAYER) - { - Player* killer = ToPlayer(); - Player* killed = victim->ToPlayer(); - sScriptMgr->OnPVPKill(killer, killed); - } - else if (victim->GetTypeId() == TYPEID_UNIT) - { - Player* killer = ToPlayer(); - Creature* killed = victim->ToCreature(); - sScriptMgr->OnCreatureKill(killer, killed); - } + if (Player* killedPlr = victim->ToPlayer()) + sScriptMgr->OnPVPKill(killerPlr, killedPlr); + else if (Creature* killedCre = victim->ToCreature()) + sScriptMgr->OnCreatureKill(killerPlr, killedCre); } - else if (GetTypeId() == TYPEID_UNIT) + else if (Creature* killerCre = ToCreature()) { - if (victim->GetTypeId() == TYPEID_PLAYER) - { - Creature* killer = ToCreature(); - Player* killed = victim->ToPlayer(); - sScriptMgr->OnPlayerKilledByCreature(killer, killed); - } + if (Player* killed = victim->ToPlayer()) + sScriptMgr->OnPlayerKilledByCreature(killerCre, killed); } if (victim->GetVehicle()) @@ -15851,9 +15857,9 @@ bool Unit::SetCharmedBy(Unit* charmer, CharmType type, AuraApplication const* au if (!charmer) return false; - // unmount players when charmed + // dismount players when charmed if (GetTypeId() == TYPEID_PLAYER) - Unmount(); + Dismount(); ASSERT(type != CHARM_TYPE_POSSESS || charmer->GetTypeId() == TYPEID_PLAYER); ASSERT((type == CHARM_TYPE_VEHICLE) == IsVehicle()); @@ -16999,7 +17005,7 @@ void Unit::_EnterVehicle(Vehicle* vehicle, int8 seatId, AuraApplication const* a InterruptNonMeleeSpells(false); player->StopCastingCharm(); player->StopCastingBindSight(); - Unmount(); + Dismount(); RemoveAurasByType(SPELL_AURA_MOUNTED); // drop flag at invisible in bg @@ -17099,7 +17105,7 @@ void Unit::_ExitVehicle(Position const* exitPosition) // Vehicle just died, we die too if (vehicle->GetBase()->getDeathState() == JUST_DIED) setDeathState(JUST_DIED); - // If for other reason we as minion are exiting the vehicle (ejected, master unmounted) - unsummon + // If for other reason we as minion are exiting the vehicle (ejected, master dismounted) - unsummon else ToTempSummon()->UnSummon(2000); // Approximation } diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index 5906a7f3a2b..b18223ae3ce 100755 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -65,7 +65,7 @@ enum SpellAuraInterruptFlags AURA_INTERRUPT_FLAG_MOVE = 0x00000008, // 3 removed by any movement AURA_INTERRUPT_FLAG_TURNING = 0x00000010, // 4 removed by any turning AURA_INTERRUPT_FLAG_JUMP = 0x00000020, // 5 removed by entering combat - AURA_INTERRUPT_FLAG_NOT_MOUNTED = 0x00000040, // 6 removed by unmounting + AURA_INTERRUPT_FLAG_NOT_MOUNTED = 0x00000040, // 6 removed by dismounting AURA_INTERRUPT_FLAG_NOT_ABOVEWATER = 0x00000080, // 7 removed by entering water AURA_INTERRUPT_FLAG_NOT_UNDERWATER = 0x00000100, // 8 removed by leaving water AURA_INTERRUPT_FLAG_NOT_SHEATHED = 0x00000200, // 9 removed by unsheathing @@ -1441,7 +1441,7 @@ class Unit : public WorldObject bool IsMounted() const { return HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_MOUNT); } uint32 GetMountID() const { return GetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID); } void Mount(uint32 mount, uint32 vehicleId = 0, uint32 creatureEntry = 0); - void Unmount(); + void Dismount(); uint16 GetMaxSkillValueForLevel(Unit const* target = NULL) const { return (target ? getLevelForTarget(target) : getLevel()) * 5; } void DealDamageMods(Unit* pVictim, uint32 &damage, uint32* absorb); @@ -2233,7 +2233,7 @@ class Unit : public WorldObject } protected: - explicit Unit (); + explicit Unit (bool isWorldObject); UnitAI* i_AI, *i_disabledAI; diff --git a/src/server/game/Entities/Vehicle/Vehicle.cpp b/src/server/game/Entities/Vehicle/Vehicle.cpp index fe018ec78ce..d3c3268e9ce 100755 --- a/src/server/game/Entities/Vehicle/Vehicle.cpp +++ b/src/server/game/Entities/Vehicle/Vehicle.cpp @@ -341,7 +341,7 @@ bool Vehicle::AddPassenger(Unit* unit, int8 seatId) } } - if (seat->second.SeatInfo->m_flags && !(seat->second.SeatInfo->m_flags & VEHICLE_SEAT_FLAG_UNK11)) + if (seat->second.SeatInfo->m_flags && !(seat->second.SeatInfo->m_flags & VEHICLE_SEAT_FLAG_UNK1)) unit->AddUnitState(UNIT_STAT_ONVEHICLE); unit->AddUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT); diff --git a/src/server/game/Events/GameEventMgr.cpp b/src/server/game/Events/GameEventMgr.cpp index d3cc27c9e6c..5cb130b93e4 100755 --- a/src/server/game/Events/GameEventMgr.cpp +++ b/src/server/game/Events/GameEventMgr.cpp @@ -27,6 +27,8 @@ #include "GossipDef.h" #include "Player.h" #include "BattlegroundMgr.h" +#include "UnitAI.h" +#include "GameObjectAI.h" bool GameEventMgr::CheckOneGameEvent(uint16 entry) const { @@ -1059,6 +1061,8 @@ uint32 GameEventMgr::Update() // return the next e void GameEventMgr::UnApplyEvent(uint16 event_id) { sLog->outDetail("GameEvent %u \"%s\" removed.", event_id, mGameEvent[event_id].description.c_str()); + //! Run SAI scripts with SMART_EVENT_GAME_EVENT_END + RunSmartAIScripts(event_id, false); // un-spawn positive event tagged objects GameEventUnspawn(event_id); // spawn negative event tagget objects @@ -1090,6 +1094,9 @@ void GameEventMgr::ApplyNewEvent(uint16 event_id) sLog->outDetail("GameEvent %u \"%s\" started.", event_id, mGameEvent[event_id].description.c_str()); + //! Run SAI scripts with SMART_EVENT_GAME_EVENT_END + RunSmartAIScripts(event_id, true); + // spawn positive event tagget objects GameEventSpawn(event_id); // un-spawn negative event tagged objects @@ -1601,6 +1608,26 @@ void GameEventMgr::SendWorldStateUpdate(Player* player, uint16 event_id) } } +void GameEventMgr::RunSmartAIScripts(uint16 event_id, bool activate) +{ + //! Iterate over every supported source type (creature and gameobject) + //! Not entirely sure how this will affect units in non-loaded grids. + { + TRINITY_READ_GUARD(HashMapHolder<Creature>::LockType, *HashMapHolder<Creature>::GetLock()); + HashMapHolder<Creature>::MapType const& m = ObjectAccessor::GetCreatures(); + for (HashMapHolder<Creature>::MapType::const_iterator iter = m.begin(); iter != m.end(); ++iter) + if (iter->second->IsInWorld()) + iter->second->AI()->sOnGameEvent(activate, event_id); + } + { + TRINITY_READ_GUARD(HashMapHolder<GameObject>::LockType, *HashMapHolder<GameObject>::GetLock()); + HashMapHolder<GameObject>::MapType const& m = ObjectAccessor::GetGameObjects(); + for (HashMapHolder<GameObject>::MapType::const_iterator iter = m.begin(); iter != m.end(); ++iter) + if (iter->second->IsInWorld()) + iter->second->AI()->OnGameEvent(activate, event_id); + } +} + bool IsHolidayActive(HolidayIds id) { if (id == HOLIDAY_NONE) diff --git a/src/server/game/Events/GameEventMgr.h b/src/server/game/Events/GameEventMgr.h index a2a35a85098..bba92b4d24c 100755 --- a/src/server/game/Events/GameEventMgr.h +++ b/src/server/game/Events/GameEventMgr.h @@ -132,6 +132,7 @@ class GameEventMgr void UpdateEventNPCFlags(uint16 event_id); void UpdateEventNPCVendor(uint16 event_id, bool activate); void UpdateBattlegroundSettings(); + void RunSmartAIScripts(uint16 event_id, bool activate); //! Runs SMART_EVENT_GAME_EVENT_START/_END SAI bool CheckOneGameEventConditions(uint16 event_id); void SaveWorldEventStateToDB(uint16 event_id); bool hasCreatureQuestActiveEventExcept(uint32 quest_id, uint16 event_id); diff --git a/src/server/game/Globals/ObjectAccessor.h b/src/server/game/Globals/ObjectAccessor.h index 25fa20dce70..92c947eb86f 100755 --- a/src/server/game/Globals/ObjectAccessor.h +++ b/src/server/game/Globals/ObjectAccessor.h @@ -201,16 +201,16 @@ class ObjectAccessor } // when using this, you must use the hashmapholder's lock - //HashMapHolder<Creature>::MapType& GetCreatures() - //{ - // return HashMapHolder<Creature>::GetContainer(); - //} - - //// when using this, you must use the hashmapholder's lock - //HashMapHolder<GameObject>::MapType& GetGameObjects() - //{ - // return HashMapHolder<GameObject>::GetContainer(); - //} + static HashMapHolder<Creature>::MapType const& GetCreatures() + { + return HashMapHolder<Creature>::GetContainer(); + } + + // when using this, you must use the hashmapholder's lock + static HashMapHolder<GameObject>::MapType const& GetGameObjects() + { + return HashMapHolder<GameObject>::GetContainer(); + } template<class T> static void AddObject(T* object) { diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index 75573367241..5353e048066 100755 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -3818,11 +3818,11 @@ void ObjectMgr::LoadQuests() // no changes, quest not dependent from this value but can have problems at client (note some may be 0, we must allow this so no check) } //check for proper RequiredSkillId value (skill case) - if (int32 skill_id = SkillByQuestSort(-int32(qinfo->ZoneOrSort))) + if (uint32 skill_id = SkillByQuestSort(-int32(qinfo->ZoneOrSort))) { if (qinfo->RequiredSkillId != skill_id) { - sLog->outErrorDb("Quest %u has `ZoneOrSort` = %i but `RequiredSkillId` does not have a corresponding value (%i).", + sLog->outErrorDb("Quest %u has `ZoneOrSort` = %i but `RequiredSkillId` does not have a corresponding value (%d).", qinfo->GetQuestId(), qinfo->ZoneOrSort, skill_id); //override, and force proper value here? } @@ -6721,9 +6721,15 @@ void ObjectMgr::LoadCorpses() { Field* fields = result->Fetch(); uint32 guid = fields[16].GetUInt32(); + CorpseType type = CorpseType(fields[13].GetUInt8()); + if (type >= MAX_CORPSE_TYPE) + { + sLog->outError("Corpse (guid: %u) have wrong corpse type (%u), not loading.", guid, type); + continue; + } - Corpse* corpse = new Corpse(); - if (!corpse->LoadFromDB(guid, fields)) + Corpse* corpse = new Corpse(type); + if (!corpse->LoadCorpseFromDB(guid, fields)) { delete corpse; continue; @@ -8040,8 +8046,11 @@ bool ObjectMgr::AddGameTele(GameTele& tele) m_GameTeleMap[new_id] = tele; + std::string safeName(tele.name); + WorldDatabase.EscapeString(safeName); + WorldDatabase.PExecute("INSERT INTO game_tele (id, position_x, position_y, position_z, orientation, map, name) VALUES (%u, %f, %f, %f, %f, %d, '%s')", - new_id, tele.position_x, tele.position_y, tele.position_z, tele.orientation, tele.mapId, tele.name.c_str()); + new_id, tele.position_x, tele.position_y, tele.position_z, tele.orientation, tele.mapId, safeName.c_str()); return true; } diff --git a/src/server/game/Grids/Grid.h b/src/server/game/Grids/Grid.h index 448c4cb35fd..7e66cf1080a 100755 --- a/src/server/game/Grids/Grid.h +++ b/src/server/game/Grids/Grid.h @@ -100,7 +100,12 @@ class Grid /** Returns the number of object within the grid. */ - unsigned int ActiveObjectsInGrid(void) const { return /*m_activeGridObjects.size()+*/i_objects.template Count<ACTIVE_OBJECT>(); } + //unsigned int ActiveObjectsInGrid(void) const { return i_objects.template Count<ACTIVE_OBJECT>(); } + template<class T> + uint32 GetWorldObjectCountInGrid() const + { + return i_objects.template Count<T>(); + } /** Inserts a container type object into the grid. */ diff --git a/src/server/game/Grids/GridStates.cpp b/src/server/game/Grids/GridStates.cpp index 5f88516c9ac..4e63388c356 100755 --- a/src/server/game/Grids/GridStates.cpp +++ b/src/server/game/Grids/GridStates.cpp @@ -31,7 +31,7 @@ void ActiveState::Update(Map &m, NGridType &grid, GridInfo & info, const uint32 info.UpdateTimeTracker(t_diff); if (info.getTimeTracker().Passed()) { - if (grid.ActiveObjectsInGrid() == 0 && !m.ActiveObjectsNearGrid(grid)) + if (!grid.GetWorldObjectCountInNGrid<Player>() && !m.ActiveObjectsNearGrid(grid)) { ObjectGridStoper worker; TypeContainerVisitor<ObjectGridStoper, GridTypeMapContainer> visitor(worker); diff --git a/src/server/game/Grids/NGrid.h b/src/server/game/Grids/NGrid.h index 97a47f7d272..c87fd7e6129 100755 --- a/src/server/game/Grids/NGrid.h +++ b/src/server/game/Grids/NGrid.h @@ -158,14 +158,28 @@ class NGrid GetGridType(x, y).Visit(visitor); } - unsigned int ActiveObjectsInGrid(void) const + //This gets the player count in grid + //I disable this to avoid confusion (active object usually means something else) + /* + uint32 GetActiveObjectCountInGrid() const { - unsigned int count=0; - for (unsigned int x=0; x < N; ++x) - for (unsigned int y=0; y < N; ++y) + uint32 count = 0; + for (uint32 x = 0; x < N; ++x) + for (uint32 y = 0; y < N; ++y) count += i_cells[x][y].ActiveObjectsInGrid(); return count; } + */ + + template<class T> + uint32 GetWorldObjectCountInNGrid() const + { + uint32 count = 0; + for (uint32 x = 0; x < N; ++x) + for (uint32 y = 0; y < N; ++y) + count += i_cells[x][y].template GetWorldObjectCountInGrid<T>(); + return count; + } private: uint32 i_gridId; diff --git a/src/server/game/Grids/Notifiers/GridNotifiers.cpp b/src/server/game/Grids/Notifiers/GridNotifiers.cpp index ca61a82e840..99d402b4add 100755 --- a/src/server/game/Grids/Notifiers/GridNotifiers.cpp +++ b/src/server/game/Grids/Notifiers/GridNotifiers.cpp @@ -344,7 +344,7 @@ bool AnyDeadUnitObjectInRangeCheck::operator()(Creature* u) bool AnyDeadUnitSpellTargetInRangeCheck::operator()(Player* u) { return AnyDeadUnitObjectInRangeCheck::operator()(u) - && i_spellInfo->CheckTarget(i_searchObj, u, true) + && (i_spellInfo->CheckTarget(i_searchObj, u, true) == SPELL_CAST_OK) && i_searchObj->IsTargetMatchingCheck(u, i_check); } @@ -352,14 +352,14 @@ bool AnyDeadUnitSpellTargetInRangeCheck::operator()(Corpse* u) { Player* owner = ObjectAccessor::FindPlayer(u->GetOwnerGUID()); return owner && AnyDeadUnitObjectInRangeCheck::operator()(u) - && i_spellInfo->CheckTarget(i_searchObj, owner, true) + && (i_spellInfo->CheckTarget(i_searchObj, owner, true) == SPELL_CAST_OK) && i_searchObj->IsTargetMatchingCheck(owner, i_check); } bool AnyDeadUnitSpellTargetInRangeCheck::operator()(Creature* u) { return AnyDeadUnitObjectInRangeCheck::operator()(u) - && i_spellInfo->CheckTarget(i_searchObj, u, true) + && (i_spellInfo->CheckTarget(i_searchObj, u, true) == SPELL_CAST_OK) && i_searchObj->IsTargetMatchingCheck(u, i_check); } diff --git a/src/server/game/Groups/Group.cpp b/src/server/game/Groups/Group.cpp index 6311066f597..11175b13114 100755 --- a/src/server/game/Groups/Group.cpp +++ b/src/server/game/Groups/Group.cpp @@ -1121,6 +1121,7 @@ void Group::CountTheRoll(Rolls::iterator rollI, uint32 NumberOfPlayers) roll->getLoot()->unlootedCount--; ItemTemplate const* pProto = sObjectMgr->GetItemTemplate(roll->itemid); player->AutoStoreLoot(pProto->DisenchantID, LootTemplates_Disenchant, true); + player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL, 13262); // Disenchant } } } diff --git a/src/server/game/Guilds/Guild.cpp b/src/server/game/Guilds/Guild.cpp index 59c107bd40f..94fcbbdda25 100755 --- a/src/server/game/Guilds/Guild.cpp +++ b/src/server/game/Guilds/Guild.cpp @@ -1993,6 +1993,7 @@ bool Guild::Validate() } } } + if (broken_ranks) { m_ranks.clear(); diff --git a/src/server/game/Mails/Mail.cpp b/src/server/game/Mails/Mail.cpp index 6d54aacb311..e5de3e35956 100755 --- a/src/server/game/Mails/Mail.cpp +++ b/src/server/game/Mails/Mail.cpp @@ -171,6 +171,7 @@ void MailDraft::SendReturnToSender(uint32 sender_acc, uint32 sender_guid, uint32 void MailDraft::SendMailTo(SQLTransaction& trans, MailReceiver const& receiver, MailSender const& sender, MailCheckMask checked, uint32 deliver_delay) { Player* pReceiver = receiver.GetPlayer(); // can be NULL + Player* pSender = sObjectMgr->GetPlayerByLowGUID(sender.GetSenderId()); if (pReceiver) prepareItems(pReceiver, trans); // generate mail template items @@ -188,9 +189,12 @@ void MailDraft::SendMailTo(SQLTransaction& trans, MailReceiver const& receiver, // mail from battlemaster (rewardmarks) should last only one day else if (sender.GetMailMessageType() == MAIL_CREATURE && sBattlegroundMgr->GetBattleMasterBG(sender.GetSenderId()) != BATTLEGROUND_TYPE_NONE) expire_delay = DAY; - // default case: expire time if COD 3 days, if no COD 30 days + // default case: expire time if COD 3 days, if no COD 30 days (or 90 days if sender is a game master) else - expire_delay = (m_COD > 0) ? 3 * DAY : 30 * DAY; + if (m_COD) + expire_delay = 3 * DAY; + else + expire_delay = pSender && pSender->isGameMaster() ? 90 * DAY : 30 * DAY; time_t expire_time = deliver_time + expire_delay; diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp index 13a47633b53..34a7b60bcbd 100755 --- a/src/server/game/Maps/Map.cpp +++ b/src/server/game/Maps/Map.cpp @@ -30,6 +30,7 @@ #include "MapManager.h" #include "ObjectMgr.h" #include "Group.h" +#include "LFGMgr.h" union u_map_magic { @@ -58,7 +59,7 @@ Map::~Map() while (!i_worldObjects.empty()) { WorldObject* obj = *i_worldObjects.begin(); - ASSERT(obj->m_isWorldObject); + ASSERT(obj->IsWorldObject()); //ASSERT(obj->GetTypeId() == TYPEID_CORPSE); obj->RemoveFromWorld(); obj->ResetMap(); @@ -237,7 +238,7 @@ template<class T> void Map::AddToGrid(T* obj, Cell const& cell) { NGridType* grid = getNGrid(cell.GridX(), cell.GridY()); - if (obj->m_isWorldObject) + if (obj->IsWorldObject()) grid->GetGridType(cell.CellX(), cell.CellY()).template AddWorldObject<T>(obj); else grid->GetGridType(cell.CellX(), cell.CellY()).template AddGridObject<T>(obj); @@ -247,7 +248,7 @@ template<> void Map::AddToGrid(Creature* obj, Cell const& cell) { NGridType* grid = getNGrid(cell.GridX(), cell.GridY()); - if (obj->m_isWorldObject) + if (obj->IsWorldObject()) grid->GetGridType(cell.CellX(), cell.CellY()).AddWorldObject(obj); else grid->GetGridType(cell.CellX(), cell.CellY()).AddGridObject(obj); @@ -255,9 +256,9 @@ void Map::AddToGrid(Creature* obj, Cell const& cell) obj->SetCurrentCell(cell); } -template<class T> -void Map::SwitchGridContainers(T* obj, bool on) +void Map::SwitchGridContainers(Creature* obj, bool on) { + ASSERT(!obj->IsPermanentWorldObject()); CellCoord p = Trinity::ComputeCellCoord(obj->GetPositionX(), obj->GetPositionY()); if (!p.IsCoordValid()) { @@ -277,15 +278,18 @@ void Map::SwitchGridContainers(T* obj, bool on) obj->RemoveFromGrid(); //This step is not really necessary but we want to do ASSERT in remove/add if (on) - grid.AddWorldObject<T>(obj); + { + grid.AddWorldObject(obj); + AddWorldObject(obj); + } else - grid.AddGridObject<T>(obj); - obj->m_isWorldObject = on; + { + grid.AddGridObject(obj); + RemoveWorldObject(obj); + } + obj->m_isTempWorldObject = on; } -template void Map::SwitchGridContainers(Creature*, bool); -//template void Map::SwitchGridContainers(DynamicObject*, bool); - template<class T> void Map::DeleteFromWorld(T* obj) { @@ -685,8 +689,7 @@ void Map::RemoveFromMap(T *obj, bool remove) } } -void -Map::PlayerRelocation(Player* player, float x, float y, float z, float orientation) +void Map::PlayerRelocation(Player* player, float x, float y, float z, float orientation) { ASSERT(player); @@ -710,8 +713,7 @@ Map::PlayerRelocation(Player* player, float x, float y, float z, float orientati player->UpdateObjectVisibility(false); } -void -Map::CreatureRelocation(Creature* creature, float x, float y, float z, float ang, bool respawnRelocationOnFail) +void Map::CreatureRelocation(Creature* creature, float x, float y, float z, float ang, bool respawnRelocationOnFail) { ASSERT(CheckGridIntegrity(creature, false)); @@ -910,8 +912,15 @@ bool Map::UnloadGrid(NGridType& ngrid, bool unloadAll) const uint32 y = ngrid.getY(); { - if (!unloadAll && ActiveObjectsNearGrid(ngrid)) - return false; + if (!unloadAll) + { + //pets, possessed creatures (must be active), transport passengers + if (ngrid.GetWorldObjectCountInNGrid<Creature>()) + return false; + + if (ActiveObjectsNearGrid(ngrid)) + return false; + } sLog->outDebug(LOG_FILTER_MAPS, "Unloading grid[%u, %u] for map %u", x, y, GetId()); @@ -1161,7 +1170,7 @@ bool GridMap::loadHeihgtData(FILE* in, uint32 offset, uint32 /*size*/) return true; } -bool GridMap::loadLiquidData(FILE* in, uint32 offset, uint32 /*size*/) +bool GridMap::loadLiquidData(FILE* in, uint32 offset, uint32 /*size*/) { map_liquidHeader header; fseek(in, offset, SEEK_SET); @@ -1203,12 +1212,12 @@ uint16 GridMap::getArea(float x, float y) return m_area_map[lx*16 + ly]; } -float GridMap::getHeightFromFlat(float /*x*/, float /*y*/) const +float GridMap::getHeightFromFlat(float /*x*/, float /*y*/) const { return m_gridHeight; } -float GridMap::getHeightFromFloat(float x, float y) const +float GridMap::getHeightFromFloat(float x, float y) const { if (!m_V8 || !m_V9) return m_gridHeight; @@ -1290,7 +1299,7 @@ float GridMap::getHeightFromFloat(float x, float y) const return a * x + b * y + c; } -float GridMap::getHeightFromUint8(float x, float y) const +float GridMap::getHeightFromUint8(float x, float y) const { if (!m_uint8_V8 || !m_uint8_V9) return m_gridHeight; @@ -1357,7 +1366,7 @@ float GridMap::getHeightFromUint8(float x, float y) const return (float)((a * x) + (b * y) + c)*m_gridIntHeightMultiplier + m_gridHeight; } -float GridMap::getHeightFromUint16(float x, float y) const +float GridMap::getHeightFromUint16(float x, float y) const { if (!m_uint16_V8 || !m_uint16_V9) return m_gridHeight; @@ -1424,7 +1433,7 @@ float GridMap::getHeightFromUint16(float x, float y) const return (float)((a * x) + (b * y) + c)*m_gridIntHeightMultiplier + m_gridHeight; } -float GridMap::getLiquidLevel(float x, float y) +float GridMap::getLiquidLevel(float x, float y) { if (!m_liquid_map) return m_liquidLevel; @@ -1443,7 +1452,7 @@ float GridMap::getLiquidLevel(float x, float y) return m_liquid_map[cx_int*m_liquid_width + cy_int]; } -uint8 GridMap::getTerrainType(float x, float y) +uint8 GridMap::getTerrainType(float x, float y) { if (!m_liquid_type) return 0; @@ -1530,41 +1539,28 @@ inline GridMap* Map::GetGrid(float x, float y) return GridMaps[gx][gy]; } -float Map::GetHeight(float x, float y, float z, bool pUseVmaps, float maxSearchDist) const +float Map::GetHeight(float x, float y, float z, bool checkVMap /*= true*/, float maxSearchDist /*= DEFAULT_HEIGHT_SEARCH*/) const { // find raw .map surface under Z coordinates - float mapHeight; + float mapHeight = VMAP_INVALID_HEIGHT_VALUE; if (GridMap* gmap = const_cast<Map*>(this)->GetGrid(x, y)) { - float _mapheight = gmap->getHeight(x, y); - + float gridHeight = gmap->getHeight(x, y); // look from a bit higher pos to find the floor, ignore under surface case - if (z + 2.0f > _mapheight) - mapHeight = _mapheight; - else - mapHeight = VMAP_INVALID_HEIGHT_VALUE; + if (z + 2.0f > gridHeight) + mapHeight = gridHeight; } - else - mapHeight = VMAP_INVALID_HEIGHT_VALUE; - float vmapHeight; - if (pUseVmaps) + float vmapHeight = VMAP_INVALID_HEIGHT_VALUE; + if (checkVMap) { VMAP::IVMapManager* vmgr = VMAP::VMapFactory::createOrGetVMapManager(); if (vmgr->isHeightCalcEnabled()) - { - // look from a bit higher pos to find the floor - vmapHeight = vmgr->getHeight(GetId(), x, y, z + 2.0f, maxSearchDist); - } - else - vmapHeight = VMAP_INVALID_HEIGHT_VALUE; + vmapHeight = vmgr->getHeight(GetId(), x, y, z + 2.0f, maxSearchDist); // look from a bit higher pos to find the floor } - else - vmapHeight = VMAP_INVALID_HEIGHT_VALUE; // mapHeight set for any above raw ground Z or <= INVALID_HEIGHT // vmapheight set for any under Z value or <= INVALID_HEIGHT - if (vmapHeight > INVALID_HEIGHT) { if (mapHeight > INVALID_HEIGHT) @@ -1581,15 +1577,8 @@ float Map::GetHeight(float x, float y, float z, bool pUseVmaps, float maxSearchD else return vmapHeight; // we have only vmapHeight (if have) } - else - { - if (!pUseVmaps) - return mapHeight; // explicitly use map data (if have) - else if (mapHeight > INVALID_HEIGHT && (z < mapHeight + 2 || z == MAX_HEIGHT)) - return mapHeight; // explicitly use map data if original z < mapHeight but map found (z+2 > mapHeight) - else - return VMAP_INVALID_HEIGHT_VALUE; // we not have any height - } + + return mapHeight; // explicitly use map data } inline bool IsOutdoorWMO(uint32 mogpFlags, int32 /*adtId*/, int32 /*rootId*/, int32 /*groupId*/, WMOAreaTableEntry const* wmoEntry, AreaTableEntry const* atEntry) @@ -1826,7 +1815,7 @@ bool Map::CheckGridIntegrity(Creature* c, bool moved) const return true; } -const char* Map::GetMapName() const +char const* Map::GetMapName() const { return i_mapEntry ? i_mapEntry->name[sWorld->GetDefaultDbcLocale()] : "UNNAMEDMAP\x0"; } @@ -1996,15 +1985,8 @@ void Map::RemoveAllObjectsInRemoveList() bool on = itr->second; i_objectsToSwitch.erase(itr); - switch (obj->GetTypeId()) - { - case TYPEID_UNIT: - if (!obj->ToCreature()->isPet()) - SwitchGridContainers(obj->ToCreature(), on); - break; - default: - break; - } + if (obj->GetTypeId() == TYPEID_UNIT && !obj->IsPermanentWorldObject()) + SwitchGridContainers(obj->ToCreature(), on); } //sLog->outDebug(LOG_FILTER_MAPS, "Object remover 1 check."); @@ -2340,6 +2322,13 @@ bool InstanceMap::AddPlayerToMap(Player* player) ASSERT(playerBind->save == mapSave); } } + + if (group && group->isLFGGroup()) + if (uint32 dungeonId = sLFGMgr->GetDungeon(group->GetGUID(), true)) + if (LFGDungeonEntry const* dungeon = sLFGDungeonStore.LookupEntry(dungeonId)) + if (LFGDungeonEntry const* randomDungeon = sLFGDungeonStore.LookupEntry(*(sLFGMgr->GetSelectedDungeons(player->GetGUID()).begin()))) + if (dungeon->map == GetId() && dungeon->difficulty == GetDifficulty() && randomDungeon->type == LFG_TYPE_RANDOM) + player->CastSpell(player, LFG_SPELL_LUCK_OF_THE_DRAW, true); } // for normal instances cancel the reset schedule when the @@ -2623,20 +2612,17 @@ void BattlegroundMap::RemoveAllPlayers() player->TeleportTo(player->GetBattlegroundEntryPoint()); } -Creature* -Map::GetCreature(uint64 guid) +Creature* Map::GetCreature(uint64 guid) { return ObjectAccessor::GetObjectInMap(guid, this, (Creature*)NULL); } -GameObject* -Map::GetGameObject(uint64 guid) +GameObject* Map::GetGameObject(uint64 guid) { return ObjectAccessor::GetObjectInMap(guid, this, (GameObject*)NULL); } -DynamicObject* -Map::GetDynamicObject(uint64 guid) +DynamicObject* Map::GetDynamicObject(uint64 guid) { return ObjectAccessor::GetObjectInMap(guid, this, (DynamicObject*)NULL); } diff --git a/src/server/game/Maps/Map.h b/src/server/game/Maps/Map.h index 5b652a2524a..542d9119830 100755 --- a/src/server/game/Maps/Map.h +++ b/src/server/game/Maps/Map.h @@ -296,7 +296,7 @@ class Map : public GridRefManager<NGridType> // some calls like isInWater should not use vmaps due to processor power // can return INVALID_HEIGHT if under z+2 z coord not found height - float GetHeight(float x, float y, float z, bool pCheckVMap=true, float maxSearchDist=DEFAULT_HEIGHT_SEARCH) const; + float GetHeight(float x, float y, float z, bool checkVMap = true, float maxSearchDist = DEFAULT_HEIGHT_SEARCH) const; ZLiquidStatus getLiquidStatus(float x, float y, float z, uint8 ReqLiquidType, LiquidData* data = 0) const; @@ -405,7 +405,7 @@ class Map : public GridRefManager<NGridType> void RemoveFromActive(Creature* obj); - template<class T> void SwitchGridContainers(T* obj, bool active); + void SwitchGridContainers(Creature* creature, bool toWorldContainer); template<class NOTIFIER> void VisitAll(const float &x, const float &y, float radius, NOTIFIER ¬ifier); template<class NOTIFIER> void VisitFirstFound(const float &x, const float &y, float radius, NOTIFIER ¬ifier); template<class NOTIFIER> void VisitWorld(const float &x, const float &y, float radius, NOTIFIER ¬ifier); diff --git a/src/server/game/Miscellaneous/Language.h b/src/server/game/Miscellaneous/Language.h index ffdf0131143..a5935e1de9f 100755 --- a/src/server/game/Miscellaneous/Language.h +++ b/src/server/game/Miscellaneous/Language.h @@ -42,8 +42,8 @@ enum TrinityStrings LANG_GMS_ON_SRV = 16, LANG_GMS_NOT_LOGGED = 17, LANG_YOU_IN_FLIGHT = 18, - //LANG_YOU_IN_BATTLEGROUND = 19, not used - //LANG_TARGET_IN_FLIGHT = 20, not used + LANG_UPDATE_DIFF = 19, + LANG_SHUTDOWN_TIMELEFT = 20, LANG_CHAR_IN_FLIGHT = 21, LANG_CHAR_NON_MOUNTED = 22, LANG_YOU_IN_COMBAT = 23, @@ -946,8 +946,9 @@ enum TrinityStrings LANG_GOINFO_NAME = 5027, LANG_GOINFO_LOOTID = 5028, LANG_COMMAND_LOOKUP_MAX_RESULTS = 5029, - // Room for more Trinity strings 5030-9999 LANG_FLEE = 5030, + LANG_NPCINFO_AIINFO = 5031, + // Room for more Trinity strings 5032-9999 // Level requirement notifications LANG_SAY_REQ = 6604, diff --git a/src/server/game/Miscellaneous/SharedDefines.h b/src/server/game/Miscellaneous/SharedDefines.h index a99d0f37c02..952df731c19 100755 --- a/src/server/game/Miscellaneous/SharedDefines.h +++ b/src/server/game/Miscellaneous/SharedDefines.h @@ -312,13 +312,13 @@ enum SpellAttr1 SPELL_ATTR1_MELEE_COMBAT_START = 0x00000200, // 9 player starts melee combat after this spell is cast SPELL_ATTR1_NO_THREAT = 0x00000400, // 10 no generates threat on cast 100% (old NO_INITIAL_AGGRO) SPELL_ATTR1_UNK11 = 0x00000800, // 11 aura - SPELL_ATTR1_UNK12 = 0x00001000, // 12 + SPELL_ATTR1_UNK12 = 0x00001000, // 12 pickpoket SPELL_ATTR1_FARSIGHT = 0x00002000, // 13 Client removes farsight on aura loss SPELL_ATTR1_CHANNEL_TRACK_TARGET = 0x00004000, // 14 Client automatically forces player to face target when channeling SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY = 0x00008000, // 15 remove auras on immunity SPELL_ATTR1_UNAFFECTED_BY_SCHOOL_IMMUNE = 0x00010000, // 16 on immuniy SPELL_ATTR1_UNAUTOCASTABLE_BY_PET = 0x00020000, // 17 - SPELL_ATTR1_UNK18 = 0x00040000, // 18 + SPELL_ATTR1_UNK18 = 0x00040000, // 18 stun, polymorph, daze, hex SPELL_ATTR1_CANT_TARGET_SELF = 0x00080000, // 19 SPELL_ATTR1_REQ_COMBO_POINTS1 = 0x00100000, // 20 Req combo points on target SPELL_ATTR1_UNK21 = 0x00200000, // 21 @@ -327,17 +327,17 @@ enum SpellAttr1 SPELL_ATTR1_UNK24 = 0x01000000, // 24 only fishing spells SPELL_ATTR1_UNK25 = 0x02000000, // 25 SPELL_ATTR1_UNK26 = 0x04000000, // 26 works correctly with [target=focus] and [target=mouseover] macros? - SPELL_ATTR1_UNK27 = 0x08000000, // 27 + SPELL_ATTR1_UNK27 = 0x08000000, // 27 melee spell? SPELL_ATTR1_DONT_DISPLAY_IN_AURA_BAR = 0x10000000, // 28 client doesn't display these spells in aura bar SPELL_ATTR1_CHANNEL_DISPLAY_SPELL_NAME = 0x20000000, // 29 spell name is displayed in cast bar instead of 'channeling' text - SPELL_ATTR1_ENABLE_AT_DODGE = 0x40000000, // 30 Overpower, Wolverine Bite + SPELL_ATTR1_ENABLE_AT_DODGE = 0x40000000, // 30 Overpower SPELL_ATTR1_UNK31 = 0x80000000 // 31 }; enum SpellAttr2 { SPELL_ATTR2_CAN_TARGET_DEAD = 0x00000001, // 0 can target dead unit or corpse - SPELL_ATTR2_UNK1 = 0x00000002, // 1 ? many triggered spells have this flag + SPELL_ATTR2_UNK1 = 0x00000002, // 1 vanish, shadowform, Ghost Wolf and other SPELL_ATTR2_CAN_TARGET_NOT_IN_LOS = 0x00000004, // 2 26368 4.0.1 dbc change SPELL_ATTR2_UNK3 = 0x00000008, // 3 SPELL_ATTR2_DISPLAY_IN_STANCE_BAR = 0x00000010, // 4 client displays icon in stance bar when learned, even if not shapeshift @@ -346,9 +346,9 @@ enum SpellAttr2 SPELL_ATTR2_UNK7 = 0x00000080, // 7 SPELL_ATTR2_UNK8 = 0x00000100, // 8 not set in 3.0.3 SPELL_ATTR2_UNK9 = 0x00000200, // 9 - SPELL_ATTR2_UNK10 = 0x00000400, // 10 + SPELL_ATTR2_UNK10 = 0x00000400, // 10 related to tame SPELL_ATTR2_HEALTH_FUNNEL = 0x00000800, // 11 - SPELL_ATTR2_UNK12 = 0x00001000, // 12 + SPELL_ATTR2_UNK12 = 0x00001000, // 12 Cleave, Heart Strike, Maul, Sunder Armor, Swipe SPELL_ATTR2_UNK13 = 0x00002000, // 13 Items enchanted by spells with this flag preserve the enchant to arenas SPELL_ATTR2_UNK14 = 0x00004000, // 14 SPELL_ATTR2_UNK15 = 0x00008000, // 15 not set in 3.0.3 @@ -358,13 +358,13 @@ enum SpellAttr2 SPELL_ATTR2_NOT_NEED_SHAPESHIFT = 0x00080000, // 19 does not necessarly need shapeshift SPELL_ATTR2_UNK20 = 0x00100000, // 20 SPELL_ATTR2_DAMAGE_REDUCED_SHIELD = 0x00200000, // 21 for ice blocks, pala immunity buffs, priest absorb shields, but used also for other spells -> not sure! - SPELL_ATTR2_UNK22 = 0x00400000, // 22 + SPELL_ATTR2_UNK22 = 0x00400000, // 22 Ambush, Backstab, Cheap Shot, Death Grip, Garrote, Judgements, Mutilate, Pounce, Ravage, Shiv, Shred SPELL_ATTR2_UNK23 = 0x00800000, // 23 Only mage Arcane Concentration have this flag SPELL_ATTR2_UNK24 = 0x01000000, // 24 SPELL_ATTR2_UNK25 = 0x02000000, // 25 SPELL_ATTR2_UNK26 = 0x04000000, // 26 unaffected by school immunity SPELL_ATTR2_UNK27 = 0x08000000, // 27 - SPELL_ATTR2_UNK28 = 0x10000000, // 28 no breaks stealth if it fails?? + SPELL_ATTR2_UNK28 = 0x10000000, // 28 SPELL_ATTR2_CANT_CRIT = 0x20000000, // 29 Spell can't crit SPELL_ATTR2_TRIGGERED_CAN_TRIGGER_PROC = 0x40000000, // 30 spell can trigger even if triggered SPELL_ATTR2_FOOD_BUFF = 0x80000000 // 31 Food or Drink Buff (like Well Fed) @@ -393,7 +393,7 @@ enum SpellAttr3 SPELL_ATTR3_IGNORE_HIT_RESULT = 0x00040000, // 18 Spell should always hit its target SPELL_ATTR3_DISABLE_PROC = 0x00080000, // 19 during aura proc no spells can trigger (20178, 20375) SPELL_ATTR3_DEATH_PERSISTENT = 0x00100000, // 20 Death persistent spells - SPELL_ATTR3_UNK21 = 0x00200000, // 21 + SPELL_ATTR3_UNK21 = 0x00200000, // 21 unused SPELL_ATTR3_REQ_WAND = 0x00400000, // 22 Req wand SPELL_ATTR3_UNK23 = 0x00800000, // 23 SPELL_ATTR3_REQ_OFFHAND = 0x01000000, // 24 Req offhand weapon @@ -417,7 +417,7 @@ enum SpellAttr4 SPELL_ATTR4_NOT_STEALABLE = 0x00000040, // 6 although such auras might be dispellable, they cannot be stolen SPELL_ATTR4_TRIGGERED = 0x00000080, // 7 spells forced to be triggered SPELL_ATTR4_UNK8 = 0x00000100, // 8 ignores taken percent damage mods? - SPELL_ATTR4_UNK9 = 0x00000200, // 9 + SPELL_ATTR4_TRIGGER_ACTIVATE = 0x00000200, // 9 initially disabled / trigger activate from event (Execute, Riposte, Deep Freeze end other) SPELL_ATTR4_SPELL_VS_EXTEND_COST = 0x00000400, // 10 Rogue Shiv have this flag SPELL_ATTR4_UNK11 = 0x00000800, // 11 SPELL_ATTR4_UNK12 = 0x00001000, // 12 @@ -427,16 +427,16 @@ enum SpellAttr4 SPELL_ATTR4_NOT_USABLE_IN_ARENA = 0x00010000, // 16 SPELL_ATTR4_USABLE_IN_ARENA = 0x00020000, // 17 SPELL_ATTR4_AREA_TARGET_CHAIN = 0x00040000, // 18 (NYI)hits area targets one after another instead of all at once - SPELL_ATTR4_UNK19 = 0x00080000, // 19 + SPELL_ATTR4_UNK19 = 0x00080000, // 19 proc dalayed, after damage or don't proc on absorb? SPELL_ATTR4_NOT_CHECK_SELFCAST_POWER = 0x00100000, // 20 supersedes message "More powerful spell applied" for self casts. - SPELL_ATTR4_UNK21 = 0x00200000, // 21 + SPELL_ATTR4_UNK21 = 0x00200000, // 21 Pally aura, dk presence, dudu form, warrior stance, shadowform, hunter track SPELL_ATTR4_UNK22 = 0x00400000, // 22 SPELL_ATTR4_UNK23 = 0x00800000, // 23 - SPELL_ATTR4_UNK24 = 0x01000000, // 24 + SPELL_ATTR4_UNK24 = 0x01000000, // 24 some shoot spell SPELL_ATTR4_UNK25 = 0x02000000, // 25 pet scaling auras SPELL_ATTR4_CAST_ONLY_IN_OUTLAND = 0x04000000, // 26 Can only be used in Outland. SPELL_ATTR4_UNK27 = 0x08000000, // 27 - SPELL_ATTR4_UNK28 = 0x10000000, // 28 + SPELL_ATTR4_UNK28 = 0x10000000, // 28 Aimed Shot SPELL_ATTR4_UNK29 = 0x20000000, // 29 SPELL_ATTR4_UNK30 = 0x40000000, // 30 SPELL_ATTR4_UNK31 = 0x80000000 // 31 @@ -456,7 +456,7 @@ enum SpellAttr5 SPELL_ATTR5_START_PERIODIC_AT_APPLY = 0x00000200, // 9 begin periodic tick at aura apply SPELL_ATTR5_HIDE_DURATION = 0x00000400, // 10 do not send duration to client SPELL_ATTR5_ALLOW_TARGET_OF_TARGET_AS_TARGET = 0x00000800, // 11 (NYI) uses target's target as target if original target not valid (intervene for example) - SPELL_ATTR5_UNK12 = 0x00001000, // 12 + SPELL_ATTR5_UNK12 = 0x00001000, // 12 Cleave related? SPELL_ATTR5_HASTE_AFFECT_DURATION = 0x00002000, // 13 haste effects decrease duration of this SPELL_ATTR5_UNK14 = 0x00004000, // 14 SPELL_ATTR5_UNK15 = 0x00008000, // 15 @@ -470,7 +470,7 @@ enum SpellAttr5 SPELL_ATTR5_UNK23 = 0x00800000, // 23 SPELL_ATTR5_UNK24 = 0x01000000, // 24 SPELL_ATTR5_UNK25 = 0x02000000, // 25 - SPELL_ATTR5_UNK26 = 0x04000000, // 26 + SPELL_ATTR5_UNK26 = 0x04000000, // 26 aoe related - Boulder, Cannon, Corpse Explosion, Fire Nova, Flames, Frost Bomb, Living Bomb, Seed of Corruption, Starfall, Thunder Clap, Volley SPELL_ATTR5_UNK27 = 0x08000000, // 27 SPELL_ATTR5_UNK28 = 0x10000000, // 28 SPELL_ATTR5_UNK29 = 0x20000000, // 29 @@ -495,23 +495,23 @@ enum SpellAttr6 SPELL_ATTR6_CASTABLE_WHILE_ON_VEHICLE = 0x00001000, // 12 castable while caster is on vehicle SPELL_ATTR6_CAN_TARGET_INVISIBLE = 0x00002000, // 13 ignore visibility requirement for spell target (phases, invisibility, etc.) SPELL_ATTR6_UNK14 = 0x00004000, // 14 - SPELL_ATTR6_UNK15 = 0x00008000, // 15 not set in 3.0.3 + SPELL_ATTR6_UNK15 = 0x00008000, // 15 only 54368, 67892 SPELL_ATTR6_UNK16 = 0x00010000, // 16 - SPELL_ATTR6_UNK17 = 0x00020000, // 17 + SPELL_ATTR6_UNK17 = 0x00020000, // 17 Mount spell SPELL_ATTR6_CAST_BY_CHARMER = 0x00040000, // 18 client won't allow to cast these spells when unit is not possessed && charmer of caster will be original caster - SPELL_ATTR6_UNK19 = 0x00080000, // 19 - SPELL_ATTR6_UNK20 = 0x00100000, // 20 + SPELL_ATTR6_UNK19 = 0x00080000, // 19 only 47488, 50782 + SPELL_ATTR6_UNK20 = 0x00100000, // 20 only 58371, 62218 SPELL_ATTR6_CLIENT_UI_TARGET_EFFECTS = 0x00200000, // 21 it's only client-side attribute - SPELL_ATTR6_UNK22 = 0x00400000, // 22 + SPELL_ATTR6_UNK22 = 0x00400000, // 22 only 72054 SPELL_ATTR6_UNK23 = 0x00800000, // 23 SPELL_ATTR6_CAN_TARGET_UNTARGETABLE = 0x01000000, // 24 - SPELL_ATTR6_UNK25 = 0x02000000, // 25 - SPELL_ATTR6_UNK26 = 0x04000000, // 26 + SPELL_ATTR6_UNK25 = 0x02000000, // 25 Exorcism, Flash of Light + SPELL_ATTR6_UNK26 = 0x04000000, // 26 related to player castable positive buff SPELL_ATTR6_UNK27 = 0x08000000, // 27 - SPELL_ATTR6_UNK28 = 0x10000000, // 28 + SPELL_ATTR6_UNK28 = 0x10000000, // 28 Death Grip SPELL_ATTR6_NO_DONE_PCT_DAMAGE_MODS = 0x20000000, // 29 ignores done percent damage mods? SPELL_ATTR6_UNK30 = 0x40000000, // 30 - SPELL_ATTR6_UNK31 = 0x80000000 // 31 some special cooldown calc? + SPELL_ATTR6_UNK31 = 0x80000000 // 31 some special cooldown calc? only 2894 }; enum SpellAttr7 @@ -520,7 +520,7 @@ enum SpellAttr7 SPELL_ATTR7_UNK1 = 0x00000002, // 1 Not set in 3.2.2a. SPELL_ATTR7_REACTIVATE_AT_RESURRECT = 0x00000004, // 2 Paladin's auras and 65607 only. SPELL_ATTR7_IS_CHEAT_SPELL = 0x00000008, // 3 Cannot cast if caster doesn't have UnitFlag2 & UNIT_FLAG2_ALLOW_CHEAT_SPELLS - SPELL_ATTR7_UNK4 = 0x00000010, // 4 Only 66109 test spell. + SPELL_ATTR7_UNK4 = 0x00000010, // 4 Only 47883 (Soulstone Resurrection) and test spell. SPELL_ATTR7_SUMMON_PLAYER_TOTEM = 0x00000020, // 5 Only Shaman player totems. SPELL_ATTR7_UNK6 = 0x00000040, // 6 Dark Surge, Surge of Light, Burning Breath triggers (boss spells). SPELL_ATTR7_UNK7 = 0x00000080, // 7 66218 (Launch) spell. @@ -536,18 +536,18 @@ enum SpellAttr7 SPELL_ATTR7_UNK17 = 0x00020000, // 17 Only 27965 (Suicide) spell. SPELL_ATTR7_HAS_CHARGE_EFFECT = 0x00040000, // 18 Only spells that have Charge among effects. SPELL_ATTR7_ZONE_TELEPORT = 0x00080000, // 19 Teleports to specific zones. - SPELL_ATTR7_UNK20 = 0x00100000, // 20 - SPELL_ATTR7_UNK21 = 0x00200000, // 21 + SPELL_ATTR7_UNK20 = 0x00100000, // 20 Blink, Divine Shield, Ice Block + SPELL_ATTR7_UNK21 = 0x00200000, // 21 Not set SPELL_ATTR7_UNK22 = 0x00400000, // 22 - SPELL_ATTR7_UNK23 = 0x00800000, // 23 - SPELL_ATTR7_UNK24 = 0x01000000, // 24 + SPELL_ATTR7_UNK23 = 0x00800000, // 23 Motivate, Mutilate, Shattering Throw + SPELL_ATTR7_UNK24 = 0x01000000, // 24 Motivate, Mutilate, Perform Speech, Shattering Throw SPELL_ATTR7_UNK25 = 0x02000000, // 25 SPELL_ATTR7_UNK26 = 0x04000000, // 26 - SPELL_ATTR7_UNK27 = 0x08000000, // 27 - SPELL_ATTR7_UNK28 = 0x10000000, // 28 - SPELL_ATTR7_UNK29 = 0x20000000, // 29 - SPELL_ATTR7_UNK30 = 0x40000000, // 30 - SPELL_ATTR7_UNK31 = 0x80000000 // 31 + SPELL_ATTR7_UNK27 = 0x08000000, // 27 Not set + SPELL_ATTR7_UNK28 = 0x10000000, // 28 related to player positive buff + SPELL_ATTR7_UNK29 = 0x20000000, // 29 only 69028, 71237 + SPELL_ATTR7_UNK30 = 0x40000000, // 30 Burning Determination, Divine Sacrifice, Earth Shield, Prayer of Mending + SPELL_ATTR7_UNK31 = 0x80000000 // 31 only 70769 }; #define MIN_TALENT_SPEC 0 diff --git a/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.cpp index 5bd0a23207e..09af2303397 100755 --- a/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.cpp @@ -47,11 +47,10 @@ template<> void RandomMovementGenerator<Creature>::_setRandomLocation(Creature &creature) { - float X, Y, Z, z, nx, ny, nz, ori, dist; + float X, Y, Z, nx, ny, nz, ori, dist; creature.GetHomePosition(X, Y, Z, ori); - z = creature.GetPositionZ(); Map const* map = creature.GetBaseMap(); // For 2D/3D system selection diff --git a/src/server/game/Server/Protocol/Handlers/AuctionHouseHandler.cpp b/src/server/game/Server/Protocol/Handlers/AuctionHouseHandler.cpp index 2f8a27740be..1710a387307 100755 --- a/src/server/game/Server/Protocol/Handlers/AuctionHouseHandler.cpp +++ b/src/server/game/Server/Protocol/Handlers/AuctionHouseHandler.cpp @@ -115,6 +115,8 @@ void WorldSession::SendAuctionOwnerNotification(AuctionEntry* auction) //this void creates new auction and adds auction to some auctionhouse void WorldSession::HandleAuctionSellItem(WorldPacket & recv_data) { + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_AUCTION_SELL_ITEM"); + uint64 auctioneer, item; uint32 etime, bid, buyout, count; recv_data >> auctioneer; @@ -253,6 +255,8 @@ void WorldSession::HandleAuctionSellItem(WorldPacket & recv_data) //this function is called when client bids or buys out auction void WorldSession::HandleAuctionPlaceBid(WorldPacket & recv_data) { + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_AUCTION_PLACE_BID"); + uint64 auctioneer; uint32 auctionId; uint32 price; @@ -374,6 +378,8 @@ void WorldSession::HandleAuctionPlaceBid(WorldPacket & recv_data) //this void is called when auction_owner cancels his auction void WorldSession::HandleAuctionRemoveItem(WorldPacket & recv_data) { + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_AUCTION_REMOVE_ITEM"); + uint64 auctioneer; uint32 auctionId; recv_data >> auctioneer; @@ -452,6 +458,8 @@ void WorldSession::HandleAuctionRemoveItem(WorldPacket & recv_data) //called when player lists his bids void WorldSession::HandleAuctionListBidderItems(WorldPacket & recv_data) { + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_AUCTION_LIST_BIDDER_ITEMS"); + uint64 guid; //NPC guid uint32 listfrom; //page of auctions uint32 outbiddedCount; //count of outbidded auctions @@ -469,6 +477,7 @@ void WorldSession::HandleAuctionListBidderItems(WorldPacket & recv_data) if (!creature) { sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: HandleAuctionListBidderItems - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid))); + recv_data.rfinish(); return; } @@ -506,6 +515,8 @@ void WorldSession::HandleAuctionListBidderItems(WorldPacket & recv_data) //this void sends player info about his auctions void WorldSession::HandleAuctionListOwnerItems(WorldPacket & recv_data) { + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_AUCTION_LIST_OWNER_ITEMS"); + uint32 listfrom; uint64 guid; @@ -541,6 +552,8 @@ void WorldSession::HandleAuctionListOwnerItems(WorldPacket & recv_data) //this void is called when player clicks on search button void WorldSession::HandleAuctionListItems(WorldPacket & recv_data) { + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_AUCTION_LIST_ITEMS"); + std::string searchedname; uint8 levelmin, levelmax, usable; uint32 listfrom, auctionSlotID, auctionMainCategory, auctionSubCategory, quality; @@ -606,7 +619,7 @@ void WorldSession::HandleAuctionListItems(WorldPacket & recv_data) void WorldSession::HandleAuctionListPendingSales(WorldPacket & recv_data) { - sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_AUCTION_LIST_PENDING_SALES"); + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_AUCTION_LIST_PENDING_SALES"); recv_data.read_skip<uint64>(); diff --git a/src/server/game/Server/Protocol/Handlers/CharacterHandler.cpp b/src/server/game/Server/Protocol/Handlers/CharacterHandler.cpp index 83b9ab048ad..2a4e1c50ac5 100755 --- a/src/server/game/Server/Protocol/Handlers/CharacterHandler.cpp +++ b/src/server/game/Server/Protocol/Handlers/CharacterHandler.cpp @@ -196,7 +196,7 @@ bool LoginQueryHolder::Initialize() return res; } -void WorldSession::HandleCharEnum(QueryResult result) +void WorldSession::HandleCharEnum(PreparedQueryResult result) { WorldPacket data(SMSG_CHAR_ENUM, 100); // we guess size @@ -232,35 +232,16 @@ void WorldSession::HandleCharEnumOpcode(WorldPacket & /*recv_data*/) CharacterDatabase.Execute(stmt); /// get all the data necessary for loading all characters (along with their pets) on the account - _charEnumCallback = - CharacterDatabase.AsyncPQuery( - !sWorld->getBoolConfig(CONFIG_DECLINED_NAMES_USED) ? - // ------- Query Without Declined Names -------- - // 0 1 2 3 4 5 6 7 - "SELECT characters.guid, characters.name, characters.race, characters.class, characters.gender, characters.playerBytes, characters.playerBytes2, characters.level, " - // 8 9 10 11 12 13 14 - "characters.zone, characters.map, characters.position_x, characters.position_y, characters.position_z, guild_member.guildid, characters.playerFlags, " - // 15 16 17 18 19 20 - "characters.at_login, character_pet.entry, character_pet.modelid, character_pet.level, characters.equipmentCache, character_banned.guid " - "FROM characters LEFT JOIN character_pet ON characters.guid=character_pet.owner AND character_pet.slot='%u' " - "LEFT JOIN guild_member ON characters.guid = guild_member.guid " - "LEFT JOIN character_banned ON characters.guid = character_banned.guid AND character_banned.active = 1 " - "WHERE characters.account = '%u' ORDER BY characters.guid" - : - // --------- Query With Declined Names --------- - // 0 1 2 3 4 5 6 7 - "SELECT characters.guid, characters.name, characters.race, characters.class, characters.gender, characters.playerBytes, characters.playerBytes2, characters.level, " - // 8 9 10 11 12 13 14 - "characters.zone, characters.map, characters.position_x, characters.position_y, characters.position_z, guild_member.guildid, characters.playerFlags, " - // 15 16 17 18 19 20 21 - "characters.at_login, character_pet.entry, character_pet.modelid, character_pet.level, characters.equipmentCache, character_banned.guid, character_declinedname.genitive " - "FROM characters LEFT JOIN character_pet ON characters.guid = character_pet.owner AND character_pet.slot='%u' " - "LEFT JOIN character_declinedname ON characters.guid = character_declinedname.guid " - "LEFT JOIN guild_member ON characters.guid = guild_member.guid " - "LEFT JOIN character_banned ON characters.guid = character_banned.guid AND character_banned.active = 1 " - "WHERE characters.account = '%u' ORDER BY characters.guid", - PET_SAVE_AS_CURRENT, GetAccountId() - ); + + if (sWorld->getBoolConfig(CONFIG_DECLINED_NAMES_USED)) + stmt = CharacterDatabase.GetPreparedStatement(CHAR_GET_ENUM_DECLINED_NAME); + else + stmt = CharacterDatabase.GetPreparedStatement(CHAR_GET_ENUM); + + stmt->setUInt8(0, PET_SAVE_AS_CURRENT); + stmt->setUInt32(1, GetAccountId()); + + _charEnumCallback = CharacterDatabase.AsyncQuery(stmt); } void WorldSession::HandleCharCreateOpcode(WorldPacket & recv_data) @@ -413,7 +394,7 @@ void WorldSession::HandleCharCreateCallback(PreparedQueryResult result, Characte This is much more efficient than synchronous requests on packet handler, and much less DoS prone. It also prevents data syncrhonisation errors. */ - switch (createInfo->Stage) + switch (_charCreateCallback.GetStage()) { case 0: { @@ -423,8 +404,7 @@ void WorldSession::HandleCharCreateCallback(PreparedQueryResult result, Characte data << uint8(CHAR_CREATE_NAME_IN_USE); SendPacket(&data); delete createInfo; - _charCreateCallback.SetParam(NULL); - _charCreateCallback.FreeResult(); + _charCreateCallback.Reset(); return; } @@ -435,8 +415,7 @@ void WorldSession::HandleCharCreateCallback(PreparedQueryResult result, Characte _charCreateCallback.FreeResult(); _charCreateCallback.SetFutureResult(LoginDatabase.AsyncQuery(stmt)); - - createInfo->Stage++; + _charCreateCallback.NextStage(); } break; case 1: @@ -457,8 +436,7 @@ void WorldSession::HandleCharCreateCallback(PreparedQueryResult result, Characte data << uint8(CHAR_CREATE_ACCOUNT_LIMIT); SendPacket(&data); delete createInfo; - _charCreateCallback.SetParam(NULL); - _charCreateCallback.FreeResult(); + _charCreateCallback.Reset(); return; } @@ -470,8 +448,7 @@ void WorldSession::HandleCharCreateCallback(PreparedQueryResult result, Characte _charCreateCallback.FreeResult(); _charCreateCallback.SetFutureResult(CharacterDatabase.AsyncQuery(stmt)); - - createInfo->Stage++; + _charCreateCallback.NextStage(); } break; case 2: @@ -487,8 +464,7 @@ void WorldSession::HandleCharCreateCallback(PreparedQueryResult result, Characte data << uint8(CHAR_CREATE_SERVER_LIMIT); SendPacket(&data); delete createInfo; - _charCreateCallback.SetParam(NULL); - _charCreateCallback.FreeResult(); + _charCreateCallback.Reset(); return; } } @@ -504,11 +480,11 @@ void WorldSession::HandleCharCreateCallback(PreparedQueryResult result, Characte stmt->setUInt32(0, GetAccountId()); stmt->setUInt32(1, (skipCinematics == 1 || createInfo->Class == CLASS_DEATH_KNIGHT) ? 10 : 1); _charCreateCallback.SetFutureResult(CharacterDatabase.AsyncQuery(stmt)); - createInfo->Stage++; + _charCreateCallback.NextStage(); return; } - createInfo->Stage++; + _charCreateCallback.NextStage(); HandleCharCreateCallback(PreparedQueryResult(NULL), createInfo); // Will jump to case 3 } break; @@ -542,8 +518,7 @@ void WorldSession::HandleCharCreateCallback(PreparedQueryResult result, Characte data << uint8(CHAR_CREATE_UNIQUE_CLASS_LIMIT); SendPacket(&data); delete createInfo; - _charCreateCallback.SetParam(NULL); - _charCreateCallback.FreeResult(); + _charCreateCallback.Reset(); return; } } @@ -570,8 +545,7 @@ void WorldSession::HandleCharCreateCallback(PreparedQueryResult result, Characte data << uint8(CHAR_CREATE_PVP_TEAMS_VIOLATION); SendPacket(&data); delete createInfo; - _charCreateCallback.SetParam(NULL); - _charCreateCallback.FreeResult(); + _charCreateCallback.Reset(); return; } } @@ -603,8 +577,7 @@ void WorldSession::HandleCharCreateCallback(PreparedQueryResult result, Characte data << uint8(CHAR_CREATE_UNIQUE_CLASS_LIMIT); SendPacket(&data); delete createInfo; - _charCreateCallback.SetParam(NULL); - _charCreateCallback.FreeResult(); + _charCreateCallback.Reset(); return; } } @@ -625,8 +598,7 @@ void WorldSession::HandleCharCreateCallback(PreparedQueryResult result, Characte data << uint8(CHAR_CREATE_LEVEL_REQUIREMENT); SendPacket(&data); delete createInfo; - _charCreateCallback.SetParam(NULL); - _charCreateCallback.FreeResult(); + _charCreateCallback.Reset(); return; } @@ -647,8 +619,7 @@ void WorldSession::HandleCharCreateCallback(PreparedQueryResult result, Characte data << uint8(CHAR_CREATE_ERROR); SendPacket(&data); delete createInfo; - _charCreateCallback.SetParam(NULL); - _charCreateCallback.FreeResult(); + _charCreateCallback.Reset(); return; } @@ -689,8 +660,7 @@ void WorldSession::HandleCharCreateCallback(PreparedQueryResult result, Characte sWorld->AddCharacterNameData(newChar.GetGUIDLow(), std::string(newChar.GetName()), newChar.getGender(), newChar.getRace(), newChar.getClass()); delete createInfo; - _charCreateCallback.SetParam(NULL); - _charCreateCallback.FreeResult(); + _charCreateCallback.Reset(); } break; } @@ -791,7 +761,7 @@ void WorldSession::HandlePlayerLoginOpcode(WorldPacket & recv_data) _charLoginCallback = CharacterDatabase.DelayQueryHolder((SQLQueryHolder*)holder); } -void WorldSession::HandlePlayerLogin(LoginQueryHolder * holder) +void WorldSession::HandlePlayerLogin(LoginQueryHolder* holder) { uint64 playerGuid = holder->GetGuid(); @@ -997,7 +967,7 @@ void WorldSession::HandlePlayerLogin(LoginQueryHolder * holder) pCurrChar->RemoveAtLoginFlag(AT_LOGIN_FIRST); // show time before shutdown if shutdown planned. - if (sWorld->IsShutdowning()) + if (sWorld->IsShuttingDown()) sWorld->ShutdownMsg(true, pCurrChar); if (sWorld->getBoolConfig(CONFIG_ALL_TAXI_PATHS)) @@ -1085,28 +1055,30 @@ void WorldSession::HandleSetFactionInactiveOpcode(WorldPacket & recv_data) _player->GetReputationMgr().SetInactive(replistid, inactive); } -void WorldSession::HandleShowingHelmOpcode(WorldPacket & /*recv_data*/) +void WorldSession::HandleShowingHelmOpcode(WorldPacket& recv_data) { sLog->outStaticDebug("CMSG_SHOWING_HELM for %s", _player->GetName()); + recv_data.read_skip<uint8>(); // unknown, bool? _player->ToggleFlag(PLAYER_FLAGS, PLAYER_FLAGS_HIDE_HELM); } -void WorldSession::HandleShowingCloakOpcode(WorldPacket & /*recv_data*/) +void WorldSession::HandleShowingCloakOpcode(WorldPacket& recv_data) { sLog->outStaticDebug("CMSG_SHOWING_CLOAK for %s", _player->GetName()); + recv_data.read_skip<uint8>(); // unknown, bool? _player->ToggleFlag(PLAYER_FLAGS, PLAYER_FLAGS_HIDE_CLOAK); } void WorldSession::HandleCharRenameOpcode(WorldPacket& recv_data) { uint64 guid; - std::string newname; + std::string newName; recv_data >> guid; - recv_data >> newname; + recv_data >> newName; // prevent character rename to invalid name - if (!normalizePlayerName(newname)) + if (!normalizePlayerName(newName)) { WorldPacket data(SMSG_CHAR_RENAME, 1); data << uint8(CHAR_NAME_NO_NAME); @@ -1114,7 +1086,7 @@ void WorldSession::HandleCharRenameOpcode(WorldPacket& recv_data) return; } - uint8 res = ObjectMgr::CheckPlayerName(newname, true); + uint8 res = ObjectMgr::CheckPlayerName(newName, true); if (res != CHAR_NAME_SUCCESS) { WorldPacket data(SMSG_CHAR_RENAME, 1); @@ -1124,7 +1096,7 @@ void WorldSession::HandleCharRenameOpcode(WorldPacket& recv_data) } // check name limitations - if (AccountMgr::IsPlayerAccount(GetSecurity()) && sObjectMgr->IsReservedName(newname)) + if (AccountMgr::IsPlayerAccount(GetSecurity()) && sObjectMgr->IsReservedName(newName)) { WorldPacket data(SMSG_CHAR_RENAME, 1); data << uint8(CHAR_NAME_RESERVED); @@ -1132,21 +1104,22 @@ void WorldSession::HandleCharRenameOpcode(WorldPacket& recv_data) return; } - std::string escaped_newname = newname; - CharacterDatabase.EscapeString(escaped_newname); - - // make sure that the character belongs to the current account, that rename at login is enabled + // Ensure that the character belongs to the current account, that rename at login is enabled // and that there is no character with the desired new name - _charRenameCallback.SetParam(newname); - _charRenameCallback.SetFutureResult( - CharacterDatabase.AsyncPQuery( - "SELECT guid, name FROM characters WHERE guid = %d AND account = %d AND (at_login & %d) = %d AND NOT EXISTS (SELECT NULL FROM characters WHERE name = '%s')", - GUID_LOPART(guid), GetAccountId(), AT_LOGIN_RENAME, AT_LOGIN_RENAME, escaped_newname.c_str() - ) - ); + _charRenameCallback.SetParam(newName); + + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_GET_FREE_NAME); + + stmt->setUInt32(0, GUID_LOPART(guid)); + stmt->setUInt32(1, GetAccountId()); + stmt->setUInt16(2, AT_LOGIN_RENAME); + stmt->setUInt16(3, AT_LOGIN_RENAME); + stmt->setString(4, newName); + + _charRenameCallback.SetFutureResult(CharacterDatabase.AsyncQuery(stmt)); } -void WorldSession::HandleChangePlayerNameOpcodeCallBack(QueryResult result, std::string newname) +void WorldSession::HandleChangePlayerNameOpcodeCallBack(PreparedQueryResult result, std::string newName) { if (!result) { @@ -1156,22 +1129,38 @@ void WorldSession::HandleChangePlayerNameOpcodeCallBack(QueryResult result, std: return; } - uint32 guidLow = result->Fetch()[0].GetUInt32(); + Field* fields = result->Fetch(); + + uint32 guidLow = fields[0].GetUInt32(); + std::string oldName = fields[1].GetString(); + uint64 guid = MAKE_NEW_GUID(guidLow, 0, HIGHGUID_PLAYER); - std::string oldname = result->Fetch()[1].GetString(); - CharacterDatabase.PExecute("UPDATE characters set name = '%s', at_login = at_login & ~ %u WHERE guid ='%u'", newname.c_str(), uint32(AT_LOGIN_RENAME), guidLow); - CharacterDatabase.PExecute("DELETE FROM character_declinedname WHERE guid ='%u'", guidLow); + // Update name and at_login flag in the db + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPDATE_NAME); + + stmt->setString(0, newName); + stmt->setUInt16(1, AT_LOGIN_RENAME); + stmt->setUInt32(2, guidLow); - sLog->outChar("Account: %d (IP: %s) Character:[%s] (guid:%u) Changed name to: %s", GetAccountId(), GetRemoteAddress().c_str(), oldname.c_str(), guidLow, newname.c_str()); + CharacterDatabase.Execute(stmt); + + // Removed declined name from db + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_DECLINED_NAME); - WorldPacket data(SMSG_CHAR_RENAME, 1+8+(newname.size()+1)); + stmt->setUInt32(0, guidLow); + + CharacterDatabase.Execute(stmt); + + sLog->outChar("Account: %d (IP: %s) Character:[%s] (guid:%u) Changed name to: %s", GetAccountId(), GetRemoteAddress().c_str(), oldName.c_str(), guidLow, newName.c_str()); + + WorldPacket data(SMSG_CHAR_RENAME, 1+8+(newName.size()+1)); data << uint8(RESPONSE_SUCCESS); data << uint64(guid); - data << newname; + data << newName; SendPacket(&data); - sWorld->UpdateCharacterNameData(guidLow, newname); + sWorld->UpdateCharacterNameData(guidLow, newName); } void WorldSession::HandleSetPlayerDeclinedNames(WorldPacket& recv_data) diff --git a/src/server/game/Server/Protocol/Handlers/CombatHandler.cpp b/src/server/game/Server/Protocol/Handlers/CombatHandler.cpp index 31a09e830ff..e6c4499baab 100755 --- a/src/server/game/Server/Protocol/Handlers/CombatHandler.cpp +++ b/src/server/game/Server/Protocol/Handlers/CombatHandler.cpp @@ -23,13 +23,15 @@ #include "ObjectAccessor.h" #include "CreatureAI.h" #include "ObjectDefines.h" +#include "Vehicle.h" +#include "VehicleDefines.h" -void WorldSession::HandleAttackSwingOpcode(WorldPacket & recv_data) +void WorldSession::HandleAttackSwingOpcode(WorldPacket& recv_data) { uint64 guid; recv_data >> guid; - sLog->outStaticDebug("WORLD: Recvd CMSG_ATTACKSWING Message guidlow:%u guidhigh:%u", GUID_LOPART(guid), GUID_HIPART(guid)); + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Recvd CMSG_ATTACKSWING Message guidlow:%u guidhigh:%u", GUID_LOPART(guid), GUID_HIPART(guid)); Unit* pEnemy = ObjectAccessor::GetUnit(*_player, guid); @@ -47,6 +49,20 @@ void WorldSession::HandleAttackSwingOpcode(WorldPacket & recv_data) return; } + //! Client explicitly checks the following before sending CMSG_ATTACKSWING packet, + //! so we'll place the same check here. Note that it might be possible to reuse this snippet + //! in other places as well. + if (Vehicle* vehicle = _player->GetVehicle()) + { + VehicleSeatEntry const* seat = vehicle->GetSeatForPassenger(_player); + ASSERT(seat); + if (!(seat->m_flags & VEHICLE_SEAT_FLAG_CAN_ATTACK)) + { + SendAttackStop(pEnemy); + return; + } + } + _player->Attack(pEnemy, true); } @@ -55,7 +71,7 @@ void WorldSession::HandleAttackStopOpcode(WorldPacket & /*recv_data*/) GetPlayer()->AttackStop(); } -void WorldSession::HandleSetSheathedOpcode(WorldPacket & recv_data) +void WorldSession::HandleSetSheathedOpcode(WorldPacket& recv_data) { uint32 sheathed; recv_data >> sheathed; @@ -79,4 +95,3 @@ void WorldSession::SendAttackStop(Unit const* enemy) data << uint32(0); // unk, can be 1 also SendPacket(&data); } - diff --git a/src/server/game/Server/Protocol/Handlers/ItemHandler.cpp b/src/server/game/Server/Protocol/Handlers/ItemHandler.cpp index f4e3af72892..4d323996de7 100755 --- a/src/server/game/Server/Protocol/Handlers/ItemHandler.cpp +++ b/src/server/game/Server/Protocol/Handlers/ItemHandler.cpp @@ -938,6 +938,7 @@ void WorldSession::HandleAutoBankItemOpcode(WorldPacket& recvPacket) } _player->RemoveItem(srcbag, srcslot, true); + _player->ItemRemovedQuestCheck(pItem->GetEntry(), pItem->GetCount()); _player->BankItem(dest, pItem, true); } @@ -965,6 +966,7 @@ void WorldSession::HandleAutoStoreBankItemOpcode(WorldPacket& recvPacket) _player->RemoveItem(srcbag, srcslot, true); _player->StoreItem(dest, pItem, true); + _player->ItemAddedQuestCheck(pItem->GetEntry(), pItem->GetCount()); } else // moving from inventory to bank { diff --git a/src/server/game/Server/Protocol/Handlers/MiscHandler.cpp b/src/server/game/Server/Protocol/Handlers/MiscHandler.cpp index 7327cdbba65..aef3bf03bd9 100755 --- a/src/server/game/Server/Protocol/Handlers/MiscHandler.cpp +++ b/src/server/game/Server/Protocol/Handlers/MiscHandler.cpp @@ -531,24 +531,23 @@ void WorldSession::HandleAddFriendOpcode(WorldPacket & recv_data) if (!normalizePlayerName(friendName)) return; - CharacterDatabase.EscapeString(friendName); // prevent SQL injection - normal name must not be changed by this call + sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: %s asked to add friend : '%s'", GetPlayer()->GetName(), friendName.c_str()); - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: %s asked to add friend : '%s'", - GetPlayer()->GetName(), friendName.c_str()); + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_GET_GUID_RACE_ACC_BY_NAME); + + stmt->setString(0, friendName); _addFriendCallback.SetParam(friendNote); - _addFriendCallback.SetFutureResult( - CharacterDatabase.AsyncPQuery("SELECT guid, race, account FROM characters WHERE name = '%s'", friendName.c_str()) - ); + _addFriendCallback.SetFutureResult(CharacterDatabase.AsyncQuery(stmt)); } -void WorldSession::HandleAddFriendOpcodeCallBack(QueryResult result, std::string friendNote) +void WorldSession::HandleAddFriendOpcodeCallBack(PreparedQueryResult result, std::string friendNote) { if (!GetPlayer()) return; uint64 friendGuid; - uint32 friendAcctid; + uint32 friendAccountId; uint32 team; FriendsResult friendResult; @@ -557,11 +556,13 @@ void WorldSession::HandleAddFriendOpcodeCallBack(QueryResult result, std::string if (result) { - friendGuid = MAKE_NEW_GUID((*result)[0].GetUInt32(), 0, HIGHGUID_PLAYER); - team = Player::TeamForRace((*result)[1].GetUInt8()); - friendAcctid = (*result)[2].GetUInt32(); + Field* fields = result->Fetch(); + + friendGuid = MAKE_NEW_GUID(fields[0].GetUInt32(), 0, HIGHGUID_PLAYER); + team = Player::TeamForRace(fields[1].GetUInt8()); + friendAccountId = fields[2].GetUInt32(); - if (!AccountMgr::IsPlayerAccount(GetSecurity()) || sWorld->getBoolConfig(CONFIG_ALLOW_GM_FRIEND) || AccountMgr::IsPlayerAccount(AccountMgr::GetSecurity(friendAcctid, realmID))) + if (!AccountMgr::IsPlayerAccount(GetSecurity()) || sWorld->getBoolConfig(CONFIG_ALLOW_GM_FRIEND) || AccountMgr::IsPlayerAccount(AccountMgr::GetSecurity(friendAccountId, realmID))) { if (friendGuid) { @@ -613,22 +614,24 @@ void WorldSession::HandleAddIgnoreOpcode(WorldPacket & recv_data) { sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_ADD_IGNORE"); - std::string IgnoreName = GetTrinityString(LANG_FRIEND_IGNORE_UNKNOWN); + std::string ignoreName = GetTrinityString(LANG_FRIEND_IGNORE_UNKNOWN); - recv_data >> IgnoreName; + recv_data >> ignoreName; - if (!normalizePlayerName(IgnoreName)) + if (!normalizePlayerName(ignoreName)) return; - CharacterDatabase.EscapeString(IgnoreName); // prevent SQL injection - normal name must not be changed by this call - sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: %s asked to Ignore: '%s'", - GetPlayer()->GetName(), IgnoreName.c_str()); + GetPlayer()->GetName(), ignoreName.c_str()); + + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_GET_GUID_BY_NAME); + + stmt->setString(0, ignoreName); - _addIgnoreCallback = CharacterDatabase.AsyncPQuery("SELECT guid FROM characters WHERE name = '%s'", IgnoreName.c_str()); + _addIgnoreCallback = CharacterDatabase.AsyncQuery(stmt); } -void WorldSession::HandleAddIgnoreOpcodeCallBack(QueryResult result) +void WorldSession::HandleAddIgnoreOpcodeCallBack(PreparedQueryResult result) { if (!GetPlayer()) return; @@ -1607,7 +1610,7 @@ void WorldSession::HandleCancelMountAuraOpcode(WorldPacket & /*recv_data*/) return; } - _player->Unmount(); + _player->Dismount(); _player->RemoveAurasByType(SPELL_AURA_MOUNTED); } diff --git a/src/server/game/Server/Protocol/Handlers/MovementHandler.cpp b/src/server/game/Server/Protocol/Handlers/MovementHandler.cpp index 4e45eb2d6c6..ae2612e4ced 100755 --- a/src/server/game/Server/Protocol/Handlers/MovementHandler.cpp +++ b/src/server/game/Server/Protocol/Handlers/MovementHandler.cpp @@ -299,7 +299,7 @@ void WorldSession::HandleMovementOpcodes(WorldPacket & recv_data) // if we boarded a transport, add us to it if (plMover && !plMover->GetTransport()) { - // elevators also cause the client to send MOVEMENTFLAG_ONTRANSPORT - just unmount if the guid can be found in the transport list + // elevators also cause the client to send MOVEMENTFLAG_ONTRANSPORT - just dismount if the guid can be found in the transport list for (MapManager::TransportSet::const_iterator iter = sMapMgr->m_Transports.begin(); iter != sMapMgr->m_Transports.end(); ++iter) { if ((*iter)->GetGUID() == movementInfo.t_guid) diff --git a/src/server/game/Server/Protocol/Handlers/NPCHandler.cpp b/src/server/game/Server/Protocol/Handlers/NPCHandler.cpp index a675214930a..92f4a0380f9 100755 --- a/src/server/game/Server/Protocol/Handlers/NPCHandler.cpp +++ b/src/server/game/Server/Protocol/Handlers/NPCHandler.cpp @@ -618,39 +618,43 @@ void WorldSession::HandleStablePet(WorldPacket & recv_data) return; } - _stablePetCallback = CharacterDatabase.AsyncPQuery("SELECT owner, slot, id FROM character_pet WHERE owner = '%u' AND slot >= '%u' AND slot <= '%u' ORDER BY slot ", - _player->GetGUIDLow(), PET_SAVE_FIRST_STABLE_SLOT, PET_SAVE_LAST_STABLE_SLOT); + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_GET_PET_SLOTS); + stmt->setUInt32(0, _player->GetGUIDLow()); + stmt->setUInt8(1, PET_SAVE_FIRST_STABLE_SLOT); + stmt->setUInt8(2, PET_SAVE_LAST_STABLE_SLOT); + + _stablePetCallback = CharacterDatabase.AsyncQuery(stmt); } -void WorldSession::HandleStablePetCallback(QueryResult result) +void WorldSession::HandleStablePetCallback(PreparedQueryResult result) { if (!GetPlayer()) return; - uint32 free_slot = 1; + uint8 freeSlot = 1; if (result) { do { Field* fields = result->Fetch(); - uint32 slot = fields[1].GetUInt32(); + uint8 slot = fields[1].GetUInt8(); // slots ordered in query, and if not equal then free - if (slot != free_slot) + if (slot != freeSlot) break; // this slot not free, skip - ++free_slot; + ++freeSlot; } while (result->NextRow()); } WorldPacket data(SMSG_STABLE_RESULT, 1); - if (free_slot > 0 && free_slot <= GetPlayer()->m_stableSlots) + if (freeSlot > 0 && freeSlot <= GetPlayer()->m_stableSlots) { - _player->RemovePet(_player->GetPet(), PetSaveMode(free_slot)); + _player->RemovePet(_player->GetPet(), PetSaveMode(freeSlot)); SendStableResult(STABLE_SUCCESS_STABLE); } else @@ -801,7 +805,7 @@ void WorldSession::HandleStableSwapPet(WorldPacket & recv_data) // find swapped pet slot in stable _stableSwapCallback.SetParam(pet_number); _stableSwapCallback.SetFutureResult( - CharacterDatabase.PQuery("SELECT slot, entry FROM character_pet WHERE owner = '%u' AND id = '%u'", + CharacterDatabase.AsyncPQuery("SELECT slot, entry FROM character_pet WHERE owner = '%u' AND id = '%u'", _player->GetGUIDLow(), pet_number) ); } @@ -878,19 +882,18 @@ void WorldSession::HandleRepairItemOpcode(WorldPacket & recv_data) // reputation discount float discountMod = _player->GetReputationPriceDiscount(unit); - uint32 TotalCost = 0; if (itemGUID) { sLog->outDebug(LOG_FILTER_NETWORKIO, "ITEM: Repair item, itemGUID = %u, npcGUID = %u", GUID_LOPART(itemGUID), GUID_LOPART(npcGUID)); Item* item = _player->GetItemByGuid(itemGUID); if (item) - TotalCost = _player->DurabilityRepair(item->GetPos(), true, discountMod, guildBank); + _player->DurabilityRepair(item->GetPos(), true, discountMod, guildBank); } else { sLog->outDebug(LOG_FILTER_NETWORKIO, "ITEM: Repair all items, npcGUID = %u", GUID_LOPART(npcGUID)); - TotalCost = _player->DurabilityRepairAll(true, discountMod, guildBank); + _player->DurabilityRepairAll(true, discountMod, guildBank); } } diff --git a/src/server/game/Server/Protocol/Handlers/PetitionsHandler.cpp b/src/server/game/Server/Protocol/Handlers/PetitionsHandler.cpp index a931d8a5b3d..2e9b88bd3f0 100755 --- a/src/server/game/Server/Protocol/Handlers/PetitionsHandler.cpp +++ b/src/server/game/Server/Protocol/Handlers/PetitionsHandler.cpp @@ -311,21 +311,17 @@ void WorldSession::SendPetitionQueryOpcode(uint64 petitionguid) uint64 ownerguid = 0; uint32 type; std::string name = "NO_NAME_FOR_GUID"; - uint8 signs = 0; - QueryResult result = CharacterDatabase.PQuery( - "SELECT ownerguid, name, " - " (SELECT COUNT(playerguid) FROM petition_sign WHERE petition_sign.petitionguid = '%u') AS signs, " - " type " - "FROM petition WHERE petitionguid = '%u'", GUID_LOPART(petitionguid), GUID_LOPART(petitionguid)); + // TODO: Use CHAR_LOAD_PETITION PS + QueryResult result = CharacterDatabase.PQuery("SELECT ownerguid, name, type " + "FROM petition WHERE petitionguid = '%u'", GUID_LOPART(petitionguid)); if (result) { Field* fields = result->Fetch(); ownerguid = MAKE_NEW_GUID(fields[0].GetUInt32(), 0, HIGHGUID_PLAYER); name = fields[1].GetString(); - signs = fields[2].GetUInt8(); - type = fields[3].GetUInt32(); + type = fields[2].GetUInt32(); } else { diff --git a/src/server/game/Server/Protocol/Handlers/QueryHandler.cpp b/src/server/game/Server/Protocol/Handlers/QueryHandler.cpp index bf951619e63..042b1242a95 100755 --- a/src/server/game/Server/Protocol/Handlers/QueryHandler.cpp +++ b/src/server/game/Server/Protocol/Handlers/QueryHandler.cpp @@ -413,7 +413,10 @@ void WorldSession::HandleQuestPOIQuery(WorldPacket& recv_data) recv_data >> count; // quest count, max=25 if (count >= MAX_QUEST_LOG_SIZE) + { + recv_data.rfinish(); return; + } WorldPacket data(SMSG_QUEST_POI_QUERY_RESPONSE, 4+(4+4)*count); data << uint32(count); // count diff --git a/src/server/game/Server/WorldSession.cpp b/src/server/game/Server/WorldSession.cpp index 14c86286718..54d477abf69 100755 --- a/src/server/game/Server/WorldSession.cpp +++ b/src/server/game/Server/WorldSession.cpp @@ -222,7 +222,18 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater) ///- Retrieve packets from the receive queue and call the appropriate handlers /// not process packets if socket already closed WorldPacket* packet = NULL; - while (m_Socket && !m_Socket->IsClosed() && _recvQueue.next(packet, updater)) + //! Delete packet after processing by default + bool deletePacket = true; + //! To prevent infinite loop + WorldPacket* firstDelayedPacket = NULL; + //! If _recvQueue.peek() == firstDelayedPacket it means that in this Update call, we've processed all + //! *properly timed* packets, and we're now at the part of the queue where we find + //! delayed packets that were re-enqueued due to improper timing. To prevent an infinite + //! loop caused by re-enqueueing the same packets over and over again, we stop updating this session + //! and continue updating others. The re-enqueued packets will be handled in the next Update call for this session. + while (m_Socket && !m_Socket->IsClosed() && + !_recvQueue.empty() && _recvQueue.peek(true) != firstDelayedPacket && + _recvQueue.next(packet, updater)) { if (packet->GetOpcode() >= NUM_MSG_TYPES) { @@ -240,8 +251,21 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater) if (!_player) { // skip STATUS_LOGGEDIN opcode unexpected errors if player logout sometime ago - this can be network lag delayed packets + //! If player didn't log out a while ago, it means packets are being sent while the server does not recognize + //! the client to be in world yet. We will re-add the packets to the bottom of the queue and process them later. if (!m_playerRecentlyLogout) - LogUnexpectedOpcode(packet, "STATUS_LOGGEDIN", "the player has not logged in yet"); + { + //! Prevent infinite loop + if (!firstDelayedPacket) + firstDelayedPacket = packet; + //! Because checking a bool is faster than reallocating memory + deletePacket = false; + QueuePacket(packet); + //! Log + sLog->outDebug(LOG_FILTER_NETWORKIO, "Re-enqueueing packet with opcode %s (0x%.4X) with with status STATUS_LOGGEDIN. " + "Player is currently not in world yet.", opHandle.name, packet->GetOpcode()); + } + } else if (_player->IsInWorld()) { @@ -258,7 +282,7 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater) "the player has not logged in yet and not recently logout"); else { - // not expected _player or must checked in packet hanlder + // not expected _player or must checked in packet handler sScriptMgr->OnPacketReceive(m_Socket, WorldPacket(*packet)); (this->*opHandle.handler)(*packet); if (sLog->IsOutDebug() && packet->rpos() < packet->wpos()) @@ -308,7 +332,7 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater) break; } } - catch(ByteBufferException &) + catch (ByteBufferException &) { sLog->outError("WorldSession::Update ByteBufferException occured while parsing a packet (opcode: %u) from client %s, accountid=%i. Skipped packet.", packet->GetOpcode(), GetRemoteAddress().c_str(), GetAccountId()); @@ -320,7 +344,8 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater) } } - delete packet; + if (deletePacket) + delete packet; } ProcessQueryCallbacks(); @@ -344,6 +369,7 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater) if (!m_Socket) return false; //Will remove this session from the world session map } + return true; } @@ -983,12 +1009,13 @@ void WorldSession::InitializeQueryCallbackParameters() void WorldSession::ProcessQueryCallbacks() { QueryResult result; + PreparedQueryResult result2; //! HandleCharEnumOpcode if (_charEnumCallback.ready()) { - _charEnumCallback.get(result); - HandleCharEnum(result); + _charEnumCallback.get(result2); + HandleCharEnum(result2); _charEnumCallback.cancel(); } @@ -1013,8 +1040,8 @@ void WorldSession::ProcessQueryCallbacks() if (_addFriendCallback.IsReady()) { std::string param = _addFriendCallback.GetParam(); - _addFriendCallback.GetResult(result); - HandleAddFriendOpcodeCallBack(result, param); + _addFriendCallback.GetResult(result2); + HandleAddFriendOpcodeCallBack(result2, param); _addFriendCallback.FreeResult(); } @@ -1022,16 +1049,16 @@ void WorldSession::ProcessQueryCallbacks() if (_charRenameCallback.IsReady()) { std::string param = _charRenameCallback.GetParam(); - _charRenameCallback.GetResult(result); - HandleChangePlayerNameOpcodeCallBack(result, param); + _charRenameCallback.GetResult(result2); + HandleChangePlayerNameOpcodeCallBack(result2, param); _charRenameCallback.FreeResult(); } //- HandleCharAddIgnoreOpcode if (_addIgnoreCallback.ready()) { - _addIgnoreCallback.get(result); - HandleAddIgnoreOpcodeCallBack(result); + _addIgnoreCallback.get(result2); + HandleAddIgnoreOpcodeCallBack(result2); _addIgnoreCallback.cancel(); } @@ -1047,8 +1074,8 @@ void WorldSession::ProcessQueryCallbacks() //- HandleStablePet if (_stablePetCallback.ready()) { - _stablePetCallback.get(result); - HandleStablePetCallback(result); + _stablePetCallback.get(result2); + HandleStablePetCallback(result2); _stablePetCallback.cancel(); } diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h index 4a83c2d4092..d1f607704b9 100755 --- a/src/server/game/Server/WorldSession.h +++ b/src/server/game/Server/WorldSession.h @@ -184,7 +184,7 @@ class CharacterCreateInfo protected: CharacterCreateInfo(std::string name, uint8 race, uint8 cclass, uint8 gender, uint8 skin, uint8 face, uint8 hairStyle, uint8 hairColor, uint8 facialHair, uint8 outfitId, WorldPacket& data) : Name(name), Race(race), Class(cclass), Gender(gender), Skin(skin), Face(face), HairStyle(hairStyle), HairColor(hairColor), FacialHair(facialHair), - OutfitId(outfitId), Data(data), CharCount(0), Stage(0) + OutfitId(outfitId), Data(data), CharCount(0) {} /// User specified variables @@ -203,9 +203,6 @@ class CharacterCreateInfo /// Server side data uint8 CharCount; - /// Internal - uint8 Stage; // Stage of the callback chain - private: virtual ~CharacterCreateInfo(){}; }; @@ -400,7 +397,7 @@ class WorldSession void HandleCharCreateOpcode(WorldPacket& recvPacket); void HandleCharCreateCallback(PreparedQueryResult result, CharacterCreateInfo* createInfo); void HandlePlayerLoginOpcode(WorldPacket& recvPacket); - void HandleCharEnum(QueryResult result); + void HandleCharEnum(PreparedQueryResult result); void HandlePlayerLogin(LoginQueryHolder * holder); void HandleCharFactionOrRaceChange(WorldPacket& recv_data); @@ -469,10 +466,10 @@ class WorldSession void HandleEmoteOpcode(WorldPacket& recvPacket); void HandleContactListOpcode(WorldPacket& recvPacket); void HandleAddFriendOpcode(WorldPacket& recvPacket); - void HandleAddFriendOpcodeCallBack(QueryResult result, std::string friendNote); + void HandleAddFriendOpcodeCallBack(PreparedQueryResult result, std::string friendNote); void HandleDelFriendOpcode(WorldPacket& recvPacket); void HandleAddIgnoreOpcode(WorldPacket& recvPacket); - void HandleAddIgnoreOpcodeCallBack(QueryResult result); + void HandleAddIgnoreOpcodeCallBack(PreparedQueryResult result); void HandleDelIgnoreOpcode(WorldPacket& recvPacket); void HandleSetContactNotesOpcode(WorldPacket& recvPacket); void HandleBugOpcode(WorldPacket& recvPacket); @@ -588,7 +585,7 @@ class WorldSession void HandleBinderActivateOpcode(WorldPacket& recvPacket); void HandleListStabledPetsOpcode(WorldPacket& recvPacket); void HandleStablePet(WorldPacket& recvPacket); - void HandleStablePetCallback(QueryResult result); + void HandleStablePetCallback(PreparedQueryResult result); void HandleUnstablePet(WorldPacket& recvPacket); void HandleUnstablePetCallback(QueryResult result, uint32 petnumber); void HandleBuyStableSlot(WorldPacket& recvPacket); @@ -747,7 +744,7 @@ class WorldSession void HandleSetActionBarToggles(WorldPacket& recv_data); void HandleCharRenameOpcode(WorldPacket& recv_data); - void HandleChangePlayerNameOpcodeCallBack(QueryResult result, std::string newname); + void HandleChangePlayerNameOpcodeCallBack(PreparedQueryResult result, std::string newName); void HandleSetPlayerDeclinedNames(WorldPacket& recv_data); void HandleTotemDestroyed(WorldPacket& recv_data); @@ -896,16 +893,15 @@ class WorldSession void InitializeQueryCallbackParameters(); void ProcessQueryCallbacks(); - ACE_Future_Set<QueryResult> _nameQueryCallbacks; - QueryResultFuture _charEnumCallback; - QueryResultFuture _addIgnoreCallback; - QueryResultFuture _stablePetCallback; - QueryCallback<QueryResult, std::string> _charRenameCallback; - QueryCallback<QueryResult, std::string> _addFriendCallback; + PreparedQueryResultFuture _charEnumCallback; + PreparedQueryResultFuture _addIgnoreCallback; + PreparedQueryResultFuture _stablePetCallback; + QueryCallback<PreparedQueryResult, std::string> _charRenameCallback; + QueryCallback<PreparedQueryResult, std::string> _addFriendCallback; QueryCallback<QueryResult, uint32> _unstablePetCallback; QueryCallback<QueryResult, uint32> _stableSwapCallback; QueryCallback<QueryResult, uint64> _sendStabledPetCallback; - QueryCallback<PreparedQueryResult, CharacterCreateInfo*> _charCreateCallback; + QueryCallback<PreparedQueryResult, CharacterCreateInfo*, true> _charCreateCallback; QueryResultHolderFuture _charLoginCallback; private: diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp index b690a811fbb..12c40c15db4 100755 --- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp +++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp @@ -1518,7 +1518,7 @@ void AuraEffect::HandleShapeshiftBoosts(Unit* target, bool apply) const spellId3 = 47180; break; } - target->CastSpell(target, spellId, true, NULL, this); + target->CastSpell(target, spellId3, true, NULL, this); } // Master Shapeshifter - Cat if (AuraEffect const* aurEff = target->GetDummyAuraEffect(SPELLFAMILY_GENERIC, 2851, 0)) @@ -2821,7 +2821,7 @@ void AuraEffect::HandleAuraMounted(AuraApplication const* aurApp, uint8 mode, bo } else { - target->Unmount(); + target->Dismount(); //some mounts like Headless Horseman's Mount or broom stick are skill based spell // need to remove ALL arura related to mounts, this will stop client crash with broom stick // and never endless flying after using Headless Horseman's Mount @@ -4794,18 +4794,22 @@ void AuraEffect::HandleAuraDummy(AuraApplication const* aurApp, uint8 mode, bool break; case 63322: // Saronite Vapors { - int32 mana = int32(GetAmount() * pow(2.0f, GetBase()->GetStackAmount())); // mana restore - bp * 2^stackamount - int32 damage = mana * 2; // damage - caster->CastCustomSpell(target, 63337, &mana, NULL, NULL, true); - caster->CastCustomSpell(target, 63338, &damage, NULL, NULL, true); + if (caster) + { + int32 mana = int32(GetAmount() * pow(2.0f, GetBase()->GetStackAmount())); // mana restore - bp * 2^stackamount + int32 damage = mana * 2; // damage + caster->CastCustomSpell(target, 63337, &mana, NULL, NULL, true); + caster->CastCustomSpell(target, 63338, &damage, NULL, NULL, true); + } break; } case 71563: if (Aura* newAura = target->AddAura(71564, target)) newAura->SetStackAmount(newAura->GetSpellInfo()->StackAmount); break; - case 59628: // Tricks of the Trade - target->SetReducedThreatPercent(100,caster->GetGUID()); + case 59628: // Tricks of the Trade + if (caster && caster->GetMisdirectionTarget()) + target->SetReducedThreatPercent(100, caster->GetMisdirectionTarget()->GetGUID()); break; } } @@ -4958,9 +4962,14 @@ void AuraEffect::HandleAuraDummy(AuraApplication const* aurApp, uint8 mode, bool // Tricks of the trade switch(GetId()) { - case 59628: - case 57934: + case 59628: //Tricks of the trade buff on rogue (6sec duration) target->SetReducedThreatPercent(0,0); + break; + case 57934: //Tricks of the trade buff on rogue (30sec duration) + if (aurApp->GetRemoveMode() == AURA_REMOVE_BY_EXPIRE || !caster->GetMisdirectionTarget()) + target->SetReducedThreatPercent(0,0); + else + target->SetReducedThreatPercent(0,caster->GetMisdirectionTarget()->GetGUID()); break; } default: @@ -5201,7 +5210,7 @@ void AuraEffect::HandleAuraDummy(AuraApplication const* aurApp, uint8 mode, bool if (!(mode & AURA_EFFECT_HANDLE_REAL)) break; // Sentry Totem - if (GetId() == 6495 && caster->GetTypeId() == TYPEID_PLAYER) + if (GetId() == 6495 && caster && caster->GetTypeId() == TYPEID_PLAYER) { if (apply) { diff --git a/src/server/game/Spells/Auras/SpellAuras.cpp b/src/server/game/Spells/Auras/SpellAuras.cpp index 525084a70ed..91ecc328fd8 100755 --- a/src/server/game/Spells/Auras/SpellAuras.cpp +++ b/src/server/game/Spells/Auras/SpellAuras.cpp @@ -1332,6 +1332,7 @@ void Aura::HandleAuraSpecificMods(AuraApplication const* aurApp, Unit* caster, b if (removeMode != AURA_REMOVE_BY_EXPIRE) break; target->CastSpell(target, 32612, true, NULL, GetEffect(1)); + target->CombatStop(); break; case 74396: // Fingers of Frost // Remove the IGNORE_AURASTATE aura diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index 8a4c0a768d8..fbb1a1965d8 100755 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -3254,6 +3254,12 @@ void Spell::handle_immediate() m_caster->AddInterruptMask(m_spellInfo->ChannelInterruptFlags); SendChannelStart(duration); } + else if (duration == -1) + { + m_spellState = SPELL_STATE_CASTING; + m_caster->AddInterruptMask(m_spellInfo->ChannelInterruptFlags); + SendChannelStart(duration); + } } PrepareTargetProcessing(); @@ -3279,7 +3285,6 @@ void Spell::handle_immediate() if (m_spellInfo->IsRangedWeaponSpell() && m_spellInfo->IsChanneled()) TakeAmmo(); - if (m_spellState != SPELL_STATE_CASTING) finish(true); // successfully finish spell cast (not last in case autorepeat or channel spell) } @@ -3478,9 +3483,9 @@ void Spell::update(uint32 difftime) { case SPELL_STATE_PREPARING: { - if (m_timer) + if (m_timer > 0) { - if (difftime >= m_timer) + if (difftime >= (uint32)m_timer) m_timer = 0; else m_timer -= difftime; @@ -3489,10 +3494,11 @@ void Spell::update(uint32 difftime) if (m_timer == 0 && !IsNextMeleeSwingSpell() && !IsAutoRepeat()) // don't CheckCast for instant spells - done in spell::prepare, skip duplicate checks, needed for range checks for example cast(!m_casttime); - } break; + break; + } case SPELL_STATE_CASTING: { - if (m_timer > 0) + if (m_timer) { // check if there are alive targets left if (!UpdateChanneledTargetList()) @@ -3502,10 +3508,13 @@ void Spell::update(uint32 difftime) finish(); } - if (difftime >= m_timer) - m_timer = 0; - else - m_timer -= difftime; + if (m_timer > 0) + { + if (difftime >= (uint32)m_timer) + m_timer = 0; + else + m_timer -= difftime; + } } if (m_timer == 0) @@ -3547,10 +3556,10 @@ void Spell::update(uint32 difftime) finish(); } - } break; + break; + } default: - { - }break; + break; } } @@ -3666,9 +3675,9 @@ void Spell::SendCastResult(Player* caster, SpellInfo const* spellInfo, uint8 cas switch (result) { case SPELL_FAILED_REQUIRES_SPELL_FOCUS: - data << uint32(spellInfo->RequiresSpellFocus); + data << uint32(spellInfo->RequiresSpellFocus); // SpellFocusObject.dbc id break; - case SPELL_FAILED_REQUIRES_AREA: + case SPELL_FAILED_REQUIRES_AREA: // AreaTable.dbc id // hardcode areas limitation case switch (spellInfo->Id) { @@ -3701,14 +3710,15 @@ void Spell::SendCastResult(Player* caster, SpellInfo const* spellInfo, uint8 cas data << uint32(spellInfo->TotemCategory[1]); break; case SPELL_FAILED_EQUIPPED_ITEM_CLASS: + case SPELL_FAILED_EQUIPPED_ITEM_CLASS_MAINHAND: + case SPELL_FAILED_EQUIPPED_ITEM_CLASS_OFFHAND: data << uint32(spellInfo->EquippedItemClass); data << uint32(spellInfo->EquippedItemSubClassMask); - //data << uint32(spellInfo->EquippedItemInventoryTypeMask); break; case SPELL_FAILED_TOO_MANY_OF_ITEM: { uint32 item = 0; - for (int8 x = 0;x < 3; x++) + for (int8 x = 0; x < 3; x++) if (spellInfo->Effects[x].ItemType) item = spellInfo->Effects[x].ItemType; ItemTemplate const* pProto = sObjectMgr->GetItemTemplate(item); @@ -3757,7 +3767,7 @@ void Spell::SendSpellStart() data << uint8(m_cast_count); // pending spell cast? data << uint32(m_spellInfo->Id); // spellId data << uint32(castFlags); // cast flags - data << uint32(m_timer); // delay? + data << int32(m_timer); // delay? m_targets.Write(data); @@ -3856,7 +3866,7 @@ void Spell::SendSpellGo() } } - if (castFlags & CAST_FLAG_UNKNOWN_18) // unknown wotlk + if (castFlags & CAST_FLAG_UNKNOWN_18) { data << float(0); data << uint32(0); @@ -3865,7 +3875,7 @@ void Spell::SendSpellGo() if (castFlags & CAST_FLAG_AMMO) WriteAmmoToPacket(&data); - if (castFlags & CAST_FLAG_UNKNOWN_20) // unknown wotlk + if (castFlags & CAST_FLAG_UNKNOWN_20) { data << uint32(0); data << uint32(0); @@ -4126,9 +4136,6 @@ void Spell::SendChannelUpdate(uint32 time) m_caster->SetUInt32Value(UNIT_CHANNEL_SPELL, 0); } - if (m_caster->GetTypeId() != TYPEID_PLAYER) - return; - WorldPacket data(MSG_CHANNEL_UPDATE, 8+4); data.append(m_caster->GetPackGUID()); data << uint32(time); @@ -5646,7 +5653,8 @@ SpellCastResult Spell::CheckRange(bool strict) if (m_spellInfo->RangeEntry) { - // self cast is used for triggered spells, no range checking needed + // check needed by 68766 51693 - both spells are cast on enemies and have 0 max range + // these are triggered by other spells - possibly we should omit range check in that case? if (m_spellInfo->RangeEntry->ID == 1) return SPELL_CAST_OK; @@ -6263,7 +6271,7 @@ void Spell::Delayed() // only called in DealDamage() AddPctN(delaytime, -delayReduce); - if (int32(m_timer) + delaytime > m_casttime) + if (m_timer + delaytime > m_casttime) { delaytime = m_casttime - m_timer; m_timer = m_casttime; @@ -6298,7 +6306,7 @@ void Spell::DelayedChannel() AddPctN(delaytime, -delayReduce); - if (int32(m_timer) <= delaytime) + if (m_timer <= delaytime) { delaytime = m_timer; m_timer = 0; diff --git a/src/server/game/Spells/Spell.h b/src/server/game/Spells/Spell.h index 624c3b9b9b3..f57b3114a70 100755 --- a/src/server/game/Spells/Spell.h +++ b/src/server/game/Spells/Spell.h @@ -647,7 +647,7 @@ class Spell // ------------------------------------------- uint32 m_spellState; - uint32 m_timer; + int32 m_timer; TriggerCastFlags _triggeredCastFlags; diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index e42294f59ae..95917070b5d 100755 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -606,57 +606,67 @@ void Spell::EffectSchoolDMG(SpellEffIndex effIndex) case SPELLFAMILY_ROGUE: { // Envenom - if (m_caster->GetTypeId() == TYPEID_PLAYER && (m_spellInfo->SpellFamilyFlags[1] & 0x8)) + if (m_spellInfo->SpellFamilyFlags[1] & 0x00000008) { - // consume from stack dozes not more that have combo-points - if (uint32 combo = m_caster->ToPlayer()->GetComboPoints()) + if (Player* player = m_caster->ToPlayer()) { - // Lookup for Deadly poison (only attacker applied) - if (AuraEffect const* aurEff = unitTarget->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_ROGUE, 0x10000, 0, 0, m_caster->GetGUID())) + // consume from stack dozes not more that have combo-points + if (uint32 combo = player->GetComboPoints()) { - // count consumed deadly poison doses at target - bool needConsume = true; - uint32 spellId = aurEff->GetId(); - uint32 doses = aurEff->GetBase()->GetStackAmount(); - if (doses > combo) - doses = combo; - // Master Poisoner - Unit::AuraEffectList const& auraList = m_caster->ToPlayer()->GetAuraEffectsByType(SPELL_AURA_MOD_AURA_DURATION_BY_DISPEL_NOT_STACK); - for (Unit::AuraEffectList::const_iterator iter = auraList.begin(); iter != auraList.end(); ++iter) + // Lookup for Deadly poison (only attacker applied) + if (AuraEffect const* aurEff = unitTarget->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_ROGUE, 0x00010000, 0, 0, m_caster->GetGUID())) { - if ((*iter)->GetSpellInfo()->SpellFamilyName == SPELLFAMILY_ROGUE && (*iter)->GetSpellInfo()->SpellIconID == 1960) + // count consumed deadly poison doses at target + bool needConsume = true; + uint32 spellId = aurEff->GetId(); + + uint32 doses = aurEff->GetBase()->GetStackAmount(); + if (doses > combo) + doses = combo; + + // Master Poisoner + Unit::AuraEffectList const& auraList = player->GetAuraEffectsByType(SPELL_AURA_MOD_AURA_DURATION_BY_DISPEL_NOT_STACK); + for (Unit::AuraEffectList::const_iterator iter = auraList.begin(); iter != auraList.end(); ++iter) { - uint32 chance = (*iter)->GetSpellInfo()->Effects[EFFECT_2].CalcValue(m_caster); + if ((*iter)->GetSpellInfo()->SpellFamilyName == SPELLFAMILY_ROGUE && (*iter)->GetSpellInfo()->SpellIconID == 1960) + { + uint32 chance = (*iter)->GetSpellInfo()->Effects[EFFECT_2].CalcValue(m_caster); - if (chance && roll_chance_i(chance)) - needConsume = false; + if (chance && roll_chance_i(chance)) + needConsume = false; - break; + break; + } } + + if (needConsume) + for (uint32 i = 0; i < doses; ++i) + unitTarget->RemoveAuraFromStack(spellId); + + damage *= doses; + damage += int32(player->GetTotalAttackPowerValue(BASE_ATTACK) * 0.09f * combo); } - if (needConsume) - for (uint32 i = 0; i < doses; ++i) - unitTarget->RemoveAuraFromStack(spellId); - damage *= doses; - damage += int32(((Player*)m_caster)->GetTotalAttackPowerValue(BASE_ATTACK) * 0.09f * doses); + // Eviscerate and Envenom Bonus Damage (item set effect) + if (m_caster->HasAura(37169)) + damage += combo * 40; } - // Eviscerate and Envenom Bonus Damage (item set effect) - if (m_caster->HasAura(37169)) - damage += ((Player*)m_caster)->GetComboPoints()*40; } } // Eviscerate - else if ((m_spellInfo->SpellFamilyFlags[0] & 0x00020000) && m_caster->GetTypeId() == TYPEID_PLAYER) + else if (m_spellInfo->SpellFamilyFlags[0] & 0x00020000) { - if (uint32 combo = ((Player*)m_caster)->GetComboPoints()) + if (m_caster->GetTypeId() == TYPEID_PLAYER) { - float ap = m_caster->GetTotalAttackPowerValue(BASE_ATTACK); - damage += irand(int32(ap * combo * 0.03f), int32(ap * combo * 0.07f)); + if (uint32 combo = ((Player*)m_caster)->GetComboPoints()) + { + float ap = m_caster->GetTotalAttackPowerValue(BASE_ATTACK); + damage += irand(int32(ap * combo * 0.03f), int32(ap * combo * 0.07f)); - // Eviscerate and Envenom Bonus Damage (item set effect) - if (m_caster->HasAura(37169)) - damage += combo*40; + // Eviscerate and Envenom Bonus Damage (item set effect) + if (m_caster->HasAura(37169)) + damage += combo*40; + } } } break; @@ -1421,11 +1431,19 @@ void Spell::EffectDummy(SpellEffIndex effIndex) { if (!unitTarget) return; - // Restorative Totems if (Unit* owner = m_caster->GetOwner()) + { + if (m_triggeredByAuraSpell) + damage = int32(owner->SpellHealingBonus(unitTarget, m_triggeredByAuraSpell, damage, HEAL)); + + // Restorative Totems if (AuraEffect* dummy = owner->GetAuraEffect(SPELL_AURA_DUMMY, SPELLFAMILY_SHAMAN, 338, 1)) AddPctN(damage, dummy->GetAmount()); + // Glyph of Healing Stream Totem + if (AuraEffect const* aurEff = owner->GetAuraEffect(55456, EFFECT_0)) + AddPctN(damage, aurEff->GetAmount()); + } m_caster->CastCustomSpell(unitTarget, 52042, &damage, 0, 0, true, 0, 0, m_originalCasterGUID); return; } @@ -2093,12 +2111,12 @@ void Spell::EffectUnlearnSpecialization(SpellEffIndex effIndex) if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) return; - Player* _player = unitTarget->ToPlayer(); + Player* player = unitTarget->ToPlayer(); uint32 spellToUnlearn = m_spellInfo->Effects[effIndex].TriggerSpell; - _player->removeSpell(spellToUnlearn); + player->removeSpell(spellToUnlearn); - sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "Spell: Player %u has unlearned spell %u from NpcGUID: %u", _player->GetGUIDLow(), spellToUnlearn, m_caster->GetGUIDLow()); + sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "Spell: Player %u has unlearned spell %u from NpcGUID: %u", player->GetGUIDLow(), spellToUnlearn, m_caster->GetGUIDLow()); } void Spell::EffectPowerDrain(SpellEffIndex effIndex) @@ -2145,19 +2163,9 @@ void Spell::EffectSendEvent(SpellEffIndex effIndex) && effectHandleMode != SPELL_EFFECT_HANDLE_HIT) return; - //! it's possible for spells with this spell effect to either have a target or no target - //! in case of a target, we will execute this handler on SPELL_EFFECT_HANDLE_HIT_TARGET - //! with all relevant variables, and we will skip SPELL_EFFECT_HANDLE_HIT - if (effectHandleMode == SPELL_EFFECT_HANDLE_HIT) - { - if (GetSpellInfo()->Effects[effIndex].TargetA.GetTarget() != 0 || - GetSpellInfo()->Effects[effIndex].TargetB.GetTarget() != 0) - return; - } - WorldObject* target = NULL; - // call events for target if present + // call events for object target if present if (effectHandleMode == SPELL_EFFECT_HANDLE_HIT_TARGET) { if (unitTarget) @@ -2165,9 +2173,15 @@ void Spell::EffectSendEvent(SpellEffIndex effIndex) else if (gameObjTarget) target = gameObjTarget; } - // call event with no target or focus target when no targets could be found due to no dbc entry - else if (!m_spellInfo->Effects[effIndex].GetProvidedTargetMask()) + else // if (effectHandleMode == SPELL_EFFECT_HANDLE_HIT) { + // let's prevent executing effect handler twice in case when spell effect is capable of targeting an object + // this check was requested by scripters, but it has some downsides: + // now it's impossible to script (using sEventScripts) a cast which misses all targets + // or to have an ability to script the moment spell hits dest (in a case when there are object targets present) + if (m_spellInfo->Effects[effIndex].GetProvidedTargetMask() & (TARGET_FLAG_UNIT_MASK | TARGET_FLAG_GAMEOBJECT_MASK)) + return; + // some spells have no target entries in dbc and they use focus target if (focusObject) target = focusObject; // TODO: there should be a possibility to pass dest target to event script @@ -2588,8 +2602,8 @@ void Spell::EffectPersistentAA(SpellEffIndex effIndex) // Caster not in world, might be spell triggered from aura removal if (!caster->IsInWorld()) return; - DynamicObject* dynObj = new DynamicObject(); - if (!dynObj->CreateDynamicObject(sObjectMgr->GenerateLowGuid(HIGHGUID_DYNAMICOBJECT), caster, m_spellInfo->Id, *m_targets.GetDst(), radius, false, DYNAMIC_OBJECT_AREA_SPELL)) + DynamicObject* dynObj = new DynamicObject(false); + if (!dynObj->CreateDynamicObject(sObjectMgr->GenerateLowGuid(HIGHGUID_DYNAMICOBJECT), caster, m_spellInfo->Id, *m_targets.GetDst(), radius, DYNAMIC_OBJECT_AREA_SPELL)) { delete dynObj; return; @@ -3437,8 +3451,8 @@ void Spell::EffectAddFarsight(SpellEffIndex effIndex) if (!m_caster->IsInWorld()) return; - DynamicObject* dynObj = new DynamicObject(); - if (!dynObj->CreateDynamicObject(sObjectMgr->GenerateLowGuid(HIGHGUID_DYNAMICOBJECT), m_caster, m_spellInfo->Id, *m_targets.GetDst(), radius, true, DYNAMIC_OBJECT_FARSIGHT_FOCUS)) + DynamicObject* dynObj = new DynamicObject(true); + if (!dynObj->CreateDynamicObject(sObjectMgr->GenerateLowGuid(HIGHGUID_DYNAMICOBJECT), m_caster, m_spellInfo->Id, *m_targets.GetDst(), radius, DYNAMIC_OBJECT_FARSIGHT_FOCUS)) { delete dynObj; return; @@ -5875,16 +5889,15 @@ void Spell::EffectFeedPet(SpellEffIndex effIndex) if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET) return; - if (m_caster->GetTypeId() != TYPEID_PLAYER) + Player* player = m_caster->ToPlayer(); + if (!player) return; - Player* _player = m_caster->ToPlayer(); - Item* foodItem = itemTarget; if (!foodItem) return; - Pet* pet = _player->GetPet(); + Pet* pet = player->GetPet(); if (!pet) return; @@ -5898,7 +5911,7 @@ void Spell::EffectFeedPet(SpellEffIndex effIndex) ExecuteLogEffectDestroyItem(effIndex, foodItem->GetEntry()); uint32 count = 1; - _player->DestroyItemCount(foodItem, count, true); + player->DestroyItemCount(foodItem, count, true); // TODO: fix crash when a spell has two effects, both pointed at the same item target m_caster->CastCustomSpell(pet, m_spellInfo->Effects[effIndex].TriggerSpell, &benefit, NULL, NULL, true); @@ -6097,7 +6110,7 @@ void Spell::EffectReputation(SpellEffIndex effIndex) if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) return; - Player* _player = unitTarget->ToPlayer(); + Player* player = unitTarget->ToPlayer(); int32 rep_change = damage; @@ -6114,10 +6127,10 @@ void Spell::EffectReputation(SpellEffIndex effIndex) } // Bonus from spells that increase reputation gain - float bonus = rep_change * _player->GetTotalAuraModifier(SPELL_AURA_MOD_REPUTATION_GAIN) / 100.0f; // 10% + float bonus = rep_change * player->GetTotalAuraModifier(SPELL_AURA_MOD_REPUTATION_GAIN) / 100.0f; // 10% rep_change += (int32)bonus; - _player->GetReputationMgr().ModifyReputation(factionEntry, rep_change); + player->GetReputationMgr().ModifyReputation(factionEntry, rep_change); } void Spell::EffectQuestComplete(SpellEffIndex effIndex) @@ -6227,9 +6240,13 @@ void Spell::EffectCharge(SpellEffIndex /*effIndex*/) if (!unitTarget) return; - float x, y, z; - unitTarget->GetContactPoint(m_caster, x, y, z); - m_caster->GetMotionMaster()->MoveCharge(x, y, z); + float angle = unitTarget->GetRelativeAngle(m_caster); + Position pos; + + unitTarget->GetContactPoint(m_caster, pos.m_positionX, pos.m_positionY, pos.m_positionZ); + unitTarget->GetFirstCollisionPosition(pos, unitTarget->GetObjectSize(), angle); + + m_caster->GetMotionMaster()->MoveCharge(pos.m_positionX, pos.m_positionY, pos.m_positionZ + unitTarget->GetObjectSize()); } if (effectHandleMode == SPELL_EFFECT_HANDLE_HIT_TARGET) @@ -6250,9 +6267,13 @@ void Spell::EffectChargeDest(SpellEffIndex /*effIndex*/) if (m_targets.HasDst()) { - float x, y, z; - m_targets.GetDst()->GetPosition(x, y, z); - m_caster->GetMotionMaster()->MoveCharge(x, y, z); + Position pos; + m_targets.GetDst()->GetPosition(&pos); + float angle = m_caster->GetRelativeAngle(pos.GetPositionX(), pos.GetPositionY()); + float dist = m_caster->GetDistance(pos); + m_caster->GetFirstCollisionPosition(pos, dist, angle); + + m_caster->GetMotionMaster()->MoveCharge(pos.m_positionX, pos.m_positionY, pos.m_positionZ); } } @@ -6432,20 +6453,20 @@ void Spell::EffectSummonDeadPet(SpellEffIndex /*effIndex*/) if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT) return; - if (m_caster->GetTypeId() != TYPEID_PLAYER) - return; - Player* _player = m_caster->ToPlayer(); - Pet* pet = _player->GetPet(); - if (!pet) + Player* player = m_caster->ToPlayer(); + if (!player) return; - if (pet->isAlive()) + + Pet* pet = player->GetPet(); + if (!pet || pet->isAlive()) return; + if (damage < 0) return; float x, y, z; - _player->GetPosition(x, y, z); - _player->GetMap()->CreatureRelocation(pet, x, y, z, _player->GetOrientation()); + player->GetPosition(x, y, z); + player->GetMap()->CreatureRelocation(pet, x, y, z, player->GetOrientation()); pet->SetUInt32Value(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_NONE); pet->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE); @@ -6454,7 +6475,7 @@ void Spell::EffectSummonDeadPet(SpellEffIndex /*effIndex*/) pet->SetHealth(pet->CountPctFromMaxHealth(damage)); //pet->AIM_Initialize(); - //_player->PetSpellInitialize(); + //player->PetSpellInitialize(); pet->SavePetToDB(PET_SAVE_AS_CURRENT); } diff --git a/src/server/game/Spells/SpellInfo.cpp b/src/server/game/Spells/SpellInfo.cpp index 972276c7d26..463b46972fa 100644 --- a/src/server/game/Spells/SpellInfo.cpp +++ b/src/server/game/Spells/SpellInfo.cpp @@ -2304,6 +2304,19 @@ bool SpellInfo::_IsPositiveEffect(uint8 effIndex, bool deep) const if (Id == 30708) return false; break; + case SPELLFAMILY_ROGUE: + switch (Id) + { + // Envenom must be considered as a positive effect even though it deals damage + case 32645: // Envenom (Rank 1) + case 32684: // Envenom (Rank 2) + case 57992: // Envenom (Rank 3) + case 57993: // Envenom (Rank 4) + return true; + default: + break; + } + break; default: break; } diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp index 6cfbb04e179..8976f90690c 100755 --- a/src/server/game/Spells/SpellMgr.cpp +++ b/src/server/game/Spells/SpellMgr.cpp @@ -3230,6 +3230,10 @@ void SpellMgr::LoadDbcDataCorrections() // this needs research on modifier applying rules, does not seem to be in Attributes fields spellInfo->EffectSpellClassMask[0] = flag96(0x00000040, 0x00000000, 0x00000000); break; + case 63163: // Apply Enchanted Bridle (Argent Tournament) + spellInfo->EffectDieSides[0] = 0; // was 1, that should probably mean seat 0, but instead it's treated as spell 1 + spellInfo->EffectBasePoints[0] = 52391; // Ride Vehicle (forces seat 0) + break; case 19970: // Entangling Roots (Rank 6) -- Nature's Grasp Proc case 19971: // Entangling Roots (Rank 5) -- Nature's Grasp Proc case 19972: // Entangling Roots (Rank 4) -- Nature's Grasp Proc diff --git a/src/server/game/World/World.h b/src/server/game/World/World.h index f643ae60287..9354c14f51c 100755 --- a/src/server/game/World/World.h +++ b/src/server/game/World/World.h @@ -634,7 +634,8 @@ class World void SendServerMessage(ServerMessageType type, const char *text = "", Player* player = NULL); /// Are we in the middle of a shutdown? - bool IsShutdowning() const { return m_ShutdownTimer > 0; } + bool IsShuttingDown() const { return m_ShutdownTimer > 0; } + uint32 GetShutDownTimeLeft() const { return m_ShutdownTimer; } void ShutdownServ(uint32 time, uint32 options, uint8 exitcode); void ShutdownCancel(); void ShutdownMsg(bool show = false, Player* player = NULL); diff --git a/src/server/scripts/Commands/cs_modify.cpp b/src/server/scripts/Commands/cs_modify.cpp index 28bc17a7450..c32abb9537b 100644 --- a/src/server/scripts/Commands/cs_modify.cpp +++ b/src/server/scripts/Commands/cs_modify.cpp @@ -1129,7 +1129,12 @@ public: uint16 drunkMod = drunklevel * 0xFFFF / 100; - handler->GetSession()->GetPlayer()->SetDrunkValue(drunkMod); + Player* target = handler->getSelectedPlayer(); + if (!target) + target = handler->GetSession()->GetPlayer(); + + if (target) + target->SetDrunkValue(drunkMod); return true; } diff --git a/src/server/scripts/Commands/cs_npc.cpp b/src/server/scripts/Commands/cs_npc.cpp index b9ac21cc040..a5aa2a516f3 100644 --- a/src/server/scripts/Commands/cs_npc.cpp +++ b/src/server/scripts/Commands/cs_npc.cpp @@ -552,15 +552,13 @@ public: handler->PSendSysMessage(LANG_NPCINFO_PHASEMASK, target->GetPhaseMask()); handler->PSendSysMessage(LANG_NPCINFO_ARMOR, target->GetArmor()); handler->PSendSysMessage(LANG_NPCINFO_POSITION, float(target->GetPositionX()), float(target->GetPositionY()), float(target->GetPositionZ())); + handler->PSendSysMessage(LANG_NPCINFO_AIINFO, target->GetAIName().c_str(), target->GetScriptName().c_str()); - if ((npcflags & UNIT_NPC_FLAG_VENDOR)) - { + if (npcflags & UNIT_NPC_FLAG_VENDOR) handler->SendSysMessage(LANG_NPCINFO_VENDOR); - } - if ((npcflags & UNIT_NPC_FLAG_TRAINER)) - { + + if (npcflags & UNIT_NPC_FLAG_TRAINER) handler->SendSysMessage(LANG_NPCINFO_TRAINER); - } return true; } diff --git a/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter2.cpp b/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter2.cpp index ebd30aa2f5d..8179c9fccaa 100644 --- a/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter2.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter2.cpp @@ -248,7 +248,7 @@ public: me->Mount(MODEL_DEATH_KNIGHT_MOUNT); break; case 10: - me->Unmount(); + me->Dismount(); break; } } @@ -378,7 +378,7 @@ public: void EnterCombat(Unit* /*who*/) { DoScriptText(SAY_TREE2, me); - me->Unmount(); + me->Dismount(); uiStage = 0; } diff --git a/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter5.cpp b/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter5.cpp index 18316d67cd4..3ee71ce3609 100644 --- a/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter5.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter5.cpp @@ -526,13 +526,13 @@ public: NPCChangeTarget(uiOrbazGUID); NPCChangeTarget(uiThassarianGUID); - me->Unmount(); + me->Dismount(); me->CastSpell(me, SPELL_THE_MIGHT_OF_MOGRAINE, true); // need to fix, on player only if (Creature* temp = Unit::GetCreature(*me, uiKoltiraGUID)) - temp->Unmount(); + temp->Dismount(); if (Creature* temp = Unit::GetCreature(*me, uiThassarianGUID)) - temp->Unmount(); + temp->Dismount(); bIsBattle = true; break; diff --git a/src/server/scripts/EasternKingdoms/ZulGurub/boss_mandokir.cpp b/src/server/scripts/EasternKingdoms/ZulGurub/boss_mandokir.cpp index f45c943b0f1..7dc357f692a 100644 --- a/src/server/scripts/EasternKingdoms/ZulGurub/boss_mandokir.cpp +++ b/src/server/scripts/EasternKingdoms/ZulGurub/boss_mandokir.cpp @@ -149,7 +149,7 @@ class boss_mandokir : public CreatureScript if (!CombatStart) { //At combat Start Mandokir is mounted so we must unmount it first - me->Unmount(); + me->Dismount(); //And summon his raptor me->SummonCreature(14988, me->getVictim()->GetPositionX(), me->getVictim()->GetPositionY(), me->getVictim()->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 35000); diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/boss_mal_ganis.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/boss_mal_ganis.cpp index 1a43472365a..798ea3925dc 100644 --- a/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/boss_mal_ganis.cpp +++ b/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/boss_mal_ganis.cpp @@ -34,7 +34,8 @@ enum Spells H_SPELL_MIND_BLAST = 58850, SPELL_SLEEP = 52721, //Puts an enemy to sleep for up to 10 sec. Any damage caused will awaken the target. H_SPELL_SLEEP = 58849, - SPELL_VAMPIRIC_TOUCH = 52723 //Heals the caster for half the damage dealt by a melee attack. + SPELL_VAMPIRIC_TOUCH = 52723, //Heals the caster for half the damage dealt by a melee attack. + SPELL_KILL_CREDIT = 58630 // Non-existing spell as encounter credit, created in spell_dbc }; enum Yells @@ -237,9 +238,8 @@ public: { instance->SetData(DATA_MAL_GANIS_EVENT, DONE); - // give achievement credit to players. criteria use spell 58630 which doesn't exist. - if (instance) - instance->DoUpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET, 58630); + // give achievement credit and LFG rewards to players. criteria use spell 58630 which doesn't exist, but it was created in spell_dbc + DoCast(me, SPELL_KILL_CREDIT); } } diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/culling_of_stratholme.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/culling_of_stratholme.cpp index 82f16dd7784..7cbb1b91755 100644 --- a/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/culling_of_stratholme.cpp +++ b/src/server/scripts/Kalimdor/CavernsOfTime/CullingOfStratholme/culling_of_stratholme.cpp @@ -582,7 +582,7 @@ public: { Unit* pJaina = GetClosestCreatureWithEntry(me, NPC_JAINA, 50.0f); if (!pJaina) - pJaina = pJaina = me->SummonCreature(NPC_JAINA, 1895.48f, 1292.66f, 143.706f, 0.023475f, TEMPSUMMON_DEAD_DESPAWN, 180000); + pJaina = me->SummonCreature(NPC_JAINA, 1895.48f, 1292.66f, 143.706f, 0.023475f, TEMPSUMMON_DEAD_DESPAWN, 180000); if (pJaina) uiJainaGUID = pJaina->GetGUID(); bStepping = false; diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/EscapeFromDurnholdeKeep/old_hillsbrad.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/EscapeFromDurnholdeKeep/old_hillsbrad.cpp index 1f0342b3804..65ae3287381 100644 --- a/src/server/scripts/Kalimdor/CavernsOfTime/EscapeFromDurnholdeKeep/old_hillsbrad.cpp +++ b/src/server/scripts/Kalimdor/CavernsOfTime/EscapeFromDurnholdeKeep/old_hillsbrad.cpp @@ -498,7 +498,7 @@ public: } void DoUnmount() { - me->Unmount(); + me->Dismount(); me->SetSpeed(MOVE_RUN, SPEED_RUN); } void EnterCombat(Unit* /*who*/) diff --git a/src/server/scripts/Kalimdor/durotar.cpp b/src/server/scripts/Kalimdor/durotar.cpp index 1f64353901c..d6d2d633890 100644 --- a/src/server/scripts/Kalimdor/durotar.cpp +++ b/src/server/scripts/Kalimdor/durotar.cpp @@ -400,7 +400,7 @@ class npc_troll_volunteer : public CreatureScript DoCast(me, SPELL_TURNIN); DoCast(me, SPELL_QUEST_CREDIT); me->RemoveAurasDueToSpell(SPELL_MOUNTING_CHECK); - me->Unmount(); + me->Dismount(); Talk(SAY_VOLUNTEER_END); me->GetMotionMaster()->MovePoint(POINT_URUZIN, caster->GetPositionX(), caster->GetPositionY(), caster->GetPositionZ()); } @@ -447,7 +447,7 @@ class spell_mount_check : public SpellScriptLoader target->Mount(mountid); } else if (!owner->IsMounted() && target->IsMounted()) - target->Unmount(); + target->Dismount(); target->SetSpeed(MOVE_RUN, owner->GetSpeedRate(MOVE_RUN)); target->SetSpeed(MOVE_WALK, owner->GetSpeedRate(MOVE_WALK)); diff --git a/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/boss_anubarak.cpp b/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/boss_anubarak.cpp index 545dc79453d..e0892ffb009 100644 --- a/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/boss_anubarak.cpp +++ b/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/boss_anubarak.cpp @@ -91,49 +91,50 @@ public: struct boss_anub_arakAI : public ScriptedAI { - boss_anub_arakAI(Creature* c) : ScriptedAI(c), lSummons(me) + boss_anub_arakAI(Creature* creature) : ScriptedAI(creature), Summons(me) { - instance = c->GetInstanceScript(); + instance = creature->GetInstanceScript(); } InstanceScript* instance; - bool bChanneling; - bool bGuardianSummoned; - bool bVenomancerSummoned; - bool bDatterSummoned; - uint8 uiPhase; - uint32 uiUndergroundPhase; - uint32 uiCarrionBeetlesTimer; - uint32 uiLeechingSwarmTimer; - uint32 uiPoundTimer; - uint32 uiSubmergeTimer; - uint32 uiUndergroundTimer; - uint32 uiVenomancerTimer; - uint32 uiDatterTimer; - - uint32 uiImpaleTimer; - uint32 uiImpalePhase; - uint64 uiImpaleTarget; - - SummonList lSummons; + bool Channeling; + bool GuardianSummoned; + bool VenomancerSummoned; + bool DatterSummoned; + uint8 Phase; + uint32 UndergroundPhase; + uint32 CarrionBeetlesTimer; + uint32 LeechingSwarmTimer; + uint32 PoundTimer; + uint32 SubmergeTimer; + uint32 UndergroundTimer; + uint32 VenomancerTimer; + uint32 DatterTimer; + uint32 DelayTimer; + + uint32 ImpaleTimer; + uint32 ImpalePhase; + uint64 ImpaleTarget; + + SummonList Summons; void Reset() { - uiCarrionBeetlesTimer = 8*IN_MILLISECONDS; - uiLeechingSwarmTimer = 20*IN_MILLISECONDS; - uiImpaleTimer = 9*IN_MILLISECONDS; - uiPoundTimer = 15*IN_MILLISECONDS; + CarrionBeetlesTimer = 8*IN_MILLISECONDS; + LeechingSwarmTimer = 20*IN_MILLISECONDS; + ImpaleTimer = 9*IN_MILLISECONDS; + PoundTimer = 15*IN_MILLISECONDS; - uiPhase = PHASE_MELEE; - uiUndergroundPhase = 0; - bChanneling = false; - uiImpalePhase = IMPALE_PHASE_TARGET; + Phase = PHASE_MELEE; + UndergroundPhase = 0; + Channeling = false; + ImpalePhase = IMPALE_PHASE_TARGET; me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE|UNIT_FLAG_NOT_SELECTABLE); me->RemoveAura(SPELL_SUBMERGE); - lSummons.DespawnAll(); + Summons.DespawnAll(); if (instance) { @@ -147,13 +148,13 @@ public: Position targetPos; target->GetPosition(&targetPos); - if (TempSummon* pImpaleTarget = me->SummonCreature(CREATURE_IMPALE_TARGET, targetPos, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 6*IN_MILLISECONDS)) + if (TempSummon* impaleTarget = me->SummonCreature(CREATURE_IMPALE_TARGET, targetPos, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 6*IN_MILLISECONDS)) { - uiImpaleTarget = pImpaleTarget->GetGUID(); - pImpaleTarget->SetReactState(REACT_PASSIVE); - pImpaleTarget->SetDisplayId(DISPLAY_INVISIBLE); - pImpaleTarget->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE|UNIT_FLAG_NON_ATTACKABLE|UNIT_FLAG_NOT_SELECTABLE); - return pImpaleTarget; + ImpaleTarget = impaleTarget->GetGUID(); + impaleTarget->SetReactState(REACT_PASSIVE); + impaleTarget->SetDisplayId(DISPLAY_INVISIBLE); + impaleTarget->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE|UNIT_FLAG_NON_ATTACKABLE|UNIT_FLAG_NOT_SELECTABLE); + return impaleTarget; } return NULL; @@ -162,11 +163,15 @@ public: void EnterCombat(Unit* /*who*/) { DoScriptText(SAY_AGGRO, me); + DelayTimer = 0; if (instance) - { - instance->SetData(DATA_ANUBARAK_EVENT, IN_PROGRESS); instance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_TIMED_START_EVENT); - } + } + + void DelayEventStart() + { + if (instance) + instance->SetData(DATA_ANUBARAK_EVENT, IN_PROGRESS); } void UpdateAI(const uint32 diff) @@ -174,41 +179,45 @@ public: if (!UpdateVictim()) return; - switch (uiPhase) + if (DelayTimer && DelayTimer > 5000) + DelayEventStart(); + else DelayTimer+=diff; + + switch (Phase) { case PHASE_UNDERGROUND: - if (uiImpaleTimer <= diff) + if (ImpaleTimer <= diff) { - switch (uiImpalePhase) + switch (ImpalePhase) { case IMPALE_PHASE_TARGET: if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true)) { - if (Creature* pImpaleTarget = DoSummonImpaleTarget(target)) - pImpaleTarget->CastSpell(pImpaleTarget, SPELL_IMPALE_SHAKEGROUND, true); - uiImpaleTimer = 3*IN_MILLISECONDS; - uiImpalePhase = IMPALE_PHASE_ATTACK; + if (Creature* impaleTarget = DoSummonImpaleTarget(target)) + impaleTarget->CastSpell(impaleTarget, SPELL_IMPALE_SHAKEGROUND, true); + ImpaleTimer = 3*IN_MILLISECONDS; + ImpalePhase = IMPALE_PHASE_ATTACK; } break; case IMPALE_PHASE_ATTACK: - if (Creature* pImpaleTarget = Unit::GetCreature(*me, uiImpaleTarget)) + if (Creature* impaleTarget = Unit::GetCreature(*me, ImpaleTarget)) { - pImpaleTarget->CastSpell(pImpaleTarget, SPELL_IMPALE_SPIKE, false); - pImpaleTarget->RemoveAurasDueToSpell(SPELL_IMPALE_SHAKEGROUND); + impaleTarget->CastSpell(impaleTarget, SPELL_IMPALE_SPIKE, false); + impaleTarget->RemoveAurasDueToSpell(SPELL_IMPALE_SHAKEGROUND); } - uiImpalePhase = IMPALE_PHASE_DMG; - uiImpaleTimer = 1*IN_MILLISECONDS; + ImpalePhase = IMPALE_PHASE_DMG; + ImpaleTimer = 1*IN_MILLISECONDS; break; case IMPALE_PHASE_DMG: - if (Creature* pImpaleTarget = Unit::GetCreature(*me, uiImpaleTarget)) - me->CastSpell(pImpaleTarget, DUNGEON_MODE(SPELL_IMPALE_DMG, SPELL_IMPALE_DMG_H), true); - uiImpalePhase = IMPALE_PHASE_TARGET; - uiImpaleTimer = 9*IN_MILLISECONDS; + if (Creature* impaleTarget = Unit::GetCreature(*me, ImpaleTarget)) + me->CastSpell(impaleTarget, DUNGEON_MODE(SPELL_IMPALE_DMG, SPELL_IMPALE_DMG_H), true); + ImpalePhase = IMPALE_PHASE_TARGET; + ImpaleTimer = 9*IN_MILLISECONDS; break; } - } else uiImpaleTimer -= diff; + } else ImpaleTimer -= diff; - if (!bGuardianSummoned) + if (!GuardianSummoned) { for (uint8 i = 0; i < 2; ++i) { @@ -218,14 +227,14 @@ public: DoZoneInCombat(Guardian); } } - bGuardianSummoned = true; + GuardianSummoned = true; } - if (!bVenomancerSummoned) + if (!VenomancerSummoned) { - if (uiVenomancerTimer <= diff) + if (VenomancerTimer <= diff) { - if (uiUndergroundPhase > 1) + if (UndergroundPhase > 1) { for (uint8 i = 0; i < 2; ++i) { @@ -235,16 +244,16 @@ public: DoZoneInCombat(Venomancer); } } - bVenomancerSummoned = true; + VenomancerSummoned = true; } - } else uiVenomancerTimer -= diff; + } else VenomancerTimer -= diff; } - if (!bDatterSummoned) + if (!DatterSummoned) { - if (uiDatterTimer <= diff) + if (DatterTimer <= diff) { - if (uiUndergroundPhase > 2) + if (UndergroundPhase > 2) { for (uint8 i = 0; i < 2; ++i) { @@ -254,71 +263,74 @@ public: DoZoneInCombat(Datter); } } - bDatterSummoned = true; + DatterSummoned = true; } - } else uiDatterTimer -= diff; + } else DatterTimer -= diff; + + if(me->HasAura(SPELL_LEECHING_SWARM)) + me->RemoveAurasDueToSpell(SPELL_LEECHING_SWARM); } - if (uiUndergroundTimer <= diff) + if (UndergroundTimer <= diff) { me->RemoveAura(SPELL_SUBMERGE); me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE|UNIT_FLAG_NOT_SELECTABLE); - uiPhase = PHASE_MELEE; - } else uiUndergroundTimer -= diff; + Phase = PHASE_MELEE; + } else UndergroundTimer -= diff; break; case PHASE_MELEE: - if (((uiUndergroundPhase == 0 && HealthBelowPct(75)) - || (uiUndergroundPhase == 1 && HealthBelowPct(50)) - || (uiUndergroundPhase == 2 && HealthBelowPct(25))) + if (((UndergroundPhase == 0 && HealthBelowPct(75)) + || (UndergroundPhase == 1 && HealthBelowPct(50)) + || (UndergroundPhase == 2 && HealthBelowPct(25))) && !me->HasUnitState(UNIT_STAT_CASTING)) { - bGuardianSummoned = false; - bVenomancerSummoned = false; - bDatterSummoned = false; + GuardianSummoned = false; + VenomancerSummoned = false; + DatterSummoned = false; - uiUndergroundTimer = 40*IN_MILLISECONDS; - uiVenomancerTimer = 25*IN_MILLISECONDS; - uiDatterTimer = 32*IN_MILLISECONDS; + UndergroundTimer = 40*IN_MILLISECONDS; + VenomancerTimer = 25*IN_MILLISECONDS; + DatterTimer = 32*IN_MILLISECONDS; - uiImpalePhase = 0; - uiImpaleTimer = 9*IN_MILLISECONDS; + ImpalePhase = 0; + ImpaleTimer = 9*IN_MILLISECONDS; DoCast(me, SPELL_SUBMERGE, false); me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE|UNIT_FLAG_NOT_SELECTABLE); - uiPhase = PHASE_UNDERGROUND; - ++uiUndergroundPhase; + Phase = PHASE_UNDERGROUND; + ++UndergroundPhase; } - if (bChanneling == true) + if (Channeling == true) { for (uint8 i = 0; i < 8; ++i) DoCast(me->getVictim(), SPELL_SUMMON_CARRION_BEETLES, true); - bChanneling = false; + Channeling = false; } - else if (uiCarrionBeetlesTimer <= diff) + else if (CarrionBeetlesTimer <= diff) { - bChanneling = true; + Channeling = true; DoCastVictim(SPELL_CARRION_BEETLES); - uiCarrionBeetlesTimer = 25*IN_MILLISECONDS; - } else uiCarrionBeetlesTimer -= diff; + CarrionBeetlesTimer = 25*IN_MILLISECONDS; + } else CarrionBeetlesTimer -= diff; - if (uiLeechingSwarmTimer <= diff) + if (LeechingSwarmTimer <= diff) { DoCast(me, SPELL_LEECHING_SWARM, true); - uiLeechingSwarmTimer = 19*IN_MILLISECONDS; - } else uiLeechingSwarmTimer -= diff; + LeechingSwarmTimer = 19*IN_MILLISECONDS; + } else LeechingSwarmTimer -= diff; - if (uiPoundTimer <= diff) + if (PoundTimer <= diff) { if (Unit* target = me->getVictim()) { if (Creature* pImpaleTarget = DoSummonImpaleTarget(target)) me->CastSpell(pImpaleTarget, DUNGEON_MODE(SPELL_POUND, SPELL_POUND_H), false); } - uiPoundTimer = 16500; - } else uiPoundTimer -= diff; + PoundTimer = 16500; + } else PoundTimer -= diff; DoMeleeAttackIfReady(); break; @@ -328,7 +340,7 @@ public: void JustDied(Unit* /*killer*/) { DoScriptText(SAY_DEATH, me); - lSummons.DespawnAll(); + Summons.DespawnAll(); if (instance) instance->SetData(DATA_ANUBARAK_EVENT, DONE); } @@ -342,7 +354,7 @@ public: void JustSummoned(Creature* summon) { - lSummons.Summon(summon); + Summons.Summon(summon); } }; diff --git a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheChampion/boss_black_knight.cpp b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheChampion/boss_black_knight.cpp index fd84c1eec8a..f73e9779248 100644 --- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheChampion/boss_black_knight.cpp +++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheChampion/boss_black_knight.cpp @@ -54,8 +54,10 @@ enum eSpells SPELL_BLACK_KNIGHT_RES = 67693, - SPELL_LEAP = 67749, - SPELL_LEAP_H = 67880 + SPELL_LEAP = 67749, + SPELL_LEAP_H = 67880, + + SPELL_KILL_CREDIT = 68663 }; enum eModels @@ -288,6 +290,8 @@ public: void JustDied(Unit* /*killer*/) { + DoCast(me, SPELL_KILL_CREDIT); + if (instance) instance->SetData(BOSS_BLACK_KNIGHT, DONE); } diff --git a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheChampion/boss_grand_champions.cpp b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheChampion/boss_grand_champions.cpp index 2fbe381fed5..2f6a01e73d7 100644 --- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheChampion/boss_grand_champions.cpp +++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheChampion/boss_grand_champions.cpp @@ -839,7 +839,8 @@ public: if (target && me->IsInRange(target, 5.0f, 30.0f, false)) { DoCast(target, SPELL_MULTI_SHOT); - } else + } + else { Map::PlayerList const& players = me->GetMap()->GetPlayers(); if (me->GetMap()->IsDungeon() && !players.isEmpty()) @@ -849,7 +850,7 @@ public: Player* player = itr->getSource(); if (player && !player->isGameMaster() && me->IsInRange(player, 5.0f, 30.0f, false)) { - DoCast(target, SPELL_MULTI_SHOT); + DoCast(player, SPELL_MULTI_SHOT); break; } } diff --git a/src/server/scripts/Northrend/DraktharonKeep/boss_tharon_ja.cpp b/src/server/scripts/Northrend/DraktharonKeep/boss_tharon_ja.cpp index e552341fd1e..d877bbd0842 100644 --- a/src/server/scripts/Northrend/DraktharonKeep/boss_tharon_ja.cpp +++ b/src/server/scripts/Northrend/DraktharonKeep/boss_tharon_ja.cpp @@ -237,7 +237,8 @@ public: for (Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i) if (Player* player = i->getSource()) player->DeMorph(); - instance->DoUpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET2, SPELL_ACHIEVEMENT_CHECK); + + DoCast(me, SPELL_ACHIEVEMENT_CHECK); instance->SetData(DATA_THARON_JA_EVENT, DONE); } diff --git a/src/server/scripts/Northrend/FrozenHalls/ForgeOfSouls/boss_bronjahm.cpp b/src/server/scripts/Northrend/FrozenHalls/ForgeOfSouls/boss_bronjahm.cpp index eacb800f15a..1e29ec55dc8 100644 --- a/src/server/scripts/Northrend/FrozenHalls/ForgeOfSouls/boss_bronjahm.cpp +++ b/src/server/scripts/Northrend/FrozenHalls/ForgeOfSouls/boss_bronjahm.cpp @@ -215,7 +215,6 @@ class mob_corrupted_soul_fragment : public CreatureScript if (Creature* bronjahm = ObjectAccessor::GetCreature(*me, BronjahmGUID)) me->CastSpell(bronjahm, SPELL_CONSUME_SOUL, true); - summ->GetMotionMaster()->MoveIdle(); summ->UnSummon(); } } diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp index 29c3276467b..25610341a2f 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_sindragosa.cpp @@ -341,7 +341,7 @@ class boss_sindragosa : public CreatureScript { if (uint32 spellId = sSpellMgr->GetSpellIdForDifficulty(_isThirdPhase ? SPELL_FROST_BREATH_P2 : SPELL_FROST_BREATH_P1, me)) { - if (player->GetQuestStatus(QUEST_FROST_INFUSION) != QUEST_STATUS_REWARDED && spellId == spell->Id) + if (player->GetQuestStatus(QUEST_FROST_INFUSION) == QUEST_STATUS_INCOMPLETE && spellId == spell->Id) { if (Item* shadowsEdge = player->GetWeaponForAttack(BASE_ATTACK, true)) { diff --git a/src/server/scripts/Northrend/Nexus/Oculus/boss_urom.cpp b/src/server/scripts/Northrend/Nexus/Oculus/boss_urom.cpp index 16c258af756..e63d50b0133 100644 --- a/src/server/scripts/Northrend/Nexus/Oculus/boss_urom.cpp +++ b/src/server/scripts/Northrend/Nexus/Oculus/boss_urom.cpp @@ -289,6 +289,7 @@ public: void JustDied(Unit* /*killer*/) { _JustDied(); + DoCast(me, SPELL_DEATH_SPELL, true); // we cast the spell as triggered or the summon effect does not occur } void LeaveCombat() diff --git a/src/server/scripts/Northrend/Nexus/Oculus/boss_varos.cpp b/src/server/scripts/Northrend/Nexus/Oculus/boss_varos.cpp index f3384b7ec15..4dcd2618895 100644 --- a/src/server/scripts/Northrend/Nexus/Oculus/boss_varos.cpp +++ b/src/server/scripts/Northrend/Nexus/Oculus/boss_varos.cpp @@ -144,8 +144,8 @@ public: void JustDied(Unit* /*killer*/) { _JustDied(); - Talk(SAY_DEATH); + DoCast(me, SPELL_DEATH_SPELL, true); // we cast the spell as triggered or the summon effect does not occur } private: bool firstCoreEnergize; diff --git a/src/server/scripts/Northrend/Nexus/Oculus/oculus.cpp b/src/server/scripts/Northrend/Nexus/Oculus/oculus.cpp index f8839aa0028..b9799103214 100644 --- a/src/server/scripts/Northrend/Nexus/Oculus/oculus.cpp +++ b/src/server/scripts/Northrend/Nexus/Oculus/oculus.cpp @@ -50,6 +50,12 @@ enum Drakes NPC_ETERNOS = 27659 }; +enum Says +{ + SAY_VAROS = 0, + SAY_UROM = 1 +}; + class npc_oculus_drake : public CreatureScript { public: @@ -174,7 +180,38 @@ public: }; +class npc_image_belgaristrasz : public CreatureScript +{ +public: + npc_image_belgaristrasz() : CreatureScript("npc_image_belgaristrasz") { } + + struct npc_image_belgaristraszAI : public ScriptedAI + { + npc_image_belgaristraszAI(Creature* creature) : ScriptedAI(creature) {} + + void IsSummonedBy(Unit* summoner) + { + if (summoner->GetEntry() == NPC_VAROS) + { + Talk(SAY_VAROS); + me->DespawnOrUnsummon(60000); + } + if (summoner->GetEntry() == NPC_UROM) + { + Talk(SAY_UROM); + me->DespawnOrUnsummon(60000); + } + } + }; + + CreatureAI* GetAI(Creature* creature) const + { + return new npc_image_belgaristraszAI(creature); + } +}; + void AddSC_oculus() { new npc_oculus_drake(); + new npc_image_belgaristrasz(); } diff --git a/src/server/scripts/Northrend/Nexus/Oculus/oculus.h b/src/server/scripts/Northrend/Nexus/Oculus/oculus.h index e04f2c8aab9..dab2821b5e5 100644 --- a/src/server/scripts/Northrend/Nexus/Oculus/oculus.h +++ b/src/server/scripts/Northrend/Nexus/Oculus/oculus.h @@ -71,6 +71,7 @@ enum OculusWorldStates enum OculusSpells { - SPELL_CENTRIFUGE_SHIELD = 50053 + SPELL_CENTRIFUGE_SHIELD = 50053, + SPELL_DEATH_SPELL = 50415 }; #endif diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_freya.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_freya.cpp index e7d8b070e53..13c174a9607 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_freya.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_freya.cpp @@ -526,7 +526,7 @@ class boss_freya : public CreatureScript { uint8 n = 0; - // Handling recieved data + // Handling received data for (uint8 i = 0; i < 5; ++i) // We have created "instances" for keeping informations about last 6 death lashers - needed because of respawning { deforestation[i][0] = deforestation[(i + 1)][0]; // Time @@ -590,7 +590,7 @@ class boss_freya : public CreatureScript waveCount++; } - void JustDied(Unit* who) + void JustDied(Unit* /*who*/) { //! Freya's chest is dynamically spawned on death by different spells. const uint32 summonSpell[2][4] = diff --git a/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/boss_ingvar_the_plunderer.cpp b/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/boss_ingvar_the_plunderer.cpp index dc2d34326a7..3712bd748a5 100644 --- a/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/boss_ingvar_the_plunderer.cpp +++ b/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/boss_ingvar_the_plunderer.cpp @@ -173,7 +173,11 @@ public: DoScriptText(YELL_DEAD_2, me); if (instance) + { + // Ingvar has MOB_INGVAR_UNDEAD id in this moment, so we have to update encounter state for his original id + instance->UpdateEncounterState(ENCOUNTER_CREDIT_KILL_CREATURE, MOB_INGVAR_HUMAN, me); instance->SetData(DATA_INGVAR_EVENT, DONE); + } } void KilledUnit(Unit* /*victim*/) diff --git a/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_skadi.cpp b/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_skadi.cpp index 7b459e7410d..f31271b825e 100644 --- a/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_skadi.cpp +++ b/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_skadi.cpp @@ -218,7 +218,7 @@ public: void JustReachedHome() { me->SetFlying(false); - me->Unmount(); + me->Dismount(); me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NON_ATTACKABLE); if (Unit::GetCreature((*me), m_uiGraufGUID) == NULL) me->SummonCreature(CREATURE_GRAUF, Location[0].GetPositionX(), Location[0].GetPositionY(), Location[0].GetPositionZ(), 3.0f); @@ -285,7 +285,7 @@ public: { Phase = SKADI; me->SetFlying(false); - me->Unmount(); + me->Dismount(); if (Creature* pGrauf = me->SummonCreature(CREATURE_GRAUF, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), 0, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 3*IN_MILLISECONDS)) { pGrauf->GetMotionMaster()->MoveFall(0); diff --git a/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_warchief_kargath_bladefist.cpp b/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_warchief_kargath_bladefist.cpp index 4f837870612..5965c352975 100644 --- a/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_warchief_kargath_bladefist.cpp +++ b/src/server/scripts/Outland/HellfireCitadel/ShatteredHalls/boss_warchief_kargath_bladefist.cpp @@ -303,9 +303,7 @@ class boss_warchief_kargath_bladefist : public CreatureScript if (resetcheck_timer <= diff) { - uint32 tempx, tempy; - tempx = uint32(me->GetPositionX()); - tempy = uint32(me->GetPositionY()); + uint32 tempx = uint32(me->GetPositionX()); if (tempx > 255 || tempx < 205) { EnterEvadeMode(); diff --git a/src/server/scripts/Outland/nagrand.cpp b/src/server/scripts/Outland/nagrand.cpp index c556253ecf1..bae3aa65b98 100644 --- a/src/server/scripts/Outland/nagrand.cpp +++ b/src/server/scripts/Outland/nagrand.cpp @@ -573,7 +573,7 @@ public: { Talk(SAY_KUR_MORE); - if (Creature* temp = me->SummonCreature(NPC_KUR_MURK_PUTRIFIER, kurenaiAmbushB[0], kurenaiAmbushB[1], kurenaiAmbushB[2], 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 25000)) + if (me->SummonCreature(NPC_KUR_MURK_PUTRIFIER, kurenaiAmbushB[0], kurenaiAmbushB[1], kurenaiAmbushB[2], 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 25000)) Talk(SAY_KUR_MORE_TWO); me->SummonCreature(NPC_KUR_MURK_PUTRIFIER, kurenaiAmbushB[0]-2.5f, kurenaiAmbushB[1]-2.5f, kurenaiAmbushB[2], 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 25000); diff --git a/src/server/scripts/Spells/spell_generic.cpp b/src/server/scripts/Spells/spell_generic.cpp index 260b0c57563..298e9b6410e 100644 --- a/src/server/scripts/Spells/spell_generic.cpp +++ b/src/server/scripts/Spells/spell_generic.cpp @@ -26,6 +26,8 @@ #include "SpellAuraEffects.h" #include "SkillDiscovery.h" #include "GridNotifiers.h" +#include "Group.h" +#include "LFGMgr.h" class spell_gen_absorb0_hitlimit1 : public SpellScriptLoader { @@ -564,6 +566,9 @@ class spell_creature_permanent_feign_death : public SpellScriptLoader Unit* target = GetTarget(); target->SetFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_DEAD); target->SetFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_FEIGN_DEATH); + + if (target->GetTypeId() == TYPEID_UNIT) + target->ToCreature()->SetReactState(REACT_PASSIVE); } void Register() @@ -1419,6 +1424,53 @@ public: } }; +class spell_gen_luck_of_the_draw : public SpellScriptLoader +{ + public: + spell_gen_luck_of_the_draw() : SpellScriptLoader("spell_gen_luck_of_the_draw") { } + + class spell_gen_luck_of_the_draw_AuraScript : public AuraScript + { + PrepareAuraScript(spell_gen_luck_of_the_draw_AuraScript); + + // cheap hax to make it have update calls + void CalcPeriodic(AuraEffect const* /*effect*/, bool& isPeriodic, int32& amplitude) + { + isPeriodic = true; + amplitude = 5 * IN_MILLISECONDS; + } + + void Update(AuraEffect* /*effect*/) + { + if (GetUnitOwner()->GetTypeId() != TYPEID_PLAYER) + return; + + LFGDungeonEntry const* randomDungeon = sLFGDungeonStore.LookupEntry(*(sLFGMgr->GetSelectedDungeons(GetUnitOwner()->GetGUID()).begin())); + Group* group = GetUnitOwner()->ToPlayer()->GetGroup(); + Map const* map = GetUnitOwner()->GetMap(); + if (group && group->isLFGGroup()) + if (uint32 dungeonId = sLFGMgr->GetDungeon(group->GetGUID(), true)) + if (LFGDungeonEntry const* dungeon = sLFGDungeonStore.LookupEntry(dungeonId)) + if (dungeon->map == map->GetId() && dungeon->difficulty == map->GetDifficulty()) + if (randomDungeon && randomDungeon->type == LFG_TYPE_RANDOM) + return; // in correct dungeon + + Remove(AURA_REMOVE_BY_DEFAULT); + } + + void Register() + { + DoEffectCalcPeriodic += AuraEffectCalcPeriodicFn(spell_gen_luck_of_the_draw_AuraScript::CalcPeriodic, EFFECT_0, SPELL_AURA_MOD_DAMAGE_PERCENT_DONE); + OnEffectUpdatePeriodic += AuraEffectUpdatePeriodicFn(spell_gen_luck_of_the_draw_AuraScript::Update, EFFECT_0, SPELL_AURA_MOD_DAMAGE_PERCENT_DONE); + } + }; + + AuraScript* GetAuraScript() const + { + return new spell_gen_luck_of_the_draw_AuraScript(); + } +}; + void AddSC_generic_spell_scripts() { new spell_gen_absorb0_hitlimit1(); @@ -1451,4 +1503,5 @@ void AddSC_generic_spell_scripts() new spell_gen_vehicle_scaling(); new spell_gen_oracle_wolvar_reputation(); new spell_gen_damage_reduction_aura(); + new spell_gen_luck_of_the_draw(); } diff --git a/src/server/scripts/World/go_scripts.cpp b/src/server/scripts/World/go_scripts.cpp index 3bb969977b6..4799b893286 100644 --- a/src/server/scripts/World/go_scripts.cpp +++ b/src/server/scripts/World/go_scripts.cpp @@ -16,13 +16,6 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ -/* ScriptData -SDName: GO_Scripts -SD%Complete: 100 -SDComment: Quest support: 4285, 4287, 4288(crystal pylons), 4296, 6481, 10990, 10991, 10992, Field_Repair_Bot->Teaches spell 22704. Barov_journal->Teaches spell 26089, 12843, 12982, 2936. Soulwell -SDCategory: Game Objects -EndScriptData */ - /* ContentData go_cat_figurine (the "trap" version of GO, two different exist) go_northern_crystal_pylon @@ -47,6 +40,16 @@ go_jotunheim_cage go_table_theka go_soulwell go_bashir_crystalforge +go_ethereal_teleport_pad +go_soulwell +go_dragonflayer_cage +go_tadpole_cage +go_black_cage +go_amberpine_outhouse +go_hive_pod +go_gjalerbron_cage +go_large_gjalerbron_cage +go_veil_skith_cage EndContentData */ #include "ScriptPCH.h" @@ -922,6 +925,32 @@ public: }; /*###### +## go_ethereal_teleport_pad +######*/ + +enum eEtherealTeleportPad +{ + NPC_IMAGE_WIND_TRADER = 20518, + ITEM_TELEPORTER_POWER_PACK = 28969, +}; + +class go_ethereal_teleport_pad : public GameObjectScript +{ +public: + go_ethereal_teleport_pad() : GameObjectScript("go_ethereal_teleport_pad") { } + + bool OnGossipHello(Player* player, GameObject* pGO) + { + if (!player->HasItemCount(ITEM_TELEPORTER_POWER_PACK, 1)) + return false; + + pGO->SummonCreature(NPC_IMAGE_WIND_TRADER, pGO->GetPositionX(), pGO->GetPositionY(), pGO->GetPositionZ(), pGO->GetAngle(player), TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 60000); + + return true; + } +}; + +/*###### ## go_soulwell ######*/ @@ -1152,6 +1181,7 @@ public: /*###### ## Quest 1126: Hive in the Tower +## go_hive_pod ######*/ enum eHives @@ -1251,6 +1281,42 @@ class go_large_gjalerbron_cage : public GameObjectScript } }; +/*######## +#### go_veil_skith_cage +#####*/ + +enum MissingFriends +{ + QUEST_MISSING_FRIENDS = 10852, + NPC_CAPTIVE_CHILD = 22314, + SAY_FREE = 0, +}; + +class go_veil_skith_cage : public GameObjectScript +{ + public: + go_veil_skith_cage() : GameObjectScript("go_veil_skith_cage") { } + + bool OnGossipHello(Player* player, GameObject* go) + { + if (player->GetQuestStatus(QUEST_MISSING_FRIENDS) == QUEST_STATUS_INCOMPLETE) + { + std::list<Creature*> ChildrenList; + GetCreatureListWithEntryInGrid(ChildrenList, go, NPC_CAPTIVE_CHILD, INTERACTION_DISTANCE); + for (std::list<Creature*>::const_iterator itr = ChildrenList.begin(); itr != ChildrenList.end(); ++itr) + { + go->UseDoorOrButton(); + player->KilledMonsterCredit(NPC_CAPTIVE_CHILD, (*itr)->GetGUID()); + (*itr)->ForcedDespawn(5000); + (*itr)->GetMotionMaster()->MovePoint(1, go->GetPositionX()+5, go->GetPositionY(), go->GetPositionZ()); + (*itr)->AI()->Talk(SAY_FREE); + (*itr)->GetMotionMaster()->Clear(); + } + } + return false; + } +}; + void AddSC_go_scripts() { new go_cat_figurine; @@ -1282,6 +1348,7 @@ void AddSC_go_scripts() new go_jotunheim_cage; new go_table_theka; new go_inconspicuous_landmark; + new go_ethereal_teleport_pad; new go_soulwell; new go_tadpole_cage; new go_dragonflayer_cage; @@ -1291,4 +1358,5 @@ void AddSC_go_scripts() new go_massive_seaforium_charge; new go_gjalerbron_cage; new go_large_gjalerbron_cage; + new go_veil_skith_cage; } diff --git a/src/server/scripts/World/npcs_special.cpp b/src/server/scripts/World/npcs_special.cpp index a5e5b467fc7..38a56f7b64a 100644 --- a/src/server/scripts/World/npcs_special.cpp +++ b/src/server/scripts/World/npcs_special.cpp @@ -1623,46 +1623,44 @@ public: ## npc_winter_reveler ####*/ +enum WinterReveler +{ + SPELL_MISTLETOE_DEBUFF = 26218, + SPELL_CREATE_MISTLETOE = 26206, + SPELL_CREATE_HOLLY = 26207, + SPELL_CREATE_SNOWFLAKES = 45036, +}; + class npc_winter_reveler : public CreatureScript { -public: - npc_winter_reveler() : CreatureScript("npc_winter_reveler") { } + public: + npc_winter_reveler() : CreatureScript("npc_winter_reveler") { } - struct npc_winter_revelerAI : public ScriptedAI - { - npc_winter_revelerAI(Creature* c) : ScriptedAI(c) {} - void ReceiveEmote(Player* player, uint32 emote) + struct npc_winter_revelerAI : public ScriptedAI { - if (!IsHolidayActive(HOLIDAY_FEAST_OF_WINTER_VEIL)) - return; - //TODO: check auralist. - if (player->HasAura(26218)) - return; + npc_winter_revelerAI(Creature* c) : ScriptedAI(c) {} - if (emote == TEXT_EMOTE_KISS) + void ReceiveEmote(Player* player, uint32 emote) { - me->CastSpell(me, 26218, false); - player->CastSpell(player, 26218, false); - switch (urand(0, 2)) + if (player->HasAura(SPELL_MISTLETOE_DEBUFF)) + return; + + if (!IsHolidayActive(HOLIDAY_FEAST_OF_WINTER_VEIL)) + return; + + if (emote == TEXT_EMOTE_KISS) { - case 0: - me->CastSpell(player, 26207, false); - break; - case 1: - me->CastSpell(player, 26206, false); - break; - case 2: - me->CastSpell(player, 45036, false); - break; + uint32 spellId = RAND<uint32>(SPELL_CREATE_MISTLETOE, SPELL_CREATE_HOLLY, SPELL_CREATE_SNOWFLAKES); + me->CastSpell(player, spellId, false); + me->CastSpell(player, SPELL_MISTLETOE_DEBUFF, false); } } - } - }; + }; - CreatureAI* GetAI(Creature* creature) const - { - return new npc_winter_revelerAI(creature); - } + CreatureAI* GetAI(Creature* creature) const + { + return new npc_winter_revelerAI(creature); + } }; /*#### @@ -1678,8 +1676,6 @@ public: #define C_VIPER 19921 -#define RAND 5 - class npc_snake_trap : public CreatureScript { public: @@ -1726,7 +1722,7 @@ public: float attackRadius = me->GetAttackDistance(who); if (me->IsWithinDistInMap(who, attackRadius) && me->IsWithinLOSInMap(who)) { - if (!(rand() % RAND)) + if (!(rand() % 5)) { me->setAttackTimer(BASE_ATTACK, (rand() % 10) * 100); SpellTimer = (rand() % 10) * 100; @@ -2164,6 +2160,121 @@ public: }; /*###### +# npc_fire_elemental +######*/ +#define SPELL_FIRENOVA 12470 +#define SPELL_FIRESHIELD 13376 +#define SPELL_FIREBLAST 57984 + +class npc_fire_elemental : public CreatureScript +{ +public: + npc_fire_elemental() : CreatureScript("npc_fire_elemental") { } + + struct npc_fire_elementalAI : public ScriptedAI + { + npc_fire_elementalAI(Creature* creature) : ScriptedAI(creature) {} + + uint32 FireNova_Timer; + uint32 FireShield_Timer; + uint32 FireBlast_Timer; + + void Reset() + { + FireNova_Timer = 5000 + rand() % 15000; // 5-20 sec cd + FireBlast_Timer = 5000 + rand() % 15000; // 5-20 sec cd + FireShield_Timer = 0; + me->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_FIRE, true); + } + + void UpdateAI(const uint32 diff) + { + if (!UpdateVictim()) + return; + + if (me->HasUnitState(UNIT_STAT_CASTING)) + return; + + if (FireShield_Timer <= diff) + { + DoCast(me->getVictim(), SPELL_FIRESHIELD); + FireShield_Timer = 2 * IN_MILLISECONDS; + } + else + FireShield_Timer -= diff; + + if (FireBlast_Timer <= diff) + { + DoCast(me->getVictim(), SPELL_FIREBLAST); + FireBlast_Timer = 5000 + rand() % 15000; // 5-20 sec cd + } + else + FireBlast_Timer -= diff; + + if (FireNova_Timer <= diff) + { + DoCast(me->getVictim(), SPELL_FIRENOVA); + FireNova_Timer = 5000 + rand() % 15000; // 5-20 sec cd + } + else + FireNova_Timer -= diff; + + DoMeleeAttackIfReady(); + } + }; + + CreatureAI *GetAI(Creature* creature) const + { + return new npc_fire_elementalAI(creature); + } +}; + +/*###### +# npc_earth_elemental +######*/ +#define SPELL_ANGEREDEARTH 36213 + +class npc_earth_elemental : public CreatureScript +{ +public: + npc_earth_elemental() : CreatureScript("npc_earth_elemental") { } + + struct npc_earth_elementalAI : public ScriptedAI + { + npc_earth_elementalAI(Creature* creature) : ScriptedAI(creature) {} + + uint32 AngeredEarth_Timer; + + void Reset() + { + AngeredEarth_Timer = 0; + me->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_NATURE, true); + } + + void UpdateAI(const uint32 diff) + { + if (!UpdateVictim()) + return; + + if (AngeredEarth_Timer <= diff) + { + DoCast(me->getVictim(), SPELL_ANGEREDEARTH); + AngeredEarth_Timer = 5000 + rand() % 15000; // 5-20 sec cd + } + else + AngeredEarth_Timer -= diff; + + DoMeleeAttackIfReady(); + } + }; + + CreatureAI *GetAI(Creature* creature) const + { + return new npc_earth_elementalAI(creature); + } +}; + +/*###### # npc_wormhole ######*/ @@ -2673,5 +2784,7 @@ void AddSC_npcs_special() new npc_locksmith; new npc_tabard_vendor; new npc_experience; + new npc_fire_elemental; + new npc_earth_elemental; } diff --git a/src/server/shared/Database/DatabaseWorkerPool.h b/src/server/shared/Database/DatabaseWorkerPool.h index adf5902a591..f1d01661210 100755 --- a/src/server/shared/Database/DatabaseWorkerPool.h +++ b/src/server/shared/Database/DatabaseWorkerPool.h @@ -158,6 +158,7 @@ class DatabaseWorkerPool } //! Enqueues a one-way SQL operation in prepared statement format that will be executed asynchronously. + //! Statement must be prepared with CONNECTION_ASYNC flag. void Execute(PreparedStatement* stmt) { PreparedStatementTask* task = new PreparedStatementTask(stmt); @@ -195,6 +196,7 @@ class DatabaseWorkerPool } //! Directly executes a one-way SQL operation in prepared statement format, that will block the calling thread until finished. + //! Statement must be prepared with the CONNECTION_SYNCH flag. void DirectExecute(PreparedStatement* stmt) { T* t = GetFreeConnection(); @@ -203,7 +205,7 @@ class DatabaseWorkerPool } /** - Syncrhonous query (with resultset) methods. + Synchronous query (with resultset) methods. */ //! Directly executes an SQL query in string format that will block the calling thread until finished. @@ -256,6 +258,7 @@ class DatabaseWorkerPool //! Directly executes an SQL query in prepared format that will block the calling thread until finished. //! Returns reference counted auto pointer, no need for manual memory management in upper level code. + //! Statement must be prepared with CONNECTION_SYNCH flag. PreparedQueryResult Query(PreparedStatement* stmt) { T* t = GetFreeConnection(); @@ -297,6 +300,7 @@ class DatabaseWorkerPool //! Enqueues a query in prepared format that will set the value of the PreparedQueryResultFuture return object as soon as the query is executed. //! The return value is then processed in ProcessQueryCallback methods. + //! Statement must be prepared with CONNECTION_ASYNC flag. PreparedQueryResultFuture AsyncQuery(PreparedStatement* stmt) { PreparedQueryResultFuture res; @@ -308,6 +312,7 @@ class DatabaseWorkerPool //! Enqueues a vector of SQL operations (can be both adhoc and prepared) that will set the value of the QueryResultHolderFuture //! return object as soon as the query is executed. //! The return value is then processed in ProcessQueryCallback methods. + //! Any prepared statements added to this holder need to be prepared with the CONNECTION_ASYNC flag. QueryResultHolderFuture DelayQueryHolder(SQLQueryHolder* holder) { QueryResultHolderFuture res; diff --git a/src/server/shared/Database/Implementation/CharacterDatabase.cpp b/src/server/shared/Database/Implementation/CharacterDatabase.cpp index f93c4a70d7c..0cbf4f8f4b4 100755 --- a/src/server/shared/Database/Implementation/CharacterDatabase.cpp +++ b/src/server/shared/Database/Implementation/CharacterDatabase.cpp @@ -26,7 +26,7 @@ void CharacterDatabaseConnection::DoPrepareStatements() PREPARE_STATEMENT(CHAR_ADD_QUEST_POOL_SAVE, "INSERT INTO pool_quest_save (pool_id, quest_id) VALUES (?, ?)", CONNECTION_ASYNC) PREPARE_STATEMENT(CHAR_DEL_NONEXISTENT_GUILD_BANK_ITEM, "DELETE FROM guild_bank_item WHERE guildid = ? AND TabId = ? AND SlotId = ?", CONNECTION_ASYNC) PREPARE_STATEMENT(CHAR_DEL_EXPIRED_BANS, "UPDATE character_banned SET active = 0 WHERE unbandate <= UNIX_TIMESTAMP() AND unbandate <> bandate", CONNECTION_ASYNC) - PREPARE_STATEMENT(CHAR_GET_GUID_BY_NAME, "SELECT guid FROM characters WHERE name = ?", CONNECTION_SYNCH); + PREPARE_STATEMENT(CHAR_GET_GUID_BY_NAME, "SELECT guid FROM characters WHERE name = ?", CONNECTION_BOTH); PREPARE_STATEMENT(CHAR_GET_CHECK_NAME, "SELECT 1 FROM characters WHERE name = ?", CONNECTION_ASYNC); PREPARE_STATEMENT(CHAR_GET_SUM_CHARS, "SELECT COUNT(guid) FROM characters WHERE account = ?", CONNECTION_ASYNC); PREPARE_STATEMENT(CHAR_GET_CHAR_CREATE_INFO, "SELECT level, race, class FROM characters WHERE account = ? LIMIT 0, ?", CONNECTION_ASYNC); @@ -36,6 +36,11 @@ void CharacterDatabaseConnection::DoPrepareStatements() PREPARE_STATEMENT(CHAR_GET_GUID_BY_NAME_FILTER, "SELECT guid, name FROM characters WHERE name LIKE CONCAT('%', ?, '%')", CONNECTION_SYNCH) PREPARE_STATEMENT(CHAR_GET_BANINFO_LIST, "SELECT bandate, unbandate, bannedby, banreason FROM character_banned WHERE guid = ? ORDER BY unbandate", CONNECTION_SYNCH) PREPARE_STATEMENT(CHAR_GET_BANNED_NAME, "SELECT characters.name FROM characters, character_banned WHERE character_banned.guid = ? AND character_banned.guid = characters.guid", CONNECTION_SYNCH) + PREPARE_STATEMENT(CHAR_GET_ENUM, "SELECT c.guid, c.name, c.race, c.class, c.gender, c.playerBytes, c.playerBytes2, c.level, c.zone, c.map, c.position_x, c.position_y, c.position_z, gm.guildid, c.playerFlags, c.at_login, cp.entry, cp.modelid, cp.level, c.equipmentCache, cb.guid FROM characters AS c LEFT JOIN character_pet AS cp ON c.guid = cp.owner AND cp.slot = ? LEFT JOIN guild_member AS gm ON c.guid = gm.guid LEFT JOIN character_banned AS cb ON c.guid = cb.guid AND cb.active = 1 WHERE c.account = ? ORDER BY c.guid", CONNECTION_ASYNC); + PREPARE_STATEMENT(CHAR_GET_ENUM_DECLINED_NAME, "SELECT c.guid, c.name, c.race, c.class, c.gender, c.playerBytes, c.playerBytes2, c.level, c.zone, c.map, c.position_x, c.position_y, c.position_z, gm.guildid, c.playerFlags, c.at_login, cp.entry, cp.modelid, cp.level, c.equipmentCache, cb.guid, cd.genitive FROM characters AS c LEFT JOIN character_pet AS cp ON c.guid = cp.owner AND cp.slot = ? LEFT JOIN character_declinedname AS cd ON c.guid = cd.guid LEFT JOIN guild_member AS gm ON c.guid = gm.guid LEFT JOIN character_banned AS cb ON c.guid = cb.guid AND cb.active = 1 WHERE c.account = ? ORDER BY c.guid", CONNECTION_ASYNC); + PREPARE_STATEMENT(CHAR_GET_PET_SLOTS, "SELECT owner, slot FROM character_pet WHERE owner = ? AND slot >= ? AND slot <= ? ORDER BY slot", CONNECTION_ASYNC); + PREPARE_STATEMENT(CHAR_GET_FREE_NAME, "SELECT guid, name FROM characters WHERE guid = ? AND account = ? AND (at_login & ?) = ? AND NOT EXISTS (SELECT NULL FROM characters WHERE name = ?)", CONNECTION_ASYNC); + PREPARE_STATEMENT(CHAR_GET_GUID_RACE_ACC_BY_NAME, "SELECT guid, race, account FROM characters WHERE name = ?", CONNECTION_ASYNC); // Start LoginQueryHolder content PREPARE_STATEMENT(CHAR_LOAD_PLAYER, "SELECT guid, account, name, race, class, gender, level, xp, money, playerBytes, playerBytes2, playerFlags, " @@ -111,6 +116,8 @@ void CharacterDatabaseConnection::DoPrepareStatements() PREPARE_STATEMENT(CHAR_LOAD_PLAYER_NAME_CLASS, "SELECT name, class FROM characters WHERE guid = ?", CONNECTION_SYNCH); PREPARE_STATEMENT(CHAR_LOAD_MATCH_MAKER_RATING, "SELECT matchMakerRating FROM character_arena_stats WHERE guid = ? AND slot = ?", CONNECTION_SYNCH); PREPARE_STATEMENT(CHAR_GET_CHARACTER_COUNT, "SELECT account, COUNT(guid) FROM characters WHERE account = ? GROUP BY account", CONNECTION_ASYNC); + PREPARE_STATEMENT(CHAR_UPDATE_NAME, "UPDATE characters set name = ?, at_login = at_login & ~ ? WHERE guid = ?", CONNECTION_ASYNC); + PREPARE_STATEMENT(CHAR_DEL_DECLINED_NAME, "DELETE FROM character_declinedname WHERE guid = ?", CONNECTION_ASYNC); // Guild handling // 0: uint32, 1: string, 2: uint32, 3: string, 4: string, 5: uint64, 6-10: uint32, 11: uint64 diff --git a/src/server/shared/Database/Implementation/CharacterDatabase.h b/src/server/shared/Database/Implementation/CharacterDatabase.h index f06a17aa924..a9464aed34f 100755 --- a/src/server/shared/Database/Implementation/CharacterDatabase.h +++ b/src/server/shared/Database/Implementation/CharacterDatabase.h @@ -56,6 +56,11 @@ enum CharacterDatabaseStatements CHAR_GET_GUID_BY_NAME_FILTER, CHAR_GET_BANINFO_LIST, CHAR_GET_BANNED_NAME, + CHAR_GET_ENUM, + CHAR_GET_ENUM_DECLINED_NAME, + CHAR_GET_PET_SLOTS, + CHAR_GET_FREE_NAME, + CHAR_GET_GUID_RACE_ACC_BY_NAME, CHAR_LOAD_PLAYER, CHAR_LOAD_PLAYER_GROUP, CHAR_LOAD_PLAYER_BOUNDINSTANCES, @@ -120,6 +125,8 @@ enum CharacterDatabaseStatements CHAR_LOAD_PLAYER_NAME_CLASS, CHAR_LOAD_MATCH_MAKER_RATING, CHAR_GET_CHARACTER_COUNT, + CHAR_UPDATE_NAME, + CHAR_DEL_DECLINED_NAME, CHAR_ADD_GUILD, CHAR_DEL_GUILD, diff --git a/src/server/shared/Database/MySQLConnection.cpp b/src/server/shared/Database/MySQLConnection.cpp index 70a8beb3d70..9ce924127ba 100755 --- a/src/server/shared/Database/MySQLConnection.cpp +++ b/src/server/shared/Database/MySQLConnection.cpp @@ -527,7 +527,12 @@ bool MySQLConnection::_HandleMySQLErrno(uint32 errNo) // Query related errors - skip query case 1058: // "Column count doesn't match value count" case 1062: // "Duplicate entry '%s' for key '%d'" - case 1054: // "Unknown column '%s' in 'order clause'" + return false; + + // Outdated table or database structure - terminate core + case 1054: // "Unknown column '%s' in '%s'" + case 1146: // "Table '%s' doesn't exist" + WPFatal(!errNo, "Your database structure is not up to date. Please make sure you've executed all queries in the sql/updates folders."); return false; default: diff --git a/src/server/shared/Database/MySQLConnection.h b/src/server/shared/Database/MySQLConnection.h index 03846c47ecd..2e134cfa814 100755 --- a/src/server/shared/Database/MySQLConnection.h +++ b/src/server/shared/Database/MySQLConnection.h @@ -33,6 +33,7 @@ enum ConnectionFlags { CONNECTION_ASYNC = 0x1, CONNECTION_SYNCH = 0x2, + CONNECTION_BOTH = CONNECTION_ASYNC | CONNECTION_SYNCH, }; struct MySQLConnectionInfo diff --git a/src/server/shared/Debugging/Errors.h b/src/server/shared/Debugging/Errors.h index cfa1452864f..921363d6dc5 100755 --- a/src/server/shared/Debugging/Errors.h +++ b/src/server/shared/Debugging/Errors.h @@ -22,11 +22,12 @@ #include "Common.h" #include "Log.h" #include <ace/Stack_Trace.h> +#include <ace/OS_NS_unistd.h> #define WPAssert( assertion ) { if (!(assertion)) { ACE_Stack_Trace st; sLog->outError( "\n%s:%i in %s ASSERTION FAILED:\n %s\n%s\n", __FILE__, __LINE__, __FUNCTION__, #assertion, st.c_str()); assert( #assertion &&0 ); ((void(*)())NULL)();} } #define WPError( assertion, errmsg ) if ( ! (assertion) ) { sLog->outError( "%\n%s:%i in %s ERROR:\n %s\n", __FILE__, __LINE__, __FUNCTION__, (char *)errmsg ); assert( false ); } #define WPWarning( assertion, errmsg ) if ( ! (assertion) ) { sLog->outError( "\n%s:%i in %s WARNING:\n %s\n", __FILE__, __LINE__, __FUNCTION__, (char *)errmsg ); } -#define WPFatal( assertion, errmsg ) if ( ! (assertion) ) { sLog->outError( "\n%s:%i in %s FATAL ERROR:\n %s\n", __FILE__, __LINE__, __FUNCTION__, (char *)errmsg ); assert( #assertion &&0 ); abort(); } +#define WPFatal( assertion, errmsg ) if ( ! (assertion) ) { sLog->outError( "\n%s:%i in %s FATAL ERROR:\n %s\n", __FILE__, __LINE__, __FUNCTION__, (char *)errmsg ); ACE_OS::sleep(10); assert( #assertion &&0 ); abort(); } #define ASSERT WPAssert #endif diff --git a/src/server/shared/Threading/Callback.h b/src/server/shared/Threading/Callback.h index b179b215253..6ec2f49c8ff 100755 --- a/src/server/shared/Threading/Callback.h +++ b/src/server/shared/Threading/Callback.h @@ -29,107 +29,178 @@ typedef ACE_Future<PreparedQueryResult> PreparedQueryResultFuture; issued the request. <ParamType> is variable type of parameter that is used as parameter for the callback function. */ -template <typename Result, typename ParamType> +#define CALLBACK_STAGE_INVALID uint8(-1) + +template <typename Result, typename ParamType, bool chain = false> class QueryCallback { public: - QueryCallback() {} + QueryCallback() : _stage(chain ? 0 : CALLBACK_STAGE_INVALID) {} + //! The parameter of this function should be a resultset returned from either .AsyncQuery or .AsyncPQuery void SetFutureResult(ACE_Future<Result> value) { - result = value; + _result = value; } ACE_Future<Result> GetFutureResult() { - return result; + return _result; } int IsReady() { - return result.ready(); + return _result.ready(); } void GetResult(Result& res) { - result.get(res); + _result.get(res); } void FreeResult() { - result.cancel(); + _result.cancel(); } void SetParam(ParamType value) { - param = value; + _param = value; } ParamType GetParam() { - return param; + return _param; + } + + //! Resets the stage of the callback chain + void ResetStage() + { + if (!chain) + return; + + _stage = 0; + } + + //! Advances the callback chain to the next stage, so upper level code can act on its results accordingly + void NextStage() + { + if (!chain) + return; + + ++_stage; + } + + //! Returns the callback stage (or CALLBACK_STAGE_INVALID if invalid) + uint8 GetStage() + { + return _stage; + } + + //! Resets all underlying variables (param, result and stage) + void Reset() + { + SetParam(NULL); + FreeResult(); + ResetStage(); } private: - ACE_Future<Result> result; - ParamType param; + ACE_Future<Result> _result; + ParamType _param; + uint8 _stage; }; -template <typename Result, typename ParamType1, typename ParamType2> +template <typename Result, typename ParamType1, typename ParamType2, bool chain = false> class QueryCallback_2 { public: - QueryCallback_2() {} + QueryCallback_2() : _stage(chain ? 0 : CALLBACK_STAGE_INVALID) {} + //! The parameter of this function should be a resultset returned from either .AsyncQuery or .AsyncPQuery void SetFutureResult(ACE_Future<Result> value) { - result = value; + _result = value; } ACE_Future<Result> GetFutureResult() { - return result; + return _result; } int IsReady() { - return result.ready(); + return _result.ready(); } void GetResult(Result& res) { - result.get(res); + _result.get(res); } void FreeResult() { - result.cancel(); + _result.cancel(); } void SetFirstParam(ParamType1 value) { - param_1 = value; + _param_1 = value; } void SetSecondParam(ParamType2 value) { - param_2 = value; + _param_2 = value; } ParamType1 GetFirstParam() { - return param_1; + return _param_1; } ParamType2 GetSecondParam() { - return param_2; + return _param_2; + } + + //! Resets the stage of the callback chain + void ResetStage() + { + if (!chain) + return; + + _stage = 0; + } + + //! Advances the callback chain to the next stage, so upper level code can act on its results accordingly + void NextStage() + { + if (!chain) + return; + + ++_stage; + } + + //! Returns the callback stage (or CALLBACK_STAGE_INVALID if invalid) + uint8 GetStage() + { + return _stage; + } + + //! Resets all underlying variables (param, result and stage) + void Reset() + { + SetFirstParam(NULL); + SetSecondParam(NULL); + FreeResult(); + ResetStage(); } private: - ACE_Future<Result> result; - ParamType1 param_1; - ParamType2 param_2; + ACE_Future<Result> _result; + ParamType1 _param_1; + ParamType2 _param_2; + uint8 _stage; }; #endif
\ No newline at end of file diff --git a/src/server/shared/Threading/LockedQueue.h b/src/server/shared/Threading/LockedQueue.h index 92eab440684..4d2ddd33f5f 100755 --- a/src/server/shared/Threading/LockedQueue.h +++ b/src/server/shared/Threading/LockedQueue.h @@ -98,13 +98,16 @@ namespace ACE_Based return true; } - //! Peeks at the top of the queue. Remember to unlock after use. - T& peek() + //! Peeks at the top of the queue. Check if the queue is empty before calling! Remember to unlock after use if autoUnlock == false. + T& peek(bool autoUnlock = false) { lock(); T& result = _queue.front(); + if (autoUnlock) + unlock(); + return result; } diff --git a/src/server/worldserver/CommandLine/CliRunnable.cpp b/src/server/worldserver/CommandLine/CliRunnable.cpp index 564f6028eca..61352521d9f 100755 --- a/src/server/worldserver/CommandLine/CliRunnable.cpp +++ b/src/server/worldserver/CommandLine/CliRunnable.cpp @@ -104,7 +104,7 @@ void utf8print(void* /*arg*/, const char* str) printf(temp_buf); #else { - printf(str); + printf("%s", str); fflush(stdout); } #endif diff --git a/src/server/worldserver/RemoteAccess/RASocket.cpp b/src/server/worldserver/RemoteAccess/RASocket.cpp index 71d4d1df035..82238ee54bc 100755 --- a/src/server/worldserver/RemoteAccess/RASocket.cpp +++ b/src/server/worldserver/RemoteAccess/RASocket.cpp @@ -286,7 +286,7 @@ int RASocket::subnegotiate() if (n >= 1024) { - sLog->outRemote("RASocket::subnegotiate: allocated buffer 1024 bytes was too small for negotiation packet, size: %u", n); + sLog->outRemote("RASocket::subnegotiate: allocated buffer 1024 bytes was too small for negotiation packet, size: %u", uint32(n)); return -1; } diff --git a/src/server/worldserver/worldserver.conf.dist b/src/server/worldserver/worldserver.conf.dist index a8c0d91b2e6..1e37f50aa63 100644 --- a/src/server/worldserver/worldserver.conf.dist +++ b/src/server/worldserver/worldserver.conf.dist @@ -1744,7 +1744,8 @@ Channel.RestrictedLfg = 1 # # Channel.SilentlyGMJoin -# Description: Silently join GM characters to channels +# Description: Silently join GM characters to channels. If set to 1, channel kick and ban +# commands issued by a GM will not be broadcasted. # Default: 0 - (Disabled, Join with announcement) # 1 - (Enabled, Join without announcement) |