diff options
Diffstat (limited to 'src')
137 files changed, 2739 insertions, 1424 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/Accounts/AccountMgr.cpp b/src/server/game/Accounts/AccountMgr.cpp index ebe9a9af36b..6c3dd69c0da 100755 --- a/src/server/game/Accounts/AccountMgr.cpp +++ b/src/server/game/Accounts/AccountMgr.cpp @@ -37,8 +37,16 @@ AccountOpResult CreateAccount(std::string username, std::string password) if (GetId(username)) return AOR_NAME_ALREDY_EXIST; // username does already exist - LoginDatabase.PExecute("INSERT INTO account(username, sha_pass_hash, joindate) VALUES('%s', '%s', NOW())", username.c_str(), CalculateShaPassHash(username, password).c_str()); - LoginDatabase.Execute("INSERT INTO realmcharacters (realmid, acctid, numchars) SELECT realmlist.id, account.id, 0 FROM realmlist, account LEFT JOIN realmcharacters ON acctid=account.id WHERE acctid IS NULL"); + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_ADD_ACCOUNT); + + stmt->setString(0, username); + stmt->setString(1, CalculateShaPassHash(username, password)); + + LoginDatabase.Execute(stmt); + + stmt = LoginDatabase.GetPreparedStatement(LOGIN_ADD_REALM_CHARS); + + LoginDatabase.Execute(stmt); return AOR_OK; // everything's fine } @@ -104,11 +112,13 @@ AccountOpResult ChangeUsername(uint32 accountId, std::string newUsername, std::s normalizeString(newUsername); normalizeString(newPassword); - std::string safeNewUsername = newUsername; - LoginDatabase.EscapeString(safeNewUsername); + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPDATE_USERNAME); - LoginDatabase.PExecute("UPDATE account SET v='0', s='0', username='%s', sha_pass_hash='%s' WHERE id='%d'", safeNewUsername.c_str(), - CalculateShaPassHash(newUsername, newPassword).c_str(), accountId); + stmt->setString(0, newUsername); + stmt->setString(1, CalculateShaPassHash(newUsername, newPassword)); + stmt->setUInt32(2, accountId); + + LoginDatabase.Execute(stmt); return AOR_OK; } @@ -126,9 +136,12 @@ AccountOpResult ChangePassword(uint32 accountId, std::string newPassword) normalizeString(username); normalizeString(newPassword); - // also reset s and v to force update at next realmd login - LoginDatabase.PExecute("UPDATE account SET v='0', s='0', sha_pass_hash='%s' WHERE id='%d'", - CalculateShaPassHash(username, newPassword).c_str(), accountId); + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPDATE_PASSWORD); + + stmt->setString(0, CalculateShaPassHash(username, newPassword)); + stmt->setUInt32(1, accountId); + + LoginDatabase.Execute(stmt); return AOR_OK; } diff --git a/src/server/game/Achievements/AchievementMgr.cpp b/src/server/game/Achievements/AchievementMgr.cpp index 8967446f199..030837b2649 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) @@ -618,7 +619,13 @@ void AchievementMgr::LoadFromDB(PreparedQueryResult achievementResult, PreparedQ { // we will remove not existed criteria for all characters sLog->outError("Non-existing achievement criteria %u data removed from table `character_achievement_progress`.", id); - CharacterDatabase.PExecute("DELETE FROM character_achievement_progress WHERE criteria = %u", id); + + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_INVALID_ACHIEV_PROGRESS_CRITERIA); + + stmt->setUInt16(0, uint16(id)); + + CharacterDatabase.Execute(stmt); + continue; } @@ -846,6 +853,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 +1075,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 +1602,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 +1626,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 +1767,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 +2001,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 +2116,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) @@ -2392,16 +2381,23 @@ void AchievementGlobalMgr::LoadCompletedAchievements() { Field* fields = result->Fetch(); - uint32 achievement_id = fields[0].GetUInt32(); - if (!sAchievementStore.LookupEntry(achievement_id)) + uint32 achievementId = fields[0].GetUInt32(); + const AchievementEntry* achievement = sAchievementStore.LookupEntry(achievementId); + 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); + // Remove non existent achievements from all characters + sLog->outError("Non-existing achievement %u data removed from table `character_achievement`.", achievementId); + + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_INVALID_ACHIEVMENT); + + stmt->setUInt16(0, uint16(achievementId)); + + CharacterDatabase.Execute(stmt); + continue; } - - m_allCompletedAchievements.insert(achievement_id); + else if (achievement->flags & (ACHIEVEMENT_FLAG_REALM_FIRST_REACH | ACHIEVEMENT_FLAG_REALM_FIRST_KILL)) + m_allCompletedAchievements.insert(achievementId); } 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/Addons/AddonMgr.cpp b/src/server/game/Addons/AddonMgr.cpp index 9d5bdd159f7..ff6d16bef4d 100755 --- a/src/server/game/Addons/AddonMgr.cpp +++ b/src/server/game/Addons/AddonMgr.cpp @@ -70,8 +70,13 @@ void LoadFromDB() void SaveAddon(AddonInfo const& addon) { std::string name = addon.Name; - CharacterDatabase.EscapeString(name); - CharacterDatabase.PExecute("INSERT INTO addons (name, crc) VALUES ('%s', %u)", name.c_str(), addon.CRC); + + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_ADD_ADDON); + + stmt->setString(0, name); + stmt->setUInt32(1, addon.CRC); + + CharacterDatabase.Execute(stmt); m_knownAddons.push_back(SavedAddon(addon.Name, addon.CRC)); } 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/Chat.h b/src/server/game/Chat/Chat.h index 24652fcc6d5..d9190265bbb 100755 --- a/src/server/game/Chat/Chat.h +++ b/src/server/game/Chat/Chat.h @@ -154,8 +154,8 @@ class ChatHandler bool HandleCastTargetCommand(const char *args); bool HandleCastDestCommand(const char *args); - bool HandleCharacterCustomizeCommand(const char * args); - bool HandleCharacterChangeFactionCommand(const char * args); + bool HandleCharacterCustomizeCommand(const char* args); + bool HandleCharacterChangeFactionCommand(const char* args); bool HandleCharacterChangeRaceCommand(const char * args); bool HandleCharacterDeletedDeleteCommand(const char* args); bool HandleCharacterDeletedListCommand(const char* args); @@ -163,7 +163,7 @@ class ChatHandler bool HandleCharacterDeletedOldCommand(const char* args); bool HandleCharacterEraseCommand(const char* args); bool HandleCharacterLevelCommand(const char* args); - bool HandleCharacterRenameCommand(const char * args); + bool HandleCharacterRenameCommand(const char* args); bool HandleCharacterReputationCommand(const char* args); bool HandleCharacterTitlesCommand(const char* args); @@ -215,9 +215,9 @@ class ChatHandler bool HandleResetAllCommand(const char * args); bool HandleResetHonorCommand(const char * args); bool HandleResetLevelCommand(const char * args); - bool HandleResetSpellsCommand(const char * args); + bool HandleResetSpellsCommand(const char* args); bool HandleResetStatsCommand(const char * args); - bool HandleResetTalentsCommand(const char * args); + bool HandleResetTalentsCommand(const char* args); bool HandleSendItemsCommand(const char* args); bool HandleSendMailCommand(const char* args); @@ -355,7 +355,7 @@ class ChatHandler bool HandleBanHelper(BanMode mode, char const* args); bool HandleBanInfoHelper(uint32 accountid, char const* accountname); bool HandleUnBanHelper(BanMode mode, char const* args); - void HandleCharacterLevel(Player* player, uint64 player_guid, uint32 oldlevel, uint32 newlevel); + void HandleCharacterLevel(Player* player, uint64 playerGuid, uint32 oldLevel, uint32 newLevel); void HandleLearnSkillRecipesHelper(Player* player, uint32 skill_id); // Stores informations about a deleted character 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/Level2.cpp b/src/server/game/Chat/Commands/Level2.cpp index 41bc564759c..5411b1364c0 100755 --- a/src/server/game/Chat/Commands/Level2.cpp +++ b/src/server/game/Chat/Commands/Level2.cpp @@ -63,11 +63,11 @@ bool ChatHandler::HandleMuteCommand(const char* args) if (!extractPlayerTarget(nameStr, &target, &target_guid, &target_name)) return false; - uint32 account_id = target ? target->GetSession()->GetAccountId() : sObjectMgr->GetPlayerAccountIdByGUID(target_guid); + uint32 accountId = target ? target->GetSession()->GetAccountId() : sObjectMgr->GetPlayerAccountIdByGUID(target_guid); // find only player from same account if any if (!target) - if (WorldSession* session = sWorld->FindSession(account_id)) + if (WorldSession* session = sWorld->FindSession(accountId)) target = session->GetPlayer(); uint32 notspeaktime = (uint32) atoi(delayStr); @@ -76,21 +76,30 @@ bool ChatHandler::HandleMuteCommand(const char* args) if (HasLowerSecurity (target, target_guid, true)) return false; + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPDATE_MUTE_TIME); + if (target) { - //! Target is online, mute will be in effect right away. - int64 mutetime = time(NULL) + notspeaktime * MINUTE; - target->GetSession()->m_muteTime = mutetime; - LoginDatabase.PExecute("UPDATE account SET mutetime = " SI64FMTD " WHERE id = '%u'", mutetime, account_id); + // Target is online, mute will be in effect right away. + int64 muteTime = time(NULL) + notspeaktime * MINUTE; + target->GetSession()->m_muteTime = muteTime; + + stmt->setInt64(0, muteTime); + ChatHandler(target).PSendSysMessage(LANG_YOUR_CHAT_DISABLED, notspeaktime, mutereasonstr.c_str()); } else { - //! Target is offline, mute will be in effect starting from the next login. + // Target is offline, mute will be in effect starting from the next login. int32 muteTime = -int32(notspeaktime * MINUTE); - LoginDatabase.PExecute("UPDATE account SET mutetime = %d WHERE id = %u", muteTime, account_id); + + stmt->setInt64(0, muteTime); } + stmt->setUInt32(1, accountId); + + LoginDatabase.Execute(stmt); + std::string nameLink = playerLink(target_name); PSendSysMessage(target ? LANG_YOU_DISABLE_CHAT : LANG_COMMAND_DISABLE_CHAT_DELAYED, nameLink.c_str(), notspeaktime, mutereasonstr.c_str()); @@ -107,11 +116,11 @@ bool ChatHandler::HandleUnmuteCommand(const char* args) if (!extractPlayerTarget((char*)args, &target, &target_guid, &target_name)) return false; - uint32 account_id = target ? target->GetSession()->GetAccountId() : sObjectMgr->GetPlayerAccountIdByGUID(target_guid); + uint32 accountId = target ? target->GetSession()->GetAccountId() : sObjectMgr->GetPlayerAccountIdByGUID(target_guid); // find only player from same account if any if (!target) - if (WorldSession* session = sWorld->FindSession(account_id)) + if (WorldSession* session = sWorld->FindSession(accountId)) target = session->GetPlayer(); // must have strong lesser security level @@ -130,7 +139,12 @@ bool ChatHandler::HandleUnmuteCommand(const char* args) target->GetSession()->m_muteTime = 0; } - LoginDatabase.PExecute("UPDATE account SET mutetime = '0' WHERE id = '%u'", account_id); + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPDATE_MUTE_TIME); + + stmt->setInt64(0, 0); + stmt->setUInt32(1, accountId); + + LoginDatabase.Execute(stmt); if (target) ChatHandler(target).PSendSysMessage(LANG_YOUR_CHAT_ENABLED); @@ -441,9 +455,9 @@ bool ChatHandler::HandlePInfoCommand(const char* args) bool ChatHandler::HandleCharacterRenameCommand(const char* args) { Player* target; - uint64 target_guid; - std::string target_name; - if (!extractPlayerTarget((char*)args, &target, &target_guid, &target_name)) + uint64 targetGuid; + std::string targetName; + if (!extractPlayerTarget((char*)args, &target, &targetGuid, &targetName)) return false; if (target) @@ -458,13 +472,19 @@ bool ChatHandler::HandleCharacterRenameCommand(const char* args) else { // check offline security - if (HasLowerSecurity(NULL, target_guid)) + if (HasLowerSecurity(NULL, targetGuid)) return false; - std::string oldNameLink = playerLink(target_name); + std::string oldNameLink = playerLink(targetName); + + PSendSysMessage(LANG_RENAME_PLAYER_GUID, oldNameLink.c_str(), GUID_LOPART(targetGuid)); + + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPDATE_AT_LOGIN_FLAG); - PSendSysMessage(LANG_RENAME_PLAYER_GUID, oldNameLink.c_str(), GUID_LOPART(target_guid)); - CharacterDatabase.PExecute("UPDATE characters SET at_login = at_login | '1' WHERE guid = '%u'", GUID_LOPART(target_guid)); + stmt->setUInt16(0, uint16(AT_LOGIN_RENAME)); + stmt->setUInt32(1, GUID_LOPART(targetGuid)); + + CharacterDatabase.Execute(stmt); } return true; @@ -474,80 +494,102 @@ bool ChatHandler::HandleCharacterRenameCommand(const char* args) bool ChatHandler::HandleCharacterCustomizeCommand(const char* args) { Player* target; - uint64 target_guid; - std::string target_name; - if (!extractPlayerTarget((char*)args, &target, &target_guid, &target_name)) + uint64 targetGuid; + std::string targetName; + if (!extractPlayerTarget((char*)args, &target, &targetGuid, &targetName)) return false; + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPDATE_AT_LOGIN_FLAG); + + stmt->setUInt16(0, uint16(AT_LOGIN_CUSTOMIZE)); + if (target) { PSendSysMessage(LANG_CUSTOMIZE_PLAYER, GetNameLink(target).c_str()); target->SetAtLoginFlag(AT_LOGIN_CUSTOMIZE); - CharacterDatabase.PExecute("UPDATE characters SET at_login = at_login | '8' WHERE guid = '%u'", target->GetGUIDLow()); + + stmt->setUInt32(1, target->GetGUIDLow()); } else { - std::string oldNameLink = playerLink(target_name); + std::string oldNameLink = playerLink(targetName); - PSendSysMessage(LANG_CUSTOMIZE_PLAYER_GUID, oldNameLink.c_str(), GUID_LOPART(target_guid)); - CharacterDatabase.PExecute("UPDATE characters SET at_login = at_login | '8' WHERE guid = '%u'", GUID_LOPART(target_guid)); + stmt->setUInt32(1, GUID_LOPART(targetGuid)); + + PSendSysMessage(LANG_CUSTOMIZE_PLAYER_GUID, oldNameLink.c_str(), GUID_LOPART(targetGuid)); } + CharacterDatabase.Execute(stmt); + return true; } -bool ChatHandler::HandleCharacterChangeFactionCommand(const char * args) +bool ChatHandler::HandleCharacterChangeFactionCommand(const char* args) { Player* target; - uint64 target_guid; - std::string target_name; + uint64 targetGuid; + std::string targetName; - if (!extractPlayerTarget((char*)args, &target, &target_guid, &target_name)) + if (!extractPlayerTarget((char*)args, &target, &targetGuid, &targetName)) return false; + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPDATE_AT_LOGIN_FLAG); + + stmt->setUInt16(0, uint16(AT_LOGIN_CHANGE_FACTION)); + if (target) { - // TODO : add text into database PSendSysMessage(LANG_CUSTOMIZE_PLAYER, GetNameLink(target).c_str()); target->SetAtLoginFlag(AT_LOGIN_CHANGE_FACTION); - CharacterDatabase.PExecute("UPDATE characters SET at_login = at_login | '64' WHERE guid = %u", target->GetGUIDLow()); + + stmt->setUInt32(1, target->GetGUIDLow()); } else { - std::string oldNameLink = playerLink(target_name); + std::string oldNameLink = playerLink(targetName); - // TODO : add text into database - PSendSysMessage(LANG_CUSTOMIZE_PLAYER_GUID, oldNameLink.c_str(), GUID_LOPART(target_guid)); - CharacterDatabase.PExecute("UPDATE characters SET at_login = at_login | '64' WHERE guid = %u", GUID_LOPART(target_guid)); + PSendSysMessage(LANG_CUSTOMIZE_PLAYER_GUID, oldNameLink.c_str(), GUID_LOPART(targetGuid)); + + stmt->setUInt32(1, GUID_LOPART(targetGuid)); } + CharacterDatabase.Execute(stmt); + return true; } bool ChatHandler::HandleCharacterChangeRaceCommand(const char * args) { Player* target; - uint64 target_guid; - std::string target_name; - if (!extractPlayerTarget((char*)args, &target, &target_guid, &target_name)) + uint64 targetGuid; + std::string targetName; + if (!extractPlayerTarget((char*)args, &target, &targetGuid, &targetName)) return false; + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPDATE_AT_LOGIN_FLAG); + + stmt->setUInt16(0, uint16(AT_LOGIN_CHANGE_FACTION)); + if (target) { // TODO : add text into database PSendSysMessage(LANG_CUSTOMIZE_PLAYER, GetNameLink(target).c_str()); target->SetAtLoginFlag(AT_LOGIN_CHANGE_RACE); - CharacterDatabase.PExecute("UPDATE characters SET at_login = at_login | '128' WHERE guid = %u", target->GetGUIDLow()); + + stmt->setUInt32(1, target->GetGUIDLow()); } else { - std::string oldNameLink = playerLink(target_name); + std::string oldNameLink = playerLink(targetName); // TODO : add text into database - PSendSysMessage(LANG_CUSTOMIZE_PLAYER_GUID, oldNameLink.c_str(), GUID_LOPART(target_guid)); - CharacterDatabase.PExecute("UPDATE characters SET at_login = at_login | '128' WHERE guid = %u", GUID_LOPART(target_guid)); + PSendSysMessage(LANG_CUSTOMIZE_PLAYER_GUID, oldNameLink.c_str(), GUID_LOPART(targetGuid)); + + stmt->setUInt32(1, GUID_LOPART(targetGuid)); } + CharacterDatabase.Execute(stmt); + return true; } diff --git a/src/server/game/Chat/Commands/Level3.cpp b/src/server/game/Chat/Commands/Level3.cpp index f4f5892b587..9b29483bcb4 100755 --- a/src/server/game/Chat/Commands/Level3.cpp +++ b/src/server/game/Chat/Commands/Level3.cpp @@ -2177,28 +2177,33 @@ bool ChatHandler::HandleHoverCommand(const char *args) return true; } -void ChatHandler::HandleCharacterLevel(Player* player, uint64 player_guid, uint32 oldlevel, uint32 newlevel) +void ChatHandler::HandleCharacterLevel(Player* player, uint64 playerGuid, uint32 oldLevel, uint32 newLevel) { if (player) { - player->GiveLevel(newlevel); + player->GiveLevel(newLevel); player->InitTalentForLevel(); player->SetUInt32Value(PLAYER_XP, 0); if (needReportToTarget(player)) { - if (oldlevel == newlevel) + if (oldLevel == newLevel) ChatHandler(player).PSendSysMessage(LANG_YOURS_LEVEL_PROGRESS_RESET, GetNameLink().c_str()); - else if (oldlevel < newlevel) - ChatHandler(player).PSendSysMessage(LANG_YOURS_LEVEL_UP, GetNameLink().c_str(), newlevel); + else if (oldLevel < newLevel) + ChatHandler(player).PSendSysMessage(LANG_YOURS_LEVEL_UP, GetNameLink().c_str(), newLevel); else // if (oldlevel > newlevel) - ChatHandler(player).PSendSysMessage(LANG_YOURS_LEVEL_DOWN, GetNameLink().c_str(), newlevel); + ChatHandler(player).PSendSysMessage(LANG_YOURS_LEVEL_DOWN, GetNameLink().c_str(), newLevel); } } else { - // update level and XP at level, all other will be updated at loading - CharacterDatabase.PExecute("UPDATE characters SET level = '%u', xp = 0 WHERE guid = '%u'", newlevel, GUID_LOPART(player_guid)); + // Update level and reset XP, everything else will be updated at login + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPDATE_LEVEL); + + stmt->setUInt8(0, uint8(newLevel)); + stmt->setUInt32(1, GUID_LOPART(playerGuid)); + + CharacterDatabase.Execute(stmt); } } @@ -2562,12 +2567,12 @@ bool ChatHandler::HandleResetStatsCommand(const char * args) return true; } -bool ChatHandler::HandleResetSpellsCommand(const char * args) +bool ChatHandler::HandleResetSpellsCommand(const char* args) { Player* target; - uint64 target_guid; - std::string target_name; - if (!extractPlayerTarget((char*)args, &target, &target_guid, &target_name)) + uint64 targetGuid; + std::string targetName; + if (!extractPlayerTarget((char*)args, &target, &targetGuid, &targetName)) return false; if (target) @@ -2580,19 +2585,25 @@ bool ChatHandler::HandleResetSpellsCommand(const char * args) } else { - CharacterDatabase.PExecute("UPDATE characters SET at_login = at_login | '%u' WHERE guid = '%u'", uint32(AT_LOGIN_RESET_SPELLS), GUID_LOPART(target_guid)); - PSendSysMessage(LANG_RESET_SPELLS_OFFLINE, target_name.c_str()); + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPDATE_AT_LOGIN_FLAG); + + stmt->setUInt16(0, uint16(AT_LOGIN_RESET_SPELLS)); + stmt->setUInt32(1, GUID_LOPART(targetGuid)); + + CharacterDatabase.Execute(stmt); + + PSendSysMessage(LANG_RESET_SPELLS_OFFLINE, targetName.c_str()); } return true; } -bool ChatHandler::HandleResetTalentsCommand(const char * args) +bool ChatHandler::HandleResetTalentsCommand(const char* args) { Player* target; - uint64 target_guid; - std::string target_name; - if (!extractPlayerTarget((char*)args, &target, &target_guid, &target_name)) + uint64 targetGuid; + std::string targetName; + if (!extractPlayerTarget((char*)args, &target, &targetGuid, &targetName)) { // Try reset talents as Hunter Pet Creature* creature = getSelectedCreature(); @@ -2630,11 +2641,16 @@ bool ChatHandler::HandleResetTalentsCommand(const char * args) target->SendTalentsInfoData(true); return true; } - else if (target_guid) + else if (targetGuid) { - uint32 at_flags = AT_LOGIN_NONE | AT_LOGIN_RESET_PET_TALENTS; - CharacterDatabase.PExecute("UPDATE characters SET at_login = at_login | '%u' WHERE guid = '%u'", at_flags, GUID_LOPART(target_guid)); - std::string nameLink = playerLink(target_name); + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPDATE_AT_LOGIN_FLAG); + + stmt->setUInt16(0, uint16(AT_LOGIN_NONE | AT_LOGIN_RESET_PET_TALENTS)); + stmt->setUInt32(1, GUID_LOPART(targetGuid)); + + CharacterDatabase.Execute(stmt); + + std::string nameLink = playerLink(targetName); PSendSysMessage(LANG_RESET_TALENTS_OFFLINE, nameLink.c_str()); return true; } @@ -2675,7 +2691,11 @@ bool ChatHandler::HandleResetAllCommand(const char * args) return false; } - CharacterDatabase.PExecute("UPDATE characters SET at_login = at_login | '%u' WHERE (at_login & '%u') = '0'", atLogin, atLogin); + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPDATE_ALL_AT_LOGIN_FLAGS); + + stmt->setUInt16(0, uint16(atLogin)); + + CharacterDatabase.Execute(stmt); TRINITY_READ_GUARD(HashMapHolder<Player>::LockType, *HashMapHolder<Player>::GetLock()); HashMapHolder<Player>::MapType const& plist = sObjectAccessor->GetPlayers(); @@ -3280,7 +3300,8 @@ bool ChatHandler::HandleBanListCharacterCommand(const char *args) bool ChatHandler::HandleBanListAccountCommand(const char *args) { - LoginDatabase.Execute("DELETE FROM ip_banned WHERE unbandate <= UNIX_TIMESTAMP() AND unbandate<>bandate"); + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_DEL_OLD_BANS); + LoginDatabase.Execute(stmt); char* cFilter = strtok((char*)args, " "); std::string filter = cFilter ? cFilter : ""; @@ -3385,7 +3406,8 @@ bool ChatHandler::HandleBanListHelper(QueryResult result) bool ChatHandler::HandleBanListIPCommand(const char *args) { - LoginDatabase.Execute("DELETE FROM ip_banned WHERE unbandate <= UNIX_TIMESTAMP() AND unbandate<>bandate"); + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_DEL_OLD_IP_BANS); + LoginDatabase.Execute(stmt); char* cFilter = strtok((char*)args, " "); std::string filter = cFilter ? cFilter : ""; 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..df7aa90982e 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; @@ -770,8 +770,18 @@ void GameObject::DeleteFromDB() { sObjectMgr->RemoveGORespawnTime(m_DBTableGuid, GetInstanceId()); sObjectMgr->DeleteGOData(m_DBTableGuid); - WorldDatabase.PExecute("DELETE FROM gameobject WHERE guid = '%u'", m_DBTableGuid); - WorldDatabase.PExecute("DELETE FROM game_event_gameobject WHERE guid = '%u'", m_DBTableGuid); + + PreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_DEL_GAMEOBJECT); + + stmt->setUInt32(0, m_DBTableGuid); + + WorldDatabase.Execute(stmt); + + stmt = WorldDatabase.GetPreparedStatement(WORLD_DEL_EVENT_GAMEOBJECT); + + stmt->setUInt32(0, m_DBTableGuid); + + WorldDatabase.Execute(stmt); } GameObject* GameObject::GetGameObject(WorldObject& object, uint64 guid) 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..eb590e7b82f 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; @@ -1248,24 +1247,29 @@ void Pet::_SaveAuras(SQLTransaction& trans) } } -bool Pet::addSpell(uint32 spell_id, ActiveStates active /*= ACT_DECIDE*/, PetSpellState state /*= PETSPELL_NEW*/, PetSpellType type /*= PETSPELL_NORMAL*/) +bool Pet::addSpell(uint32 spellId, ActiveStates active /*= ACT_DECIDE*/, PetSpellState state /*= PETSPELL_NEW*/, PetSpellType type /*= PETSPELL_NORMAL*/) { - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spell_id); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId); if (!spellInfo) { // do pet spell book cleanup if (state == PETSPELL_UNCHANGED) // spell load case { - sLog->outError("Pet::addSpell: Non-existed in SpellStore spell #%u request, deleting for all pets in `pet_spell`.", spell_id); - CharacterDatabase.PExecute("DELETE FROM pet_spell WHERE spell = '%u'", spell_id); + sLog->outError("Pet::addSpell: Non-existed in SpellStore spell #%u request, deleting for all pets in `pet_spell`.", spellId); + + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_INVALID_PET_SPELL); + + stmt->setUInt32(0, spellId); + + CharacterDatabase.Execute(stmt); } else - sLog->outError("Pet::addSpell: Non-existed in SpellStore spell #%u request.", spell_id); + sLog->outError("Pet::addSpell: Non-existed in SpellStore spell #%u request.", spellId); return false; } - PetSpellMap::iterator itr = m_spells.find(spell_id); + PetSpellMap::iterator itr = m_spells.find(spellId); if (itr != m_spells.end()) { if (itr->second.state == PETSPELL_REMOVED) @@ -1304,7 +1308,7 @@ bool Pet::addSpell(uint32 spell_id, ActiveStates active /*= ACT_DECIDE*/, PetSpe newspell.active = active; // talent: unlearn all other talent ranks (high and low) - if (TalentSpellPos const* talentPos = GetTalentSpellPos(spell_id)) + if (TalentSpellPos const* talentPos = GetTalentSpellPos(spellId)) { if (TalentEntry const* talentInfo = sTalentStore.LookupEntry(talentPos->talent_id)) { @@ -1312,7 +1316,7 @@ bool Pet::addSpell(uint32 spell_id, ActiveStates active /*= ACT_DECIDE*/, PetSpe { // skip learning spell and no rank spell case uint32 rankSpellId = talentInfo->RankID[i]; - if (!rankSpellId || rankSpellId == spell_id) + if (!rankSpellId || rankSpellId == spellId) continue; // skip unknown ranks @@ -1353,17 +1357,17 @@ bool Pet::addSpell(uint32 spell_id, ActiveStates active /*= ACT_DECIDE*/, PetSpe } } - m_spells[spell_id] = newspell; + m_spells[spellId] = newspell; if (spellInfo->IsPassive() && (!spellInfo->CasterAuraState || HasAuraState(AuraStateType(spellInfo->CasterAuraState)))) - CastSpell(this, spell_id, true); + CastSpell(this, spellId, true); else m_charmInfo->AddSpellToActionBar(spellInfo); if (newspell.active == ACT_ENABLED) ToggleAutocast(spellInfo, true); - uint32 talentCost = GetTalentSpellCost(spell_id); + uint32 talentCost = GetTalentSpellCost(spellId); if (talentCost) { int32 free_points = GetMaxTalentPointsForLevel(getLevel()); diff --git a/src/server/game/Entities/Pet/Pet.h b/src/server/game/Entities/Pet/Pet.h index 973e5e99bee..ac86c061b31 100755 --- a/src/server/game/Entities/Pet/Pet.h +++ b/src/server/game/Entities/Pet/Pet.h @@ -192,7 +192,7 @@ class Pet : public Guardian void _LoadSpells(); void _SaveSpells(SQLTransaction& trans); - bool addSpell(uint32 spell_id, ActiveStates active = ACT_DECIDE, PetSpellState state = PETSPELL_NEW, PetSpellType type = PETSPELL_NORMAL); + bool addSpell(uint32 spellId, ActiveStates active = ACT_DECIDE, PetSpellState state = PETSPELL_NEW, PetSpellType type = PETSPELL_NORMAL); bool learnSpell(uint32 spell_id); void learnSpellHighRank(uint32 spellid); void InitLevelupSpellsForLevel(); diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 0e98eb27596..235613c11c4 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)) @@ -3439,19 +3416,24 @@ void Player::AddNewMailDeliverTime(time_t deliver_time) } } -bool Player::AddTalent(uint32 spell_id, uint8 spec, bool learning) +bool Player::AddTalent(uint32 spellId, uint8 spec, bool learning) { - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spell_id); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId); if (!spellInfo) { // do character spell book cleanup (all characters) if (!IsInWorld() && !learning) // spell load case { - sLog->outError("Player::addSpell: Non-existed in SpellStore spell #%u request, deleting for all characters in `character_spell`.", spell_id); - CharacterDatabase.PExecute("DELETE FROM character_talent WHERE spell = '%u'", spell_id); + sLog->outError("Player::addSpell: Non-existed in SpellStore spell #%u request, deleting for all characters in `character_spell`.", spellId); + + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_INVALID_SPELL); + + stmt->setUInt32(0, spellId); + + CharacterDatabase.Execute(stmt); } else - sLog->outError("Player::addSpell: Non-existed in SpellStore spell #%u request.", spell_id); + sLog->outError("Player::addSpell: Non-existed in SpellStore spell #%u request.", spellId); return false; } @@ -3461,19 +3443,24 @@ bool Player::AddTalent(uint32 spell_id, uint8 spec, bool learning) // do character spell book cleanup (all characters) if (!IsInWorld() && !learning) // spell load case { - sLog->outError("Player::addTalent: Broken spell #%u learning not allowed, deleting for all characters in `character_talent`.", spell_id); - CharacterDatabase.PExecute("DELETE FROM character_talent WHERE spell = '%u'", spell_id); + sLog->outError("Player::addTalent: Broken spell #%u learning not allowed, deleting for all characters in `character_talent`.", spellId); + + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_INVALID_SPELL); + + stmt->setUInt32(0, spellId); + + CharacterDatabase.Execute(stmt); } else - sLog->outError("Player::addTalent: Broken spell #%u learning not allowed.", spell_id); + sLog->outError("Player::addTalent: Broken spell #%u learning not allowed.", spellId); return false; } - PlayerTalentMap::iterator itr = m_talents[spec]->find(spell_id); + PlayerTalentMap::iterator itr = m_talents[spec]->find(spellId); if (itr != m_talents[spec]->end()) itr->second->state = PLAYERSPELL_UNCHANGED; - else if (TalentSpellPos const* talentPos = GetTalentSpellPos(spell_id)) + else if (TalentSpellPos const* talentPos = GetTalentSpellPos(spellId)) { if (TalentEntry const* talentInfo = sTalentStore.LookupEntry(talentPos->talent_id)) { @@ -3481,7 +3468,7 @@ bool Player::AddTalent(uint32 spell_id, uint8 spec, bool learning) { // skip learning spell and no rank spell case uint32 rankSpellId = talentInfo->RankID[rank]; - if (!rankSpellId || rankSpellId == spell_id) + if (!rankSpellId || rankSpellId == spellId) continue; itr = m_talents[spec]->find(rankSpellId); @@ -3496,25 +3483,30 @@ bool Player::AddTalent(uint32 spell_id, uint8 spec, bool learning) newtalent->state = state; newtalent->spec = spec; - (*m_talents[spec])[spell_id] = newtalent; + (*m_talents[spec])[spellId] = newtalent; return true; } return false; } -bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool dependent, bool disabled, bool loading /*=false*/) +bool Player::addSpell(uint32 spellId, bool active, bool learning, bool dependent, bool disabled, bool loading /*= false*/) { - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spell_id); + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId); if (!spellInfo) { // do character spell book cleanup (all characters) if (!IsInWorld() && !learning) // spell load case { - sLog->outError("Player::addSpell: Non-existed in SpellStore spell #%u request, deleting for all characters in `character_spell`.", spell_id); - CharacterDatabase.PExecute("DELETE FROM character_spell WHERE spell = '%u'", spell_id); + sLog->outError("Player::addSpell: Non-existed in SpellStore spell #%u request, deleting for all characters in `character_spell`.", spellId); + + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_INVALID_SPELL); + + stmt->setUInt32(0, spellId); + + CharacterDatabase.Execute(stmt); } else - sLog->outError("Player::addSpell: Non-existed in SpellStore spell #%u request.", spell_id); + sLog->outError("Player::addSpell: Non-existed in SpellStore spell #%u request.", spellId); return false; } @@ -3524,11 +3516,16 @@ bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool dependen // do character spell book cleanup (all characters) if (!IsInWorld() && !learning) // spell load case { - sLog->outError("Player::addSpell: Broken spell #%u learning not allowed, deleting for all characters in `character_spell`.", spell_id); - CharacterDatabase.PExecute("DELETE FROM character_spell WHERE spell = '%u'", spell_id); + sLog->outError("Player::addSpell: Broken spell #%u learning not allowed, deleting for all characters in `character_spell`.", spellId); + + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_INVALID_SPELL); + + stmt->setUInt32(0, spellId); + + CharacterDatabase.Execute(stmt); } else - sLog->outError("Player::addSpell: Broken spell #%u learning not allowed.", spell_id); + sLog->outError("Player::addSpell: Broken spell #%u learning not allowed.", spellId); return false; } @@ -3539,18 +3536,18 @@ bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool dependen bool disabled_case = false; bool superceded_old = false; - PlayerSpellMap::iterator itr = m_spells.find(spell_id); + PlayerSpellMap::iterator itr = m_spells.find(spellId); // Remove temporary spell if found to prevent conflicts if (itr != m_spells.end() && itr->second->state == PLAYERSPELL_TEMPORARY) - RemoveTemporarySpell(spell_id); + RemoveTemporarySpell(spellId); else if (itr != m_spells.end()) { uint32 next_active_spell_id = 0; // fix activate state for non-stackable low rank (and find next spell for !active case) if (!spellInfo->IsStackableWithRanks() && spellInfo->IsRanked()) { - if (uint32 next = sSpellMgr->GetNextSpellInChain(spell_id)) + if (uint32 next = sSpellMgr->GetNextSpellInChain(spellId)) { if (HasSpell(next)) { @@ -3593,7 +3590,7 @@ bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool dependen if (active) { if (spellInfo->IsPassive() && IsNeedCastPassiveSpellAtLearn(spellInfo)) - CastSpell (this, spell_id, true); + CastSpell (this, spellId, true); } else if (IsInWorld()) { @@ -3601,14 +3598,14 @@ bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool dependen { // update spell ranks in spellbook and action bar WorldPacket data(SMSG_SUPERCEDED_SPELL, 4 + 4); - data << uint32(spell_id); + data << uint32(spellId); data << uint32(next_active_spell_id); GetSession()->SendPacket(&data); } else { WorldPacket data(SMSG_REMOVED_SPELL, 4); - data << uint32(spell_id); + data << uint32(spellId); GetSession()->SendPacket(&data); } } @@ -3652,7 +3649,7 @@ bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool dependen if (!disabled_case) // skip new spell adding if spell already known (disabled spells case) { // talent: unlearn all other talent ranks (high and low) - if (TalentSpellPos const* talentPos = GetTalentSpellPos(spell_id)) + if (TalentSpellPos const* talentPos = GetTalentSpellPos(spellId)) { if (TalentEntry const* talentInfo = sTalentStore.LookupEntry(talentPos->talent_id)) { @@ -3660,7 +3657,7 @@ bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool dependen { // skip learning spell and no rank spell case uint32 rankSpellId = talentInfo->RankID[rank]; - if (!rankSpellId || rankSpellId == spell_id) + if (!rankSpellId || rankSpellId == spellId) continue; removeSpell(rankSpellId, false, false); @@ -3668,7 +3665,7 @@ bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool dependen } } // non talent spell: learn low ranks (recursive call) - else if (uint32 prev_spell = sSpellMgr->GetPrevSpellInChain(spell_id)) + else if (uint32 prev_spell = sSpellMgr->GetPrevSpellInChain(spellId)) { if (!IsInWorld() || disabled) // at spells loading, no output, but allow save addSpell(prev_spell, active, true, true, disabled); @@ -3701,7 +3698,7 @@ bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool dependen { WorldPacket data(SMSG_SUPERCEDED_SPELL, 4 + 4); data << uint32(itr2->first); - data << uint32(spell_id); + data << uint32(spellId); GetSession()->SendPacket(&data); } @@ -3716,7 +3713,7 @@ bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool dependen if (IsInWorld()) // not send spell (re-/over-)learn packets at loading { WorldPacket data(SMSG_SUPERCEDED_SPELL, 4 + 4); - data << uint32(spell_id); + data << uint32(spellId); data << uint32(itr2->first); GetSession()->SendPacket(&data); } @@ -3731,31 +3728,31 @@ bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool dependen } } - m_spells[spell_id] = newspell; + m_spells[spellId] = newspell; // return false if spell disabled if (newspell->disabled) return false; } - uint32 talentCost = GetTalentSpellCost(spell_id); + uint32 talentCost = GetTalentSpellCost(spellId); // cast talents with SPELL_EFFECT_LEARN_SPELL (other dependent spells will learned later as not auto-learned) // note: all spells with SPELL_EFFECT_LEARN_SPELL isn't passive if (!loading && talentCost > 0 && spellInfo->HasEffect(SPELL_EFFECT_LEARN_SPELL)) { // ignore stance requirement for talent learn spell (stance set for spell only for client spell description show) - CastSpell(this, spell_id, true); + CastSpell(this, spellId, true); } // also cast passive spells (including all talents without SPELL_EFFECT_LEARN_SPELL) with additional checks else if (spellInfo->IsPassive()) { if (IsNeedCastPassiveSpellAtLearn(spellInfo)) - CastSpell(this, spell_id, true); + CastSpell(this, spellId, true); } else if (spellInfo->HasEffect(SPELL_EFFECT_SKILL_STEP)) { - CastSpell(this, spell_id, true); + CastSpell(this, spellId, true); return false; } @@ -3772,9 +3769,9 @@ bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool dependen // add dependent skills uint16 maxskill = GetMaxSkillValueForLevel(); - SpellLearnSkillNode const* spellLearnSkill = sSpellMgr->GetSpellLearnSkill(spell_id); + SpellLearnSkillNode const* spellLearnSkill = sSpellMgr->GetSpellLearnSkill(spellId); - SkillLineAbilityMapBounds skill_bounds = sSpellMgr->GetSkillLineAbilityMapBounds(spell_id); + SkillLineAbilityMapBounds skill_bounds = sSpellMgr->GetSkillLineAbilityMapBounds(spellId); if (spellLearnSkill) { @@ -3832,7 +3829,7 @@ bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool dependen } // learn dependent spells - SpellLearnSpellMapBounds spell_bounds = sSpellMgr->GetSpellLearnSpellMapBounds(spell_id); + SpellLearnSpellMapBounds spell_bounds = sSpellMgr->GetSpellLearnSpellMapBounds(spellId); for (SpellLearnSpellMap::const_iterator itr2 = spell_bounds.first; itr2 != spell_bounds.second; ++itr2) { @@ -3854,7 +3851,7 @@ bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool dependen GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILLLINE_SPELLS, _spell_idx->second->skillId); } - GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LEARN_SPELL, spell_id); + GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LEARN_SPELL, spellId); } // return true (for send learn packet) only if spell active (in case ranked spells) and not replace old spell @@ -4944,8 +4941,14 @@ void Player::DeleteFromDB(uint64 playerguid, uint32 accountId, bool updateRealmC } // The character gets unlinked from the account, the name gets freed up and appears as deleted ingame case CHAR_DELETE_UNLINK: - CharacterDatabase.PExecute("UPDATE characters SET deleteInfos_Name=name, deleteInfos_Account=account, deleteDate='" UI64FMTD "', name='', account=0 WHERE guid=%u", uint64(time(NULL)), guid); + { + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPDATE_DELETE_INFO); + + stmt->setUInt32(0, guid); + + CharacterDatabase.Execute(stmt); break; + } default: sLog->outError("Player::DeleteFromDB: Unsupported delete method: %u.", charDelete_method); } @@ -7340,7 +7343,14 @@ uint32 Player::GetZoneIdFromDB(uint64 guid) zone = sMapMgr->GetZoneId(map, posx, posy, posz); if (zone > 0) - CharacterDatabase.PExecute("UPDATE characters SET zone='%u' WHERE guid='%u'", zone, guidLow); + { + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPDATE_ZONE); + + stmt->setUInt16(0, uint16(zone)); + stmt->setUInt32(1, guidLow); + + CharacterDatabase.Execute(stmt); + } } return zone; @@ -12371,7 +12381,13 @@ void Player::DestroyItem(uint8 bag, uint8 slot, bool update) DestroyItem(slot, i, update); if (pItem->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_WRAPPED)) - CharacterDatabase.PExecute("DELETE FROM character_gifts WHERE item_guid = '%u'", pItem->GetGUIDLow()); + { + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GIFT); + + stmt->setUInt32(0, pItem->GetGUIDLow()); + + CharacterDatabase.Execute(stmt); + } RemoveEnchantmentDurations(pItem); RemoveItemDurations(pItem); @@ -12885,6 +12901,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 +12916,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 +13341,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 +13356,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 +15061,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); } } @@ -16496,7 +16505,13 @@ bool Player::LoadFromDB(uint32 guid, SQLQueryHolder *holder) if (ObjectMgr::CheckPlayerName(m_name) != CHAR_NAME_SUCCESS || (AccountMgr::IsPlayerAccount(GetSession()->GetSecurity()) && sObjectMgr->IsReservedName(m_name))) { - CharacterDatabase.PExecute("UPDATE characters SET at_login = at_login | '%u' WHERE guid ='%u'", uint32(AT_LOGIN_RENAME), guid); + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPDATE_AT_LOGIN_FLAG); + + stmt->setUInt16(0, uint16(AT_LOGIN_RENAME)); + stmt->setUInt32(1, guid); + + CharacterDatabase.Execute(stmt); + return false; } @@ -17517,29 +17532,33 @@ void Player::_LoadMailedItems(Mail* mail) { Field* fields = result->Fetch(); - uint32 item_guid_low = fields[11].GetUInt32(); - uint32 item_template = fields[12].GetUInt32(); + uint32 itemGuid = fields[11].GetUInt32(); + uint32 itemTemplate = fields[12].GetUInt32(); - mail->AddItem(item_guid_low, item_template); + mail->AddItem(itemGuid, itemTemplate); - ItemTemplate const* proto = sObjectMgr->GetItemTemplate(item_template); + ItemTemplate const* proto = sObjectMgr->GetItemTemplate(itemTemplate); if (!proto) { - sLog->outError("Player %u has unknown item_template (ProtoType) in mailed items(GUID: %u template: %u) in mail (%u), deleted.", GetGUIDLow(), item_guid_low, item_template, mail->messageID); - CharacterDatabase.PExecute("DELETE FROM mail_items WHERE item_guid = '%u'", item_guid_low); + sLog->outError("Player %u has unknown item_template (ProtoType) in mailed items(GUID: %u template: %u) in mail (%u), deleted.", GetGUIDLow(), itemGuid, itemTemplate, mail->messageID); + + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_INVALID_MAIL_ITEM); + stmt->setUInt32(0, itemGuid); + CharacterDatabase.Execute(stmt); + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_INSTANCE); - stmt->setUInt32(0, item_guid_low); + stmt->setUInt32(0, itemGuid); CharacterDatabase.Execute(stmt); continue; } Item* item = NewItemOrBag(proto); - if (!item->LoadFromDB(item_guid_low, MAKE_NEW_GUID(fields[13].GetUInt32(), 0, HIGHGUID_PLAYER), fields, item_template)) + if (!item->LoadFromDB(itemGuid, MAKE_NEW_GUID(fields[13].GetUInt32(), 0, HIGHGUID_PLAYER), fields, itemTemplate)) { - sLog->outError("Player::_LoadMailedItems - Item in mail (%u) doesn't exist !!!! - item guid: %u, deleted from mail", mail->messageID, item_guid_low); - CharacterDatabase.PExecute("DELETE FROM mail_items WHERE item_guid = '%u'", item_guid_low); + sLog->outError("Player::_LoadMailedItems - Item in mail (%u) doesn't exist !!!! - item guid: %u, deleted from mail", mail->messageID, itemGuid); + CharacterDatabase.PExecute("DELETE FROM mail_items WHERE item_guid = '%u'", itemGuid); item->FSetState(ITEM_REMOVED); SQLTransaction temp = SQLTransaction(NULL); @@ -18143,8 +18162,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 +18944,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 +20246,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..a9bba9cbdc4 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); @@ -1653,7 +1650,7 @@ class Player : public Unit, public GridObject<Player> void SendProficiency(ItemClass itemClass, uint32 itemSubclassMask); void SendInitialSpells(); - bool addSpell(uint32 spell_id, bool active, bool learning, bool dependent, bool disabled, bool loading = false); + bool addSpell(uint32 spellId, bool active, bool learning, bool dependent, bool disabled, bool loading = false); void learnSpell(uint32 spell_id, bool dependent); void removeSpell(uint32 spell_id, bool disabled = false, bool learn_low_rank = true); void resetSpells(bool myClassOnly = false); @@ -1677,7 +1674,7 @@ class Player : public Unit, public GridObject<Player> void LearnTalent(uint32 talentId, uint32 talentRank); void LearnPetTalent(uint64 petGuid, uint32 talentId, uint32 talentRank); - bool AddTalent(uint32 spell, uint8 spec, bool learning); + bool AddTalent(uint32 spellId, uint8 spec, bool learning); bool HasTalent(uint32 spell_id, uint8 spec) const; uint32 CalculateTalentsPoints() const; @@ -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..ffb5e0ca1aa 100755 --- a/src/server/game/Groups/Group.cpp +++ b/src/server/game/Groups/Group.cpp @@ -123,12 +123,30 @@ bool Group::Create(Player* leader) sGroupMgr->RegisterGroupDbStoreId(m_dbStoreId, this); - // store group in database - CharacterDatabase.PExecute("INSERT INTO groups (guid, leaderGuid, lootMethod, looterGuid, lootThreshold, icon1, icon2, icon3, icon4, icon5, icon6, icon7, icon8, groupType, difficulty, raiddifficulty) " - "VALUES ('%u', '%u', '%u', '%u', '%u', '" UI64FMTD "', '" UI64FMTD "', '" UI64FMTD "', '" UI64FMTD "', '" UI64FMTD "', '" UI64FMTD "', '" UI64FMTD "', '" UI64FMTD "', '%u', '%u', '%u')", - m_dbStoreId, GUID_LOPART(m_leaderGuid), uint32(m_lootMethod), - GUID_LOPART(m_looterGuid), uint32(m_lootThreshold), m_targetIcons[0], m_targetIcons[1], m_targetIcons[2], m_targetIcons[3], m_targetIcons[4], m_targetIcons[5], m_targetIcons[6], - m_targetIcons[7], uint8(m_groupType), uint32(m_dungeonDifficulty), m_raidDifficulty); + // Store group in database + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_ADD_GROUP); + + uint8 index = 0; + + stmt->setUInt32(index++, m_dbStoreId); + stmt->setUInt32(index++, GUID_LOPART(m_leaderGuid)); + stmt->setUInt8(index++, uint8(m_lootMethod)); + stmt->setUInt32(index++, GUID_LOPART(m_looterGuid)); + stmt->setUInt8(index++, uint8(m_lootThreshold)); + stmt->setUInt32(index++, uint32(m_targetIcons[0])); + stmt->setUInt32(index++, uint32(m_targetIcons[1])); + stmt->setUInt32(index++, uint32(m_targetIcons[2])); + stmt->setUInt32(index++, uint32(m_targetIcons[3])); + stmt->setUInt32(index++, uint32(m_targetIcons[4])); + stmt->setUInt32(index++, uint32(m_targetIcons[5])); + stmt->setUInt32(index++, uint32(m_targetIcons[6])); + stmt->setUInt32(index++, uint32(m_targetIcons[7])); + stmt->setUInt8(index++, uint8(m_groupType)); + stmt->setUInt32(index++, uint8(m_dungeonDifficulty)); + stmt->setUInt32(index++, uint8(m_raidDifficulty)); + + CharacterDatabase.Execute(stmt); + ASSERT(AddMember(leader)); // If the leader can't be added to a new group because it appears full, something is clearly wrong. @@ -200,7 +218,15 @@ void Group::ConvertToLFG() m_groupType = GroupType(m_groupType | GROUPTYPE_LFG | GROUPTYPE_UNK1); m_lootMethod = NEED_BEFORE_GREED; if (!isBGGroup()) - CharacterDatabase.PExecute("UPDATE groups SET groupType='%u' WHERE guid='%u'", uint8(m_groupType), m_dbStoreId); + { + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPDATE_GROUP_TYPE); + + stmt->setUInt8(0, uint8(m_groupType)); + stmt->setUInt32(1, m_dbStoreId); + + CharacterDatabase.Execute(stmt); + } + SendUpdate(); } @@ -211,7 +237,15 @@ void Group::ConvertToRaid() _initRaidSubGroupsCounter(); if (!isBGGroup()) - CharacterDatabase.PExecute("UPDATE groups SET groupType='%u' WHERE guid='%u'", uint8(m_groupType), m_dbStoreId); + { + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPDATE_GROUP_TYPE); + + stmt->setUInt8(0, uint8(m_groupType)); + stmt->setUInt32(1, m_dbStoreId); + + CharacterDatabase.Execute(stmt); + } + SendUpdate(); // update quest related GO states (quest activity dependent from raid membership) @@ -343,8 +377,18 @@ bool Group::AddMember(Player* player) // insert into the table if we're not a battleground group if (!isBGGroup()) - CharacterDatabase.PExecute("INSERT INTO group_member (guid, memberGuid, memberFlags, subgroup, roles) VALUES(%u, %u, %u, %u, %u)", - m_dbStoreId, GUID_LOPART(member.guid), member.flags, member.group, member.roles); + { + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_ADD_GROUP_MEMBER); + + stmt->setUInt32(0, m_dbStoreId); + stmt->setUInt32(1, GUID_LOPART(member.guid)); + stmt->setUInt8(2, member.flags); + stmt->setUInt8(3, member.group); + stmt->setUInt8(4, member.roles); + + CharacterDatabase.Execute(stmt); + + } SendUpdate(); sScriptMgr->OnGroupAddMember(this, player->GetGUID()); @@ -435,7 +479,11 @@ bool Group::RemoveMember(uint64 guid, const RemoveMethod &method /*= GROUP_REMOV } // Remove player from group in DB - CharacterDatabase.PExecute("DELETE FROM group_member WHERE memberGuid=%u", GUID_LOPART(guid)); + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GROUP_MEMBER); + + stmt->setUInt32(0, GUID_LOPART(guid)); + + CharacterDatabase.Execute(stmt); // Reevaluate group enchanter if the leaving player had enchanting skill or the player is offline if ((player && player->GetSkillValue(SKILL_ENCHANTING)) || !player) @@ -530,14 +578,24 @@ void Group::ChangeLeader(uint64 guid) } // Same in the database - CharacterDatabase.PExecute("DELETE FROM group_instance WHERE guid=%u AND (permanent = 1 OR instance IN (SELECT instance FROM character_instance WHERE guid = '%u'))", - m_dbStoreId, player->GetGUIDLow()); + + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GROUP_INSTANCE_PERM_BINDING); + + stmt->setUInt32(0, m_dbStoreId); + stmt->setUInt32(1, player->GetGUIDLow()); + + CharacterDatabase.Execute(stmt); // Copy the permanent binds from the new leader to the group Player::ConvertInstancesToGroup(player, this, true); - // update the group leader - CharacterDatabase.PExecute("UPDATE groups SET leaderGuid='%u' WHERE guid='%u'", player->GetGUIDLow(), m_dbStoreId); + // Update the group leader + stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPDATE_GROUP_LEADER); + + stmt->setUInt32(0, player->GetGUIDLow()); + stmt->setUInt32(1, m_dbStoreId); + + CharacterDatabase.Execute(stmt); } m_leaderGuid = player->GetGUID(); @@ -1121,6 +1179,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 } } } @@ -1320,7 +1379,14 @@ bool Group::_setMembersGroup(uint64 guid, uint8 group) SubGroupCounterIncrease(group); if (!isBGGroup()) - CharacterDatabase.PExecute("UPDATE group_member SET subgroup='%u' WHERE memberGuid='%u'", group, GUID_LOPART(guid)); + { + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPDATE_GROUP_MEMBER_SUBGROUP); + + stmt->setUInt8(0, group); + stmt->setUInt32(1, GUID_LOPART(guid)); + + CharacterDatabase.Execute(stmt); + } return true; } @@ -1364,7 +1430,14 @@ void Group::ChangeMembersGroup(uint64 guid, uint8 group) // Preserve new sub group in database for non-raid groups if (!isBGGroup()) - CharacterDatabase.PExecute("UPDATE group_member SET subgroup='%u' WHERE memberGuid='%u'", group, GUID_LOPART(guid)); + { + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPDATE_GROUP_MEMBER_SUBGROUP); + + stmt->setUInt8(0, group); + stmt->setUInt32(1, GUID_LOPART(guid)); + + CharacterDatabase.Execute(stmt); + } // In case the moved player is online, update the player object with the new sub group references if (Player* player = ObjectAccessor::FindPlayer(guid)) @@ -1552,7 +1625,14 @@ void Group::SetDungeonDifficulty(Difficulty difficulty) { m_dungeonDifficulty = difficulty; if (!isBGGroup()) - CharacterDatabase.PExecute("UPDATE groups SET difficulty = %u WHERE guid ='%u'", m_dungeonDifficulty, m_dbStoreId); + { + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPDATE_GROUP_DIFFICULTY); + + stmt->setUInt8(0, uint8(m_dungeonDifficulty)); + stmt->setUInt32(1, m_dbStoreId); + + CharacterDatabase.Execute(stmt); + } for (GroupReference* itr = GetFirstMember(); itr != NULL; itr = itr->next()) { @@ -1569,7 +1649,14 @@ void Group::SetRaidDifficulty(Difficulty difficulty) { m_raidDifficulty = difficulty; if (!isBGGroup()) - CharacterDatabase.PExecute("UPDATE groups SET raiddifficulty = %u WHERE guid ='%u'", m_raidDifficulty, m_dbStoreId); + { + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPDATE_GROUP_RAID_DIFFICULTY); + + stmt->setUInt8(0, uint8(m_raidDifficulty)); + stmt->setUInt32(1, m_dbStoreId); + + CharacterDatabase.Execute(stmt); + } for (GroupReference* itr = GetFirstMember(); itr != NULL; itr = itr->next()) { @@ -1607,9 +1694,9 @@ void Group::ResetInstances(uint8 method, bool isRaid, Player* SendMsgTo) for (BoundInstancesMap::iterator itr = m_boundInstances[diff].begin(); itr != m_boundInstances[diff].end();) { - InstanceSave* p = itr->second.save; + InstanceSave* instanceSave = itr->second.save; const MapEntry* entry = sMapStore.LookupEntry(itr->first); - if (!entry || entry->IsRaid() != isRaid || (!p->CanReset() && method != INSTANCE_RESET_GROUP_DISBAND)) + if (!entry || entry->IsRaid() != isRaid || (!instanceSave->CanReset() && method != INSTANCE_RESET_GROUP_DISBAND)) { ++itr; continue; @@ -1627,10 +1714,10 @@ void Group::ResetInstances(uint8 method, bool isRaid, Player* SendMsgTo) bool isEmpty = true; // if the map is loaded, reset it - Map* map = sMapMgr->FindMap(p->GetMapId(), p->GetInstanceId()); - if (map && map->IsDungeon() && !(method == INSTANCE_RESET_GROUP_DISBAND && !p->CanReset())) + Map* map = sMapMgr->FindMap(instanceSave->GetMapId(), instanceSave->GetInstanceId()); + if (map && map->IsDungeon() && !(method == INSTANCE_RESET_GROUP_DISBAND && !instanceSave->CanReset())) { - if (p->CanReset()) + if (instanceSave->CanReset()) isEmpty = ((InstanceMap*)map)->Reset(method); else isEmpty = !map->HavePlayers(); @@ -1639,25 +1726,32 @@ void Group::ResetInstances(uint8 method, bool isRaid, Player* SendMsgTo) if (SendMsgTo) { if (isEmpty) - SendMsgTo->SendResetInstanceSuccess(p->GetMapId()); + SendMsgTo->SendResetInstanceSuccess(instanceSave->GetMapId()); else - SendMsgTo->SendResetInstanceFailed(0, p->GetMapId()); + SendMsgTo->SendResetInstanceFailed(0, instanceSave->GetMapId()); } if (isEmpty || method == INSTANCE_RESET_GROUP_DISBAND || method == INSTANCE_RESET_CHANGE_DIFFICULTY) { // do not reset the instance, just unbind if others are permanently bound to it - if (p->CanReset()) - p->DeleteFromDB(); + if (instanceSave->CanReset()) + instanceSave->DeleteFromDB(); else - CharacterDatabase.PExecute("DELETE FROM group_instance WHERE instance = '%u'", p->GetInstanceId()); + { + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GROUP_INSTANCE_BY_INSTANCE); + + stmt->setUInt32(0, instanceSave->GetInstanceId()); + + CharacterDatabase.Execute(stmt); + } + // i don't know for sure if hash_map iterators m_boundInstances[diff].erase(itr); itr = m_boundInstances[diff].begin(); // this unloads the instance save unless online players are bound to it // (eg. permanent binds or GM solo binds) - p->RemoveGroup(this); + instanceSave->RemoveGroup(this); } else ++itr; @@ -1710,7 +1804,15 @@ InstanceGroupBind* Group::BindToInstance(InstanceSave* save, bool permanent, boo InstanceGroupBind& bind = m_boundInstances[save->GetDifficulty()][save->GetMapId()]; if (!load && (!bind.save || permanent != bind.perm || save != bind.save)) - CharacterDatabase.PExecute("REPLACE INTO group_instance (guid, instance, permanent) VALUES (%u, %u, %u)", m_dbStoreId, save->GetInstanceId(), permanent); + { + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_ADD_GROUP_INSTANCE); + + stmt->setUInt32(0, m_dbStoreId); + stmt->setUInt32(1, save->GetInstanceId()); + stmt->setBool(2, permanent); + + CharacterDatabase.Execute(stmt); + } if (bind.save != save) { @@ -1734,7 +1836,15 @@ void Group::UnbindInstance(uint32 mapid, uint8 difficulty, bool unload) if (itr != m_boundInstances[difficulty].end()) { if (!unload) - CharacterDatabase.PExecute("DELETE FROM group_instance WHERE guid=%u AND instance=%u", m_dbStoreId, itr->second.save->GetInstanceId()); + { + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GROUP_INSTANCE_BY_GUID); + + stmt->setUInt32(0, m_dbStoreId); + stmt->setUInt32(1, itr->second.save->GetInstanceId()); + + CharacterDatabase.Execute(stmt); + } + itr->second.save->RemoveGroup(this); // save can become invalid m_boundInstances[difficulty].erase(itr); } @@ -1963,7 +2073,12 @@ void Group::SetGroupMemberFlag(uint64 guid, bool apply, GroupMemberFlags flag) ToggleGroupMemberFlag(slot, flag, apply); // Preserve the new setting in the db - CharacterDatabase.PExecute("UPDATE group_member SET memberFlags='%u' WHERE memberGuid='%u'", slot->flags, GUID_LOPART(guid)); + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPDATE_GROUP_MEMBER_FLAG); + + stmt->setUInt8(0, slot->flags); + stmt->setUInt32(0, GUID_LOPART(guid)); + + CharacterDatabase.Execute(stmt); // Broadcast the changes to the group SendUpdate(); 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/Instances/InstanceSaveMgr.cpp b/src/server/game/Instances/InstanceSaveMgr.cpp index 7a2368161d8..9d5ffb6542a 100755 --- a/src/server/game/Instances/InstanceSaveMgr.cpp +++ b/src/server/game/Instances/InstanceSaveMgr.cpp @@ -138,7 +138,14 @@ void InstanceSaveManager::RemoveInstanceSave(uint32 InstanceId) { // save the resettime for normal instances only when they get unloaded if (time_t resettime = itr->second->GetResetTimeForDB()) - CharacterDatabase.PExecute("UPDATE instance SET resettime = '"UI64FMTD"' WHERE id = '%u'", (uint64)resettime, InstanceId); + { + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPDATE_INSTANCE_RESETTIME); + + stmt->setUInt32(0, uint32(resettime)); + stmt->setUInt32(1, InstanceId); + + CharacterDatabase.Execute(stmt); + } delete itr->second; m_instanceSaveById.erase(itr); @@ -573,13 +580,19 @@ void InstanceSaveManager::_ResetOrWarnAll(uint32 mapid, Difficulty difficulty, b if (period < DAY) period = DAY; - uint64 next_reset = ((resetTime + MINUTE) / DAY * DAY) + period + diff; + uint32 next_reset = ((resetTime + MINUTE) / DAY * DAY) + period + diff; SetResetTimeFor(mapid, difficulty, next_reset); ScheduleReset(true, time_t(next_reset-3600), InstResetEvent(1, mapid, difficulty, 0)); - // update it in the DB - CharacterDatabase.PExecute("UPDATE instance_reset SET resettime = '%u' WHERE mapid = '%d' AND difficulty = '%d'", uint32(next_reset), mapid, difficulty); + // Update it in the DB + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPDATE_GLOBAL_INSTANCE_RESETTIME); + + stmt->setUInt32(0, next_reset); + stmt->setUInt16(1, uint16(mapid)); + stmt->setUInt8(2, uint8(difficulty)); + + CharacterDatabase.Execute(stmt); } // note: this isn't fast but it's meant to be executed very rarely 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..6b972f94dd5 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); - _addIgnoreCallback = CharacterDatabase.AsyncPQuery("SELECT guid FROM characters WHERE name = '%s'", IgnoreName.c_str()); + stmt->setString(0, ignoreName); + + _addIgnoreCallback = CharacterDatabase.AsyncQuery(stmt); } -void WorldSession::HandleAddIgnoreOpcodeCallBack(QueryResult result) +void WorldSession::HandleAddIgnoreOpcodeCallBack(PreparedQueryResult result) { if (!GetPlayer()) return; @@ -706,9 +709,12 @@ void WorldSession::HandleBugOpcode(WorldPacket & recv_data) sLog->outDebug(LOG_FILTER_NETWORKIO, "%s", type.c_str()); sLog->outDebug(LOG_FILTER_NETWORKIO, "%s", content.c_str()); - CharacterDatabase.EscapeString(type); - CharacterDatabase.EscapeString(content); - CharacterDatabase.PExecute ("INSERT INTO bugreport (type, content) VALUES('%s', '%s')", type.c_str(), content.c_str()); + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_ADD_BUG_REPORT); + + stmt->setString(0, type); + stmt->setString(1, content); + + CharacterDatabase.Execute(stmt); } void WorldSession::HandleReclaimCorpseOpcode(WorldPacket &recv_data) @@ -1607,7 +1613,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..4162289f0ce 100755 --- a/src/server/game/Server/Protocol/Handlers/NPCHandler.cpp +++ b/src/server/game/Server/Protocol/Handlers/NPCHandler.cpp @@ -519,14 +519,17 @@ void WorldSession::HandleListStabledPetsOpcode(WorldPacket & recv_data) void WorldSession::SendStablePet(uint64 guid) { + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_GET_PET_SLOTS_DETAIL); + + stmt->setUInt32(0, _player->GetGUIDLow()); + stmt->setUInt8(1, PET_SAVE_FIRST_STABLE_SLOT); + stmt->setUInt8(2, PET_SAVE_LAST_STABLE_SLOT); + _sendStabledPetCallback.SetParam(guid); - _sendStabledPetCallback.SetFutureResult( - CharacterDatabase.AsyncPQuery("SELECT owner, id, entry, level, name 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) - ); + _sendStabledPetCallback.SetFutureResult(CharacterDatabase.AsyncQuery(stmt)); } -void WorldSession::SendStablePetCallback(QueryResult result, uint64 guid) +void WorldSession::SendStablePetCallback(PreparedQueryResult result, uint64 guid) { if (!GetPlayer()) return; @@ -618,39 +621,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 @@ -675,32 +682,36 @@ void WorldSession::HandleUnstablePet(WorldPacket & recv_data) if (GetPlayer()->HasUnitState(UNIT_STAT_DIED)) GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_GET_PET_ENTRY); + + stmt->setUInt32(0, _player->GetGUIDLow()); + stmt->setUInt32(1, petnumber); + stmt->setUInt8(2, PET_SAVE_FIRST_STABLE_SLOT); + stmt->setUInt8(3, PET_SAVE_LAST_STABLE_SLOT); + _unstablePetCallback.SetParam(petnumber); - _unstablePetCallback.SetFutureResult( - CharacterDatabase.AsyncPQuery("SELECT entry FROM character_pet WHERE owner = '%u' AND id = '%u' AND slot >='%u' AND slot <= '%u'", - _player->GetGUIDLow(), petnumber, PET_SAVE_FIRST_STABLE_SLOT, PET_SAVE_LAST_STABLE_SLOT) - ); + _unstablePetCallback.SetFutureResult(CharacterDatabase.AsyncQuery(stmt)); } -void WorldSession::HandleUnstablePetCallback(QueryResult result, uint32 petnumber) +void WorldSession::HandleUnstablePetCallback(PreparedQueryResult result, uint32 petId) { if (!GetPlayer()) return; - uint32 creature_id = 0; + uint32 petEntry = 0; if (result) { Field* fields = result->Fetch(); - creature_id = fields[0].GetUInt32(); + petEntry = fields[0].GetUInt32(); } - if (!creature_id) + if (!petEntry) { SendStableResult(STABLE_ERR_STABLE); return; } - CreatureTemplate const* creatureInfo = sObjectMgr->GetCreatureTemplate(creature_id); + CreatureTemplate const* creatureInfo = sObjectMgr->GetCreatureTemplate(petEntry); if (!creatureInfo || !creatureInfo->isTameable(_player->CanTameExoticPets())) { // if problem in exotic pet @@ -722,11 +733,11 @@ void WorldSession::HandleUnstablePetCallback(QueryResult result, uint32 petnumbe if (pet) _player->RemovePet(pet, PET_SAVE_AS_DELETED); - Pet* newpet = new Pet(_player, HUNTER_PET); - if (!newpet->LoadPetFromDB(_player, creature_id, petnumber)) + Pet* newPet = new Pet(_player, HUNTER_PET); + if (!newPet->LoadPetFromDB(_player, petEntry, petId)) { - delete newpet; - newpet = NULL; + delete newPet; + newPet = NULL; SendStableResult(STABLE_ERR_STABLE); return; } @@ -776,9 +787,9 @@ void WorldSession::HandleStableSwapPet(WorldPacket & recv_data) { sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Recv CMSG_STABLE_SWAP_PET."); uint64 npcGUID; - uint32 pet_number; + uint32 petId; - recv_data >> npcGUID >> pet_number; + recv_data >> npcGUID >> petId; if (!CheckStableMaster(npcGUID)) { @@ -798,15 +809,18 @@ void WorldSession::HandleStableSwapPet(WorldPacket & recv_data) return; } - // 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'", - _player->GetGUIDLow(), pet_number) - ); + // Find swapped pet slot in stable + + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_GET_PET_SLOT_BY_ID); + + stmt->setUInt32(0, _player->GetGUIDLow()); + stmt->setUInt32(1, petId); + + _stableSwapCallback.SetParam(petId); + _stableSwapCallback.SetFutureResult(CharacterDatabase.AsyncQuery(stmt)); } -void WorldSession::HandleStableSwapPetCallback(QueryResult result, uint32 petnumber) +void WorldSession::HandleStableSwapPetCallback(PreparedQueryResult result, uint32 petId) { if (!GetPlayer()) return; @@ -819,16 +833,16 @@ void WorldSession::HandleStableSwapPetCallback(QueryResult result, uint32 petnum Field* fields = result->Fetch(); - uint32 slot = fields[0].GetUInt8(); - uint32 creature_id = fields[1].GetUInt32(); + uint32 slot = fields[0].GetUInt8(); + uint32 petEntry = fields[1].GetUInt32(); - if (!creature_id) + if (!petEntry) { SendStableResult(STABLE_ERR_STABLE); return; } - CreatureTemplate const* creatureInfo = sObjectMgr->GetCreatureTemplate(creature_id); + CreatureTemplate const* creatureInfo = sObjectMgr->GetCreatureTemplate(petEntry); if (!creatureInfo || !creatureInfo->isTameable(_player->CanTameExoticPets())) { // if problem in exotic pet @@ -846,7 +860,7 @@ void WorldSession::HandleStableSwapPetCallback(QueryResult result, uint32 petnum // summon unstabled pet Pet* newpet = new Pet(_player); - if (!newpet->LoadPetFromDB(_player, creature_id, petnumber)) + if (!newpet->LoadPetFromDB(_player, petEntry, petId)) { delete newpet; SendStableResult(STABLE_ERR_STABLE); @@ -878,19 +892,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..fed84728efd 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 { @@ -376,18 +372,18 @@ void WorldSession::HandlePetitionRenameOpcode(WorldPacket & recv_data) { sLog->outDebug(LOG_FILTER_NETWORKIO, "Received opcode MSG_PETITION_RENAME"); // ok - uint64 petitionguid; + uint64 petitionGuid; uint32 type; - std::string newname; + std::string newName; - recv_data >> petitionguid; // guid - recv_data >> newname; // new name + recv_data >> petitionGuid; // guid + recv_data >> newName; // new name - Item* item = _player->GetItemByGuid(petitionguid); + Item* item = _player->GetItemByGuid(petitionGuid); if (!item) return; - QueryResult result = CharacterDatabase.PQuery("SELECT type FROM petition WHERE petitionguid = '%u'", GUID_LOPART(petitionguid)); + QueryResult result = CharacterDatabase.PQuery("SELECT type FROM petition WHERE petitionguid = '%u'", GUID_LOPART(petitionGuid)); if (result) { @@ -396,46 +392,48 @@ void WorldSession::HandlePetitionRenameOpcode(WorldPacket & recv_data) } else { - sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_PETITION_QUERY failed for petition (GUID: %u)", GUID_LOPART(petitionguid)); + sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_PETITION_QUERY failed for petition (GUID: %u)", GUID_LOPART(petitionGuid)); return; } if (type == GUILD_CHARTER_TYPE) { - if (sGuildMgr->GetGuildByName(newname)) + if (sGuildMgr->GetGuildByName(newName)) { - Guild::SendCommandResult(this, GUILD_CREATE_S, ERR_GUILD_NAME_EXISTS_S, newname); + Guild::SendCommandResult(this, GUILD_CREATE_S, ERR_GUILD_NAME_EXISTS_S, newName); return; } - if (sObjectMgr->IsReservedName(newname) || !ObjectMgr::IsValidCharterName(newname)) + if (sObjectMgr->IsReservedName(newName) || !ObjectMgr::IsValidCharterName(newName)) { - Guild::SendCommandResult(this, GUILD_CREATE_S, ERR_GUILD_NAME_INVALID, newname); + Guild::SendCommandResult(this, GUILD_CREATE_S, ERR_GUILD_NAME_INVALID, newName); return; } } else { - if (sArenaTeamMgr->GetArenaTeamByName(newname)) + if (sArenaTeamMgr->GetArenaTeamByName(newName)) { - SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, newname, "", ERR_ARENA_TEAM_NAME_EXISTS_S); + SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, newName, "", ERR_ARENA_TEAM_NAME_EXISTS_S); return; } - if (sObjectMgr->IsReservedName(newname) || !ObjectMgr::IsValidCharterName(newname)) + if (sObjectMgr->IsReservedName(newName) || !ObjectMgr::IsValidCharterName(newName)) { - SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, newname, "", ERR_ARENA_TEAM_NAME_INVALID); + SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, newName, "", ERR_ARENA_TEAM_NAME_INVALID); return; } } - std::string db_newname = newname; - CharacterDatabase.EscapeString(db_newname); - CharacterDatabase.PExecute("UPDATE petition SET name = '%s' WHERE petitionguid = '%u'", - db_newname.c_str(), GUID_LOPART(petitionguid)); + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_PETITION_NAME); - sLog->outDebug(LOG_FILTER_NETWORKIO, "Petition (GUID: %u) renamed to '%s'", GUID_LOPART(petitionguid), newname.c_str()); - WorldPacket data(MSG_PETITION_RENAME, (8+newname.size()+1)); - data << uint64(petitionguid); - data << newname; + stmt->setString(0, newName); + stmt->setUInt32(1, GUID_LOPART(petitionGuid)); + + CharacterDatabase.Execute(stmt); + + sLog->outDebug(LOG_FILTER_NETWORKIO, "Petition (GUID: %u) renamed to '%s'", GUID_LOPART(petitionGuid), newName.c_str()); + WorldPacket data(MSG_PETITION_RENAME, (8+newName.size()+1)); + data << uint64(petitionGuid); + data << newName; SendPacket(&data); } @@ -444,34 +442,34 @@ void WorldSession::HandlePetitionSignOpcode(WorldPacket & recv_data) sLog->outDebug(LOG_FILTER_NETWORKIO, "Received opcode CMSG_PETITION_SIGN"); // ok Field* fields; - uint64 petitionguid; + uint64 petitionGuid; uint8 unk; - recv_data >> petitionguid; // petition guid + recv_data >> petitionGuid; // petition guid recv_data >> unk; QueryResult result = CharacterDatabase.PQuery( "SELECT ownerguid, " " (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)); + "FROM petition WHERE petitionguid = '%u'", GUID_LOPART(petitionGuid), GUID_LOPART(petitionGuid)); if (!result) { - sLog->outError("Petition %u is not found for player %u %s", GUID_LOPART(petitionguid), GetPlayer()->GetGUIDLow(), GetPlayer()->GetName()); + sLog->outError("Petition %u is not found for player %u %s", GUID_LOPART(petitionGuid), GetPlayer()->GetGUIDLow(), GetPlayer()->GetName()); return; } fields = result->Fetch(); - uint64 ownerguid = MAKE_NEW_GUID(fields[0].GetUInt32(), 0, HIGHGUID_PLAYER); + uint64 ownerGuid = MAKE_NEW_GUID(fields[0].GetUInt32(), 0, HIGHGUID_PLAYER); uint8 signs = fields[1].GetUInt8(); uint32 type = fields[2].GetUInt32(); - uint32 plguidlo = _player->GetGUIDLow(); - if (GUID_LOPART(ownerguid) == plguidlo) + uint32 playerGuid = _player->GetGUIDLow(); + if (GUID_LOPART(ownerGuid) == playerGuid) return; // not let enemies sign guild charter - if (!sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD) && GetPlayer()->GetTeam() != sObjectMgr->GetPlayerTeamByGUID(ownerguid)) + if (!sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD) && GetPlayer()->GetTeam() != sObjectMgr->GetPlayerTeamByGUID(ownerGuid)) { if (type != GUILD_CHARTER_TYPE) SendArenaTeamCommandResult(ERR_ARENA_TEAM_INVITE_SS, "", "", ERR_ARENA_TEAM_NOT_ALLIED); @@ -523,12 +521,12 @@ void WorldSession::HandlePetitionSignOpcode(WorldPacket & recv_data) //client doesn't allow to sign petition two times by one character, but not check sign by another character from same account //not allow sign another player from already sign player account - result = CharacterDatabase.PQuery("SELECT playerguid FROM petition_sign WHERE player_account = '%u' AND petitionguid = '%u'", GetAccountId(), GUID_LOPART(petitionguid)); + result = CharacterDatabase.PQuery("SELECT playerguid FROM petition_sign WHERE player_account = '%u' AND petitionguid = '%u'", GetAccountId(), GUID_LOPART(petitionGuid)); if (result) { WorldPacket data(SMSG_PETITION_SIGN_RESULTS, (8+8+4)); - data << uint64(petitionguid); + data << uint64(petitionGuid); data << uint64(_player->GetGUID()); data << (uint32)PETITION_SIGN_ALREADY_SIGNED; @@ -536,17 +534,24 @@ void WorldSession::HandlePetitionSignOpcode(WorldPacket & recv_data) SendPacket(&data); // update for owner if online - if (Player* owner = ObjectAccessor::FindPlayer(ownerguid)) + if (Player* owner = ObjectAccessor::FindPlayer(ownerGuid)) owner->GetSession()->SendPacket(&data); return; } - CharacterDatabase.PExecute("INSERT INTO petition_sign (ownerguid, petitionguid, playerguid, player_account) VALUES ('%u', '%u', '%u', '%u')", GUID_LOPART(ownerguid), GUID_LOPART(petitionguid), plguidlo, GetAccountId()); + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_ADD_PETITION_SIGNATURE); + + stmt->setUInt32(0, GUID_LOPART(ownerGuid)); + stmt->setUInt32(1, GUID_LOPART(petitionGuid)); + stmt->setUInt32(2, playerGuid); + stmt->setUInt32(3, GetAccountId()); + + CharacterDatabase.Execute(stmt); - sLog->outDebug(LOG_FILTER_NETWORKIO, "PETITION SIGN: GUID %u by player: %s (GUID: %u Account: %u)", GUID_LOPART(petitionguid), _player->GetName(), plguidlo, GetAccountId()); + sLog->outDebug(LOG_FILTER_NETWORKIO, "PETITION SIGN: GUID %u by player: %s (GUID: %u Account: %u)", GUID_LOPART(petitionGuid), _player->GetName(), playerGuid, GetAccountId()); WorldPacket data(SMSG_PETITION_SIGN_RESULTS, (8+8+4)); - data << uint64(petitionguid); + data << uint64(petitionGuid); data << uint64(_player->GetGUID()); data << uint32(PETITION_SIGN_OK); @@ -559,7 +564,7 @@ void WorldSession::HandlePetitionSignOpcode(WorldPacket & recv_data) // item->SetUInt32Value(ITEM_FIELD_ENCHANTMENT_1_1+1, signs); // update for owner if online - if (Player* owner = ObjectAccessor::FindPlayer(ownerguid)) + if (Player* owner = ObjectAccessor::FindPlayer(ownerGuid)) owner->GetSession()->SendPacket(&data); } 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/Protocol/Handlers/SpellHandler.cpp b/src/server/game/Server/Protocol/Handlers/SpellHandler.cpp index 269576a5696..ffe205304e3 100755 --- a/src/server/game/Server/Protocol/Handlers/SpellHandler.cpp +++ b/src/server/game/Server/Protocol/Handlers/SpellHandler.cpp @@ -213,26 +213,26 @@ void WorldSession::HandleOpenItemOpcode(WorldPacket& recvPacket) sLog->outDetail("bagIndex: %u, slot: %u", bagIndex, slot); - Item* pItem = pUser->GetItemByPos(bagIndex, slot); - if (!pItem) + Item* item = pUser->GetItemByPos(bagIndex, slot); + if (!item) { pUser->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL); return; } - ItemTemplate const* proto = pItem->GetTemplate(); + ItemTemplate const* proto = item->GetTemplate(); if (!proto) { - pUser->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, pItem, NULL); + pUser->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, item, NULL); return; } // Verify that the bag is an actual bag or wrapped item that can be used "normally" - if (!(proto->Flags & ITEM_PROTO_FLAG_OPENABLE) && !pItem->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_WRAPPED)) + if (!(proto->Flags & ITEM_PROTO_FLAG_OPENABLE) && !item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_WRAPPED)) { - pUser->SendEquipError(EQUIP_ERR_CANT_DO_RIGHT_NOW, pItem, NULL); + pUser->SendEquipError(EQUIP_ERR_CANT_DO_RIGHT_NOW, item, NULL); sLog->outError("Possible hacking attempt: Player %s [guid: %u] tried to open item [guid: %u, entry: %u] which is not openable!", - pUser->GetName(), pUser->GetGUIDLow(), pItem->GetGUIDLow(), proto->ItemId); + pUser->GetName(), pUser->GetGUIDLow(), item->GetGUIDLow(), proto->ItemId); return; } @@ -244,43 +244,48 @@ void WorldSession::HandleOpenItemOpcode(WorldPacket& recvPacket) if (!lockInfo) { - pUser->SendEquipError(EQUIP_ERR_ITEM_LOCKED, pItem, NULL); - sLog->outError("WORLD::OpenItem: item [guid = %u] has an unknown lockId: %u!", pItem->GetGUIDLow(), lockId); + pUser->SendEquipError(EQUIP_ERR_ITEM_LOCKED, item, NULL); + sLog->outError("WORLD::OpenItem: item [guid = %u] has an unknown lockId: %u!", item->GetGUIDLow(), lockId); return; } // was not unlocked yet - if (pItem->IsLocked()) + if (item->IsLocked()) { - pUser->SendEquipError(EQUIP_ERR_ITEM_LOCKED, pItem, NULL); + pUser->SendEquipError(EQUIP_ERR_ITEM_LOCKED, item, NULL); return; } } - if (pItem->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_WRAPPED))// wrapped? + if (item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FLAG_WRAPPED))// wrapped? { - QueryResult result = CharacterDatabase.PQuery("SELECT entry, flags FROM character_gifts WHERE item_guid = '%u'", pItem->GetGUIDLow()); + QueryResult result = CharacterDatabase.PQuery("SELECT entry, flags FROM character_gifts WHERE item_guid = '%u'", item->GetGUIDLow()); if (result) { Field* fields = result->Fetch(); uint32 entry = fields[0].GetUInt32(); uint32 flags = fields[1].GetUInt32(); - pItem->SetUInt64Value(ITEM_FIELD_GIFTCREATOR, 0); - pItem->SetEntry(entry); - pItem->SetUInt32Value(ITEM_FIELD_FLAGS, flags); - pItem->SetState(ITEM_CHANGED, pUser); + item->SetUInt64Value(ITEM_FIELD_GIFTCREATOR, 0); + item->SetEntry(entry); + item->SetUInt32Value(ITEM_FIELD_FLAGS, flags); + item->SetState(ITEM_CHANGED, pUser); } else { - sLog->outError("Wrapped item %u don't have record in character_gifts table and will deleted", pItem->GetGUIDLow()); - pUser->DestroyItem(pItem->GetBagSlot(), pItem->GetSlot(), true); + sLog->outError("Wrapped item %u don't have record in character_gifts table and will deleted", item->GetGUIDLow()); + pUser->DestroyItem(item->GetBagSlot(), item->GetSlot(), true); return; } - CharacterDatabase.PExecute("DELETE FROM character_gifts WHERE item_guid = '%u'", pItem->GetGUIDLow()); + + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GIFT); + + stmt->setUInt32(0, item->GetGUIDLow()); + + CharacterDatabase.Execute(stmt); } else - pUser->SendLoot(pItem->GetGUID(), LOOT_CORPSE); + pUser->SendLoot(item->GetGUID(), LOOT_CORPSE); } void WorldSession::HandleGameObjectUseOpcode(WorldPacket & recv_data) diff --git a/src/server/game/Server/WorldSession.cpp b/src/server/game/Server/WorldSession.cpp index 14c86286718..3288224e1f2 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; } @@ -503,7 +529,13 @@ void WorldSession::LogoutPlayer(bool Save) ///- Since each account can only have one online character at any given time, ensure all characters for active account are marked as offline //No SQL injection as AccountId is uint32 - CharacterDatabase.PExecute("UPDATE characters SET online = 0 WHERE account = '%u'", GetAccountId()); + + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_ACCOUNT_ONLINE); + + stmt->setUInt32(0, GetAccountId()); + + CharacterDatabase.Execute(stmt); + sLog->outDebug(LOG_FILTER_NETWORKIO, "SESSION: Sent SMSG_LOGOUT_COMPLETE Message"); } @@ -982,7 +1014,7 @@ void WorldSession::InitializeQueryCallbackParameters() void WorldSession::ProcessQueryCallbacks() { - QueryResult result; + PreparedQueryResult result; //! HandleCharEnumOpcode if (_charEnumCallback.ready()) @@ -994,9 +1026,8 @@ void WorldSession::ProcessQueryCallbacks() if (_charCreateCallback.IsReady()) { - PreparedQueryResult pResult; - _charCreateCallback.GetResult(pResult); - HandleCharCreateCallback(pResult, _charCreateCallback.GetParam()); + _charCreateCallback.GetResult(result); + HandleCharCreateCallback(result, _charCreateCallback.GetParam()); // Don't call FreeResult() here, the callback handler will do that depending on the events in the callback chain } diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h index 4a83c2d4092..ebed71c7da3 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(){}; }; @@ -304,7 +301,7 @@ class WorldSession // Pet void SendPetNameQuery(uint64 guid, uint32 petnumber); void SendStablePet(uint64 guid); - void SendStablePetCallback(QueryResult result, uint64 guid); + void SendStablePetCallback(PreparedQueryResult result, uint64 guid); void SendStableResult(uint8 guid); bool CheckStableMaster(uint64 guid); @@ -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,13 +585,13 @@ 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 HandleUnstablePetCallback(PreparedQueryResult result, uint32 petId); void HandleBuyStableSlot(WorldPacket& recvPacket); void HandleStableRevivePet(WorldPacket& recvPacket); void HandleStableSwapPet(WorldPacket& recvPacket); - void HandleStableSwapPetCallback(QueryResult result, uint32 petnumber); + void HandleStableSwapPetCallback(PreparedQueryResult result, uint32 petId); void HandleDuelAcceptedOpcode(WorldPacket& recvPacket); void HandleDuelCancelledOpcode(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; - QueryCallback<QueryResult, uint32> _unstablePetCallback; - QueryCallback<QueryResult, uint32> _stableSwapCallback; - QueryCallback<QueryResult, uint64> _sendStabledPetCallback; - QueryCallback<PreparedQueryResult, CharacterCreateInfo*> _charCreateCallback; + PreparedQueryResultFuture _charEnumCallback; + PreparedQueryResultFuture _addIgnoreCallback; + PreparedQueryResultFuture _stablePetCallback; + QueryCallback<PreparedQueryResult, std::string> _charRenameCallback; + QueryCallback<PreparedQueryResult, std::string> _addFriendCallback; + QueryCallback<PreparedQueryResult, uint32> _unstablePetCallback; + QueryCallback<PreparedQueryResult, uint32> _stableSwapCallback; + QueryCallback<PreparedQueryResult, uint64> _sendStabledPetCallback; + QueryCallback<PreparedQueryResult, CharacterCreateInfo*, true> _charCreateCallback; QueryResultHolderFuture _charLoginCallback; private: diff --git a/src/server/game/Server/WorldSocket.cpp b/src/server/game/Server/WorldSocket.cpp index 0ddc03e3d5c..e0ba9eaaaa4 100755 --- a/src/server/game/Server/WorldSocket.cpp +++ b/src/server/game/Server/WorldSocket.cpp @@ -889,7 +889,13 @@ int WorldSocket::HandleAuthSession (WorldPacket& recvPacket) if (mutetime < 0) { mutetime = time(NULL) + llabs(mutetime); - LoginDatabase.PExecute("UPDATE account SET mutetime = " SI64FMTD " WHERE id = '%u'", mutetime, id); + + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPDATE_MUTE_TIME); + + stmt->setInt64(0, mutetime); + stmt->setUInt32(1, id); + + LoginDatabase.Execute(stmt); } locale = LocaleConstant (fields[8].GetUInt8()); @@ -985,14 +991,13 @@ int WorldSocket::HandleAuthSession (WorldPacket& recvPacket) isRecruiter = true; // Update the last_ip in the database - // No SQL injection, username escaped. - LoginDatabase.EscapeString (address); - LoginDatabase.PExecute ("UPDATE account " - "SET last_ip = '%s' " - "WHERE username = '%s'", - address.c_str(), - safe_account.c_str()); + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(LOGIN_UPDATE_LAST_IP); + + stmt->setString(0, address); + stmt->setString(1, account); + + CharacterDatabase.Execute(stmt); // NOTE ATM the socket is single-threaded, have this in mind ... ACE_NEW_RETURN (m_Session, WorldSession (id, this, AccountTypes(security), expansion, mutetime, locale, recruiter, isRecruiter), -1); 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..de49b2cf579 100755 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -2033,7 +2033,7 @@ uint32 Spell::SelectEffectTargets(uint32 i, SpellImplicitTargetInfo const& cur) float max_dis = m_spellInfo->GetMaxRange(true); float dis = (float)rand_norm() * (max_dis - min_dis) + min_dis; float x, y, z, angle; - angle = (float)rand_norm() * static_cast<float>(M_PI * 70.0f / 180.0f) - static_cast<float>(M_PI * 35.0f / 180.0f); + angle = (float)rand_norm() * static_cast<float>(M_PI * 35.0f / 180.0f) - static_cast<float>(M_PI * 17.5f / 180.0f); m_caster->GetClosePoint(x, y, z, DEFAULT_WORLD_OBJECT_SIZE, dis, angle); m_targets.SetDst(x, y, z, m_caster->GetOrientation()); break; @@ -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 058ddf7d269..8976f90690c 100755 --- a/src/server/game/Spells/SpellMgr.cpp +++ b/src/server/game/Spells/SpellMgr.cpp @@ -3149,6 +3149,9 @@ void SpellMgr::LoadDbcDataCorrections() case 64904: // Hymn of Hope spellInfo->EffectApplyAuraName[EFFECT_1] = SPELL_AURA_MOD_INCREASE_ENERGY_PERCENT; break; + case 19465: // Improved Stings (Rank 2) + spellInfo->EffectImplicitTargetA[EFFECT_2] = TARGET_UNIT_CASTER; + break; case 30421: // Nether Portal - Perseverence spellInfo->EffectBasePoints[2] += 30000; break; @@ -3227,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/Tickets/TicketMgr.cpp b/src/server/game/Tickets/TicketMgr.cpp index 10c1f4a1dfd..c657248c595 100755 --- a/src/server/game/Tickets/TicketMgr.cpp +++ b/src/server/game/Tickets/TicketMgr.cpp @@ -207,7 +207,10 @@ void TicketMgr::ResetTickets() sTicketMgr->RemoveTicket(itr->second->GetId()); _lastTicketId = 0; - CharacterDatabase.PExecute("TRUNCATE TABLE gm_tickets"); + + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ALL_GM_TICKETS); + + CharacterDatabase.Execute(stmt); } void TicketMgr::LoadTickets() diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index a139c50fb3e..9ad847615d1 100755 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -2687,7 +2687,10 @@ void World::InitRandomBGResetTime() void World::ResetDailyQuests() { sLog->outDetail("Daily quests reset for all characters."); - CharacterDatabase.Execute("DELETE FROM character_queststatus_daily"); + + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_QUEST_STATUS_DAILY); + CharacterDatabase.Execute(stmt); + for (SessionMap::const_iterator itr = m_sessions.begin(); itr != m_sessions.end(); ++itr) if (itr->second->GetPlayer()) itr->second->GetPlayer()->ResetDailyQuestStatus(); 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_account.cpp b/src/server/scripts/Commands/cs_account.cpp index ae3250ad7b7..bcef7ac9ba9 100644 --- a/src/server/scripts/Commands/cs_account.cpp +++ b/src/server/scripts/Commands/cs_account.cpp @@ -81,8 +81,13 @@ public: return false; } - // No SQL injection - LoginDatabase.PExecute("UPDATE account SET expansion = '%d' WHERE id = '%u'", expansion, accountId); + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPDATE_EXPANSION); + + stmt->setUInt8(0, uint8(expansion)); + stmt->setUInt32(1, accountId); + + LoginDatabase.Execute(stmt); + handler->PSendSysMessage(LANG_ACCOUNT_ADDON, expansion); return true; } @@ -242,17 +247,25 @@ public: } std::string param = (char*)args; - if (param == "on") - { - LoginDatabase.PExecute("UPDATE account SET locked = '1' WHERE id = '%d'", handler->GetSession()->GetAccountId()); - handler->PSendSysMessage(LANG_COMMAND_ACCLOCKLOCKED); - return true; - } - if (param == "off") + if (!param.empty()) { - LoginDatabase.PExecute("UPDATE account SET locked = '0' WHERE id = '%d'", handler->GetSession()->GetAccountId()); - handler->PSendSysMessage(LANG_COMMAND_ACCLOCKUNLOCKED); + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPDATE_ACCOUNT_LOCK); + + if (param == "on") + { + stmt->setBool(0, true); // locked + handler->PSendSysMessage(LANG_COMMAND_ACCLOCKLOCKED); + } + else if (param == "off") + { + stmt->setBool(0, false); // unlocked + handler->PSendSysMessage(LANG_COMMAND_ACCLOCKUNLOCKED); + } + + stmt->setUInt32(1, handler->GetSession()->GetAccountId()); + + LoginDatabase.Execute(stmt); return true; } 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/EasternKingdoms/blasted_lands.cpp b/src/server/scripts/EasternKingdoms/blasted_lands.cpp index 048fd8dfd2a..38a577b9ba9 100644 --- a/src/server/scripts/EasternKingdoms/blasted_lands.cpp +++ b/src/server/scripts/EasternKingdoms/blasted_lands.cpp @@ -72,6 +72,13 @@ public: /*###### ## npc_fallen_hero_of_horde ######*/ + +enum HeroesOfOld +{ + QUEST_HEROES_OF_OLD = 2702, + NPC_THUND_SPLITHOOF = 7750, +}; + #define GOSSIP_H_F1 "Why are you here?" #define GOSSIP_H_F2 "Continue story..." @@ -159,6 +166,14 @@ public: return true; } + bool OnQuestAccept(Player* /*player*/, Creature* creature, Quest const* quest) + { + if (quest->GetQuestId() == QUEST_HEROES_OF_OLD) + creature->SummonCreature(NPC_THUND_SPLITHOOF, -10630.3f, -2987.05f, 28.96f, 4.54f, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 9000000); + + return true; + } + }; void AddSC_blasted_lands() 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/desolace.cpp b/src/server/scripts/Kalimdor/desolace.cpp index 71372f1d9e4..5badc7fe725 100644 --- a/src/server/scripts/Kalimdor/desolace.cpp +++ b/src/server/scripts/Kalimdor/desolace.cpp @@ -25,6 +25,9 @@ EndScriptData */ /* ContentData npc_aged_dying_ancient_kodo +go_iruxos +npc_dalinda_malem +go_demon_portal EndContentData */ #include "ScriptPCH.h" @@ -168,22 +171,28 @@ public: }; /*###### -## go_iruxos. Quest 5381 +## go_iruxos +## Hand of Iruxos ######*/ +enum +{ + QUEST_HAND_IRUXOS = 5381, + NPC_DEMON_SPIRIT = 11876, +}; + class go_iruxos : public GameObjectScript { -public: - go_iruxos() : GameObjectScript("go_iruxos") { } + public: + go_iruxos() : GameObjectScript("go_iruxos") { } - bool OnGossipHello(Player* player, GameObject* /*pGO*/) - { - if (player->GetQuestStatus(5381) == QUEST_STATUS_INCOMPLETE) - player->SummonCreature(11876, player->GetInnPosX(), player->GetInnPosY(), player->GetInnPosZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 10000); + bool OnGossipHello(Player* player, GameObject* go) + { + if (player->GetQuestStatus(QUEST_HAND_IRUXOS) == QUEST_STATUS_INCOMPLETE && !go->FindNearestCreature(NPC_DEMON_SPIRIT, 25.0f, true)) + player->SummonCreature(NPC_DEMON_SPIRIT, go->GetPositionX(), go->GetPositionY(), go->GetPositionZ(), 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 10000); return true; - } - + } }; /*###### @@ -254,7 +263,34 @@ public: DoMeleeAttackIfReady(); } }; +}; + +/*###### +## go_demon_portal +######*/ +enum DemonPortal +{ + NPC_DEMON_GUARDIAN = 11937, + + QUEST_PORTAL_OF_THE_LEGION = 5581, +}; + +class go_demon_portal : public GameObjectScript +{ + public: + go_demon_portal() : GameObjectScript("go_demon_portal") { } + + bool OnGossipHello(Player* player, GameObject* go) + { + if (player->GetQuestStatus(QUEST_PORTAL_OF_THE_LEGION) == QUEST_STATUS_INCOMPLETE && !go->FindNearestCreature(NPC_DEMON_GUARDIAN, 5.0f, true)) + { + if (Creature* guardian = player->SummonCreature(NPC_DEMON_GUARDIAN, go->GetPositionX(), go->GetPositionY(), go->GetPositionZ(), 0.0f, TEMPSUMMON_DEAD_DESPAWN, 0)) + guardian->AI()->AttackStart(player); + } + + return true; + } }; void AddSC_desolace() @@ -262,4 +298,5 @@ void AddSC_desolace() new npc_aged_dying_ancient_kodo(); new go_iruxos(); new npc_dalinda(); + new go_demon_portal(); } 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/blades_edge_mountains.cpp b/src/server/scripts/Outland/blades_edge_mountains.cpp index f94a7d2725c..87304a3f721 100644 --- a/src/server/scripts/Outland/blades_edge_mountains.cpp +++ b/src/server/scripts/Outland/blades_edge_mountains.cpp @@ -30,6 +30,7 @@ npc_daranelle npc_overseer_nuaar npc_saikkal_the_elder go_legion_obelisk +go_thunderspike EndContentData */ #include "ScriptPCH.h" @@ -537,9 +538,30 @@ public: }; /*###### -## AddSC +## go_thunderspike ######*/ +enum TheThunderspike +{ + NPC_GOR_GRIMGUT = 21319, + QUEST_THUNDERSPIKE = 10526, +}; + +class go_thunderspike : public GameObjectScript +{ + public: + go_thunderspike() : GameObjectScript("go_thunderspike") { } + + bool OnGossipHello(Player* player, GameObject* go) + { + if (player->GetQuestStatus(QUEST_THUNDERSPIKE) == QUEST_STATUS_INCOMPLETE && !go->FindNearestCreature(NPC_GOR_GRIMGUT, 25.0f, true)) + if (Creature* gorGrimgut = go->SummonCreature(NPC_GOR_GRIMGUT, -2413.4f, 6914.48f, 25.01f, 3.67f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 300000)) + gorGrimgut->AI()->AttackStart(player); + + return true; + } +}; + void AddSC_blades_edge_mountains() { new mobs_bladespire_ogre(); @@ -550,4 +572,5 @@ void AddSC_blades_edge_mountains() new go_legion_obelisk(); new npc_bloodmaul_brutebane(); new npc_ogre_brute(); + new go_thunderspike(); } 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/Outland/netherstorm.cpp b/src/server/scripts/Outland/netherstorm.cpp index 5f2626c0039..e5ee8d19c59 100644 --- a/src/server/scripts/Outland/netherstorm.cpp +++ b/src/server/scripts/Outland/netherstorm.cpp @@ -29,6 +29,7 @@ go_manaforge_control_console npc_commander_dawnforge npc_bessy npc_maxx_a_million +go_captain_tyralius_prison EndContentData */ #include "ScriptPCH.h" @@ -1046,6 +1047,36 @@ public: } }; +/*###### +## go_captain_tyralius_prison +######*/ + +enum CaptainTyralius +{ + NPC_CAPTAIN_TYRALIUS = 20787, + SAY_FREE = 0, +}; + +class go_captain_tyralius_prison : public GameObjectScript +{ + public: + go_captain_tyralius_prison() : GameObjectScript("go_captain_tyralius_prison") { } + + bool OnGossipHello(Player* player, GameObject* go) + { + if (Creature* tyralius = go->FindNearestCreature(NPC_CAPTAIN_TYRALIUS, 1.0f)) + { + go->UseDoorOrButton(); + + player->KilledMonsterCredit(NPC_CAPTAIN_TYRALIUS, 0); + + tyralius->AI()->Talk(SAY_FREE); + tyralius->ForcedDespawn(8000); + } + return true; + } +}; + void AddSC_netherstorm() { new go_manaforge_control_console(); @@ -1056,4 +1087,5 @@ void AddSC_netherstorm() new mob_phase_hunter(); new npc_bessy(); new npc_maxx_a_million_escort(); + new go_captain_tyralius_prison(); } diff --git a/src/server/scripts/Outland/shadowmoon_valley.cpp b/src/server/scripts/Outland/shadowmoon_valley.cpp index 610cf684a77..ecbdb921567 100644 --- a/src/server/scripts/Outland/shadowmoon_valley.cpp +++ b/src/server/scripts/Outland/shadowmoon_valley.cpp @@ -635,26 +635,31 @@ public: # npc_karynaku ####*/ -enum eKarynaku +enum Karynaku { QUEST_ALLY_OF_NETHER = 10870, + QUEST_ZUHULED_THE_WACK = 10866, - TAXI_PATH_ID = 649 + NPC_ZUHULED_THE_WACKED = 11980, + + TAXI_PATH_ID = 649, }; class npc_karynaku : public CreatureScript { -public: - npc_karynaku() : CreatureScript("npc_karynaku") { } + public: + npc_karynaku() : CreatureScript("npc_karynaku") { } - bool OnQuestAccept(Player* player, Creature* /*creature*/, Quest const* quest) - { - if (quest->GetQuestId() == QUEST_ALLY_OF_NETHER) - player->ActivateTaxiPathTo(TAXI_PATH_ID); //player->ActivateTaxiPathTo(649); + bool OnQuestAccept(Player* player, Creature* creature, Quest const* quest) + { + if (quest->GetQuestId() == QUEST_ALLY_OF_NETHER) + player->ActivateTaxiPathTo(TAXI_PATH_ID); - return true; - } + if (quest->GetQuestId() == QUEST_ZUHULED_THE_WACK) + creature->SummonCreature(NPC_ZUHULED_THE_WACKED, -4204.94f, 316.397f, 122.508f, 1.309f, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 300000); + return true; + } }; /*#### 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/Spells/spell_quest.cpp b/src/server/scripts/Spells/spell_quest.cpp index 3b2cc5f5e00..ecdbd582b76 100644 --- a/src/server/scripts/Spells/spell_quest.cpp +++ b/src/server/scripts/Spells/spell_quest.cpp @@ -1026,6 +1026,54 @@ public: } }; +// http://old01.wowhead.com/quest=9452 - Red Snapper - Very Tasty! +enum RedSnapperVeryTasty +{ + SPELL_CAST_NET = 29866, + ITEM_RED_SNAPPER = 23614, + NPC_ANGRY_MURLOC = 17102, +}; + +class spell_q9452_cast_net: public SpellScriptLoader +{ + public: + spell_q9452_cast_net() : SpellScriptLoader("spell_q9452_cast_net") { } + + class spell_q9452_cast_net_SpellScript : public SpellScript + { + PrepareSpellScript(spell_q9452_cast_net_SpellScript) + + void HandleDummy(SpellEffIndex /*effIndex*/) + { + Player* caster = GetCaster()->ToPlayer(); + + if (!caster) + return; + + switch (urand(0, 2)) + { + case 0: case 1: + caster->AddItem(ITEM_RED_SNAPPER, 1); + break; + case 2: + if (Creature* murloc = caster->SummonCreature(NPC_ANGRY_MURLOC, caster->GetPositionX()+5, caster->GetPositionY(), caster->GetPositionZ(), 0.0f, TEMPSUMMON_MANUAL_DESPAWN, 120000)) + murloc->AI()->AttackStart(caster); + break; + } + } + + void Register() + { + OnEffectHit += SpellEffectFn(spell_q9452_cast_net_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_q9452_cast_net_SpellScript(); + } +}; + void AddSC_quest_spell_scripts() { new spell_q55_sacred_cleansing(); @@ -1050,4 +1098,5 @@ void AddSC_quest_spell_scripts() new spell_q12805_lifeblood_dummy(); new spell_q13280_13283_plant_battle_standard(); new spell_q14112_14145_chum_the_water(); + new spell_q9452_cast_net(); } diff --git a/src/server/scripts/World/areatrigger_scripts.cpp b/src/server/scripts/World/areatrigger_scripts.cpp index 517746dac55..9e3e64f1860 100644 --- a/src/server/scripts/World/areatrigger_scripts.cpp +++ b/src/server/scripts/World/areatrigger_scripts.cpp @@ -29,6 +29,9 @@ at_legion_teleporter 4560 Teleporter TO Invasion Point: Cataclysm at_stormwright_shelf q12741 at_last_rites q12019 at_sholazar_waygate q12548 +at_nats_landing q11209 +at_bring_your_orphan_to q910 q910 q1800 q1479 q1687 q1558 q10951 q10952 +at_brewfest EndContentData */ #include "ScriptPCH.h" @@ -257,6 +260,166 @@ class AreaTrigger_at_sholazar_waygate : public AreaTriggerScript } }; +/*###### +## at_nats_landing +######*/ + +enum NatsLanding +{ + QUEST_NATS_BARGAIN = 11209, + SPELL_FISH_PASTE = 42644, + NPC_LURKING_SHARK = 23928 +}; + +class AreaTrigger_at_nats_landing : public AreaTriggerScript +{ + public: + AreaTrigger_at_nats_landing() : AreaTriggerScript("at_nats_landing") { } + + bool OnTrigger(Player* player, AreaTriggerEntry const* trigger) + { + if (!player->isAlive() || !player->HasAura(SPELL_FISH_PASTE)) + return false; + + if (player->GetQuestStatus(QUEST_NATS_BARGAIN) == QUEST_STATUS_INCOMPLETE) + { + if (!player->FindNearestCreature(NPC_LURKING_SHARK, 20.0f)) + { + if (Creature* shark = player->SummonCreature(NPC_LURKING_SHARK, -4246.243f, -3922.356f, -7.488f, 5.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 100000)) + shark->AI()->AttackStart(player); + + return false; + } + } + return true; + } +}; + +/*###### +## at_bring_your_orphan_to +######*/ + +enum BringYourOrphanTo +{ + QUEST_DOWN_AT_THE_DOCKS = 910, + QUEST_GATEWAY_TO_THE_FRONTIER = 911, + QUEST_LORDAERON_THRONE_ROOM = 1800, + QUEST_BOUGHT_OF_ETERNALS = 1479, + QUEST_SPOOKY_LIGHTHOUSE = 1687, + QUEST_STONEWROUGHT_DAM = 1558, + QUEST_DARK_PORTAL_H = 10951, + QUEST_DARK_PORTAL_A = 10952, + + AT_DOWN_AT_THE_DOCKS = 3551, + AT_GATEWAY_TO_THE_FRONTIER = 3549, + AT_LORDAERON_THRONE_ROOM = 3547, + AT_BOUGHT_OF_ETERNALS = 3546, + AT_SPOOKY_LIGHTHOUSE = 3552, + AT_STONEWROUGHT_DAM = 3548, + AT_DARK_PORTAL = 4356, + + AURA_ORPHAN_OUT = 58818, +}; + +class AreaTrigger_at_bring_your_orphan_to : public AreaTriggerScript +{ + public: + AreaTrigger_at_bring_your_orphan_to() : AreaTriggerScript("at_bring_your_orphan_to") { } + + bool OnTrigger(Player* player, AreaTriggerEntry const* trigger) + { + uint32 questId = 0; + + if (player->isDead() || !player->HasAura(AURA_ORPHAN_OUT)) + return false; + + switch (trigger->id) + { + case AT_DOWN_AT_THE_DOCKS: + questId = QUEST_DOWN_AT_THE_DOCKS; + break; + case AT_GATEWAY_TO_THE_FRONTIER: + questId = QUEST_GATEWAY_TO_THE_FRONTIER; + break; + case AT_LORDAERON_THRONE_ROOM: + questId = QUEST_LORDAERON_THRONE_ROOM; + break; + case AT_BOUGHT_OF_ETERNALS: + questId = QUEST_BOUGHT_OF_ETERNALS; + break; + case AT_SPOOKY_LIGHTHOUSE: + questId = QUEST_SPOOKY_LIGHTHOUSE; + break; + case AT_STONEWROUGHT_DAM: + questId = QUEST_STONEWROUGHT_DAM; + break; + case AT_DARK_PORTAL: + questId = player->GetTeam() == ALLIANCE ? QUEST_DARK_PORTAL_A : QUEST_DARK_PORTAL_H; + break; + } + + if (questId && player->GetQuestStatus(questId) == QUEST_STATUS_INCOMPLETE) + player->AreaExploredOrEventHappens(questId); + + return true; + } +}; + +/*###### +## at_brewfest +######*/ + +enum Brewfest +{ + NPC_TAPPER_SWINDLEKEG = 24711, + NPC_IPFELKOFER_IRONKEG = 24710, + + AT_BREWFEST_DUROTAR = 4829, + AT_BREWFEST_DUN_MOROGH = 4820, + + SAY_WELCOME = 4, + + AREATRIGGER_TALK_COOLDOWN = 5, // in seconds +}; + +class AreaTrigger_at_brewfest : public AreaTriggerScript +{ + public: + AreaTrigger_at_brewfest() : AreaTriggerScript("at_brewfest") + { + // Initialize for cooldown + _triggerTimes[AT_BREWFEST_DUROTAR] = _triggerTimes[AT_BREWFEST_DUN_MOROGH] = 0; + } + + bool OnTrigger(Player* player, AreaTriggerEntry const* trigger) + { + uint32 triggerId = trigger->id; + // Second trigger happened too early after first, skip for now + if (sWorld->GetGameTime() - _triggerTimes[triggerId] < AREATRIGGER_TALK_COOLDOWN) + return false; + + switch (triggerId) + { + case AT_BREWFEST_DUROTAR: + if (Creature* tapper = player->FindNearestCreature(NPC_TAPPER_SWINDLEKEG, 20.0f)) + tapper->AI()->Talk(SAY_WELCOME, player->GetGUID()); + break; + case AT_BREWFEST_DUN_MOROGH: + if (Creature* ipfelkofer = player->FindNearestCreature(NPC_IPFELKOFER_IRONKEG, 20.0f)) + ipfelkofer->AI()->Talk(SAY_WELCOME, player->GetGUID()); + break; + default: + break; + } + + _triggerTimes[triggerId] = sWorld->GetGameTime(); + return false; + } + + private: + std::map<uint32, time_t> _triggerTimes; +}; + void AddSC_areatrigger_scripts() { new AreaTrigger_at_coilfang_waterfall(); @@ -265,4 +428,7 @@ void AddSC_areatrigger_scripts() new AreaTrigger_at_scent_larkorwi(); new AreaTrigger_at_last_rites(); new AreaTrigger_at_sholazar_waygate(); + new AreaTrigger_at_nats_landing(); + new AreaTrigger_at_bring_your_orphan_to(); + new AreaTrigger_at_brewfest(); } diff --git a/src/server/scripts/World/go_scripts.cpp b/src/server/scripts/World/go_scripts.cpp index 3bb969977b6..e93dd2751e6 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 = 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_0); + (*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/item_scripts.cpp b/src/server/scripts/World/item_scripts.cpp index 4099c03384c..9bfa77271f5 100644 --- a/src/server/scripts/World/item_scripts.cpp +++ b/src/server/scripts/World/item_scripts.cpp @@ -24,7 +24,6 @@ SDCategory: Items EndScriptData */ /* ContentData -item_draenei_fishing_net(i23654) Hacklike implements chance to spawn item or creature item_nether_wraith_beacon(i31742) Summons creatures for quest Becoming a Spellfire Tailor (q10832) item_flying_machine(i34060, i34061) Engineering crafted flying machines item_gor_dreks_ointment(i30175) Protecting Our Own(q10488) @@ -81,45 +80,6 @@ public: }; /*##### -# item_draenei_fishing_net -#####*/ - -class item_draenei_fishing_net : public ItemScript -{ -public: - item_draenei_fishing_net() : ItemScript("item_draenei_fishing_net") { } - - //This is just a hack and should be removed from here. - //Creature/Item are in fact created before spell are sucessfully casted, without any checks at all to ensure proper/expected behavior. - bool OnUse(Player* player, Item* /*pItem*/, SpellCastTargets const& /*targets*/) - { - if (player->GetQuestStatus(9452) == QUEST_STATUS_INCOMPLETE) - { - if (urand(0, 99) < 35) - { - Creature* Murloc = player->SummonCreature(17102, player->GetPositionX(), player->GetPositionY()+20, player->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 10000); - if (Murloc) - Murloc->AI()->AttackStart(player); - } - else - { - ItemPosCountVec dest; - uint32 itemId = 23614; - InventoryResult msg = player->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, itemId, 1); - if (msg == EQUIP_ERR_OK) - { - if (Item* item = player->StoreNewItem(dest, itemId, true)) - player->SendNewItem(item, 1, false, true); - } - else - player->SendEquipError(msg, NULL, NULL, itemId); - } - } - return false; - } -}; - -/*##### # item_nether_wraith_beacon #####*/ @@ -452,7 +412,6 @@ public: void AddSC_item_scripts() { new item_only_for_flight(); - new item_draenei_fishing_net(); new item_nether_wraith_beacon(); new item_gor_dreks_ointment(); new item_incendiary_explosives(); diff --git a/src/server/scripts/World/npcs_special.cpp b/src/server/scripts/World/npcs_special.cpp index deb1e702ab9..03fc07c9582 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; @@ -2174,6 +2170,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 ######*/ @@ -2683,5 +2794,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..a128eda3b70 100755 --- a/src/server/shared/Database/DatabaseWorkerPool.h +++ b/src/server/shared/Database/DatabaseWorkerPool.h @@ -92,7 +92,7 @@ class DatabaseWorkerPool ++m_connectionCount[IDX_SYNCH]; } - sLog->outSQLDriver("Databasepool opened succesfuly. %u total connections running.", (m_connectionCount[IDX_SYNCH] + m_connectionCount[IDX_ASYNC])); + sLog->outSQLDriver("Databasepool opened successfully. %u total connections running.", (m_connectionCount[IDX_SYNCH] + m_connectionCount[IDX_ASYNC])); return res; } @@ -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..fb43a7286dd 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,15 @@ 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_PET_SLOTS_DETAIL, "SELECT owner, id, entry, level, name FROM character_pet WHERE owner = ? AND slot >= ? AND slot <= ? ORDER BY slot", CONNECTION_ASYNC); + PREPARE_STATEMENT(CHAR_GET_PET_ENTRY, "SELECT entry FROM character_pet WHERE owner = ? AND id = ? AND slot >= ? AND slot <= ?", CONNECTION_ASYNC); + PREPARE_STATEMENT(CHAR_GET_PET_SLOT_BY_ID, "SELECT slot, entry FROM character_pet WHERE owner = ? AND id = ?", 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); + PREPARE_STATEMENT(CHAR_DEL_QUEST_STATUS_DAILY, "DELETE FROM character_queststatus_daily", CONNECTION_ASYNC); // Start LoginQueryHolder content PREPARE_STATEMENT(CHAR_LOAD_PLAYER, "SELECT guid, account, name, race, class, gender, level, xp, money, playerBytes, playerBytes2, playerFlags, " @@ -86,6 +95,7 @@ void CharacterDatabaseConnection::DoPrepareStatements() PREPARE_STATEMENT(CHAR_ADD_MAIL, "INSERT INTO mail(id, messageType, stationery, mailTemplateId, sender, receiver, subject, body, has_items, expire_time, deliver_time, money, cod, checked) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC) PREPARE_STATEMENT(CHAR_DEL_MAIL, "DELETE FROM mail WHERE id = ?", CONNECTION_ASYNC) PREPARE_STATEMENT(CHAR_ADD_MAIL_ITEM, "INSERT INTO mail_items(mail_id, item_guid, receiver) VALUES (?, ?, ?)", CONNECTION_ASYNC) + PREPARE_STATEMENT(CHAR_DEL_INVALID_MAIL_ITEM, "DELETE FROM mail_items WHERE item_guid = ?", CONNECTION_ASYNC); PREPARE_STATEMENT(CHAR_DEL_EMPTY_EXPIRED_MAIL, "DELETE FROM mail WHERE expire_time < ? AND has_items = 0 AND body = ''", CONNECTION_ASYNC) PREPARE_STATEMENT(CHAR_GET_EXPIRED_MAIL, "SELECT id, messageType, sender, receiver, has_items, expire_time, cod, checked, mailTemplateId FROM mail WHERE expire_time < ?", CONNECTION_SYNCH) PREPARE_STATEMENT(CHAR_GET_EXPIRED_MAIL_ITEMS, "SELECT item_guid, itemEntry, mail_id FROM mail_items mi INNER JOIN item_instance ii ON ii.guid = mi.item_guid LEFT JOIN mail mm ON mi.mail_id = mm.id WHERE mm.id IS NOT NULL AND mm.expire_time < ?", CONNECTION_SYNCH) @@ -111,6 +121,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 @@ -316,4 +328,35 @@ void CharacterDatabaseConnection::DoPrepareStatements() "arenaPoints=?,totalHonorPoints=?,todayHonorPoints=?,yesterdayHonorPoints=?,totalKills=?,todayKills=?,yesterdayKills=?,chosenTitle=?,knownCurrencies=?," "watchedFaction=?,drunk=?,health=?,power1=?,power2=?,power3=?,power4=?,power5=?,power6=?,power7=?,latency=?,speccount=?,activespec=?,exploredZones=?," "equipmentCache=?,ammoId=?,knownTitles=?,actionBars=?,grantableLevels=?,online=? WHERE guid=?", CONNECTION_ASYNC); + + PREPARE_STATEMENT(CHAR_UPDATE_AT_LOGIN_FLAG, "UPDATE characters SET at_login = at_login | ? WHERE guid = ?", CONNECTION_ASYNC); + PREPARE_STATEMENT(CHAR_UPDATE_ALL_AT_LOGIN_FLAGS, "UPDATE characters SET at_login = at_login | ?", CONNECTION_ASYNC); + PREPARE_STATEMENT(CHAR_ADD_BUG_REPORT, "INSERT INTO bugreport (type, content) VALUES(?, ?)", CONNECTION_ASYNC); + PREPARE_STATEMENT(CHAR_UPD_PETITION_NAME, "UPDATE petition SET name = ? WHERE petitionguid = ?", CONNECTION_ASYNC); + PREPARE_STATEMENT(CHAR_ADD_PETITION_SIGNATURE, "INSERT INTO petition_sign (ownerguid, petitionguid, playerguid, player_account) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC); + PREPARE_STATEMENT(CHAR_UPD_ACCOUNT_ONLINE, "UPDATE characters SET online = 0 WHERE account = ?", CONNECTION_ASYNC); + PREPARE_STATEMENT(CHAR_ADD_GROUP, "INSERT INTO groups (guid, leaderGuid, lootMethod, looterGuid, lootThreshold, icon1, icon2, icon3, icon4, icon5, icon6, icon7, icon8, groupType, difficulty, raiddifficulty) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); + PREPARE_STATEMENT(CHAR_ADD_GROUP_MEMBER, "INSERT INTO group_member (guid, memberGuid, memberFlags, subgroup, roles) VALUES(?, ?, ?, ?, ?)", CONNECTION_ASYNC); + PREPARE_STATEMENT(CHAR_DEL_GROUP_MEMBER, "DELETE FROM group_member WHERE memberGuid = ?", CONNECTION_ASYNC); + PREPARE_STATEMENT(CHAR_DEL_GROUP_INSTANCE_PERM_BINDING, "DELETE FROM group_instance WHERE guid = ? AND (permanent = 1 OR instance IN (SELECT instance FROM character_instance WHERE guid = ?))", CONNECTION_ASYNC); + PREPARE_STATEMENT(CHAR_UPDATE_GROUP_LEADER, "UPDATE groups SET leaderGuid = ? WHERE guid = ?", CONNECTION_ASYNC); + PREPARE_STATEMENT(CHAR_UPDATE_GROUP_TYPE, "UPDATE groups SET groupType = ? WHERE guid = ?", CONNECTION_ASYNC); + PREPARE_STATEMENT(CHAR_UPDATE_GROUP_MEMBER_SUBGROUP, "UPDATE group_member SET subgroup = ? WHERE memberGuid = ?", CONNECTION_ASYNC); + PREPARE_STATEMENT(CHAR_UPDATE_GROUP_MEMBER_FLAG, "UPDATE group_member SET memberFlags = ? WHERE memberGuid = ?", CONNECTION_ASYNC); + PREPARE_STATEMENT(CHAR_UPDATE_GROUP_DIFFICULTY, "UPDATE groups SET difficulty = ? WHERE guid = ?", CONNECTION_ASYNC); + PREPARE_STATEMENT(CHAR_UPDATE_GROUP_RAID_DIFFICULTY, "UPDATE groups SET raiddifficulty = ? WHERE guid = ?", CONNECTION_ASYNC); + PREPARE_STATEMENT(CHAR_DEL_ALL_GM_TICKETS, "TRUNCATE TABLE gm_tickets", CONNECTION_ASYNC); + PREPARE_STATEMENT(CHAR_DEL_INVALID_SPELL, "DELETE FROM character_talent WHERE spell = ?", CONNECTION_ASYNC); + PREPARE_STATEMENT(CHAR_UPDATE_DELETE_INFO, "UPDATE characters SET deleteInfos_Name = name, deleteInfos_Account = account, deleteDate = UNIX_TIMESTAMP(), name = '', account = 0 WHERE guid = ?", CONNECTION_ASYNC); + PREPARE_STATEMENT(CHAR_UPDATE_ZONE, "UPDATE characters SET zone = ? WHERE guid = ?", CONNECTION_ASYNC); + PREPARE_STATEMENT(CHAR_UPDATE_LEVEL, "UPDATE characters SET level = ?, xp = 0 WHERE guid = ?", CONNECTION_ASYNC); + PREPARE_STATEMENT(CHAR_DEL_INVALID_ACHIEV_PROGRESS_CRITERIA, "DELETE FROM character_achievement_progress WHERE criteria = ?", CONNECTION_ASYNC); + PREPARE_STATEMENT(CHAR_DEL_INVALID_ACHIEVMENT, "DELETE FROM character_achievement WHERE achievement = ?", CONNECTION_ASYNC); + PREPARE_STATEMENT(CHAR_ADD_ADDON, "INSERT INTO addons (name, crc) VALUES (?, ?)", CONNECTION_ASYNC); + PREPARE_STATEMENT(CHAR_DEL_INVALID_PET_SPELL, "DELETE FROM pet_spell WHERE spell = ?", CONNECTION_ASYNC); + PREPARE_STATEMENT(CHAR_DEL_GROUP_INSTANCE_BY_INSTANCE, "DELETE FROM group_instance WHERE instance = ?", CONNECTION_ASYNC); + PREPARE_STATEMENT(CHAR_DEL_GROUP_INSTANCE_BY_GUID, "DELETE FROM group_instance WHERE guid = ? AND instance = ?", CONNECTION_ASYNC); + PREPARE_STATEMENT(CHAR_ADD_GROUP_INSTANCE, "REPLACE INTO group_instance (guid, instance, permanent) VALUES (?, ?, ?)", CONNECTION_ASYNC); + PREPARE_STATEMENT(CHAR_UPDATE_INSTANCE_RESETTIME, "UPDATE instance SET resettime = ? WHERE id = ?", CONNECTION_ASYNC); + PREPARE_STATEMENT(CHAR_UPDATE_GLOBAL_INSTANCE_RESETTIME, "UPDATE instance_reset SET resettime = ? WHERE mapid = ? AND difficulty = ?", CONNECTION_ASYNC); } diff --git a/src/server/shared/Database/Implementation/CharacterDatabase.h b/src/server/shared/Database/Implementation/CharacterDatabase.h index f06a17aa924..691b1f61706 100755 --- a/src/server/shared/Database/Implementation/CharacterDatabase.h +++ b/src/server/shared/Database/Implementation/CharacterDatabase.h @@ -56,6 +56,15 @@ 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_PET_SLOTS_DETAIL, + CHAR_GET_PET_ENTRY, + CHAR_GET_PET_SLOT_BY_ID, + CHAR_GET_FREE_NAME, + CHAR_GET_GUID_RACE_ACC_BY_NAME, + CHAR_DEL_QUEST_STATUS_DAILY, CHAR_LOAD_PLAYER, CHAR_LOAD_PLAYER_GROUP, CHAR_LOAD_PLAYER_BOUNDINSTANCES, @@ -95,6 +104,7 @@ enum CharacterDatabaseStatements CHAR_ADD_MAIL, CHAR_DEL_MAIL, CHAR_ADD_MAIL_ITEM, + CHAR_DEL_INVALID_MAIL_ITEM, CHAR_DEL_EMPTY_EXPIRED_MAIL, CHAR_GET_EXPIRED_MAIL, CHAR_GET_EXPIRED_MAIL_ITEMS, @@ -120,6 +130,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, @@ -267,6 +279,7 @@ enum CharacterDatabaseStatements CHAR_LOAD_GM_TICKETS, CHAR_ADD_GM_TICKET, CHAR_DEL_GM_TICKET, + CHAR_DEL_ALL_GM_TICKETS, CHAR_DEL_PLAYER_GM_TICKETS, CHAR_ADD_GM_SURVEY, @@ -278,6 +291,36 @@ enum CharacterDatabaseStatements CHAR_ADD_CHARACTER, CHAR_UPD_CHARACTER, + CHAR_UPDATE_AT_LOGIN_FLAG, + CHAR_UPDATE_ALL_AT_LOGIN_FLAGS, + CHAR_ADD_BUG_REPORT, + CHAR_UPD_PETITION_NAME, + CHAR_ADD_PETITION_SIGNATURE, + CHAR_UPD_ACCOUNT_ONLINE, + CHAR_ADD_GROUP, + CHAR_ADD_GROUP_MEMBER, + CHAR_DEL_GROUP_MEMBER, + CHAR_DEL_GROUP_INSTANCE_PERM_BINDING, + CHAR_UPDATE_GROUP_LEADER, + CHAR_UPDATE_GROUP_TYPE, + CHAR_UPDATE_GROUP_MEMBER_SUBGROUP, + CHAR_UPDATE_GROUP_MEMBER_FLAG, + CHAR_UPDATE_GROUP_DIFFICULTY, + CHAR_UPDATE_GROUP_RAID_DIFFICULTY, + CHAR_DEL_INVALID_SPELL, + CHAR_UPDATE_DELETE_INFO, + CHAR_UPDATE_ZONE, + CHAR_UPDATE_LEVEL, + CHAR_DEL_INVALID_ACHIEV_PROGRESS_CRITERIA, + CHAR_DEL_INVALID_ACHIEVMENT, + CHAR_ADD_ADDON, + CHAR_DEL_INVALID_PET_SPELL, + CHAR_DEL_GROUP_INSTANCE_BY_INSTANCE, + CHAR_DEL_GROUP_INSTANCE_BY_GUID, + CHAR_ADD_GROUP_INSTANCE, + CHAR_UPDATE_INSTANCE_RESETTIME, + CHAR_UPDATE_GLOBAL_INSTANCE_RESETTIME, + MAX_CHARACTERDATABASE_STATEMENTS, }; diff --git a/src/server/shared/Database/Implementation/LoginDatabase.cpp b/src/server/shared/Database/Implementation/LoginDatabase.cpp index 13cfe09914d..713d4a31e6d 100755 --- a/src/server/shared/Database/Implementation/LoginDatabase.cpp +++ b/src/server/shared/Database/Implementation/LoginDatabase.cpp @@ -45,4 +45,15 @@ void LoginDatabaseConnection::DoPrepareStatements() PREPARE_STATEMENT(LOGIN_DEL_REALMCHARACTERS, "DELETE FROM realmcharacters WHERE acctid = ? AND realmid = ?", CONNECTION_ASYNC) PREPARE_STATEMENT(LOGIN_ADD_REALMCHARACTERS, "INSERT INTO realmcharacters (numchars, acctid, realmid) VALUES (?, ?, ?)", CONNECTION_ASYNC) PREPARE_STATEMENT(LOGIN_GET_SUM_REALMCHARS, "SELECT SUM(numchars) FROM realmcharacters WHERE acctid = ?", CONNECTION_ASYNC); + PREPARE_STATEMENT(LOGIN_ADD_ACCOUNT, "INSERT INTO account(username, sha_pass_hash, joindate) VALUES(?, ?, NOW())", CONNECTION_ASYNC); + PREPARE_STATEMENT(LOGIN_ADD_REALM_CHARS, "INSERT INTO realmcharacters (realmid, acctid, numchars) SELECT realmlist.id, account.id, 0 FROM realmlist, account LEFT JOIN realmcharacters ON acctid=account.id WHERE acctid IS NULL", CONNECTION_ASYNC); + PREPARE_STATEMENT(LOGIN_DEL_OLD_BANS, "DELETE FROM ip_banned WHERE unbandate <= UNIX_TIMESTAMP() AND unbandate<>bandate", CONNECTION_ASYNC); + PREPARE_STATEMENT(LOGIN_DEL_OLD_IP_BANS, "DELETE FROM ip_banned WHERE unbandate <= UNIX_TIMESTAMP() AND unbandate<>bandate", CONNECTION_ASYNC); + PREPARE_STATEMENT(LOGIN_UPDATE_EXPANSION, "UPDATE account SET expansion = ? WHERE id = ?", CONNECTION_ASYNC); + PREPARE_STATEMENT(LOGIN_UPDATE_ACCOUNT_LOCK, "UPDATE account SET locked = ? WHERE id = ?", CONNECTION_ASYNC); + PREPARE_STATEMENT(LOGIN_ADD_LOG, "INSERT INTO logs (time, realm, type, string) VALUES (UNIX_TIMESTAMP(), ? , ?, ?)", CONNECTION_ASYNC); + PREPARE_STATEMENT(LOGIN_UPDATE_USERNAME, "UPDATE account SET v = 0, s = 0, username = ?, sha_pass_hash = ? WHERE id = ?", CONNECTION_ASYNC); + PREPARE_STATEMENT(LOGIN_UPDATE_PASSWORD, "UPDATE account SET v = 0, s = 0, sha_pass_hash = ? WHERE id = ?", CONNECTION_ASYNC); + PREPARE_STATEMENT(LOGIN_UPDATE_MUTE_TIME, "UPDATE account SET mutetime = ? WHERE id = ?", CONNECTION_ASYNC); + PREPARE_STATEMENT(LOGIN_UPDATE_LAST_IP, "UPDATE account SET last_ip = ? WHERE username = ?", CONNECTION_ASYNC); } diff --git a/src/server/shared/Database/Implementation/LoginDatabase.h b/src/server/shared/Database/Implementation/LoginDatabase.h index b5f927ffe28..98d9c505fa0 100755 --- a/src/server/shared/Database/Implementation/LoginDatabase.h +++ b/src/server/shared/Database/Implementation/LoginDatabase.h @@ -65,6 +65,17 @@ enum LoginDatabaseStatements LOGIN_DEL_REALMCHARACTERS, LOGIN_ADD_REALMCHARACTERS, LOGIN_GET_SUM_REALMCHARS, + LOGIN_ADD_ACCOUNT, + LOGIN_ADD_REALM_CHARS, + LOGIN_DEL_OLD_BANS, + LOGIN_DEL_OLD_IP_BANS, + LOGIN_UPDATE_EXPANSION, + LOGIN_UPDATE_ACCOUNT_LOCK, + LOGIN_ADD_LOG, + LOGIN_UPDATE_USERNAME, + LOGIN_UPDATE_PASSWORD, + LOGIN_UPDATE_MUTE_TIME, + LOGIN_UPDATE_LAST_IP, MAX_LOGINDATABASE_STATEMENTS, }; diff --git a/src/server/shared/Database/Implementation/WorldDatabase.cpp b/src/server/shared/Database/Implementation/WorldDatabase.cpp index ebf60e3d20e..5df8299310f 100755 --- a/src/server/shared/Database/Implementation/WorldDatabase.cpp +++ b/src/server/shared/Database/Implementation/WorldDatabase.cpp @@ -26,6 +26,8 @@ void WorldDatabaseConnection::DoPrepareStatements() PREPARE_STATEMENT(WORLD_DEL_CRELINKED_RESPAWN, "DELETE FROM linked_respawn WHERE guid = ?", CONNECTION_ASYNC) PREPARE_STATEMENT(WORLD_REP_CRELINKED_RESPAWN, "REPLACE INTO linked_respawn (guid, linkedGuid) VALUES (?, ?)", CONNECTION_ASYNC) PREPARE_STATEMENT(WORLD_LOAD_CRETEXT, "SELECT entry, groupid, id, text, type, language, probability, emote, duration, sound FROM creature_text", CONNECTION_SYNCH) - PREPARE_STATEMENT(WORLD_LOAD_SMART_SCRIPTS, "SELECT entryorguid, source_type, id, link, event_type, event_phase_mask, event_chance, event_flags, event_param1, event_param2, event_param3, event_param4, action_type, action_param1, action_param2, action_param3, action_param4, action_param5, action_param6, target_type, target_param1, target_param2, target_param3, target_x, target_y, target_z, target_o FROM smart_scripts ORDER BY entryorguid, source_type, id, link", CONNECTION_SYNCH) - PREPARE_STATEMENT(WORLD_LOAD_SMARTAI_WP, "SELECT entry, pointid, position_x, position_y, position_z FROM waypoints ORDER BY entry, pointid", CONNECTION_SYNCH) + PREPARE_STATEMENT(WORLD_LOAD_SMART_SCRIPTS, "SELECT entryorguid, source_type, id, link, event_type, event_phase_mask, event_chance, event_flags, event_param1, event_param2, event_param3, event_param4, action_type, action_param1, action_param2, action_param3, action_param4, action_param5, action_param6, target_type, target_param1, target_param2, target_param3, target_x, target_y, target_z, target_o FROM smart_scripts ORDER BY entryorguid, source_type, id, link", CONNECTION_SYNCH) + PREPARE_STATEMENT(WORLD_LOAD_SMARTAI_WP, "SELECT entry, pointid, position_x, position_y, position_z FROM waypoints ORDER BY entry, pointid", CONNECTION_SYNCH) + PREPARE_STATEMENT(WORLD_DEL_GAMEOBJECT, "DELETE FROM gameobject WHERE guid = ?", CONNECTION_ASYNC); + PREPARE_STATEMENT(WORLD_DEL_EVENT_GAMEOBJECT, "DELETE FROM game_event_gameobject WHERE guid = ?", CONNECTION_ASYNC); } diff --git a/src/server/shared/Database/Implementation/WorldDatabase.h b/src/server/shared/Database/Implementation/WorldDatabase.h index 274ea4350c9..94d6365c081 100755 --- a/src/server/shared/Database/Implementation/WorldDatabase.h +++ b/src/server/shared/Database/Implementation/WorldDatabase.h @@ -48,6 +48,8 @@ enum WorldDatabaseStatements WORLD_LOAD_CRETEXT, WORLD_LOAD_SMART_SCRIPTS, WORLD_LOAD_SMARTAI_WP, + WORLD_DEL_GAMEOBJECT, + WORLD_DEL_EVENT_GAMEOBJECT, MAX_WORLDDATABASE_STATEMENTS, }; 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/Logging/Log.cpp b/src/server/shared/Logging/Log.cpp index 697e7616c40..11f2fc090b1 100755 --- a/src/server/shared/Logging/Log.cpp +++ b/src/server/shared/Logging/Log.cpp @@ -370,13 +370,17 @@ void Log::outDB(LogTypes type, const char * str) if (!str || type >= MAX_LOG_TYPES) return; - std::string new_str(str); - if (new_str.empty()) + std::string logStr(str); + if (logStr.empty()) return; - LoginDatabase.EscapeString(new_str); - LoginDatabase.PExecute("INSERT INTO logs (time, realm, type, string) " - "VALUES (" UI64FMTD ", %u, %u, '%s');", uint64(time(0)), realm, type, new_str.c_str()); + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_ADD_LOG); + + stmt->setInt32(0, realm); + stmt->setInt32(1, type); + stmt->setString(2, logStr); + + LoginDatabase.Execute(stmt); } void Log::outString(const char * str, ...) 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) |